Skip to content

What's New

Every Foundry Connect release, newest first. The Product Updates panel in the app carries a one line summary of each entry; this page has the full text.

[v2.23.0] – 2026-09-20

New Features

  • Connect Copilot, Codex And ChatGPT From Your Profile: The profile tab that connected Claude only is now Connect AI Assistants and covers four assistants from one page. The connector URL and the list of active connections are shared, because they were never Claude specific: Foundry Connect already registers each assistant automatically, so Copilot and Codex need no setup of their own. Choosing an assistant swaps just the steps for it, and the choice travels in the address bar so a link can open on a particular one. ChatGPT is listed with a plain explanation that no self serve route exists yet, rather than being left out and leaving people to search for one. The route is unchanged, so existing links and bookmarks still work. The sign in page that every assistant sees while authorising no longer greets them with another vendor's name. On the personal access credential route, the configuration snippet can now be generated for Copilot CLI and Codex CLI as well as Cursor and VS Code, and both of the new ones read the value from an environment variable instead of writing it into the file.
  • Example Output For A Process Revision: A process revision can now carry an example: a record of what it actually produced on one accepted test run. Capturing one stores a manifest listing every output file with its port, size and checksum, plus a self-contained report you can read in the process editor under a new Example tab, and publication commits both under examples/ in the revision's repository. The tab appears only once an example has been captured, so it never shows an empty panel, and it disappears again the moment the revision is edited, because an example describes exactly the content it was captured from and stops matching when that content changes. Nothing about the example is folded into the revision's content hash or its projection, so capturing one cannot invalidate the test evidence that justified it. The report is generated rather than copied from the run's own output, carries no scripts or external references, and is rendered inside a sandboxed frame, so it stays readable without being able to act.
  • AWS Account Bootstrap Command: provision-aws --foundation creates the account level resources Foundry Connect needs before any organization can use AWS: a shared compute launch template, a permissions boundary that caps every role created later, and a provisioning role that only a named administrator presenting MFA can assume. The running server gains no standing AWS privilege, and --plan shows the rendered template without creating anything.
  • Import Many Processes From A Repository At Once: The Import Process from Git wizard, opened from the pipeline workflow editor's sidebar toolbar, can now import several processes from one repository in a single pass instead of one at a time. Scanning a repository lists every published process revision together with a status of New, Update available, Already imported, UUID conflict, Contract refused, or Unreadable, so it is clear before selecting anything which rows can actually be imported; only New rows can be picked, and picking a second revision of an already selected process disables every other revision of that same one. Selection is bounded by a configurable batch cap that stays visible while picking. Before anything is written, one consent screen lists the full commit id of every selected revision, states plainly that the code will be stored but not executed, and requires both ticking an acknowledgement and choosing the menu group the imports go under before the Import button enables; each process is still checked again at import time, so a row can be reported as skipped or failed even after consent is given. The wizard cannot be closed while a batch is importing, so nobody loses track of a multi process import partway through, and the results screen afterward names every process by its own name and groups outcomes as imported, skipped, or failed, with the exact reason shown for anything that did not go through. If the browser stops waiting for a long import, the wizard says honestly that some processes may already be imported and asks for a fresh scan before anything can be sent again, instead of claiming nothing was imported. Scanning the same repository again correctly shows a previously imported process as already imported instead of offering it a second time. Importing a revision into a process that is already in Foundry now requires write access to that process: the import refuses, naming the process, when you cannot write to it. Git imports no longer follow HTTP redirects, so a repository that was renamed or moved on its host must be entered with its current URL.
  • Reading Stored Validation And Test Evidence Through The API: The API can now read back the evidence Foundry Connect stores for a process. GET /v1/process/{processId}/validations lists every stored validation, newest first, including ones later marked out of date with when and why, and GET /v1/process/{processId}/test-runs/{evidenceId} returns the test run evidence record whose id a compare response gives you. Both require permission to edit the process, and evidence from a different process is reported as not found.
  • Alternative Required Inputs: Pipeline authors can declare a group of alternative inputs with //* @style @required_one_of:{params.reads, params.bam_files} in a pipeline's nextflow.config or header script. The Run button stays disabled until at least one input in every declared group has a value, and hovering it shows a warning naming the alternatives. A group naming an input the pipeline does not have is ignored. Existing pipelines are unchanged until they declare a group.
  • Organization Run Environments On Their Own Head Node: Site administrators can now switch an organization's platform managed run environment from the shared head node to the organization's own head node, through a new connection endpoint that saves the connection as pending, checks it over SSH against the head node's pinned host key and, for an AWS assume-role credential, checks that a 12 hour session can be created, and only then activates it. Runs launch only while that connection is active, take every connection setting from the organization's environment, and keep the connection they launched with even if the environment changes later. Every SSH and SFTP connection to such an environment, including file browsing, uploads and report downloads, verifies the host key and refuses on a mismatch. Switching back returns the environment to the shared head node.
  • MCP tools that update fields on existing metadata records: The bundled MCP server can now edit metadata records that already exist. update_metadata_record changes the fields you send on one record and leaves the rest as they were. update_metadata_records does the same for many records in one collection, such as setting a group on every sample in a dataset. It checks every row before writing anything, so one invalid row means nothing changes, and then reports each record on its own. Both tools refuse the keys that identify a record or control who can see it.

Resolved Issues

  • Release Notes for v2.21.1: The release notes for v2.21.1 are available again. That version shipped without a changelog entry, so it never appeared in the Product Updates panel or on the documentation site, leaving an unexplained gap between v2.21.0 and v2.22.0. The original notes have been restored, and a new check makes sure a released version cannot go undocumented again.
  • Terminating And Restarting A Run That Lost Its Cluster Job: A run whose cluster job ended without Foundry noticing could get stuck with no way out: its status stayed on Connecting, the only action offered was Terminate, and Terminate always failed because the scheduler could no longer find the job to kill. Terminate now treats a scheduler that cannot find the job as proof the job has stopped, which is what it was asking for, rather than as a rejected request; it still refuses to mark a run Terminated while the cluster reports the job alive, and it still reports a genuine refusal such as a permissions error. Separately, a run showing Connecting can now be started again from the run page, which the server had always allowed but the button did not offer, so a run that loses contact with the cluster no longer needs an administrator to recover it.
  • Output Coverage Is Now Required Before A Revision Can Publish: A process test that asserted nothing at all used to pass, and that pass counted as evidence for publication, so a process could become publishable without a single meaningful check. The clearest case was an expected results document listing no outputs, but a document that checked one of five declared outputs had the same effect. Foundry Connect now works out how much of a process's declared output a test actually covers, records that alongside the pass or fail result, and requires complete coverage before the tested step of publication is met. Complete means every output the process declares as required is either checked by the document or carries an explicit waiver with a reason, which is how a genuinely nondeterministic output is handled. A document that declares no outputs at all is now refused when it is read, rather than quietly passing. The run's Test tab names any output the document does not cover, so the reason a revision cannot publish is visible on the same screen as the result, and waivers written by hand are no longer lost when a test result is promoted again.

Test runs recorded before this release carry no coverage information, and unknown coverage does not count as complete, so a revision resting on an older test run needs one new passing run before it can publish. A revision that already reached Ready to publish keeps that status, because publication status only ever moves forward, but its tested step now reports as unmet and publishing is refused until a run with complete coverage exists. Such a revision can still be edited, so adding the missing outputs or a waiver and testing again is the way through.

  • Starting A Run While An Administrator Binds The Same Run Environment: Launching a run and binding that run environment to a cloud boundary could collide, and the launch was always the side that lost: it failed with a database error while the administrator's change completed normally. The two paths claimed the same two records in opposite orders, which is the classic shape of a deadlock, and nothing retried the launch afterwards. The launch now claims them in the same order the bind does, so the two take turns instead of colliding. Where the timing overlaps, the launch waits for the administrator's change and then proceeds against it, which is the outcome an administrator expects when they bind an environment while somebody is starting a run on it.
  • Exporting A Process To A Repository That Has A Similarly Named Branch: Exporting a process to a git repository for the first time failed whenever the repository already held a branch whose name ended in the one being exported to, for example a feature/main branch when exporting to main. Git answers a question about main with that other branch too, and the export took the answer to mean main already existed, so it tried to build on a branch that was not there and stopped with an error. The export now checks for the exact branch name, so a first export creates the branch as intended and leaves the similarly named branch untouched.
  • Revision comparison diffs: Comparing two process revisions now produces a standard unified diff for each changed file, with real @@ -start,count +start,count @@ line ranges and a \ No newline at end of file marker where a file lacks a final newline, so the diff shown in the Revisions tab and returned by the MCP compare_process_revisions tool can be applied with git apply, and verifying a published revision no longer reports "Not verified" for committed files larger than 1 MiB.
  • A Capture Now Reports What It Did To Your Expected Results: Capturing a run as expected results now reports everything it did to tests/expected-results.yaml, at the moment it did it.

A port you waived is never captured. A waiver records that an output cannot be asserted on, usually because its content varies between runs, but a capture used to match that output like any other and delete the waiver, so the next comparison failed on content you had already said was not stable. Waived ports are now listed with your own reason and left alone, and choosing a file for one in the match dialog is refused.

The result also lists entries kept for ports the process no longer declares. Those entries are not inert: every entry in the document is graded, so a stale one fails the whole comparison while nothing on screen explained why. They are still kept rather than deleted, because removing one is your editorial decision, but now the capture tells you they are there and what they will do.

Where a capture has to change what you authored, it says so on the entry. Authoring text for an output larger than the 256KB inline limit still becomes exists, and an authored byte range that excludes the run being captured is still kept as written, but both now carry a note explaining what happened and what it means for the next comparison. The notes appear in the match dialog too, before anything is written.

Output names recorded by a capture are now stored so they can only match the file they came from. A name containing glob characters, data[1].tsv being the ordinary case in this field, was previously read back as a pattern: while the file existed an exact match saved it, but once that file was absent from a later run the pattern could bind a different output and grade the wrong file. Names with no special characters are stored exactly as before, and a glob you wrote by hand is still treated as a glob.

Finally, a re-capture keeps your document's order. Entries are refreshed where they already sit and only ports new to the document are added at the end, instead of the file being rewritten with captured entries first.

  • Abandoning A Launch While A Run Environment Is Deleted: Abandoning a stuck launch and deleting the run environment it belongs to could collide, and the abandon was always the side that lost: it failed with a database error while the deletion completed normally, and nothing retried it. The two paths claimed the same two records in opposite orders, which is the classic shape of a deadlock. The deletion now claims them in the same order the abandon does, so the two take turns instead of colliding. Where the timing overlaps, the deletion waits for the abandon to finish and then removes the environment, which is the outcome an operator expects when they abandon a launch on an environment somebody is removing. All three ways a run environment can be deleted are covered, including an administrator removing an organization's own environment.
  • Runs On Shared Run Environments Keep Their Launch Identity: A run launched on someone else's run environment, through a sealed or bring-your-own-key share, was handled after launch under a different SSH identity than the one it launched with. Checking on the run, stopping it, collecting its reports and deleting its intermediate files looked for a key under the wrong name, or connected without an account, so those steps failed or skipped the run silently. A bring-your-own-key share launched correctly before those later steps failed, while a sealed share's launch itself connected without its account. The identity a run launches with is now recorded on the run attempt and used for everything that happens to that attempt afterwards, so it keeps working even if the share is changed or removed while the run is in flight. Attempts launched before this release fall back to the identity their launch would have used.
  • Deleting An Organization Run Environment With Work In Flight: Deleting a run environment that belongs to an organization, whether by the organization's administrator or by a site administrator, skipped the check every other run environment delete already makes. It went ahead even while a workspace on that environment still had a job without an outcome, and it left the environment's workspaces looking ready on an environment that no longer existed. That delete now refuses with a message naming the workspace and job that are still in flight, and when nothing is in flight it archives the environment's workspaces before removing the environment, the same as deleting a personal or organization member's run environment.
  • A Running Run Stays On The Run Environment It Launched On: A run's settings accept a different run environment while the run is still in flight. Until now, everything that happened to the running attempt afterwards followed that new choice: checking on the run (including the checks restored after a server restart), a forced sync, stopping the run, collecting its reports, the daily search for jobs left running, and deleting its intermediate files. Those steps then looked for the job on a cluster that never had it, and stopping the run could report success while its job kept running on the original cluster. Each run attempt now records the run environment it launched on, and later operations on that attempt, checking on it (including after a restart), a forced sync, stopping it, collecting its reports, the daily search for jobs left running, and deleting its intermediate files, now use that run environment (its cluster connection) instead of the newly chosen one. The run's launch, work and publish directories still come from its current settings, though, so changing the run environment of a run that is still running can still point checks, report collection and cleanup at the wrong directories. It is better to wait for the run to finish, or stop it, before changing its run environment. Attempts launched before this release keep following the run's current run environment.
  • Run Logs On Shared Run Environments: When a run environment is shared with its connection details concealed, the run log of a launch on it showed the full connection command, which named the environment's SSH account and the location of its private key, and a failed connection repeated the account in its error lines. The run log now shows the command that runs on the cluster, the host name, and a placeholder for the key, on success and on failure alike, so the concealed account stays concealed.
  • Downloads From A Shared SSH Run Environment: On an SSH run environment shared with its connection details concealed, downloading a run's report or opening one of its input files failed with "SSH key ID is required", because both requests looked for the connection details the share hides from you. They now connect with the same account and key the run launched with, and still show you neither. A report download link created before this change keeps working on your own run environments; on a shared one it asks you to generate a new link.
  • AWS Batch hosts install the AWS CLI again: The launch template created by provision-aws --foundation installs the AWS CLI on every AWS Batch host, where Nextflow mounts it into task containers. The Amazon Linux 2023 image that AWS Batch boots does not include unzip, so the install stopped before the CLI existed and every task failed with exit code 127. The startup script now installs unzip when it is missing. Accounts that already applied the foundation need to rerun provision-aws --foundation and move their compute environments to the new launch template version.
  • Test Files With A YAML Mistake: When a process's expected results file or fixture manifest under tests/ had a YAML syntax mistake, such as a wrong indent or an unclosed bracket, comparing a run against expected results, capturing results, or promoting a run failed with a server error asking you to contact support. It now refuses with a message that names the file and the line and column where the YAML stopped parsing, so you can fix the file and try again.
  • Launch Errors On SSH Run Environments: When launching a run on an SSH run environment printed anything to its error output, the launch was repeated up to three times. The repeat could never succeed, because the first attempt had already unpacked and removed the uploaded run files, so the launch failed with a confusing message about a missing file instead of the original error, and a job the first attempt had actually submitted could be reported as a failed launch. The launch now runs once and reports the error it actually hit. A brief connection problem during launch now fails the launch rather than retrying it; launch the run again once the connection is back.
  • Matching One File To Several Outputs: When a run's outputs could not all be matched automatically and you pick files by hand in the Match outputs to files dialog, nothing told you if you chose the same file for two outputs, including a file an already matched output uses. The dialog now shows a warning naming the file and the outputs it is chosen for. You can still confirm, because sharing a file between outputs can be deliberate.
  • SGE Run Environments Are Refused Until SGE Is Supported: SGE was listed as an executor for run environments, but Foundry Connect has no way to submit jobs to SGE, so a run launched on an SGE environment never started. SGE is no longer offered when you create or edit a run environment, and saving one with SGE is refused with a message telling you to choose Local, LSF or SLURM. An environment already saved with SGE shows as not supported and can be switched to another executor, and launching a run on it is refused with the same advice. Runs already in flight on such an environment can still be viewed and terminated.
  • LSF Jobs Whose Host Lost Contact: When LSF reported a run's job as UNKWN, which means the scheduler lost contact with the host running it, Foundry Connect treated the job as finished over SSH and could end the run while the job was still running. A run in that state now keeps its status and keeps being checked. If LSF still reports the job as UNKWN after 24 hours, the run is marked failed, and its server log says the scheduler lost track of the job and that the job may still be running on the cluster.
  • Process Test Fixtures Are Read Only From the Run Data Directory: When a standalone process run is created from the fixtures declared in the process's tests, each fixture file is checked for its size and checksum before the run is created. Those checks now read only files inside the server's run data directory. A fixture anywhere else, including one reached through a symbolic link that leads out of that directory, is refused before the run is created, with a message that names the directory fixtures must live in and says nothing else about the file.
  • A Run Environment Cannot Be Deleted While Runs Are Still Running On It: Deleting a run environment used to go ahead even while a run launched on it was still initializing, submitted or running. That run then lost its run environment: checking on it, stopping it and cleaning up after it all failed, and its job kept running on the cluster with no way to stop it from the app. Deleting a run environment is now refused while any run on it is still in progress, wherever the delete comes from, and the message names the runs that block it. Terminate those runs or wait for them to finish, then delete the run environment again. A run whose cluster the app could not reach does not block the delete, because the app cannot terminate such a run either.
  • Keeping A Process's Ports On Save: A save that sends a process's complete input and output lists deletes every stored port it leaves out, so a save carrying the inputs with an empty output list used to delete every output without any warning, even when nobody meant to remove them. The server now refuses such a save unless it states that the side is meant to be empty, through the new removeAllInputParameters and removeAllOutputParameters fields on the process update request. The process editor sends them when you delete the last row on a side, so removing ports there works as before, and importing a pipeline that overwrites a revision mirrors the imported ports. Scripts and assistant tools that update a process through the API must send the matching field to empty a side on purpose.
  • Processes Imported From Git Can No Longer Leave or Be Rewritten Through .vf Files: A process imported from a git repository cannot run until Foundry Connect has a sandbox for imported code, but a .vf file could carry it past that rule, because a .vf file does not record where a process came from. Exporting a pipeline that holds a process imported from git, whether as a .vf download, as a pipeline download or as an export to a repository, is now refused with a message naming the repository the process came from, so it can be imported from git on the other installation instead. Importing a .vf file can no longer overwrite a process revision that was imported from git, and Replace is no longer offered for such a revision when an import reports a conflict, so the local revision is kept.
  • Saving A Run With A Null Run Environment Is Rejected: Saving a run through the API with runEnvironmentId set to null used to succeed and store a run environment the app could not read back. The run then showed a blank run environment, and its next launch failed with "Run Environment not found", as did stopping or cleaning up its older attempts. That save is now rejected with a validation error and the run keeps the run environment it had. To leave the run environment unchanged, omit the field or send an empty string, as the run page already does.
  • Pipeline Downloads Now Say Why They Were Refused: Since #722, exporting a pipeline that holds a process imported from git is refused with a message naming the process and the repository it came from. Download VF File and Download Pipeline both fetch the pipeline as a file, so that message never reached the screen: the error toast always said the generic "We couldn't export the Foundry file." or "If issue persists, please contact support." Both toasts now show the reason the server gave, and keep the generic text only when the server gave none.
  • Deleting A Process Revision In The Editor: Deleting the revision you had open in the pipeline editor's process drawer used to save the drawer's copy of the deleted revision over the revision it switched to, which removed every input and output of that remaining revision. The drawer now loads the remaining revision as it is stored and points the pipeline at it without saving anything, and if that revision cannot be loaded the drawer closes instead. The server also refuses a process save that names ports belonging to another revision or to the other side of the process, so an outdated editor or script is asked to reload rather than silently losing ports.
  • Sign In Page When The Configuration Cannot Be Read: The sign in page read the list of enabled sign in methods straight out of the application configuration, and crashed to a blank page if that configuration arrived without the list. That happened when a request for the configuration was answered with a web page rather than configuration data, which something sitting in front of the application can do, for example by answering with its own sign in page.

The application now checks that a configuration response really is the configuration before using it. A response that is not gets treated as a failed request, so every screen keeps the configuration it last read successfully instead of replacing it with the page text. The sign in page also treats a missing list of sign in methods as an empty list rather than failing.

  • Assume-role AWS credentials for run reports and file access: Foundry Connect's own S3 access (fetching run reports, downloading results, uploads, listing datasets, data transfer and the run scheduler) refused an assume-role AWS credential as missing its access key. It now assumes the role for a short session, after rechecking that the organization still allows that role, and uses the session like any other credential.
  • File Uploads To An Agent Run Environment: Uploading a file to a run environment that uses the agent transport now stops with a clear explanation that the operation works only over SSH, and suggests using an SSH run environment instead. Previously the upload dialog reported a connection failure against the SFTP server, which gave no hint about the cause or about what to do next.
  • Job searches on LSF read the scheduler's own "no matching job" answer: A search of an LSF cluster's accounting records now reports what the scheduler answered, where before it reported that it could not tell. LSF answers a search that matched nothing with the words "No matching job found" rather than with an empty listing, and Foundry Connect read that as a failed query. Because the two records it consults are jobs that finished and jobs that exited, and a job that finished normally is absent from the second by definition, every search of a completed job ran into it. This was measured against a cluster running IBM Spectrum LSF 10.1, and the same reading is now covered by tests built from that cluster's own output.
  • Temporary AWS Credentials on Older Nextflow: A pipeline that resolves to a Nextflow release older than 23.10.0 can no longer start on a run environment whose AWS credential assumes a role. Those releases read an AWS session token only from an ~/.aws credentials file and never from the environment, so such a run used to reach the cluster and then fail against S3 with a 403 InvalidAccessKeyId that named neither the credential nor the Nextflow version responsible for it. The run is now refused before it starts, naming the version it resolved to and the remedy, which is to convert the pipeline to DSL2 so that it runs on a newer Nextflow. Runs that use static AWS keys, runs that use an instance role, and runs on Nextflow 23.10.0 or newer are all unaffected.
  • Organization Run Environment Directories: An organization's run environment now supplies the work directory, the publish directory and the execution directory that a run launches with, so a run started against one no longer has to be told all three by hand. Before this, a launch that named none was refused, and a launch that named only an execution directory reached Nextflow with the head node's local path as its work directory, which the AWS Batch executor rejects because it needs a bucket. An administrator can now also record the head node's execution directory on the organization's connection, alongside the work and publish directories it already held. Run environments that inherit their connection from the shared template are unchanged, and a run that names its own directories still overrides whatever the environment supplies.
  • Protected metadata collections now refuse record deletion: Marking a metadata collection as protected against data deletion now actually prevents its records from being deleted. The setting could already be turned on and was shown in the collection's configuration, but nothing enforced it, so records inside a protected collection could still be deleted from the data view exactly as if the box had never been ticked. Deleting a record in a protected collection is now refused with a message naming the collection, while deleting the collection itself, its fields, or a dataset is unaffected. If your team has been relying on that box, expect deletions that used to succeed to start being refused, which is what the setting was always meant to do.
  • Search With Non-English Characters: Searching the Runs, Projects and Apps lists no longer fails when the search box contains an accented letter, a curly quote pasted out of a document, or an emoji. Any such term previously returned a server error, while a plain English term worked, which made the problem look intermittent. The cause was that several long-standing tables still stored text in an older character set that cannot represent those characters, so the database refused to compare them against the search term. Those tables now use the same character set as the rest of the application, and every search term is accepted.
  • Clearer Error When The App Server Is Unavailable: Starting, listing or stopping an interactive app while the app server is unreachable now reports that the service is temporarily unavailable, and suggests trying again, rather than showing the generic "contact support" message. The clearer wording was already used when the app server answered with an error of its own, but a server that was completely unreachable took a different path and missed it, which meant the most common outage produced the least helpful message.

Enhancements

  • Per-user AWS cost tags: AWS Batch runs now carry foundry-user, foundry-run and foundry-deployment tags, plus foundry-org when the run belongs to an organization, so cost and usage can be attributed per user in AWS Cost and Usage Reports. The user's email address is no longer placed on job tags.

[v2.22.0] – 2026-09-07

New Features

  • Configurable network and download directory for GCP boundaries: A Google Cloud customer boundary now carries its own VPC network, an optional subnetwork, and a default run download location, in place of one fixed network and one fixed download bucket that every deployment previously shared. Existing boundaries keep working exactly as before, because a migration writes today's shared values onto any boundary that does not already have its own, so nothing already provisioned needs to change. An AWS boundary gains a download location of its own, which a separate change in this release makes required. Uploading boundaries by CSV enforces the same two new required columns on Google Cloud rows, and a file missing one is rejected at upload time with a message naming the row and the column, rather than failing generically or partway through the batch.
  • Run a process on its own: A process can now be run on its own, without first wrapping it in a pipeline by hand. A new Run button in the process editor creates a run attempt for just that process and takes you to the familiar run detail page, where you configure an environment and execution directory and launch it, seeing the same logs, outputs and reports as any other run.
  • Copy a dataset to the cloud so a cloud run can read it: A dataset's row menu now has Copy to Cloud: pick one of your Google or Amazon data sources and Foundry Connect copies every file in the dataset into it, leaving alone any file that already lives in the cloud, so a run on Google Batch or AWS Batch can read data that used to live only on this server's storage, which those services cannot reach because they read a bucket rather than a filesystem. You can close the page while the copy runs, and you can cancel it. Once a dataset has been copied, launching it on a Google Batch or AWS Batch run environment reads the copy, while a run on your cluster or on this server keeps reading the original files exactly as before. Running Copy to Cloud again copies only what is missing or has changed since the last copy, spotting a change by a file's size and its modification time, so a file edited in place that keeps both of those the same looks unchanged and needs to be copied again by hand after editing. A run on Google Batch or AWS Batch whose dataset has not been copied yet now stops before it starts and says so, naming the files it cannot reach, rather than starting and failing part way through.
  • Multi Modality Deployments: A single deployment is no longer limited to one execution modality. DEPLOYMENT_BOUNDARY_KIND now accepts a comma separated list, so one install can permit local HPC, AWS Batch and GCP Batch together and serve each organization from the modality that suits it, with an organization that spans clouds simply holding one boundary attachment and one run environment per cloud. A single value keeps behaving exactly as it did before, and the default is unchanged, so an existing deployment needs no action. Attaching a boundary is additive and never repoints a data source an organization is already using.
  • Run environments reached by an agent: Run environments can now be reached by an agent you install in your own account on the cluster, instead of by an inbound SSH connection. Choose Agent when creating a run environment, attach it to get a one-time credential and a paste-ready install command, then run that command on the login node as yourself. No admin access and no inbound network change is needed. The card shows the connection status live and includes a Test Connection button that reports back what the login node looks like, so you can confirm it is ready before anyone launches a run there.
  • An administrator can attach a specific cloud boundary to a specific organization: Which cloud an organization ran in used to be a property of the installation rather than a choice. Boundaries were handed out first come first served from a pool, always the oldest free one, and there was no way for an administrator to say that a particular organization should get a particular boundary. An administrator can now attach a chosen boundary to a chosen organization, and revoke that attachment later. An organization may hold boundaries in more than one cloud at the same time, which is what lets a single installation serve local HPC, Amazon and Google side by side. Attaching is additive and never repoints anything that already exists: an organization that reads its data from a local path and then gains a cloud boundary keeps that local path and gains a second data source alongside it. Revoking keeps the record of what was attached rather than erasing it, and is refused while any run environment is still bound to the boundary, so unbinding is always something an administrator does deliberately rather than a side effect of tidying up.
  • An administrator can give an existing organization its cloud run environment: Attaching a cloud boundary to an organization only went halfway. A boundary's storage and compute settings are applied to an organization's runs through a run environment that the platform generates for it, and the only thing that ever generated one was the sign-up path taken by hosted customers. An organization created any other way, which on a self-managed installation is every organization, had nothing for its boundary to reach, so the attachment sat there doing nothing. An administrator can now create that run environment for an existing organization. Running it again is safe and is the expected way to use it: an organization that already has one is reported back unchanged rather than refused, so an administrator bringing a whole installation up to date can work through every organization and re-run the ones that failed without creating anything twice. On an installation that runs only on its own cluster there is no cloud boundary to apply, so nothing is created and the response says so rather than leaving an empty environment behind.
  • Attach a cloud boundary to an organization from the admin console: An administrator could not decide which organization got which cloud boundary. Boundaries were handed out automatically, always the oldest unused one, and an administrator who wanted a particular organization to run in a particular cloud had no way to say so from the console. The Customer Boundary page now offers Attach on any boundary no organization holds, which opens a dialog to pick the organization, and Detach on one that is already held. Attaching is additive: the organization keeps every data source it already had and gains one for the boundary's bucket, so an organization that reads from a local path and then gains a cloud boundary keeps that local path. Detaching revokes the claim rather than erasing the record of it, and is refused while any run environment is still bound to the boundary, so nothing is quietly disconnected underneath a running setup. The claimed columns update as soon as either action completes, without reloading the page.
  • Launch a process test from its fixtures, and compare the run against expected results: A process revision that declares tests/fixtures.yaml can now be launched directly from those fixtures. Every declared file is verified before anything is written, so a fixture that moved or changed is reported as fixture drift, naming the file and saying which of the two it is, rather than surfacing later as a failed run that reads like a broken process. A refused launch leaves no run attempt behind.

A finished run can then be captured as that process's expected results, and any later run compared against it from a Test tab on the run detail page. The report is per output rather than a single verdict: a text output within the measured size cap shows a real difference, an output past that cap is compared by checksum and says so, and an output the run stopped producing fails rather than being quietly skipped. Capture switches timestamp and path normalisation on for text outputs, so an unchanged process does not fail its next comparison on nothing more than its own clock.

A passing comparison means a run still does what it did when it was captured. It does not mean the results are correct, and nothing in the interface says otherwise.

  • The organization console's Cloud tab can attach, detach, bind, unbind and create, and launch respects a deliberate binding: Attaching a customer boundary, detaching it, binding a run environment to one, unbinding it, and creating the organization's cloud run environment are now all possible from the organization dialog's Cloud tab, which previously only reported state. Attach opens a picker of unclaimed boundaries of the clouds this deployment permits; detach and unbind confirm before acting; every action refuses, on the server as well as in the dialog, while the organization's cloud records conflict. The bind operation is the one that launch refusals for multi-boundary organizations have been instructing operators to perform while no such operation existed.

Two concurrency gaps behind those actions are closed with database invariants: one boundary can hold only one live attachment, and one organization only one system generated run environment. Each invariant's migration checks for pre-existing duplicates first and refuses with the offending rows named, rather than failing half-applied, and the checks came back clean on every known install.

One run path change ships with this: the automatic binding a launch performs when an organization holds exactly one attached boundary no longer overwrites a binding an operator made concurrently, and no longer binds an attachment that was revoked after the launch began. The launch retries and re-reads instead, and every cloud change an administrator makes is now recorded in the audit log with actor, organization, and before and after values.

  • Process Revision Comparison: The process editor now shows a Revisions tab whenever a process has at least two revisions. It lists every revision with its comment and date, preselects the open revision against the one before it, and renders what changed between the two as a unified diff, file by file, covering the authored definition of the process. The comparison is built from the database, so it works even when no git repository is connected. When revisions have been exported to git, each side is additionally verified against what its tag committed and any divergence is labeled with its cause, and a diff too large to render is still reported as changed, with its size, rather than dropped. Each revision can also be validated in place from the same table.
  • Organizations can be granted entitlements, and the per-user feature flag view says where each flag comes from: Selected features can now be granted to an organization as a whole. A grant applies to every current and future member of that organization, everywhere that member works, including their personal resources and any other organization they belong to. Exactly seven features are grantable this way, each opened by an explicit decision (the Catalog, the Workbench, report upload, run analytics, app curation, sharing, and demo data); features carrying credentials or per-member spend stay per-user only, and a stored grant for a feature that is not grantable enables nothing.

The backing admin API validates changes against what is already stored: a newly added ineligible feature refuses the whole request naming the feature and the reason, while grants that were already recorded are preserved and removal is always allowed, so the form built on this in the next release can always save. A feature that is enabled globally, including by deployment environment variable, refuses new organization grants, since such a grant would only take effect if the global setting were later withdrawn. Every replacement is recorded in the audit log with actor, organization, and the before and after grant lists.

The per-user feature flag listing for administrators now carries provenance: each flag reports whether it is on globally, granted to the user personally, or inherited from an organization, and names the granting organizations. Previously an administrator could see a flag toggled off for a user while the feature demonstrably worked; the listing now says why.

  • New MCP tools for process git integration, script assets, and revision comparison: The bundled MCP server now ships its latest tools. Five new tools cover process git integration and script assets, and a new compare_process_revisions tool returns what changed between two revisions of a process as a unified diff of the authored files, matching the Revisions tab in the process editor. User-facing strings in the MCP server now use the Foundry Connect name.
  • The organization console gains an Entitlements tab, and the per-user feature flag screen says where each flag comes from and stops copying organization grants: Selected features can now be granted to a whole organization from the organization dialog's new Entitlements tab. The tab lists the full flag catalog with a toggle per feature and one Save: features that cannot be granted to an organization, or are already enabled globally, show a disabled toggle with the reason, and a stored grant that is no longer eligible is labelled as granted but currently inert while remaining removable. The tab states the contract plainly: granting a feature to the organization turns it on for every current and future member, everywhere that member works, including their personal resources and any other organization they belong to. A save the server refuses names the feature and the reason, and the dialog stays open.

The per-user feature flag screen now carries a Source column saying where each flag comes from: Global, User, or via the granting organization by name. Its toggle edits only the user's personal grant and the column is named User Grant accordingly. Previously the toggle reflected the merged state, so once organization grants existed, saving that screen would have silently copied every organization grant into a personal grant that outlived the organization's revocation; that path is closed.

  • Admin Run Environment Management: Site administrators can now list, create, edit and delete the run environments belonging to an organization, including AWS Batch environments, without being a member of that organization. Environments created this way are owned by the organization's own administrator rather than by the site administrator, and only credentials belonging to that organization can be attached to them. The run environment the platform manages for a cloud boundary stays read only apart from its AWS submitter identity, and cannot be deleted here.
  • Manage an organization's run environments from the admin console: Site administrators now have a Run Environments tab in the Organizations modal, which lists what an organization can launch runs on and can create, edit and delete those definitions without joining the organization. The credential pickers offer the target organization's credentials rather than the signed-in administrator's, an environment created here is owned by the organization's own administrator, and an administrator's edit never moves that ownership.

The run environment the platform manages for a cloud boundary is read only here apart from the identity its AWS Batch jobs submit as, which it offers through a separate two field form. The Cloud tab keeps its focus on boundary state and gains a link to the new tab rather than a second listing of the same rows.

The organization's own Run Environments page is unchanged, though its form now tells you when your saved credentials could not be loaded, offers a retry, and blocks saving only for the executors that cannot run without one.

  • Import a process from a git repository: The pipeline workflow editor's sidebar now has a third toolbar button, Import Process from Git, beside Create Pipeline and Create Process. There is no separate processes page in Foundry Connect, so the workflow editor is where every process is created or edited, and this is where importing one from a repository belongs too.

The button opens a four step wizard. Source points at a repository and, if it is private, the credential that reads it. Pick chooses which process the repository publishes and which revision. Review shows what the server parsed out of that revision: its name, summary, input and output counts, and the exact commit it resolved, plus which files in the repository matched the process contract. Consent is the step the wizard exists for: it shows the repository and the exact commit again, verbatim from the server, and asks the person doing the import to confirm they have read the source before anything is written. The checkbox starts unticked and the Import button stays disabled until it is, so nothing is stored on a click that was not meant to be a confirmation.

A bad repository URL, one that cannot be reached or does not resolve as expected, is reported inline on the step that tried it rather than advancing the wizard past a check that never actually passed.

An imported process is stored without being executed. This wizard is the front door for that import path; the review that decides how and when a git imported process later becomes runnable is a separate piece of work.

Resolved Issues

  • Error details in logs are now allowlisted: Errors written to the log now carry only their type, message, stack and error code. Previously an error raised with extra internal context attached could write that context into the log file, where redaction could not reach it because it nests arbitrarily deep. Anything parsing the err object in the logs should expect those four fields and nothing further.
  • One repository URL, however you spell it: A process repository URL is now stored in a single canonical form, so https://host/owner/repo.git, the same address with a trailing slash, and the plain form are recognised as one repository rather than three. Previously two processes could connect to the same remote under different spellings and claim the same directory inside it, and an export from either would overwrite the other's files. A repository URL containing a username or password is now rejected, because the credential belongs on the connection rather than in the address.
  • Long AWS runs no longer lose access partway through: A run using an assume-role AWS credential now requests the longest session that role permits rather than always asking for one hour, so a long pipeline no longer loses its access to S3 and Batch partway through. The ceiling is whatever your IAM administrator set on the role, so nothing widens without your say-so. A run that outlasts even that ceiling still expires, which needs an execution host holding an AWS identity of its own.
  • Run environment settings are no longer dropped at launch: Nextflow settings saved on a system-generated run environment, and those from the organization template it is built from, now reach the run. Previously the cloud boundary's own settings replaced them entirely at launch, so a directive could be saved, stored and shown correctly yet never take effect. The boundary's settings are applied last, so anything describing the infrastructure itself still wins.
  • A process save can no longer delete all of its ports: Saving a process is now refused when the save carries no input or output parameters at all but the process has some, instead of silently deleting every port. This could happen after switching revisions in the process editor, where a detail response arriving without its ports was read as a process that has none. Processes that genuinely have no ports are unaffected, and removing ports one at a time works as before.
  • Belonging to several organizations no longer locks you out: A user who belongs to more than one organization is no longer refused access when the first of them cannot be loaded. Previously every request checked a single membership, chosen in no particular order, and answered "Organization is not found" if that one did not resolve, even though the account held other valid memberships.
  • A process that fails to load no longer opens as an empty editor: Opening a process for editing, or switching it to another revision, now reports a failure when the process does not load completely, instead of opening an editor that shows none of its input and output parameters. Previously a response that did not carry the parameter lists was read as a process that has none, so the editor built a draft with an empty parameter table, and saving that draft asked the server to delete every parameter the process had. Switching revisions also used to leave the panel loading forever when the request failed, and now keeps the revision you already had open and tells you the new one could not be loaded.
  • Error details in logs are allowlisted wherever the error appears: The allowlist that limits logged errors to their type, message, stack and error code now applies wherever an error appears in a log entry, not only when it is the entry's sole detail. An error raised with extra internal context attached and then logged alongside other details could previously write that context to the log files, and its stack was lost at the same time. Both are now handled the same way as every other logged error.
  • Run logs keep updating when a transfer runs long: Run logs and reports no longer stop updating when a file transfer from an external server runs long or stalls. The check that decides whether a transfer is already under way could not read the process list inside the application container, so it never recognised a transfer in progress and never restarted one that had hung. It now reads that information in a way that works on every supported image, and a transfer that passes the five minute limit is stopped and started again as intended.
  • Exporting a process to git no longer holds a database transaction open: Exporting a process revision to git no longer holds a database transaction open while it talks to the repository. When a push was rejected because someone else had published in the meantime, the export retried up to three times, and the whole sequence of clone, commit and push ran inside one database transaction that stayed open until the retries finished, even after the browser had given up waiting. On a repository shared by many processes, where that contention is normal rather than rare, this could slow down other work across the application. The export now reads what it needs up front and does the repository work outside the transaction, and a retry publishes exactly the content that was read when the export started.
  • Exporting into a repository left in the pre-2.21.0 layout is refused: Versions of Foundry before 2.21.0 wrote a process's files at the root of its repository. Since 2.21.0 one repository can hold many processes, each writing into its own directory, and an export clears only that directory before writing. Exporting into a repository that still held the older layout used to succeed and leave the root level copies in place, so the repository served two versions of the process, files deleted from the process were still readable at the root, and the check that stops an older revision being published over a newer one had nothing to compare against. Such an export is now refused, naming the old revision tags it found and what to remove, because Foundry cannot tell the files left at the root from files a person committed and so must not delete them on its own.
  • Dataset download alerts reach every organization that asked for them: When someone downloads a dataset, Foundry notifies the admins of the organizations they belong to, unless an organization has turned that off. It used to notify only one of those organizations, chosen by whichever membership the database happened to return first, so an organization that had deliberately left the setting on heard nothing whenever another of that person's organizations sorted ahead of it. Every organization the person belongs to is now consulted and each one's own setting is honoured, and an organization that cannot be loaded no longer silences the rest. An admin who belongs to several of those organizations, or an address shared by two admin accounts, still receives a single notification.
  • Error details in request logs are allowlisted too: Errors recorded while handling a web request now carry only their type, message, stack and error code, the same as errors logged anywhere else. Request logging used a separate path that could write an error's internal context to the log files, and that path now applies the same limit.
  • Private pipeline imports no longer expose their access token to the host: Importing a pipeline from a private repository previously passed the access token as part of the command line it ran, which made it visible to anyone else with access to the same server for as long as the import took. The token is now handed to git privately instead, and the same applies to any submodules the repository pulls in.
  • Organization admins see their members' work in every organization they administer: An administrator of more than one organization now sees their members' runs, pipelines and reports in every organization they administer. Only one of a person's organizations was consulted when working out whose work they were allowed to see, and which one that was came down to the order the database happened to return them in, so an administrator could be shown nothing beyond their own work in an organization they genuinely ran. Redeeming a voucher code is resolved the same careful way billing already is: it applies to the organization that carries the billing record, and where a person belongs to several and none of them is identifiable as the one being paid for, the redemption now stops with an explanation instead of turning off the subscription of whichever organization came first.
  • AWS boundaries now use their own run download directory: A run launched through an AWS customer boundary now takes its default download location from that boundary. Previously only Google Cloud boundaries set one, so an AWS run either had no download location at all or, if an administrator had edited the shared run environment template by hand, silently inherited that template's Google gs:// location, which AWS Batch cannot read. The boundary's own setting now takes precedence over the shared template on both clouds, for the same reason its generated configuration block does: the boundary describes storage the installation actually has. The download location remains optional on AWS, and an AWS boundary configured without one is now given no download location at all rather than the shared template's, so a run can no longer be pointed at another cloud's storage.
  • Long AWS runs get the longest session their role allows: A run using an assume-role AWS credential asks AWS for the longest session it can get, because that session is a hard deadline: once it passes, the run loses its access to S3 and Batch partway through. When a role would not grant the full length, the request used to fall straight back to one hour, so a role configured to allow eight hours still handed its runs one and the other seven went unused.

The request now steps down through the session lengths AWS itself offers and settles at the longest one the role accepts. A role allowing eight hours now gets eight. Nothing widens beyond what your IAM administrator set on the role, which remains the only control, and a role that allows just one hour behaves exactly as before.

This shortens the window in which a run outlives its credentials. It does not close it, because twelve hours is the AWS ceiling for any role session. A pipeline that runs longer than its role's maximum still expires, and closing that properly needs the machine running the pipeline to hold an AWS identity of its own.

  • Run environments shared with any of your organizations are visible again: If you belong to more than one organization, the run page now shows run environments shared with any of them. Previously only one of your organizations was consulted, and which one was not predictable, so an environment shared with the others could be missing from the list.
  • Duplicating a run copies data into the right organization's storage: Duplicating a run can copy its dataset or its reports into your organization's cloud storage. Which organization that meant was decided by whichever of your organizations the database happened to list first, so a person who belongs to more than one could have a copy written into the storage of an organization the run had nothing to do with.

The organization is now worked out deliberately: the one already set up with cloud storage where that identifies it, or your only organization where you have one. Where you belong to several and nothing distinguishes them, the duplication stops with an explanation rather than choosing for you, the same way creating a workbench and redeeming a voucher already behave.

This is only consulted when the duplication actually copies a dataset or reports belonging to an organization. Duplicating a run that does neither is unchanged, however many organizations you belong to.

  • People are no longer given an organization of their own when they sign in: Signing in was creating an organization of your own for anyone who did not already belong to one, named after you. That was only ever meant as a fallback, and it was never meant to be how people get an organization: you belong to your lab's organization, set up from the billing record.

Because that fallback was reached on every request rather than only when signing in, a few people ended up with several copies of an organization named after them, created within the same second of each other.

Signing in no longer creates an organization at all. Organizations you already belong to are unaffected, and nothing about how they work has changed.

  • Importing a large pipeline no longer fails with a message about repository access: Importing a large pipeline no longer fails with a message about repository access when nothing was wrong with the repository. The step that copies a freshly cloned repository into place shared a short time budget meant for quick commands, even though the amount it copies grows with the repository, so a large import on a busy machine could be stopped partway and then reported as a problem with the repository, the credential or the branch. That step now has a budget matched to what it does, and a step stopped for running long now says so plainly instead of pointing at settings that were never at fault.
  • Signing in can no longer hand one person several duplicate organizations: Opening Foundry sends several authenticated requests at once, and each of them resolves which organizations the person belongs to. Where Foundry is configured to create an organization for someone who has none, every one of those requests used to find no organization and create its own, so a single sign-in could leave one person holding four or five near identical organizations, along with a group and a set of roles for each. They were created within the same second, which is what gave it away.

Creating that organization is now serialised for each person, so the first request creates it and the others find it and use it. Nothing about this limits anyone to a single organization: belonging to several remains normal and supported, and this only stops one sign-in manufacturing them by accident. If the serialisation cannot be obtained, signing in still succeeds and the next request tries again, exactly as before.

This behaviour is off by default, and turning it on stays a separate decision: the intended arrangement is that people join their lab's existing organization rather than receive one of their own.

  • Standalone run links on the dashboard: The project dashboard offered the pipeline name of a run started directly from a process as a link, but it led to a pipeline that cannot be opened or saved, so it was a dead end. The dashboard now shows that name as plain text, matching the runs list, the run detail heading and the run analytics table, which already behaved this way. Runs started from a real pipeline still link to it exactly as before.
  • Billing webhook logs no longer record the request payload: The Stripe billing webhook recorded the complete request, every header and the entire body, to the log before it checked the request's signature. That endpoint is reachable without authentication, so anyone able to call it could place content of their choosing into the log files an operator reads and ships, and a genuine delivery wrote customer billing details there as well.

It now records only what is needed to confirm that a delivery arrived: whether a signature header was present, the size of the payload, and its content type. The event's own identifier and type are recorded once the signature has been verified.

A rejected delivery is now reported through the standard logger rather than printed directly, so it carries the same request correlation id and the same limits on error detail as every other entry.

  • Deleting a group no longer silently orphans the projects and runs inside it: Deleting a group is meant to be refused while the group still holds content, so that nothing is stranded. That check was reading the wrong thing: it looked at content that had already been deleted rather than content that was still there. It therefore allowed exactly the case it existed to prevent, and blocked exactly the case it was meant to allow.

Deleting a group is permanent, so the consequence was permanent too. A group holding live projects, pipelines, processes or saved runs could be removed, and everything inside it was left pointing at a group that no longer existed. Re-creating a group with the same name did not reconnect any of it. In the other direction, a group whose contents you had already tidied away refused to be deleted at all, with a message naming content you could no longer see.

Both now behave as intended. A group you have already emptied deletes cleanly, and a group holding anything live is refused with a message saying what is in it and how much of it, for example "This group still contains 12 runs, 3 projects and 1 pipeline". Every kind of content is listed at once, so clearing a group no longer means discovering the next thing in the way one attempt at a time.

Expect this refusal to be common. In an established deployment most groups hold something, so groups you could previously delete will now ask you to empty them first. That is the point of the check, but it is a change in what you will see.

If your deployment has groups that were removed this way, the content inside them is still present and still owned by you; it is the group association that was lost, and it has to be set again by hand.

  • Clearer message when a Bitbucket connection has no SSH key: Importing a private Bitbucket repository when the connection had no SSH key attached failed with "SSH key ID is required". That message came from deep inside the internals and did not say what was missing or how to fix it.

It now reports that no SSH key is configured for the Bitbucket connection, and that Bitbucket private repositories are imported with an SSH deploy key. The previous wording also referred to a token, which does not apply to Bitbucket connections and sent people looking for a setting that does not exist.

Bitbucket connections that already have an SSH key attached are unaffected.

  • A run with no data attached to any of its inputs now says so before you launch it: A run whose pipeline takes data files can be saved and launched with nothing attached to any of them, and until now nothing said so. The pipeline starts, the first step runs against an empty placeholder file, and the failure only surfaces after the job has queued and started on the cluster.

The Run button cannot catch this on its own. It only checks inputs the pipeline marks as required, and a pipeline that accepts more than one kind of input has to mark every one of them optional, because there is no way to say "exactly one of these is needed". On the RNA-seq pipeline, which takes either sequencing reads or aligned BAM files, that means neither input is ever required and neither one holds the button back. Choosing a genome build satisfies everything else the button looks at, so it becomes available with no data selected at all.

The run settings page now warns when a pipeline has data inputs and none of them has anything attached, naming the inputs it expected. Nothing is blocked: a run can still be launched, because there are legitimate pipelines that read their data from somewhere the run settings do not describe. The warning simply makes the empty case visible while there is still time to fix it.

Separately, a required input answered with 0 or with a false value was being treated as though it had been left blank, which held the Run button back on runs that were in fact complete. Such an answer now counts as given.

  • Standalone run links on the Activity and Runs pages: The Activity page and the Runs page offered the pipeline name of a run started directly from a process as a link, but it led to a pipeline that cannot be opened or saved, so it was a dead end. Both pages now show that name as plain text, matching the project dashboard, the runs list, the run detail heading and the run analytics table. Runs started from a real pipeline still link to it exactly as before.

Both pages read the same run list, and that list did not say whether a run's subject was a pipeline or a single process, so neither page could tell the two apart. It now reports that, which is what made the fix possible in both places at once.

  • Standalone run links in the sample explorer: Expanding a sample in the sample explorer lists the runs that produced its files, and each row offered its pipeline name as a link. For a run started directly from a process that link led to a pipeline that cannot be opened or saved, so it was a dead end. Those rows now show the name as plain text, matching every other place a run's pipeline is named. Runs started from a real pipeline still link to their pipeline in a new tab exactly as before.

This was the last of the four surfaces outside the runs pages that had this problem, and it stayed unfixed the longest for a reason worth recording. The other three could be corrected in the page itself, because the data they already read said whether a run came from a pipeline or from a single process. The sample explorer's run rows came from a different query that never reported it, so the cell had no way to tell the two apart no matter how it was written. That query now reports it, which is what made the fix possible here at all.

  • The tag picker list is no longer covered by the table beneath it: Opening the tag picker now draws the tag list above the content underneath it. The list and the sticky column headers of the table below it were claiming the same layer, so the headers painted through the open list and hid part of the tags behind them. This was most visible on a dataset, where a file table sits directly under the picker. Assigning and removing tags always worked, but the list itself was hard to read while choosing.
  • The dataset picker's Select button no longer breaks its label across two lines: The dataset picker that opens from a run's data input showed its confirmation button as a broken Selecte d, with the word split across two lines. The column holding the button was pinned to a fixed width narrower than the confirmation needs, and the table breaks a cell's text at any character rather than only at spaces, so the label was split mid-word rather than allowed to overflow. That column is now wide enough for the longer confirmation, and neither label is allowed to wrap, so Select and Selected each stay on one line at any window width.
  • Workbench costs are marked up by the organization that owns each workbench: The Workbenches page marks each workbench's accumulated cost up by a margin. It took that margin from the first organization listed on the signed in user's session, and then applied it to every row on the page and to the page total.

For anyone who belongs to a single organization that was correct. For anyone who belongs to more than one it was not, because the order that list arrives in is arbitrary: the same user could be shown one set of prices on one day and another set on the next, without anything about the workbenches having changed. A workbench owned by one organization could be priced at another organization's rate.

Each row already records the organization that owns it, so each row is now priced by that organization's margin, and the page total is the sum of the rows as shown rather than one rate applied to one sum. A workbench that belongs to no organization uses the configured default, as before.

This means a user who belongs to more than one organization can now see rows marked up at different rates in the same list. That is the correct reading of the data rather than a display quirk: the rows genuinely belong to organizations with different agreements.

Nothing about who can see which workbench has changed. Visibility was never decided by that organization id; it is settled entirely by the permission query, and it still is.

  • A run environment now uses the boundary its organization already holds: A run launched on a system generated run environment reaches for the cloud boundary that carries its storage and compute settings. When that environment had no boundary bound to it yet, the platform always took the next free boundary from the shared pool, even when the organization already had one attached. That handed the organization a second boundary it never asked for and pointed the run at storage nobody uses, and on a deployment that has no pool to draw from at all it failed with a message that did not say what was wrong. The lookup now runs in order. An environment binds to the boundary its organization already holds, and only an organization holding none draws from the pool, and then only where the deployment has one. When an organization holds several boundaries and the environment is bound to none of them, the launch stops and names the organization rather than picking one of them arbitrarily.
  • Dialogs no longer close on a confirm that did nothing: Pressing the confirm button on a dialog ran whatever the dialog was set up to do and then closed it, whether or not that action had actually happened. A dialog that checks its input before acting, which most of them do, resolved perfectly normally when the check failed. So the dialog closed, the input was discarded, and the error message that had just been put on screen was destroyed along with the dialog that would have shown it.

The confirm button can now say that nothing happened, and a dialog that says so stays open with the input and the error still on screen. A failure while the action is running keeps it open too, instead of closing over the top of the problem.

Three dialogs were affected and are fixed here: sharing a project, sharing a run, and exporting from the sample explorer. Sharing also changes in a second way. It used to close the moment the request was sent rather than when it finished, so a share that failed left no dialog, no error and no way to tell whether it had worked. It now closes when the share is done.

Most other dialogs were never affected. They were already written in a way that never told the dialog to close at all, leaving that to their own success path.

  • The Activity page's Samples tab no longer empties the table right after filling it: Clicking the Samples tab on the Activity page listed samples and then emptied the table a moment later.

The tab builds its Sample Tracker scope from two independent requests, one for the trackers you own and one for the trackers shared with you, then asks the server which of those hold a readable file collection, and finally asks the explorer for the samples in the survivors. The canvas id list is part of that middle request's cache key, so when the shared list arrived after your own, the key changed and the answer went back to being unknown. The scope was derived by filtering the trackers against that answer, and an unknown answer filtered everything out, so the tab handed the explorer an empty tracker list. An empty list switches the samples query off, and a query that is off renders the empty-table message rather than a loading state, which is the table blanking that was reported.

The tab now waits for both tracker lists before asking which ones hold a readable file collection, so it asks once with the full list instead of twice with a half built one. The file collection query also holds its previous answer while a changed list is in flight, so a tracker created or shared while the tab is open cannot collapse the scope either. A regression test drives the two lists to answer at different times and asserts the tracker list handed to the explorer never returns to empty once it has been populated.

  • The SSH data connection drawer no longer offers a transport it cannot use: The SSH data connection drawer lets you create a run environment without leaving the page. That drawer can only use an environment reached over SSH, but it was also offering Agent, the option added for clusters that block inbound SSH. Picking Agent saved the environment correctly and then filtered it straight back out of the picker the drawer exists to fill, so the connection you were setting up was left pointing at an environment it could never show. The drawer now offers SSH only. Creating an agent environment is unchanged from Run Environments in your profile.
  • The Activity page's Samples tab says it is loading instead of saying it is empty: Clicking the Samples tab on the Activity page showed the empty-table message and sat on it before any rows arrived.

Nothing was wrong with the empty state itself. The tab cannot ask for samples until it knows which Sample Trackers are in scope, and working that out takes three requests in sequence: the list of trackers you own and the list shared with you, then which of those hold a readable file collection, and only then the samples themselves. For all of that the tracker list is empty, and an empty tracker list switches the samples query off. A query that is off reports that it is not loading, the table took that at face value, and so it rendered its "no data" message over a scope that was still on its way.

The tab now tells the explorer when the scope is still being resolved, and the table treats that the same as its own loading state. The two Sample Tracker dropdowns are given the same signal, so they show a loading indicator rather than looking like settled empty lists. When a user genuinely has no trackers, the flag clears as soon as the lists come back empty and the message appears as before.

Two regression tests cover it: one drives the tracker lists to answer at different times and asserts that every render where the explorer has no trackers is flagged as loading, and the other asserts the flag clears for a user with no trackers so the empty message is still reachable.

This changes what the wait looks like, not how long it is. The wait itself is real: resolving the scope costs roughly twenty milliseconds per selected tracker on the server, measured linear from one tracker to sixty-four, and it is paid again on every page change, sort and filter. Making it faster is separate work.

  • A launch bound to a detached or foreign boundary now refuses, and the Cloud tab says what a launch will do: A run environment can be bound to a specific boundary attachment. The lookup that resolved that binding at launch checked only that the boundary itself was not deleted: an attachment that had been detached from the organization, soft deleted, or that belonged to a different organization entirely still resolved, so the run went ahead against infrastructure an administrator had deliberately taken away. That lookup now requires a live attachment belonging to the launching organization, and a launch whose binding fails it refuses with a message naming the cause instead of running.

The organization dialog's Cloud tab now leads with that same decision. It shows one computed state saying what a launch will do for this organization, the boundaries attached to it with a label naming the cloud account each points at, and the run environment they bind, all read only. The Google Cloud and AWS sections appear only on deployments that permit those clouds, and a section whose cloud has no boundary attached says its entries will not reach a run until one is.

  • Agent install commands are readable again: The three copyable commands shown after attaching an agent to a run environment now render white on their dark terminal blocks. A global stylesheet rule was forcing them black on black, which made them unreadable until the text was selected.
  • Say why capturing a run as expected results was refused: Pressing Capture this run as expected on a run whose declared output ports match none of the files it published used to do nothing visible. The server refused the request and explained why, but the Test tab rendered no message, so the button simply looked inert and the reason was reachable only from the browser console.

Both the capture and the comparison now show the server's explanation. A refusal is the ordinary outcome of a first capture rather than a rare accident, so being told which port matched nothing is the difference between a fixable situation and a feature that appears broken.

  • Detaching a customer boundary now takes effect everywhere: Detaching a customer boundary from an organization now takes effect everywhere it should. The boundary list shows the revocation time while keeping the last holder for reference, and the row offers Attach again instead of a Detach that could only fail; a boundary that was detached and reattached appears once instead of twice. Sorting or filtering the list by Claimed At or Revoked At no longer errors. The detached organization's workbench and uploads stop resolving the detached boundary. A detached boundary can be attached again, to the same or another organization, from both the boundary list and the organization dialog's Cloud tab, where the attach picker previously hid it.
  • A first capture matches outputs published under a directory named after the port: Capturing a run as expected results used to refuse on the very first try for an ordinary process. A declared output port matched only a produced file whose name, or name without its extension, was exactly the port id, while the generated workflow publishes each output under a directory named after its port, so a port dirlist publishing dirlist/listfile.txt matched nothing.

The matcher now also accepts the single file sitting under the directory that carries the port's name. An authored glob still wins whenever present, an exact filename or stem match keeps first claim, and the inference refuses as ambiguous when more than one file sits under the port's directory, so it never guesses among candidates.

  • Cloud Launch Executor: Runs launched from an organization's system-generated run environment now select the compute executor from the cloud boundary attached to the organization: Google Cloud boundaries run on Google Batch and AWS boundaries run on AWS Batch. Previously the executor came from a shared platform template regardless of the boundary's cloud, which could leave a launch targeting the wrong execution service.
  • AWS Launch Credentials: Runs launched from an organization's system-generated run environment on an AWS cloud boundary now use the credential configured on that environment, either an assume-role credential or instance-role execution. A launch with neither configured is refused with a message saying where to set one, instead of silently submitting with whatever credentials the server itself holds.
  • Menu groups chosen while importing a pipeline are now applied: Importing a pipeline file now respects the menu group chosen for each entity. The import screen has always offered a group per pipeline, module and process, but those choices were discarded on the way through, and everything landed in whatever groups the file itself named, with nothing reported. Choosing a group that does not exist yet now creates it, as the screen implies. Nothing about existing pipelines changes, and imports that accepted the file's own groups behave exactly as before.
  • Run Names Containing a Percent Sign: Naming a run with a percent sign, for example "20% subsample", could break its launch. The generated cluster job name is built into the batch script through a shell format string, so a percent sign was interpreted as a formatting instruction rather than as text: the job could arrive at the scheduler under a mangled name, and in some cases the script was cut short at that point and the pipeline never started. Percent signs in run names are now replaced with an underscore, the same treatment already given to other characters that are unsafe in a job name, so these runs launch normally.
  • Organization Run Environment Updates: An organization administrator who edited a run environment belonging to a different organization used to receive a success response even though nothing was saved, because the update was correctly scoped to their own organization and simply matched no record. That request is now refused outright, the same way deleting another organization's run environment has always been refused.
  • Process test output names: Fixed process test comparisons reporting an output as missing when the file's name contains characters that have a special meaning in file patterns, such as the square brackets in data[1].tsv. Such a name was recorded when the run was captured and then read back as a pattern rather than as the name itself, so the output could never match and the port was reported absent on every later run. Names are now matched exactly before being treated as a pattern, which also repairs any expected results already captured for such files, with no edit needed.
  • The default RNA-seq pipeline ships with the Log4Shell-mitigated tool image: The seeded default RNA-seq pipeline pointed at rnaseq:4.0 on the retired viascientific registry. That image reproduces Log4Shell: igvtools evaluates a JNDI lookup from a user-controlled sample name. Fresh installs now seed quay.io/ummsbiocore/rnaseq:4.0.1, a build with JndiLookup removed from the bundled log4j jars and tool output verified unchanged. Existing installs are unaffected, since the image is a per-process field they can update in place.
  • OAuth discovery works for clients that probe the path suffixed well known URLs: MCP clients following RFC 8414 and RFC 9728 probe a path suffixed discovery URL, for example /.well-known/oauth-protected-resource/mcp, rather than the bare one. Foundry Connect served only the bare spelling, so those probes reached the web app and received HTML with a 200 status. Both spellings are now served from the same handler, and any other suffix returns 404 rather than claiming metadata for a resource that does not exist.
  • All default tool images now come from one registry, with viascientific retired: Following the RNA-seq image move, the remaining default tool images in the seed (salmon, rsem, rseqc, picard, the pipeline base image, the DE and GSEA modules, the explorers, and others) now reference quay.io/ummsbiocore instead of the retired viascientific registry, each keeping its existing tag. A guard test fails the build if a retired registry reappears in the seed, and on-prem operators can point the seed at their own registry with an FC_REGISTRY override. Existing installs are unaffected; this only changes what a fresh prod-setup seed loads.
  • A failed file download now tells you what actually went wrong: Downloading a file from a run used to answer "File not found" no matter what went wrong, so a run environment that was down looked exactly like a typo in a path.

Now the three cases are told apart. A run environment that cannot be reached is reported as unreachable, with the reason. A path that is a directory, or that does not exist, or that is not a regular file says which of those it is. A download that proves the run environment answered also clears that run's execution visibility warning, the same way a successful poll does.

Separately, a file that is empty now downloads as an empty file instead of being reported as missing.

  • Imported Process Revisions Keep Their Identity: A process revision imported from a git repository used to land as revision 0 whatever number the repository published it as. That made the published revisions panel point at the wrong tag, and it blocked every later export from that process, because the export guard saw the repository as permanently ahead. An import now keeps its published revision number.

Importing several revisions of the same source process used to create a separate process each time. They now land in one process, matched on the family identity the export writes into every commit, falling back to the source repository and path for repositories published before that identity existed.

An import is now refused when the same content is already here, not only when the same revision identity is. The identity check alone was skipped whenever a commit carried no identity trailer, so the same content could be imported without limit.

Sync from repository used to report a published revision it did not hold as impossible to bring in, which stopped being true once import shipped. Sync now imports those revisions, after showing which repository and which commits the code would come from and asking for confirmation. Restoring a revision this installation had merely hidden still needs no confirmation, because it stores nothing new. Imported code still cannot be executed.

  • MCP and OAuth sign in now work on deployed instances, not just in development: Two routes lived in the development edge configuration only. Staging and production run a different pair of edge configurations, and both were missing them.

The MCP endpoint had no route at all, so a client's request fell through to the web app, which accepts only page loads and answered 405. Nothing could connect.

The OAuth discovery paths were matched exactly rather than by prefix, so a suffixed address such as /.well-known/oauth-protected-resource/mcp returned the web page with a 200 status. Codex asks for exactly that address and never falls back to the plain one, so sign in could not begin. Copilot and Claude were unaffected, since they follow the address the server names in its authentication challenge.

All three edge configurations now carry both, and tests assert each of them across every configuration, so a fix cannot land in one edge and be missed in the others again.

Enhancements

  • Customer Boundaries By Cloud: The Customer boundaries admin page now shows one tab per cloud. It previously listed every Google Cloud and every AWS setting in a single table, and because a boundary belongs to one cloud, most columns were empty on every row and the table could only be read by scrolling sideways. Each tab now carries the columns that cloud actually uses, alongside the shared identity, claim and provisioning columns, and the cloud column itself is gone because the tab already names it. The row count and the pager describe the tab you are on rather than every boundary. Switching tabs returns you to the first page and clears any rows you had selected, so a bulk edit or delete can never act on a boundary belonging to the tab you are no longer looking at.
  • The Samples tab is much faster when several sample trackers are selected: Opening the Samples tab with more than a handful of sample trackers selected was slow, and staying on it stayed slow: the same delay was charged again every time you turned a page, sorted a column or applied a filter.

The reason was that the work being repeated is not fetching the rows you asked for. Before it can read any samples, the server has to work out the shape of each selected tracker, and it does that one tracker at a time. Each of those steps looked up a collection by name and then read that collection's fields, and neither lookup had an index behind it, so each one searched the whole set from the beginning. With 64 trackers selected that came to about 22 milliseconds per tracker, or roughly a second and a half before the first row could be requested, and none of it depended on how many rows were actually being shown. That is why turning to a page of ten rows cost as much as the first load did.

Two indexes now cover those lookups. Measured against a copy of production data with 64 trackers selected, preparing the request fell from 1,422 milliseconds to 221, and the whole request from 1,488 to 294. Per selected tracker the cost went from about 22 milliseconds to about 3.5, so the improvement grows with the number of trackers you have selected and is barely noticeable with one.

The indexes are created automatically when the server starts, and creating them again on later starts does nothing. If one cannot be created the server still starts and the page still works, just at its old speed.

Nothing about which samples you can see has changed. The rows returned are the same rows, found the same way, and permissions are still applied exactly as before.

  • Installing an agent now reads as a numbered sequence you can copy step by step: Agent run environments now open in place in the Run Environments table rather than sending you to the edit drawer, and attaching an agent gives you the install sequence as three numbered commands, each in its own terminal block with a copy button. SSH environments are unchanged and still open in the drawer.

The credential is shown once beside its fingerprint, and is never part of any command you copy. The agent asks for it instead, so it never appears in the process list where other people on a shared login node could read it.

Test Connection now leads with how long the round trip took, and says Available or Not available for bash and modules rather than leaving a gap, so you can tell a capability that was checked and found missing from one that was never checked.

  • Manage an organization from one dialog, and stop offering a margin that cannot be saved: Configuring an organization meant picking the right one of six context menu entries, each opening its own dialog, and nothing on the page showed what an organization was actually set up for. Those six are now one Manage action opening a single dialog with General, Members, Cloud and Storage tabs. View Users is gone, because it was a read only view of exactly the membership the Members tab already edits.

Margin also stopped lying. It is stored on a billing record, and those records are created only when payment is configured, so on an installation without payment there was nothing for the write to reach. Setting a margin there matched no record, yet the console reported that it had been updated. The field is now shown only for organizations that have a billing record, and an attempt to set a margin on one that does not is refused with a message saying so rather than reported as a success. Submitting the same margin twice still succeeds, because an unchanged value is not a missing record.

  • Agent install instructions carry the Python prerequisite and a PATH safe start command: The attach panel's step 1 now says the installer needs Python 3.8 or newer on PATH and shows a cluster example (module load python3/3.8.2). Step 3's copyable command is now export PATH="$HOME/.foundry/bin:$PATH"; foundry-agent start -b, because the shell the install ran from was started before the installer's PATH edit, so the bare command fails there with command not found. New logins need only the second half; the export is harmless when repeated.
  • Run Environment Reachability: When the platform cannot reach a run's execution environment, the run page now says so instead of quietly showing the last known status: after several consecutive failed reachability checks the attempt is marked unreachable and an Unreachable badge appears beside the run status, with a plain-language reason as its tooltip, visible to every project role including viewers, and it clears on the first successful contact with the environment.
  • Process test capture: Capturing a finished test run as a process's expected results now recognizes outputs by the port-named folder they are published into, so a first capture works without renaming any output file. A hand-edited tests/expected-results.yaml is respected too: its file patterns guide the capture, and its comparison choices survive a re-capture, with only the measured checksums and contents refreshed. After a capture, the Test tab lists which file each output port was captured from and names any port that could not be captured, and the refusal shown when nothing matches now explains every way to fix it.
  • Traceable Cluster Job Names: Scheduler job names submitted to LSF, SGE, and SLURM now carry a unique 20-character tag derived from the run attempt, in the form j_<name>_<tag>. The tag ties every cluster job back to the exact attempt that submitted it, which is what makes an interrupted launch resolvable instead of ambiguous, and Foundry Connect refuses a launch whose tag is already recorded rather than ever mis-attributing a job. Job ids, run monitoring, and termination are unchanged.
  • Match outputs dialog: Capturing a run as expected results no longer dead-ends when an output file's name does not match its port. The capture now checks first what would match, and when some ports would be left out it opens a dialog listing each of them beside the files the run actually published, so you pick the right file per port by looking at real names instead of editing tests/expected-results.yaml. Ports that already match are captured exactly as before, in one click, and a port can be deliberately left uncaptured.

[v2.21.1] – 2026-08-29

Resolved Issues

  • People are no longer given an organization of their own when they sign in: Signing in was creating an organization of your own for anyone who did not already belong to one, named after you. That was only ever meant as a fallback, and it was never meant to be how people get an organization: you belong to your lab's organization, set up from the billing record.

Because that fallback was reached on every request rather than only when signing in, a few people ended up with several copies of an organization named after them, created within the same second of each other.

Signing in no longer creates an organization at all. Organizations you already belong to are unaffected, and nothing about how they work has changed.

[v2.21.0] – 2026-08-27

New Features

  • Imported pipeline analysis: Imported Nextflow and nf-core pipelines now show an advisory panel on the pipeline page listing settings Foundry overrides at launch, output directories that would collide, and required schema parameters the run form cannot supply, each grouped by how likely it is to affect the run and paired with the file and line it came from. The findings are read-only advice, they never block saving or launching a pipeline, and they are also available from a new read-scoped pipeline lint endpoint for anyone driving Foundry through the API.
  • Validate a process revision's contract and record the result: A process revision's contract can now be checked against itself, and the result is recorded as evidence bound to the exact content that was checked. The check confirms that the JSON Schemas projected from the contract compile, that every declared default satisfies its own declared type and constraints, and that port identifiers are unique and survive into the projection. Recorded fidelity is reported alongside the result, and a revision lifted at loose fidelity is never failed for that alone.

A contract that does not validate is reported as a normal result rather than an error, so a caller can tell a contract problem from a failed request.

  • Attach R and Python scripts to a process from the Files tab: A process can now carry its own helper scripts, attached from a new Files tab beside Scripts. An uploaded R, Python or shell script is stored against the revision and exported into bin/ of the process repository as an executable file, which is what makes it callable by name when the process runs.

The tab also connects the process to its repository and exports the current revision, reporting the branch, revision tag and content hash it committed, and saying plainly when there was nothing to commit because the repository already matched.

  • Process helper scripts are available to the pipelines that run them: A helper script attached to a process is now written into the run directory when the run is prepared, so the process can call it by name exactly as it does in its exported repository. This works for nf-core pipelines as well as native ones, and covers a process nested inside a pipeline module. A script attached to a process takes precedence over a pipeline file of the same name, and two processes sharing an identical copy of one script get a single copy rather than a conflict; if two processes attach different scripts at the same name the run refuses to start and names both processes, because a run that completes against the wrong helper is worse than one that does not start. Scripts keep the executable flag they were uploaded with.
  • AWS customer boundaries: Administrators can now provision customer boundaries on AWS as well as Google Cloud, and an organization bound to an AWS boundary receives a run environment configured for AWS Batch, with its job queue and CLI path carried through into the generated pipeline configuration. Previously an organization could only be provisioned into Google Cloud, and AWS Batch was reachable only through a run environment an administrator had configured entirely by hand. Boundaries are uploaded one cloud per file, since a single upload carries the fields of exactly one cloud, and the region an AWS run targets continues to come from the attached credential rather than the boundary so that existing AWS Batch run environments keep the region they already resolve to.
  • Run environment drawer rebuilt as collapsible cards: Creating and editing a run environment now happens in eight collapsible cards rather than one long column with a crowded action bar. A collapsed card shows a short summary of what it holds, so a fully configured environment is readable without opening anything, and each card remembers whether you left it open.

Test Connection has moved next to the host and key it tests and now shows the result inline with the time it was checked. The group write permission and the project sharing panel have moved into an Access card at full width, where they previously shared the footer with the buttons and rendered only a few pixels wide. The footer now holds Cancel and Save and nothing else.

Fields are also named for what they do. SSH Keys is now Your SSH key, and says that runs authenticate with it and that only your own keys are listed. Once a host is filled in, a username and an SSH key are required and now fail at the field rather than at Test Connection or at launch, because an environment with a host reaches it over SSH whichever executor it uses. A blocked save opens the card holding the message rather than doing nothing.

Editing a public run environment template also works again. The edit drawer was not told the row was a template, so it asked for an SSH key that templates do not carry.

  • Every user now belongs to an organization: Organizations used to be created only as a byproduct of checkout, so anyone who signed in through single sign-on, was created by an administrator, or joined before organizations existed had none at all. Those users now get one the first time their session resolves, and existing users are given theirs by a new backfill-legacy-organizations command that an administrator runs once.

The command carries an existing organization's Google Cloud project, zone and bucket location across unchanged, so nothing about where a workbench or a project bucket lives moves. It is safe to run more than once, and it reports anything it skipped along with the ids needed to reconcile it. Run it with --dry-run first to see exactly what it would do.

Organization policies are also stricter now. Where a user belongs to more than one organization, the approved directory prefixes and the requirement for role-based AWS authentication are taken from all of them rather than from whichever one happened to be read first, so the most restrictive setting applies.

Billing is stricter in the same way. Removing someone from an organization now also removes their access to that organization's invoices, payment method and subscription, which previously survived the removal. Billing pages also identify the organization once instead of twice, so administrator permission is always checked against the organization actually being changed. In the uncommon case where an account belongs to several organizations and none of them can be singled out, billing now reports that plainly instead of choosing one.

  • One repository for many processes: A process repository is no longer dedicated to a single process. Each connected process now owns a directory, processes/<name>/, holding its contract, schemas and script files, and publishes revision tags named foundry/<name>/rev-<n> so every process keeps an independent revision counter, with a REVISIONS.md in that directory listing its published revisions and their content hashes so the history reads on the hosting provider without running git commands. Exporting a revision now clears the process's directory before writing it, so deleting a script file from a revision removes it from that directory instead of leaving it behind indefinitely. In a repository that was already in use before this change, the copies written at the repository root by the previous layout are left alone as history, so a file deleted from a revision still has a root level copy in that repository. Two processes exporting at the same time no longer collide, because a rejected push is retried against the updated branch, which is safe since a process only ever writes inside its own directory.
  • Lab organizations backfill: Administrators can now create organizations in bulk from a reviewed mapping file, one per invoiced lab, with each lab's members attached and the person listed first made its administrator so they can add and remove members afterwards. The command can be run repeatedly without duplicating anything, and a dry run reports exactly what it would create, reuse, deactivate or skip without writing anything at all. Anything it cannot decide safely, such as a name that already matches two organizations, is reported with the reason rather than guessed at.
  • Platform status page: A status page is now available at /status, showing at a glance whether the platform is operational and which of its components are responding. It lists the web server, and where they are in use the secure tunnel and interactive apps, each marked operational, not responding, or not enabled. The page needs no sign-in, because a status page that requires one cannot tell you about the outage that stopped you signing in, and it refreshes itself every thirty seconds so it can be left open during an incident. It reports component state only, and never exposes version numbers, hostnames or usage figures. Point the new STATUS_PAGE_URL setting at it to reach it from the profile menu.
  • Directory account pre-creation: Administrators can now create accounts in bulk for people their institutional directory already knows, before those people have ever signed in. This matters when organizations are being set up in advance: someone who signs in first is given an organization of their own, and that has to be unpicked by hand once their real lab is created, so preparing their account beforehand puts them straight into the right place. The command can be run repeatedly without creating anyone twice, a dry run reports exactly who it would create without writing anything, and it refuses any row that would produce an account nobody could sign in to.
  • Organization management in the admin panel: Administrators can now see and manage every organization on the deployment. The Organizations page had been listing none of them, because it required each organization to have a billing customer, which is created only when a deployment takes payment, so on a deployment that does not the page was always empty. It also skipped any organization nobody had joined yet, which is the one most likely to need attention, and it counted people who had already been removed. Each row now carries a member count, and a new Manage Members dialog adds people by email, changes what a member can do, and removes them, for any organization rather than only the administrator's own. Adding requires the account to exist already, so a mistyped address is refused instead of quietly attaching the wrong person, and removing somebody leaves their account active so that moving them between organizations does not lock them out.
  • See what a process repository holds, and sync from it: The Files tab now shows what the process repository actually holds: one line per published revision, each naming its tag, newest first, with any revision that no longer exists in this process clearly marked.

This closes a gap that could leave a process stuck with no visible cause. Exporting refuses a revision older than the newest one the repository already carries, so that the branch tip keeps meaning the newest revision. Deleting a revision in the editor does not remove what was already published, because the repository is a record of publications rather than a mirror of current state. Together those two rules meant a repository could sit permanently ahead of every revision a process still held, and the refusal named a revision that appeared nowhere in the product.

The panel now names that condition before Export is pressed, saying which revision the repository holds, which one the process still has, and that the export will be refused.

Sync from repository resolves the disagreement. Deleting a revision hides it rather than destroying it, so a revision the repository still publishes can be brought back exactly as it was. Sync restores those and reports what it restored.

Sync never changes the repository. It adds no commit and removes no tag. It also never invents a revision: a revision published by a different installation cannot be recreated, because the published files are generated from a process and there is no route back, so those are listed with the reason rather than approximated. Revisions are matched by their own identity rather than by their number, since two installations sharing a repository each have their own revision 1 and they are not the same revision.

Nothing about when an export is allowed has changed.

Resolved Issues

  • Workbench cloud identity: A workbench now launches into the GCP project and zone recorded on its organization's customer boundary, which is the same identity its pipeline runs already use. Organizations that also carried an older, separately maintained cloud identity could previously see a workbench start in one project while their runs executed in another, with nothing reporting the disagreement. The older values are copied onto the boundary on upgrade wherever the boundary has none, and organizations whose two records disagree are listed in the upgrade log so they can be reconciled deliberately rather than silently.
  • Fix the process git and script asset endpoints returning 500 in local development: The six process endpoints added by the git integration work (list, save and remove script assets, connect a repository, export a revision, and validate a contract) answered 500 in a local development deployment. Each loaded its business module with a dynamic await import() of a .js path, which only exists in the compiled output, so under pnpm dev the module was never found. They now use the same lazy require the rest of the backend uses, which resolves in both a development and a production deployment.

Production was never affected, because it runs the compiled output where those files exist.

  • Rate limiting now only limits callers it can attribute: Rate limiting no longer keys anonymous requests on the client address, and the liveness endpoint's cap is now sized for aggregate traffic rather than per caller. Behind a proxy that presents every client with the same apparent address, an address bucket is shared by the whole internet, so one caller exhausting it previously returned 429 to every anonymous request including login, and the liveness endpoint's limit of ten requests per minute could be held exhausted by any single caller. Requests carrying an authenticated user are still limited per user exactly as before.
  • Run environment deletion checks the owning organization: Deleting an organization's run environment now confirms that the run environment really belongs to that organization. An organization administrator could previously delete another organization's run environment by naming it directly, because the request was checked against the caller's role but the deletion itself was matched on the run environment alone. A request naming a run environment that does not exist is now refused as well, rather than being reported as a success.
  • Reapplying the ShinyProxy deployment overlay no longer wipes the app catalog: Reapplying the ShinyProxy deployment overlay, which happens whenever the apps cluster is rebuilt from scratch, no longer replaces the installation's app catalog with the bundled demo catalog. The overlay previously listed the demo catalog as one of the resources it applies, so a rebuild silently swapped every configured app for the five sample apps. The catalog is now left entirely to ViaTunnel, which is what maintains it in normal operation, and the demo file remains available as a starting point for brand new installations.
  • Run environments can no longer borrow another user's SSH identity: Sharing a run environment lends an execution identity rather than a configuration, because a run resolves the private key belonging to the environment's SSH record. Saving a run environment accepted any SSH record identifier without checking who owned it, so a run could be made to connect using another user's key and deliver its working directory to a machine that user did not choose.

Attaching an SSH record now resolves only for its owner, or for an administrator, and is refused for anyone else. A record that does not exist stays distinguishable from one you are not allowed to use, so a genuine mistake still reports as not found rather than as a permission problem.

Separately, the three places that derive the on-disk name of a private key disagreed about whose identifier named the file, which could leave a run looking for a key that was never written. They now derive it by one rule.

  • On-prem deployments no longer attempt cloud boundary claims: An on-prem deployment no longer attempts to claim a cloud customer boundary. Customer boundaries are provisioned only for Google Cloud and AWS, so an on-prem deployment has none to draw from, and the three places that previously asked for one (opening a workbench, uploading through cloud storage, and duplicating a run into an organization's data source) now skip that step instead of failing. Google Cloud and AWS deployments are unaffected and continue to claim exactly as before.
  • Nextflow version from the pipeline manifest: Imported Nextflow and nf-core pipelines now launch on a Nextflow version that satisfies the version range declared in their manifest. Foundry previously recognised only a single exact version written as manifest.nextflowVersion = '1.2.3', so the manifest { nextflowVersion = '!>=25.10.4' } block that every nf-core pipeline uses was ignored and the run went out on the platform default, where it died during startup with a plugin resolution error that named a plugin rather than the Nextflow version that actually caused it. Foundry now reads the block form as well as the flat one, understands the ! prefix and the >=, >, <=, < and comma separated range syntax, keeps the configured default whenever that already satisfies the pipeline so nothing that runs today changes, otherwise moves the run up to the lowest selectable version that does satisfy it, and when no available version can satisfy the range it stops the launch with a message naming the requirement and the versions the deployment offers. A version chosen by hand in the run's advanced settings still wins over the manifest, and a DSL1 pipeline is never moved off the DSL1 default.
  • Editing a run environment no longer clears its proxy: Opening a run environment configured with an HTTP proxy and saving it silently reset the proxy to None. Nothing in the form said so, and the next run connected directly instead of through the proxy. The proxy is now loaded into the form along with the executor, the SSH key and the rest of the settings, so saving keeps what was already there.
  • Process git connect panel: The git panel on the Files tab now reads the process's existing repository connection instead of always rendering an empty form. A connected process shows its repository as fixed text, because published revision tags live in it and it cannot be repointed, while the branch and the push credential stay editable and arrive prefilled, with the credential chosen from a dropdown filtered to the selected provider instead of typed in as a numeric database id. Previously the blank form invited retyping the repository URL, and any difference produced a refusal that read like a rule the user had broken rather than a field they could not change.
  • Run Logs In Grafana And Faster Pipeline Imports: Every backend log line emitted while a run launches now carries the run id and the id of the user who launched it. The Grafana run dashboard filters on that field, so its log panel showed nothing for any run until now, even though the logging stack around it was healthy. Deployments without the logging overlay are unaffected either way.

Importing a pipeline from a git repository is also markedly faster. Moving the cloned repository into place was compressing every file first, which only helps when copying across a network and cost around fourteen seconds on a typical repository whose contents are already compressed. Large imports that occasionally gave up with a misleading message about repository access should now complete well inside their time budget.

  • Dataset file count: The file count shown against a dataset in the dataset list now counts each file once, so it matches the number of files the dataset actually opens to. Datasets that held more than one internal reference to the same file previously reported the higher figure, which made a dataset look fuller than it was and could stop it matching when something searched for a dataset by its file count. Only the reported number changes; no file, dataset or reference is altered.
  • Header status and privacy links: The Foundry Status and Privacy Policy links at the foot of the profile menu no longer point everyone at the same two places. Foundry Status previously sent every installation to one hardcoded status page, which reported on one particular deployment and said nothing about anyone else's service; it now reads from the new STATUS_PAGE_URL setting and stays hidden until you point it at a status page of your own. Privacy Policy was an empty anchor that did nothing when clicked; it now opens the privacy policy page on this installation's own documentation site, worked out from the address the platform is served on, so it lands somewhere real on an installation served over HTTPS, on a custom port, or under a sub-path. Set PRIVACY_POLICY_URL to send that link to your organization's own policy instead.
  • Organization naming: Two organizations may now carry the same display name. Each one is given its own underlying group, taking a numbered variant of the name when the preferred one is already in use, so an organization is no longer silently skipped when its name collides with a group that already exists. Organizations keep the name a person reads, and only the internal group name is adjusted. A failed attempt also no longer leaves an unused group behind.
  • Run history no longer reads as empty when it fails to load: The Activity run list never handled a failed request. The table was rendered with no data, so it fell through to its empty state and told the user "It doesn't look like you have any run history", which is indistinguishable from an account that genuinely has no runs. Anyone who opened the page while the API was unreachable, during a restart for example, saw what looked like their whole run history disappear. The list now shows the same error the Runs page already showed, and the empty state is kept for the case it was written for, a successful request that returned no runs.

Failures also read better in the logs. A caught error reported as logger.error(error) arrived in the message position, where it was serialized to an empty object and every detail was lost, including the stack. Ten call sites report failures that way, among them the boot migration step, whose failure was logged with nothing behind it. Such an error now keeps its message and its stack.

  • Accepting an invitation works when you already belong to more than one organization: Somebody who had signed themselves up, had not finished setting their account up yet, and already belonged to more than one organization could not accept an invitation at all: the request failed and nothing happened. Accepting an invitation tidies away the empty organization a self sign-up creates, and it identified that organization by taking whichever of the person's organizations the database happened to return first, which is not necessarily the empty one. Where it guessed wrong the tidying could not be carried out, and the whole request was abandoned with it. The tidying now happens only when there is exactly one organization to tidy, which is the case it was written for, so the invitation is accepted either way. Anyone who belongs to several may be left with an empty organization they no longer need, which an administrator can remove from the Organizations page.
  • One cloud bucket per organization: A customer boundary's publish location is now unique across live boundaries, so uploading the same boundary twice is rejected instead of quietly handing two organizations one bucket. Soft deleting a boundary releases its location for reuse. AWS boundaries also now declare the account they belong to, and a job role from a different account is rejected at upload.
  • Importing a bundle no longer fails when it carries no revision comment: A .vf bundle is not required to carry a revision comment, and a missing one is read as empty. Creating a revision refuses an empty comment, so the import failed with "Unable to create new revision with no comment" and the whole import was rolled back.

Which bundles hit this depended on the receiving installation rather than on the file. The failing path is chosen only when the incoming process already exists here under a different revision, so the same bundle imported cleanly on a fresh installation and failed on one that had already seen the process. That is why the curated example pipelines seeded correctly on a new install and then failed on every later start, reporting one pipeline as failed on each boot without ever recovering.

An imported revision that carries no comment of its own is now given one instead of being refused. Where the revision came from is recorded separately and is unaffected.

  • Foundry Status link points at your own status page: The Foundry Status link at the foot of the profile menu no longer waits to be configured. Every installation has served its own status page at /status since that page was added, but the link stayed hidden until an operator set STATUS_PAGE_URL by hand, so the page was reachable only by typing its address directly. The link now falls back to that page automatically, worked out from the address the platform is served on, so it lands correctly on an installation served over HTTPS, on a custom port, or under a sub-path. This matches how the Privacy Policy link beside it already behaves. Set STATUS_PAGE_URL to send the link to a status page you host yourself instead.
  • Sharing a run environment no longer hands over your cluster account: Sharing a run environment used to lend the owner far more than they intended. Anyone the environment was shared with saw the owner's account name on the cluster, and their runs executed on the cluster as the owner, using the owner's key and the owner's allocation. Nothing in Foundry Connect said so, and the owner had no way to see who was running as them or to stop it.

A share is now a grant that records who it is for and how their runs execute. The recipient can attach their own key and run under their own cluster account, or the share can be sealed, in which case they may still launch runs but the owner's account and key stay on the server where they cannot be read, copied, or edited. A sealed share can be given an expiry, can be revoked, and every run launched through one is recorded with both people's names.

Nothing changes for shares that already exist: they keep working exactly as before, now recorded as sealed shares so the owner can see them. Changing the host or the account a run environment points at now asks everyone it is shared with to confirm their credentials again, rather than silently sending their work somewhere new.

Sharing stays switched off until an organization turns it on, and the controls for creating and managing a share arrive in a following release.

  • Sync from repository now refreshes the revision list it just changed: Sync from repository restores revisions that a process hid and its repository still publishes. It reported what it had restored, and the published-revisions panel updated, but the process's own revision list did not: the restored revision reappeared only after the editor was closed and reopened.

The revision list is cached separately from that panel, and Sync refreshed only the panel. Every other action that changes which revisions a process holds already refreshes the list. Sync now does too, so what it reports and what the editor shows agree immediately.

Enhancements

  • Log Visualization with Loki and Grafana: An optional logging stack ships with this release, off by default. Enabling it adds Promtail, Loki, and Grafana to the deployment and gives operators one place to see errors from every part of the platform: the backend, the MCP server, the web tier, and the renderer, each in its own section of an errors dashboard. Every log line produced while handling a request already carries one correlation identifier, and the identifier is now assigned at the web tier, so a single query follows one request from the moment it arrives to the last background task it triggers. When the stack is deployed, a run's log page links straight into a Grafana view already filtered to that run. Logs are kept for 14 days by default, which is a tuning knob documented in the administrator guide alongside its disk cost. Turn the stack on by adding one file to the compose command; leave it off and the platform runs exactly as before.
  • Shorter Product Updates, with the full notes on the docs site: The Product Updates panel now shows a summarized changelog and summarized upgrade notes, one line per change, so a release can be scanned rather than read. Every release is still listed, none have been dropped. The complete text of both, unabridged, now lives on the documentation site under Product Updates, and each tab of the panel links to the matching page.

[v2.20.1] – 2026-08-17

New Features

  • Share Run Environments with Projects: The owner of a run environment can now share it with specific projects from the run environment form. Anyone who can run in a shared project can then select that environment for their runs. Sharing only adds access and never removes visibility that a user already has, and an organization run environment can be shared only with projects in the same organization.
  • Connect a process to its git repository: Adds POST /v1/process/{processId}/git/connect to register the repository a process publishes to, and mounts the export endpoint that shipped without a route. The repository URL is create only, because published revision tags live in the repository already registered, while the branch and the stored credential can be updated as ordinary maintenance.
  • Attach R and Python scripts to a process: Adds endpoints to list, attach, replace and remove a process revision's script assets. Changing an asset is treated as a change to the process itself, so it returns the revision to draft, regenerates the contract, marks evidence gathered against the old content as stale, and is refused outright on a published revision. A file given without a directory now lands in bin/, which is the directory Nextflow puts on PATH, so an attached script is callable by name.
  • Grant Write Access to Groups on Projects and Run Environments: Project and run environment owners can now grant write access to one or more user groups from the settings and run environment forms. Members of a write group can edit and delete that project or run environment even when they are not the owner, which makes shared resources easier to maintain across a team. Runs inherit their project's write group, so a write group member can also delete and edit the inputs of runs in that project. Access permissions and write groups are independent: sharing a project for viewing does not grant write access, and a write group does not change who can view.
  • Require Role-Based AWS Auth for Runs: Organization admins can now turn on a policy that forbids static personal AWS keys for pipeline runs. When on, a run must use an approved assume-role credential or an attached instance role; the run-environment form hides the static-key option, and both the run-environment save and the run launch reject a static key. The policy also covers the run scheduler's cloud polling, so a scheduler cannot poll cloud storage with a static personal key while the policy is on. The policy defaults off and is set in Organization Settings.
  • Per-environment Download Directory: Run environments now have a first-class Default Download Directory field that sets params.DOWNDIR, the base path pipelines use to download shared reference data. Previously this had to be typed into the free-form Nextflow config field. Existing environments keep working unchanged.
  • Published processes are immutable: A published process revision can no longer be edited. Publishing records the exact commit and container image that the revision describes, so letting the content change afterwards would leave that record claiming something untrue. Corrections are made by saving a new revision. A deprecated revision is likewise not editable, but it can still be deleted, so a retired process is not stuck in the system permanently. Editing a revision that was prepared, validated, tested or ready to publish returns it to draft and cancels the open publication attempt, because the evidence no longer describes the current content. Processes created before this release are unaffected: they count as drafts and stay fully editable.
  • Approved Storage Prefixes for Runs: Organization admins can now define allowed bucket or path prefixes for run work, download, and publish directories. When set, run environments, per-run overrides, and run launches must use an approved prefix, and a run environment can lock its publish directory against per-run overrides. The policy is off by default (no prefixes means no restriction), and managed run environments are unaffected.
  • Export a process revision to its git repository: Adds POST /v1/process/{processId}/git/export. It resolves the repository and the stored credential for the process, materializes the revision, and commits and pushes it, returning the commit, the revision tag and the content hash. Write permission on the revision is checked before anything reads the repository or the credential, so an unauthorized caller cannot learn that either exists.

Resolved Issues

  • Export API documentation matches what it returns: The documented response for exporting a process revision advertised two fields that were never returned and omitted two that were. The API itself was unaffected, since the schema feeds the generated documentation rather than filtering responses, but anyone reading the docs got the wrong contract.
  • On-prem deployments do not get a stray GCP run environment: Organization creation used to build a Google Cloud run environment for every organization on every deployment, including on-prem installs that can never use one. A deployment now declares its execution modality with the DEPLOYMENT_BOUNDARY_KIND setting, one of GCP, AWS or OnPrem. Existing deployments default to GCP and are unchanged. An on-prem deployment sets it to OnPrem and organizations get no run environment stub at all, so administrators configure run environments for each site by hand instead. AWS is accepted as a value but is not implemented yet.
  • Organizations can be created on a fresh installation: Creating an organization failed with "Run Environment not found" on any installation where an operator had not manually inserted the organization run-environment template row. The template is now defined in code and created automatically the first time an organization needs it, so a brand-new installation works without a manual database step. An administrator's later edits to the template are preserved and still flow into organizations created afterwards.
  • Shiny watchdog no longer restarts a healthy control plane: The Shiny/workbench watchdog declared the Kubernetes control plane down on a single minikube status reading, so one slow or degraded reply was enough to restart a cluster that was serving normally. That restart cycles all three redis pods at once, which is what produces the sentinel split brain the watchdog then spends several minutes repairing. It now confirms across three reads and takes a second opinion from the apiserver's own readiness endpoint before starting anything, and it can restart a local viatunnel without extra configuration.
  • Concurrent process saves: Saving a process that someone else saved while you were editing it now explains what happened instead of reporting a generic server error. The second save has always been rejected, so no work was ever overwritten, but the person who lost the race was told only to contact support. They are now told that someone else saved a new version and that reloading will show those changes.
  • Process output publish patterns: Editing a process no longer erases the publish pattern on its outputs. A process imported from a .vf file carries a pattern that decides where its run outputs are published, and because the editor had no field for it, every save cleared it and quietly moved that process's outputs somewhere else on the next run. Saving as a new revision dropped it the same way.
  • Editing a shared process: The guard that protects a process used by other pipelines now works as intended. It had been rejecting every edit by a non-admin, including harmless ones, while at the same time not checking parameter changes at all. Changes that would break another pipeline are still blocked, and safe edits go through again.
  • Run cleanup on SFTP storage: Cleaning up a run whose publish target is an SSH/SFTP server now removes both the report directory and the run directory. Previously the second removal failed with "An existing SFTP connection is already defined" and the run directory was left behind. Dropped SFTP sessions are also no longer able to raise an uncaught error inside the server.
  • Size the process contract hash columns for their algorithm tag: The database columns that hold process contract and evidence hashes were sized for a bare digest and could not fit the algorithm tag that is written with it. They are now wide enough, across all nine columns rather than only the ones in use, so the remaining ones cannot hit the same problem the first time something writes to them. Reverting this migration now refuses, with an explanatory error and without changing anything, if any stored value is already too long to fit back. Rolling an older image against the wider database is the supported path instead. No environment changes.
  • Credentials Kept Out of Logs: Credential values are no longer written to run logs, application logs, or error messages. The run log now records the names of the credential variables prepared for a run, never their values. Exporting a pipeline to a private repository hands the access token to git through the environment instead of placing it in the repository address, so it cannot reach a log line or an error message shown in the interface. Branch names are passed to git as plain arguments, so a branch whose name contains punctuation now exports correctly.
  • Process delete authorization and concurrent edits: Deleting a process now checks whether you are allowed to delete it before doing anything else. Someone without permission previously received an error that revealed whether the process was used in other people's pipelines and runs, and now learns only that they are not authorized. Saves and deletes of the same process are also serialized, so two people acting at the same time can no longer overwrite each other's decision, and a save that collides with someone else's change in progress now reports that someone else is editing the process rather than failing as a server error.
  • Uploaded file permissions: Files uploaded to an SSH or SFTP data source are no longer world-writable. They previously arrived with permissions that let any other account on the same server overwrite them, which matters most on a shared cluster. They now arrive with the same permissions the platform already applies to files it downloads.
  • Directory uploads to SSH storage: Uploading a folder to an SSH or SFTP data source can no longer leave files world-writable. The upload had a retry path that took over whenever the fast transfer method was unavailable, and files written by that retry arrived writable by any other account on the same server, which matters most on a shared cluster. The retry has been removed because the platform already recovers from that failure by uploading the folder one file at a time, and that route sets permissions correctly.
  • Uploaded file permissions on chunked uploads: Files uploaded to an SSH or SFTP data source in chunks, which is every upload above the single-chunk threshold, no longer land world-writable. Only the creation of the file carried the intended permissions, and each chunk written after that silently reset them, so any other account on the same server could overwrite the finished file. This closes the half of the problem that the earlier permissions fix did not reach.
  • Google Batch Project and Run Labels: Pipeline runs on Google Batch now take the Google Cloud project from the selected Google Cloud credential when the run environment's Project ID field is left blank, which is what the run environment form has always told users they could do. Previously those runs were submitted with no project set. A Project ID typed into the run environment now also takes effect when a credential is selected, instead of being ignored. Google Batch runs are additionally labelled with the real server address rather than a placeholder, so cost reporting in Google Cloud billing groups by server correctly.
  • Documentation matches the release: The documentation site shipped with a release is now built for that release rather than being relabelled from an older build, so its version always matches the running application. Previously the two could drift apart silently, and the documentation could omit pages for features the release already contained. The release now refuses to publish if the documentation does not carry the expected version.
  • Google Batch Label Configuration Is Now Validated At Startup: The optional GOOGLE_BATCH_LABELS setting, which stamps extra labels onto every Google Batch task for cost reporting, is now checked when the server starts instead of being accepted as any JSON at all. It must be a plain object of label names to values, and both sides must fit the character set Google Batch accepts. A setting that does not fit is reported at startup with the offending label named, rather than being accepted and then rejected by Google partway through a pipeline run, where the reason only appeared in a cluster log. The documented type was previously a list, which no version of the code could ever have used correctly, so anyone following it would have produced unusable labels.
  • New Organizations No Longer Get An Unreachable Bucket: Creating an organization used to add a shared data source pointing at a fixed cloud bucket that only the vendor's own deployment could reach. Every organization got it, on every installation, including sites that run all their pipelines on a local cluster and use no cloud storage at all, so the entry was visible but unusable. The seeded data source is now optional and set per installation, and where none is configured no data source is created. Both Google Cloud Storage and Amazon S3 paths are supported, with the storage type recognised from the address.

Enhancements

  • Structured Logging: Application logs are now written as structured JSON, one object per line, with each entry carrying the service, the source module, and the acting user. Every log line produced while handling a single API request now shares one correlation identifier, so an entire request can be followed end to end by filtering on that one value, including the work that continues after the response is sent. If a request arrives with an x-request-id header the identifier is reused, which lets a proxy assign it at the edge and keep it consistent across every hop, and the identifier is always returned on the response. Log files keep the names, daily rotation, compression, and retention window they had before, and setting LOG_FORMAT=pretty gives human readable output on stdout for local development while the log file keeps its JSON.
  • Consistent API paths: Every API resource is now reachable at a single consistent address of the form /v1/<resource>, so the published API document describes one style instead of two. This is purely additive and every existing address still works unchanged, so nothing that already calls the API needs to be updated. Fixing the generated document along the way also corrected seven endpoint descriptions that were malformed and could not be used by API client tooling.

[v2.20.0] – 2026-08-03

New Features

  • AWS Run Authentication Modes (UI): Run environments now offer a three-way AWS authentication choice: a static key, an approved assume-role credential, or the compute's attached instance role. Organization admins create assume-role credentials in Organization Settings by picking an approved role ARN, and system admins manage the approved role ARN allowlist from the admin organizations page. This is the UI for the backend shipped in "AWS IAM Role Based Run Auth". No environment changes.
  • AWS IAM Role Based Run Auth: A run environment can now authenticate to AWS using an approved IAM role through assume role, or the run compute's attached instance role, instead of long lived static keys. Assume role targets are governed by a system admin approved role ARN allowlist.
  • Dataset Tags: Datasets can now be tagged, the same way runs, projects, and pipelines already could. Assign tags from a dataset's detail page, see them in a Tags column on the datasets list, and filter the list down to a single tag.

Admins manage the dataset tag vocabulary from a new Datasets tab under Admin, seeded with raw, processed, reference, and public. Each entity type keeps its own separate tag list, so a dataset tag never shows up when tagging a run, a project, or a pipeline, and tagging a dataset still requires write access to it.

  • Example Pipelines Out Of The Box: New installs now start with a curated set of example pipelines (RNA-Seq, ChIP-Seq, ATAC-Seq, single-cell, smallRNA, FastQC, Differential Expression, and a tutorial), and existing deployments add them on their next update. Each is marked with an "example" tag, so you can filter the pipeline list to find the starters.
  • Per-Run Nextflow Version Selection: Choose the Nextflow version for a run from the Advanced tab, from an admin-curated list (NEXTFLOW_VERSIONS). The selection overrides the pipeline's configured version and the global default. Leave it as Default to keep the pipeline's own setting. Works for both built-in and external nf-core pipelines.

Resolved Issues

  • In-App Documentation Links: The 404 page and the SSH credential help now open the self-hosted documentation site configured for your deployment instead of a fixed external address that could be unreachable. The API Reference link points to the built-in API docs.
  • Safer database migrations on multi-replica deployments: Database migrations now run under a cluster-wide lock, so starting several backend replicas at once no longer lets each of them apply the same migration concurrently. The migration table also gained a unique constraint on the migration name, and a duplicate left behind by an earlier concurrent start is collapsed automatically on upgrade.

Migration ordering is now explicit rather than inherited from the filesystem and the database collation, which removes a way for the backend to refuse to boot with a spurious "migration mismatch" or "incorrect parent reference" error. No environment changes.

  • Detects Cluster Jobs That Outlive Their Run: A run could be recorded as finished while its job kept running on the cluster, consuming capacity and writing into the run directory alongside any rerun started afterwards. Nothing surfaced this, so it could continue unnoticed for days.

A daily check now compares finished runs against the cluster and reports any whose job is still running, naming the run and the job id so it can be dealt with. The check only reports; it never cancels anything, and a cluster it cannot reach is never treated as evidence either way. The time window and the per-run limit are configurable.

  • Process Revision Identity On Import: Importing a pipeline file can no longer create a second copy of a process revision that this installation already has. Each process revision carries an id that means the same revision in every installation, and import used to miss a local copy that had been removed, or that had been filed under a different process, and store the revision a second time under the same id.

Such an import now stops before writing anything and asks what to do. The Conflicts step of the import wizard names every clashing process version, says whether the content differs from the file, and offers a choice per version: keep the version already here, bring back a removed version whose content matches, or delete the version here and use the incoming one. Nothing is preselected, and the import cannot be approved until every clash has an answer. Deleting is offered only when nothing depends on the local version; when something does, the option is shown disabled next to the runs and pipelines that depend on it.

  • Remote Command Reliability: A failed file listing on an SSH data source used to return the full command that had been attempted, which included the location of the SSH key file on the server. Only the message from the remote host is returned now.

Fetching run results and polling scheduled runs could also wait indefinitely when a remote host stopped responding, with nothing to interrupt them. Both now give up after the configured SSH timeout and retry on the next cycle.

  • Numeric Sorting In Report Tables: Report and run-log tables now sort numeric columns by value instead of alphabetically, so a column of counts no longer places 1,000 ahead of 2 and 900. Numbers formatted with thousands separators or percent signs are handled, and blank or non-numeric cells sort to the bottom.
  • Sample Sheet And Input Uploads: Sample sheets and other run inputs uploaded through the API now land in the run environment where the pipeline reads them, instead of a local report directory. This fixes runs on cloud storage and non-shared clusters where an uploaded input never reached the compute environment.
  • Run Launch On Pipelines Without An Initial Run: Fixed a regression that made run launches report a failure on pipelines that have no initial run step. The per-attempt log reset wrote a harmless "no such file" message to the error stream when a pipeline had no initial run directory, and the launch treated any error output as a failed submission. Affected runs were marked as errored and never recorded their scheduler job id, so their progress could not be tracked even though the job itself was submitted.
  • Rerun And Resume Status: Rerunning or resuming a failed run now stays in the running state instead of flipping back to an error a second after launch. The status check no longer mistakes a run that has just been submitted, and whose scheduler job id is not yet known, for a run whose process has died. Each attempt also starts from a clean run log, so a resumed run is no longer reported with the previous attempt's failure and can report success when it completes.
  • Run Status Order After Launch: A newly launched run now reports Initializing before Running, instead of briefly claiming it was already running and then appearing to go backwards. The status set at submission said the pipeline had started when only the job had been queued, so the next status refresh corrected it downwards.
  • Terminate Now Actually Stops The Run: Terminating a run could report success while the job kept running on the cluster. Resuming afterwards then started a second copy on the same working directory, which failed immediately with "Unable to acquire lock on session".

Three changes close this. Terminate no longer sends the placeholder process id to the scheduler, so the kill reaches the real job. It now checks what the scheduler reported back and surfaces an error instead of marking the run Terminated when the kill was rejected. And starting a run is refused while its current attempt is still initializing or running, with a message asking you to terminate that attempt first, so a second copy can no longer be launched on top of a live one. A refused start leaves the running attempt untouched.

  • Terminate Confirms The Job Actually Stopped: Terminating a run asked the scheduler to kill the job and trusted that the request was enough. A scheduler can accept a kill and still leave the job running, and when that happened the run was marked Terminated while its work carried on, consuming cluster capacity and writing into the run directory.

Terminate now checks with the cluster after the kill and reports an error instead of marking the run Terminated while its job is still visibly running. If the cluster cannot be reached for an answer, the terminate still completes, so an unreachable cluster can never leave a run impossible to stop.

Enhancements

  • Clearer Run Status Values: Run statuses returned by the API now read as plain words instead of abbreviations, so a completed run reports Completed rather than NextSuc. The web interface is unaffected, since it already displayed these as Completed, Running and Error. Scripts and integrations that filter runs by status keep working, because the previous values are still accepted for two more releases, and saved Sample Explorer views that filter on run status are updated automatically during the upgrade.

[v2.19.7] – 2026-07-28

Resolved Issues

  • Cluster Options on Run Environment Change: Switching a run to an environment that defines no cluster options now clears the previous environment's options instead of keeping them, so a leftover resource request (such as the retired cluster's -R "select[rh=8]") no longer leaks onto a cluster that rejects it and fails the job at submission. The mount-check that auto-fill adds is also no longer duplicated or run together without a space when other options are already present.
  • Old Run Links Keep Working: Links to a run that used the older /run/<id> address now redirect automatically to the current /runs/<id> page. Existing bookmarks and shared run links no longer break, and any tab or view saved in the link is preserved.

[v2.19.6] – 2026-07-24

New Features

  • Ask an AI assistant which pipeline fits your experiment: Describing an experiment in plain language now gets you a pipeline recommendation with the reasoning behind it, a past run to copy settings from, and only the handful of settings that genuinely need a decision, instead of every input the pipeline defines.
  • Prepare a run and read its results from your AI assistant: You can now get a run ready and interpret what it found without opening Foundry Connect: build a sample dataset from your sequencing files, author the design sheets, and check the run for problems before it reaches the cluster.
  • A pre-flight check catches the things that quietly waste queue time, such as a missing dataset or design files pointing at data that has since been cleaned up. Previously these surfaced only as a silently skipped step, after the wait.
  • Results are summarised by what the run found rather than which files it wrote, including which findings several methods agree on, with outputs grouped by what they are and intermediate files hidden.
  • Suggests which viewer opens a given set of results.
  • See how far along a run actually is: Asking an AI assistant about a run in progress now reports step-level progress — how many steps are finished, what is running right now, and what failed with which error — instead of a single status word.
  • Steps reused from an earlier attempt count as finished, so a largely reused run reads as complete rather than barely started.
  • When a run's files have already been cleaned up, the assistant now says the logs are gone instead of suggesting you wait for logs that will never arrive.

Resolved Issues

  • The right log when a run fails, from chat: Asking an AI assistant why a run failed returned a 42-byte job-starter stub instead of the log that carried the actual error. Cluster runs produce no .command.* files, so the assistant now falls back to the logs that do carry the failure.
  • Harden the run file-upload directory check: Uploading a file to a run accepted any directory path, including ones pointing outside the run's own report folder. Uploads are now confined to the run they belong to, and file names are stripped of any path components.

[v2.19.5] – 2026-07-24

Resolved Issues

  • Re-run and Resume clear the previous logs immediately: Starting a re-run or resume no longer shows the previous attempt's logs while the new run starts up. The log panel now clears as soon as you click and shows a loading state until the new run's logs arrive.
  • Stronger access token generation: Personal access tokens and the tokens issued when you connect Claude are now generated with a cryptographic random number generator.
  • Tokens issued before this change remain valid, but we recommend replacing long-lived ones from your Personal Access Tokens page.
  • Hashed access-token storage: Personal access tokens and the tokens issued when you connect Claude are now stored as a one-way hash instead of in a readable form, so a copy of the database no longer reveals usable tokens. Existing tokens keep working.
  • Fix runs failing to start on the compute cluster: Runs submitted to a compute cluster failed to start and stayed stuck showing "Running". The run bundle was never unpacked on the cluster, so the run log only showed the misleading "File or directory not found on remote server." Cluster runs start correctly again.
  • A failed unpack no longer falls through to the cleanup step that deleted the run bundle, so the real error is reported and the bundle is kept for diagnosis.
  • Errors while starting a run on the cluster are now recorded against the run, so it is marked as failed instead of sitting at "Running" indefinitely.
  • More detail when a run fails to start on the cluster: When a run failed to copy or unpack its files on the compute cluster, the run log only showed a generic message such as "File or directory not found on remote server." It now also includes a "Details:" line with the underlying error, so there is more to go on when reporting a stuck run.
  • Saving a pipeline no longer times out: Saving a pipeline could hang and then fail with an operation error while a background cleanup task was running. That task now uses an indexed lookup instead of scanning every run record, so it finishes in milliseconds instead of minutes and no longer holds up your work.

[v2.19.4] – 2026-07-23

New Features

  • Tag your pipelines: Pipelines can now be tagged, per revision, the same way runs and projects can. Assign tags on a pipeline's Settings tab, see them on the pipelines table, the pipeline glossary cards, and your activity, and filter a project's pipelines list by tag.

  • Owners, admins, and members of a pipeline's write group can assign tags.

  • Admins define the available pipeline tags from a new Pipelines tab in the Tags admin page; pipeline tags are kept separate from run and project tags.
  • See why a run failed, from Claude: Ask Claude why a run failed and it can now answer. Previously a failed run reported only a status code and you had to open Foundry to find out what went wrong; the connector can now fetch the run's execution log and tell you which step failed and why.

  • Run status is reported in plain language — "Running", "Completed", "Failed" — instead of internal codes like NextErr.

  • Asking about a run's configuration returns a readable summary (pipeline, samples, key settings) rather than a wall of internal parameters; the full editable configuration is still available when preparing a run to launch.
  • Launching a run now states up front that it consumes cluster compute, so you are asked to confirm before anything starts.

Resolved Issues

  • Consistent Claude connector name: Connecting Claude Code from your Profile now suggests the same server name (foundry) that the Foundry Connect plugin registers, so /mcp shows one consistent entry however you connect. If you previously added the connector as viafoundry, run claude mcp remove viafoundry before re-adding it, otherwise you will have two servers exposing the same tools.
  • Report tables no longer freeze the app: Opening a large CSV/TSV report used to lock up the whole of Foundry Connect while the file was parsed — a 7.7 MB, 15,000-row table froze the browser for about 13 seconds, and nothing else in the app would respond until it finished. Parsing is now roughly 20x faster and runs in a background worker, so the interface stays usable while a report loads and rows appear progressively as they stream in. Report files are also served compressed now, and searching within a table no longer re-filters on every keystroke.

Very large tabular reports (25 MB and above) now show the first 1,000 rows with a notice instead of attempting to render the whole file; use the download button for the complete table. Downloads, "Open in New Window", and the MCP/SDK file tools are unchanged and still return the complete file.

[v2.19.3] – 2026-07-22

New Features

  • Tag your projects: Projects can now be tagged, the same way runs can. Assign tags on a project's Settings tab, see them on the projects list and your activity cards, and filter the projects list by tag.

  • Admins define the available project tags from a new Projects tab in the Tags admin page; project tags are kept separate from run tags.

  • The projects list gains a Tags column and a tag filter, and each project's activity card shows its tags.

Enhancements

  • Filter runs by tag from Claude: The Claude/MCP connection can now filter runs by tag — ask, for example, "show my runs tagged demo" and only runs carrying that tag are returned. Run listing is also more robust to how a sort is requested, so phrasings like "most recently modified" no longer fail.

[v2.19.2] – 2026-07-21

New Features

  • Tags on the project runs list: The runs list inside a project now shows a Tags column and lets you filter runs by tag, matching what the all-runs list already offered.

  • Each run displays its assigned tags as colored labels, with the full set on hover when a run has several.

  • A tag picker above the list narrows it to runs carrying the chosen tag.

Resolved Issues

  • Connecting Claude: Approving access when connecting Claude to Foundry Connect now completes successfully. Previously the browser blocked the final "Approve" step on the sign-in screen, so the connection could not finish.

[v2.19.1] – 2026-07-20

New Features

  • Connect to Claude: Connecting Claude (claude.ai, Claude Desktop, or Claude Code) to your ViaFoundry instance now takes one step: add your ViaFoundry URL as a connector and sign in through your browser. There are no tokens to copy.
  • Active Claude connections are listed and can be revoked under Profile → Connect to Claude.
  • Tags and Run Tagging: Runs can now be organized with tags. Administrators define and manage reusable tags — including a set of predefined ones — from a new Tags panel in the admin area, grouped by the type of item they apply to. Users can then apply one or more tags to a run and filter or search the run list by tag to quickly find related runs.
  • Launch runs and connect Claude over MCP: Bumped the bundled MCP server to add run-execution tools — duplicate, update, and initiate runs — plus OAuth bearer support for the "Connect to Claude" flow. Claude and other MCP clients can now prepare, launch, and monitor pipeline runs conversationally, and connect without manually copying a token.

Resolved Issues

  • Export the full filtered users table: Exporting users from the admin Users table now includes every user matching the current filter and sort order, not just the rows loaded on the visible page. The export is assembled on the server so large, filtered result sets come through complete.
  • Preserve pipeline origin and status across .vf import: Exporting a pipeline to a .vf file and importing it again now preserves the pipeline's origin and workflow status. Previously these were dropped on import and reset to their defaults.
  • Remove unauthenticated debug endpoint and fix renderer health check: Removed a leftover /api/root debug route that was reachable without authentication and, on each request, minted and logged a Google Cloud access token before returning Vertex AI endpoint data to the caller. The route was unused by the application and has been deleted along with its hardcoded credentials. Separately, the renderer service health check now uses wget instead of curl — the renderer image ships only wget, so the container previously reported as unhealthy even while serving requests correctly.
  • Duplicating older runs no longer fails: Fixed a crash when duplicating a run whose most recent attempt predates run-option capture — for example legacy or terminated runs, where the stored run options are empty. Duplication previously failed with an internal "Failed to duplicate run" error; it now proceeds, treating the missing run options the same as a run that has no prior attempt.
  • Cleaner run startup logs: Run startup logs no longer surface benign archive-extraction warnings from the compute cluster (harmless "unknown extended header keyword" notices) that could show up as an "error" line even when the run started and completed normally.
  • Backend no longer crash-loops on startup after the log-path rename: Restored the default log directory to /var/log/viafoundry (and log file name to viafoundry) so existing deployments keep starting normally. A recent rename had changed these defaults to /var/log/foundry_connect, a path the non-root backend process cannot create at runtime and which is not the writable ./output bind-mount target used by every compose file — so any install that did not explicitly set LOG_DIR crash-looped on startup with EACCES (surfaced as "database migrations failed; refusing to start backend"). Installs that want the rebranded path can still set LOG_DIR explicitly.

Enhancements

  • Removed third-party analytics and the CommandBar help widget: The platform no longer bundles the Amplitude analytics and session-replay SDKs or the CommandBar "HelpHub" help widget. No third-party usage analytics or session recordings are collected, and the in-header HelpHub button has been removed. Installations that set the related environment variables can drop them; no other configuration changes are required, and existing .env files with the old variables continue to work (the variables are simply ignored).
  • Rebranded to Foundry Connect: The platform is now Foundry Connect. Every user-facing surface — the app UI, page titles, logo and favicon, notification emails, generated download scripts, API documentation, in-app documentation links, and the sample project — now uses the new name. Existing installations upgrade with no configuration changes: internal identifiers (Docker service and network names, environment variables, the database name, image and registry paths, and hostnames) are intentionally unchanged, so your .env files and existing data need no edits and no migration.
  • Editable App Version: The Edit App form now includes an App Version field, pre-filled with the app's current version, so you can update the version while editing an app. The field validates semantic version format (for example 1.0 or 1.0.0).
  • Terminate disabled during run start-up: The Terminate action on a run is now disabled for the first minute after a run attempt starts — until the run has an active process — so a run can no longer be accidentally terminated before it has fully started.

[v2.19.0] – 2026-07-10

New Features

  • In-app Upgrade Notes for admins: Admins now see an "Upgrade Notes" tab in the Product Updates dropdown listing version-specific configuration changes (from BREAKING_CHANGES.md) to apply when upgrading an installation.

Resolved Issues

  • Reliable Cleanup of Intermediate Run Files: Fixed an issue where the automatic cleanup of intermediate run files could stop running until the platform was restarted. Cleanup now ignores runs belonging to deleted pipelines and continues past any single problematic run instead of halting.
  • Correct Handle Pulsing in the Pipeline Builder: Fixed the pipeline design canvas so that, when you hover over a node to make a connection, only that node's still-unconnected and compatible connection points pulse. Previously a partially connected node could highlight the wrong handle, and Skill nodes were left out of the pulse logic entirely.

Enhancements

  • Reversible Rollback of Backward-Compatible Upgrades: The backend can now boot against a database that is one or more backward-compatible migrations ahead of the deployed image when ALLOW_SCHEMA_AHEAD=true, so rolling an image tag back no longer hard-fails at startup. Genuine schema divergence is still rejected.
  • Configurable default admin via environment: The default admin account created when seeding a fresh database is now taken from ADMIN_USER_EMAIL and ADMIN_USER_PASSWORD instead of a hardcoded identity, so installations are no longer tied to a built-in default.

[v2.18.6] – 2026-07-06

Resolved Issues

  • Reliable Log & Report Fetching for Completed Runs: Completed runs now reliably show their final status, logs, and reports. Files copied back from the execution environment are always fetched with permissions the platform can read, and harmless file-transfer conditions no longer cause a finished run to be reported as failed.

[v2.18.5] – 2026-07-06

Resolved Issues

  • Run Logs & Reports Not Updating: Fixed an issue where a run that completed successfully on the cluster could keep showing a stale “Error” or “Running” status with out-of-date logs and reports that failed to load. Completed runs now correctly display their final status, logs, and reports.

[v2.18.4] – 2026-07-06

New Features

  • Re-sync a Run from Disk: Added the ability to force-refresh a run’s status, logs, and reports directly from the execution environment, recovering runs whose status became stuck.

[v2.18.3] – 2026-07-03

Resolved Issues

  • Run Logs & Status After Resume: Fixed a stale log fetch from a superseded attempt overwriting a newer attempt’s live state, which could freeze a run’s logs and status after a terminate → resume.
  • Stuck “Running” Runs: Fixed finished runs that failed to update their status or copy back reports after their log/report pollers were lost; the run now re-registers its pollers and recovers automatically.

[v2.18.2] – 2026-03-24

New Features

  • Sample Explorer (Activity Page): Added a Sample Explorer view on the Activity page so users can browse samples across their projects.
  • Run Filtering: Added advanced filtering on the Run page.
  • Run Attempt Management: Added support for managing run attempts naming and deletion.
  • Sample Tracker API Configuration: Added a configuration section for Sample Tracker API settings.

Resolved Issues

  • Sample Tracker Permissions: Fixed permission inheritance issues in Sample Tracker.

[v2.17.5] – 2026-03-02

New Features

  • Run Scheduler: Automatically schedule run jobs without manual intervention.
  • Scheduling based on Sample Tracker manifest data.
  • Triggering jobs when new data is detected in defined locations.
  • Run Analytics: Added a Run Analytics view for exploring run usage metrics over time, with date range and pipeline filters, search, and CSV export.
  • Organization Invite Links (URL-Based Onboarding): Org admins can generate a unique invite URL tied to their organization. Users who register via this link are automatically linked to the organization (pending admin approval).
  • Guest Downloads – Folder-Only Mode: Added the “Add Folder for Download Only” option for guest users (requires a bucket and at least two folder levels).
  • MCP Server Management: Added MCP server creation, editing, and filtering.
  • MCP Client Connection Manager: Implemented a connection manager for registered MCP servers (connect, discover tools, execute tool calls, and monitor health).
  • System-Wide Notification Banner: System administrators can configure and preview a global notification banner via the Admin panel; the banner appears on every page and can be dismissed by users.
  • AI Insights – Knowledge Builder (RAG): Added a Knowledge Builder section to upload custom files and use them as context in AI Insights responses.
  • Admin – Test Email Notification: Admins can send a test email notification from the Foundry platform.

Enhancements

  • Pipeline Import – Initialize Git Submodules: Added a per-import option to initialize Git submodules recursively when importing pipelines from Git.
  • Datatable (Percent) – Download with Percentages: Added a “Download with Percentages” option for the Datatable (Percent) view.

[v2.16.1] – 2026-02-05

New Features

  • Sample Explorer: Released Sample Explorer with a new tab in Sample Tracker, allowing you to view and filter samples alongside their run and report data.
  • Self-Service Account Deactivation: Users can now deactivate their account directly from the Profile page.

Enhancements

  • Downloads for External Tools: Pre-signed download links have been updated to work better with app integrations (e.g., IGV) and preserve the expected filename.
  • Pipeline Variables: Added {{ FOUNDRY_RUN_NAME }} to the Foundry variables list so it can be used directly in pipeline scripts.
  • AI Insights – Smarter Chat Context & RAG: Conversations remember the page they came from with clearer in-app prompts when you reload or navigate; RAG now includes better image recognition, PDF text extraction, faster semantic search, and automatic embeddings management.

[v2.15.0] – 2026-01-21

New Features

  • Sample Tracker: Introduced the Sample Tracker feature to create and manage samples with flexible metadata tracking support.
  • New Dataset Features:
  • Flexible metadata support—define custom metadata alongside your samples.
  • Dataset editing in sample-sheet mode.
  • Drag-and-drop dataset import.
  • Dataset file downloads directly from the UI for cloud-hosted files.

Enhancements

  • AI Insights – Navigation & Resuming Saved Chats: AI responses are now page-aware, and saved chats can be resumed.

[v2.14.1] – 2025-12-24

New Features

  • Pipeline Example Runs: Added an Example Runs section to pipeline details with support for multiple links.
  • Email Notification Preferences: Added email notification preferences to the Profile page.
  • Run Cost Estimation: Run cost estimation can now be shown on the Run page upon user request.
  • Executor Profile Auto-Selection: Added an executorType-based profile approach (e.g., foundry_awsbatch, foundry_googlebatch). If a pipeline includes these profiles, Foundry automatically enables the matching one at runtime based on the selected executor.

Enhancements

  • Run Page Downloads: Download tab upgrades to display files from both report and run directories, and support downloads using a prefix-based approach.
  • Data Page Uploads: Added the ability to cancel file uploads.
  • Workbench Actions: Added a confirmation modal for terminate and stop actions.
  • Dataset GEO Retry: If GEO search fails to retrieve information from NCBI, we now list the failed IDs and allow retrying failed items.

[v2.14.0] – 2025-12-16

New Features

  • Pipeline Export & Download: You can now export and download pipelines.
  • Dataset Upload: Added the ability to create folders directly from the dataset upload page.
  • Personal Access Tokens: Added token management in user profiles—create, view, copy, and revoke personal access tokens.
  • Cloud Run Report Downloads: In cloud environments, users can list published run report files and download them from the UI.
  • Run Logs Download: Added a one-click option to download run logs as a ZIP file.

Enhancements

  • Public App Revision Flow: Improved the public app revision experience—users can now create revisions of public apps.
  • AI Insights Upgrades:
  • Create and manage multiple chat sessions (list, select, delete)
  • Support for multiple tabs
  • Page-specific context support for more relevant assistance across the app
  • Workbench Status Improvements:
  • Added new filters on the Workbench Status page
  • Added summary statistics for workbenches the user can access
  • Automatic Error Log Retrieval: When a run fails, the system automatically retrieves the .command.log file from the work directory and displays it in the run logs section for faster debugging.
  • Container Memory Limits (Apps): Added support for setting container memory limits in the App configuration.

[v2.13.0] – 2025-11-13

New Features

  • Autoscale Time Limit: Added the $AUTOSCALE_TIME flag to automatically adjust time limits for failed jobs, similar to autoscale Memory and CPU.
  • Report Ordering: Added the @report_order flag to control the ordering of run reports.

Enhancements

  • AI Insights for Run Reports: Improved run report analysis with support for selecting AI keys and models.
  • Run Duplication: Run duplication now allows users to duplicate run reports and input datasets into selected locations.

[v2.12.0] – 2025-10-17

New Features

  • AI Insights for Run Reports: Run reports are now summarized and analyzed by AI, providing clear, actionable feedback to users.
  • Dataset Creation Revamp: Reimagined dataset creation flow for a faster, more intuitive experience, including glob pattern support and folder selection.

Enhancements

  • Specify Nextflow Version: You can now change the Nextflow version a pipeline by adding manifest.nextflowVersion to the config file.
  • Workbench Cost Estimation: Organization-level cost estimation for Workbenches to improve visibility into usage and associated costs.
  • Automatic Workbench Stopping: Workbenches automatically stop after a defined idle timeout to optimize resource utilization.
  • Run Permissions: Runs inherit project permissions when created or duplicated.
  • GCP Pipelines: Enabled process.stageInMode = 'copy' for pipelines running in GCP environments to avoid related staging issues.

Resolved Issues

  • Optional Inputs in Pipelines: Improved handling of optional inputs in complex cases.
  • Pipeline Modules Tooltips: Fixed minor tooltip content issues.
  • Run Report: Resolved an issue where run report content failed to load correctly.

[v2.11.0] – 2025-09-22

New Features

  • Improved Sharing on Runs & Projects: Invite users directly from Run and Project pages via the Share button.
  • Run Duplication (with Reports & Logs): Duplicate a run along with its associated reports and logs.
  • Dataset Creation Flow Refresh: The Data page has been updated for a smoother dataset creation experience.

[v2.10.0] – 2025-09-08

New Features

  • Dataset Selection Enhancement: The Run page file modal now presents datasets as selectable units rather than individual files, enabling faster and more efficient selection.
  • Find and Replace Capability: A new find/replace feature has been introduced within both process and pipeline editors.

Enhancements

  • Bin Folder Update Handling: Resume operations will recognize the changes in bin folder and apply these updates without requiring a full rerun.
  • Custom Initial Run Support: Pipelines may now define a custom initialrun step by including an initialrun.nf file within the pipeline files section.
  • Process Input Ordering: Process inputs now follow the order in nextflow.config file.

Resolved Issues

  • Error Detection and Reporting: Error recognition logic has been refined to reduce the occurrence of misleading error screens.
  • Spreadsheet Editor Context Menu: Corrected the positioning of the context menu within the Run page spreadsheet editor.
  • Group Section Stability: Fixed an error when adding members to a group to ensure consistent functionality.
  • File Uploads: Enhanced the Run page file upload functionality to support multiple uploads.
  • Application Suggestions: Resolved issues with suggested application listings within pipeline and report pages.
  • Process Input/Output Display: Corrected the display of process inputs and outputs exceeding 10 to ensure complete visibility.
  • Project Bucket Path: Fixed inconsistencies related to project bucket path handling.

[v2.9.8] – 2025-09-02

What's New

  • Introduced User Sign-Up feature to streamline onboarding.
  • Added Organization-Level Admin Controls for improved management.

Improvements

  • Run Reports – Increased the maximum viewable file size for a smoother experience.
  • Run Page – Default Singularity and Docker image fields can now be left empty to support certain edge cases.

Bug Fixes

  • Fixed an issue on the Run Page where duplicating a run would not correctly transfer associated datasets.
  • Fixed context menu positions on spreadsheet editor
  • Pipeline file import improved for text files.

[v2.8.0-beta] – 2025-07-14

Improvements

  • GCP Project Bucket feature available for new projects.
  • Delete Process Revision button added for quick cleanup of obsolete revisions.
  • Pipeline permission controls enhanced to support development with group-shared modules.
  • Admin password reset capability introduced.
  • Default group & run-environment assignment now applied automatically when a user is created.

Bug Fixes

  • Fix applied to allow editing on existing spreadsheet file on run page.
  • Autofill feature issues resolved for run page.

[v2.7.2-beta] – 2025-06-24

Improvements

  • SAML Auth flow changes
  • Auto redirect to SAML IDP is disabled and a buton for authenticate with SAML is added.

  • Run Page

  • Table loading issue is fixed.

[v2.7.1-beta] – 2025-06-24

What's New

  • Keycloak SAML Support
  • Keycloak SAML authentication flow is added.

Bug Fixes

  • Run Page
  • App launch related issues fixed.

[v2.6.0-beta] – 2025-06-18

Features & Improvements

  • App Management
  • Introduced feature flags to control permissions for app creation and editing.
  • Refactored ShinyProxy app commands to dynamically replace URL placeholders with runtime values.

  • Pipeline Management

  • Released the “Import VIA Pipeline” feature for admin users.
  • Allowed adding pipelines to projects with version selection support.
  • Fixed loading issues with older pipeline versions.
  • Added uniqueness validation for process and module labels.

  • Run Page

  • Fixed navigation issues after duplicating runs from older attempts.
  • Resolved @array form related bugs on run page.
  • Fixed log loading issues after run submission.

  • Dataset Support

  • Added support for Triple Files on datasets.

  • GEO (NCBI) Dataset Search

  • Added functionality to show percentage of search results.

[v2.5.1-beta] – 2025-05-29

Bug Fixes

  • Run Page Resolved content-loading errors on both the nf-core and Via pipeline pages.

  • Report Page Fixed table pagination in the Reports tab.

  • Password Recovery Corrected issues preventing “Forgot Password” recovery emails from sending.

  • Workbench Fixed a failure to show passwords after launching an instance. Adjusted the instance state reload interval for more reliable updates.


[v2.4.0-beta] – 2025-05-23

What’s New

  • Better Workbench Checks We’ve added extra validations in the Workbench to catch errors early and make your experience smoother.

  • Pipeline Details Sidebar View key pipeline information at a glance with our new sidebar panel.

  • Faster Run Reports Run reports now load immediately once a run finishes, so you don’t have to wait as long.

  • Custom Columns in Spreadsheet View You can now add your own columns when looking at runs in the spreadsheet-style view.

Bug Fixes

  • Run Status Updates Fixed issues where runs weren’t showing the correct status or weren’t updating after submission.

  • Metadata/Portal Tab Reload Pages in the Metadata and Portal tabs now refresh correctly without errors.

  • Shared-Project Runs You can once again create runs inside projects that you’ve been given access to.

  • Fixed GCP Dataset Paths Resolved a misconfiguration that was pointing to the wrong folder in Google Cloud Platform.


[v2.3.0-beta] – 2025-05-02

Enhancements

  • Organizations Panel: Introduced support for managing organizations and a dedicated admin section.
  • Workbench Validation: New validations added to improve reliability and user experience within the Workbench.
  • Geo NCBI Search Improvements: Implemented a delay mechanism to NCBI requests to reduce timeout errors.

Bug Fixes

  • Dashboard Display: Runs that were not submitted will now correctly appear in the Project Dashboard.
  • Graceful Shutdown: Improved signal handling in viatunnel to ensure clean shutdown behavior.
  • Run Page Autofill: Resolved a minor issue affecting process option autofill behavior.
  • Character Encoding: Applied BOM character fix on the Run Page to prevent display issues.

[v2.2.0-beta] - 2025-04-28

Enhancements

  • Workbench Launch: Introduced the Workbench feature for GCP servers, allowing users to launch separate instances.
  • User Table: Added a User table to the Admin Dashboard.
  • Duplicate Run Modal: Simplified the Duplicate Run modal for easier use.
  • Help Section: Consolidated all help resources under a single Help icon.

Bug Fixes

  • Project Bucket Feature: The run publish location now correctly pulls from the project settings.
  • Run Page: Autofill-related issues on the Run page have been fixed.
  • Geo NCBI Search: Improved error handling for Geo NCBI search failures.
  • App Section: The "Open on New Page" checkbox settings now load correctly.
  • Pipeline Page: Fixed the apps list loading issue for apps with a green output circle indicator.

[v2.1.0-beta] - 2025-04-16

Enhancements

  • Improved Search & Filtering: Enhanced search and filtering capabilities have been added to the Pipeline, Project, Run, and App pages.
  • Duplication Features: Users can now duplicate Runs, Pipelines, and Processes.
  • Enhanced Run Report: The Run Report section now supports app execution and advanced grouping.
  • Feature Flags: A new section for managing feature flags has been introduced.
  • Project Settings: A dedicated Project Settings section is now available.
  • AI Chat Integration: An AI Chat feature has been added to assist with pipeline and process development.
  • Run Sharing: Runs can now be shared easily with collaborators.
  • SSH Retry Mechanism: A retry mechanism has been added for SSH connections to improve reliability.
  • New Executor Support: Added support for Slurm, LSF, AWS Batch, and GCP Batch job execution systems.

Bug Fixes

  • Pipeline Page Permissions: Permission controls on the Pipeline page have been upgraded.
  • Executor Settings Autofill: Autofill issues related to executor settings in Runs have been resolved.
  • App Section Permissions: Fixed permission loading issues in the App section.
  • Pipeline Loop Prevention: Additional safeguards now prevent a pipeline from being added to itself.
  • Visualization Fixes: Various visualization issues on the Pipeline page have been addressed.

[v2.0.0+release.1-beta] - 2024-10-31

✨ Enhancements

  • New spreadsheet editor inside the run settings page
  • Tables in the application do not word-wrap anymore

🐛 Bug Fixes

  • Removed unused "publish" option for datasets
  • Several fixes in the datasets UI to standardize language
  • Several fixes to Apps workflows, including creation and linking to the edit drawer when clicking on an App name.
  • Fixed an issue where Apps could not be terminated
  • Clicking on a running App will now open the page in a new tab
  • Several fixes around Apps permissions and sharing
  • Fixed some visual formatting issues on pipeline visualization tooltips