Changelog

What shipped, in product terms

A human-curated record of customer-visible changes. This is not a stream of commit messages: each note describes the capability, the operating boundary it changed, and the public product contract behind it.
Cadence
Curated weekly
Filter
Customer-visible work
Evidence
Linked product contracts

Tool calls page and one Add tool picker

Every tool call lives on its own page grouped by origin, and adding a tool uses the same picker as adding a node.

  • Tool calls (in the sidebar under Automation) lists the calls you can see from Apps, workflow steps and direct MCP requests, grouped by origin. Each origin shows how many calls need attention or wait for review; click it to see only its calls. Needs attention, Waiting for review and Failed are built-in views.
  • Add tool opens the same picker as adding a node: categories on the left, your connections included. A tool's settings open in a dialog; Remove sits in the tool's menu.
  • Adding the first tool to a workflow step that used its Agent's defaults switches the step to its own tools in the same save.
  • App pages no longer fail every tool call after a reload, and a reload never answers with an earlier load's result.
  • Save-to-workspace and AI agent tools set up before the October 10 and October 14 releases work again without being set up anew.
  • The "This app changed" notice inside an App now matches the app's theme.

Rich text reads and writes as Markdown everywhere

Descriptions, documents, comments and notes come back as Markdown from MCP, workflow nodes and agent context, and any text you write is read as Markdown.

Every place outside the editor now hands you rich text the same way: as Markdown. A Task's description, a Document's content, a comment or note, a custom record's rich-text field and a chat message read as Markdown over MCP, in workflow nodes, in the context an agent's turn starts with and in the events that start a run. Ask for format: json when you want the rich-text document itself.

Lists carry a one-line summary of up to 160 characters instead of the full body; name the body in fields to get it, or read one record by its ref.

Whatever you write back is read as Markdown, so text you read, edit and send keeps its formatting: bold, lists, task lists, highlights, callouts, tables, mentions and attachment images. A rich-text document still goes in as an object.

Configure actions where you use them

Apps, workflow steps and Agents own their action settings, consent and readable labels.

  • Configure an action inside its App, workflow step or Agent profile. Its callable alias and display label are independent.
  • Source discovery lists current native and connected actions. Saved configurations have no separate global library or query source.
  • An unavailable action returns a named failure while healthy actions remain available. Calls preserve their recorded origin and result.
  • Old Tools links open Calls. Removing an action ends its access at once; editing it keeps the accepted version running until the new one is saved live.
  • Workflow steps that inherit an Agent's actions use that Agent's own accounts; per-caller accounts are set on a step's own actions.
  • Runs and calls that were still in progress when this release deployed were cancelled. An app with fixed per-action accounts was archived.

Save native apps live

Native apps build on Save, retain one previous build for Undo, and keep your input when an update arrives.

  • Saving native app source validates and builds it before replacing the live app. A failed build leaves the running app and its actions unchanged; removed actions stop at once.
  • Unpublished native app drafts were not carried over; each app now runs its last published source.
  • Undo restores the one previous accepted native build using current permissions.
  • Git apps deploy source changes; tool settings apply on Save without restarting the container.
  • An older open app offers Reload before another action, preserving input until you choose to reload.

A steadier desktop client

Consistent desktop pages, reliable approval counts and signed update support.

Rollout Desktop 0.1.4 keeps a consistent resizable window across Activity, Connections and Settings. Approval reviews preserve focus, drafts and expanded details while work refreshes. The menu-bar approval count clears when the last request is resolved, and camera details appear only while capture is active. Home and other workspace pages share the same desktop frame. Published Apps, including those pinned to Home, load their authorized frontend assets through the dedicated desktop session and retain their page when the window reopens.

The hidden panel pauses UI polling and batches streamed output when visible. Settings supports signed in-app updates in release builds configured with a verification key and published update feed. Installation waits for active work, result recording and pending approvals. Builds without that release setup show that updates are unavailable; the DMG remains the first-install download.

Asks, answered where they appear

Agent questions, workflow gates and approvals are now one kind of ask, answered in place on the feed, in the Inbox, in the run panel and on the desktop.

An agent can now ask you something on its Task instead of guessing: a yes or no, a choice between options, a short answer, or notes on a diagram. When it draws a flowchart, you click a box or an arrow and leave a question or comment right there, then finish the ask to send everything back. The agent picks up your answer in the same turn.

Workflow approval steps, tool call and tool activation reviews, tool repairs and commands waiting on your device work the same way. Each shows as one card you answer where you see it: in the Task's feed (open asks sit at the top, and an Asks tab lists them all), in the Inbox, in the workflow run panel, or on the desktop app for a quick yes, no or choice. Several people can weigh in on one ask, and an agent can add its own vote, while only a person closes it.

The Inbox now lists only what waits on you, with nothing to open first: expand a card and answer it. Failed runs moved to Runs, under the Failed view. A command waiting on your own device can also be approved from the web, and the device runs exactly the command it showed.

More Saved Views and More Pages match the toolbar icons

The More Saved Views and More Pages buttons now match the other toolbar icons.

The More Saved Views button now matches the other toolbar icons. The More Pages button now matches the other toolbar icons.

Approved tool repairs go live

Approving a tool repair now publishes the App or workflow when its Draft has no other unpublished changes.

Approved tool repairs go live. When you approve a repair for an App's or workflow's tools and its Draft has no other unpublished changes, the approval also publishes it, so the repaired tools are in use as soon as you approve. A Draft with other unpublished edits keeps its running version, and the review page tells you to publish it yourself.

Give an agent a persona and default tools once

Every AI node acting as an agent starts from the agent's persona, tools and limits; the node's own settings win.

Give an agent a persona and default tools once. Write who the agent is and the rules it always follows on its settings page, and every AI node that acts as it, on a Task route, in a workflow that runs as it or with the agent wired in, puts that persona first in its system prompt, including Claude Code and Codex turns on your device. The agent's model, token budget and tools are defaults: a node that sets its own keeps them, and can give one task a bigger budget.

Start a workflow when a custom field changes

Record updated can start independent workflows when a Task's custom phase changes.

Start a workflow when a custom field changes. Record updated conditions can now check a Task's current and previous custom field values and exactly which fields changed. For example, a phase changing to deploy can start a deployment workflow. Writing the same value again starts nothing, and sensitive fields stay out of the event.

Workflow warnings name unscheduled input sources

See which trigger cannot run a wired source before publishing or starting a consumer.

Workflow cards now show amber warnings when a trigger cannot schedule a source wired into a consumer. The warning names the trigger and absent contributor, even if other sources feed the same input. Save and publish remain available. MCP graph reads, edits and publication return the same advisories. Existing releases record the warning on the consumer's step before execution. Terminal steps retain these warnings alongside node warnings, with accurate counts when further warning details are omitted.

Batch-data sources outside the selected plan, such as a disconnected document read, need a path from every intended trigger: task._done -> role._trigger. Streaming producers and consumers share an execution unit, so a producer with no incoming edge can still run when its consumer is reachable. Sources skipped by an ordinary branch keep their existing behavior.

Keep workflow settings readable

Ordinary workflow environment settings remain readable while selected secrets stay redacted.

Workflow Environment rows now have a Secret checkbox. New rows are plain settings, so repository names, pull-request links and checkout paths remain readable in outputs, Task notes and inspection. Selected secret values still get scrubbed. Editing environment rows also preserves existing boolean and numeric settings.

Existing environment keys stay marked Secret to preserve their protection. Uncheck verified ordinary settings and publish to apply the change to new runs. Existing runs keep their frozen classification. Use tenant Secrets for credentials; the checkbox controls redaction and does not encrypt env storage.

Group Task tables by shared fields

Follow Delivery Phase and other shared dropdown fields in Task tables.

  • Group native and embedded Task tables by shared single-select fields, including fields that are not visible columns.
  • Groups follow dropdown option order, show empty options and unset values, and support counts, expansion, load-more, URLs and saved views.
  • Both grouping pickers refresh when fields change, overflow groups keep their membership through load-more, and empty or collapsed groups stay visible.
  • Page tables bound to a Saved View let you change or clear grouping for the current session without changing the Saved View.
  • Display grouping works with viewer filtering disabled and keeps the table’s filters, including ranges, multiple values and OR conditions combined with Saved View or locked filters.
  • Removed, archived or unavailable grouping fields show a notice and an ungrouped list.
  • Filters remain editable after grouping OR queries; custom-entity numeric totals also remain available when their filters use OR.
  • Reopening a filter after an OR group keeps its selected values. Native Display changes and clearing preserve advanced filters and survive URL reloads.

Tasks

Workflow runs wait for deploy readiness

Runs starting or resuming during a server deploy wait for the secret registry and retain their upstream values.

Workflow runs starting or resuming during a server deploy now wait for secret registry readiness before progressing. Resumed runs keep their original upstream outputs instead of failing with incomplete inputs during a temporary outage. If readiness does not return within the workflow timeout, the run reports secret_registry_unavailable while sensitive error fields stay redacted.

Exact MCP reference reads

Reading a record by reference over MCP no longer returns an unrelated record when the reference doesn't match.

Reading a record by reference over MCP no longer returns an unrelated record when the reference doesn't match. Object, Attachment, Page and Record reads resolve their slugs, and Agent reads accept user UUIDs and handles. Record slugs ending in numbers also resolve; a reference that names different records as a slug and a code is rejected as ambiguous. Metric and ToolImpact remain list-only sources.

Document reads accept 16-character slugs

Read Documents by any valid slug, including 16-character slugs, in workflows and reference lookups.

Read document now resolves valid 16-character slugs for both current content and saved versions. Team and Project placement and other reference lookups also accept 16-character names and slugs, with the same access checks and content guards as reads and updates by ID.

Control concurrent device agent turns

Extra AI agent turns wait on the server until a device slot opens.

Devices now have Max concurrent agent turns, default 4. Owners and exact Managers can change it in Settings › Devices or over MCP using the Device UUID. Parkable AI Agent graph steps show Waiting for a device slot and resume in FIFO order among runnable turns when a turn finishes. Runs held by another human or approval gate do not block the device. Tool, App/MCP, session and iterated calls receive device_busy immediately at capacity. Waiting has no execution timeout and creates no prompt material or tool connection. Shell commands keep their existing behavior; the desktop protocol is unchanged.

Label filters use labels

Use labels: in queries; unknown filter fields now reject the whole query.

Label filters now use labels:. Newly supplied label: is rejected with guidance to use labels:. Custom Record fields named label, and Metric dimensions named label, keep their field meaning and saved filters.

Table label grouping uses @group:labels; the singular grouping alias is removed.

Unknown filter fields now reject the whole query, even when Strict is disabled, so a mistyped filter cannot return an unfiltered result.

AI Agent harness turns retry provider capacity failures

Codex and Claude Code turns can retry capacity and rate-limit failures and show the provider diagnosis.

AI Agent nodes using Codex or Claude Code can now retry explicit provider capacity and rate-limit failures when Retry is enabled, with backoff and up to four total attempts. The provider's message and reported code appear in the step error and command result. Other failures remain terminal. Attempts and tool budgets persist when a device turn parks and resumes.

Workflow run limits queue excess starts

Set a workflow run limit in settings or MCP; excess batch starts wait in order until a slot drains.

Set Max active runs in workflow settings or through MCP's Workflow upsert. Excess batch starts now queue and run in order after an earlier run physically drains. The run panel shows the wait reason and, when you can inspect the whole queue, its position. Waiting is indefinite by default; set a separate Queue wait limit (seconds) to fail a run that has not started in time. Clearing the cap admits the queue. A first cap still waits until runs started without a limit finish. Subflow and Loop children and hosted sessions continue to refuse their own full cap.

Delete now in Trash deletes objectives

Objectives in Trash can now be permanently deleted together with their key results. Archived objectives can also be moved to Trash by anyone with delete authority in their space.

Delete now in Settings → Trash now permanently deletes objectives and their key results. Previously, it reported that the objective was already gone while leaving it stored.

Anyone with delete authority in an objective's space can also move an archived objective to Trash or delete it permanently.

Task boards by Phase and other select fields

Choose Status, Priority or a shared single-select field for board columns.

Tasks boards now offer Display → Columns. Choose Status, Priority or a shared single-select field such as Delivery Phase, and save the choice with your view. Field columns currently support viewing; status columns still support dragging. Field columns keep their counts and bounded card windows without "more" links. Use Table view and filters to see additional tasks.

Reorder dropdown options

Move select options up or down, and sort and group records by their configured order.

  • Dropdown field editors now have keyboard-accessible move-up and move-down buttons. Save the field to keep the new order; existing values stay intact.
  • Single-select sorting for shared fields and Records follows option order in tables and row windows. Descending reverses the options; unknown and empty values stay last.
  • Record table groups follow option order, then empty and unknown groups.

Custom fields

One command node for any length

Run command now handles commands up to 90 minutes with the same approvals, output, cancellation and restart recovery.

  • Use Run command for commands of any duration, with a timeout from 10 seconds to 90 minutes; the default timeout is still five minutes.
  • Started workflow commands can park and resume after a server restart at every duration. Commands using named secrets and executions that cannot suspend keep their in-process wait.
  • Saved workflows using rollout.client.shell_long are rewritten in place with their settings unchanged. Its separate shell_long device permission is removed.
  • Assigned commands keep their payload, device, attempt and approval through the update; only pending commands receive the new executable identity and a fresh delivery approval.
  • Tools built on Run command need a new review. Device command consent remains under Command.

Large Codex command output no longer sinks a completed turn

Oversized intermediate command and MCP output stays visibly incomplete while a valid final answer can complete the step.

A Codex command or MCP result larger than the desktop's 1 MiB event limit can now complete its turn when the full event envelope validates and the answer, session and completion evidence remain intact. Previously, one large search or test log failed the whole turn even when its final structured result was valid.

The loss remains visible: a bounded retained head, a notice stating exactly how many further bytes were dropped, and a saved step warning with the number of affected events and dropped bytes. A successful step still carries an incomplete transcript. Oversized answers or completion records, malformed events and invalid structured results continue to fail closed.

Agent results survive repeated parking

AI Agent steps with Rollout tools no longer lose their finished result after a server deploy.

AI Agent steps with Rollout tools no longer lose their finished result after a server deploy.

Subtree moves to a Cycle leave Done Tasks in the backlog

Moving a parent Task to another Team's Current or Next Cycle no longer fails when its tree holds Done or Canceled Tasks; those Tasks change Team and stay in the backlog.

  • Moving a parent Task and its subtree to another Team with current_for_task or next_for_task (MCP task_planning change_team_subtree, or the task form) used to preview as applicable and then fail with state_conflict when the tree held a Done or Canceled Task. Nothing moved.
  • The move now goes through. Every Task changes Team; only the open Tasks join the destination Cycle. Done and Canceled Tasks stay in the destination Team's backlog.
  • The preview says so up front: a Done or Canceled Task shows no destination Cycle (destination_cycle_id: null over MCP, "Backlog" in the task form), and the apply's assignments lists only the open Tasks.
  • Moving a parent Task to another Project with a Team change follows the same rule.

Runs interrupted by a deploy fail within minutes

A run whose server stops mid-step now fails as interrupted within about 10 minutes, with the reason on the step, instead of showing Running for up to 3 hours.

When a server deploy or crash stops the server running a workflow run, the run now fails within about 10 minutes with the error code interrupted. The step that was running shows the same reason. Before, such a run kept showing Running until its timeout, up to 3 hours, and its step never finished.

Steps already finished are not run again. A device command the run still tracks is stopped on the device. An AI Agent turn with Rollout tools attached is not tracked that way and can keep running on the device until it ends.

Steps that park while they wait still resume on another server after a deploy: long shell commands, and AI Agent turns with no Rollout tools attached on desktop app 0.1.3 or later.

Running commands name their step and Task

The desktop tray card for a running command leads with the workflow step and the Task it serves, shows its latest output line and how long it has been silent, and the run panel shows the same.

  • A running command's card in the desktop tray now leads with the workflow step's label ("Merge", "Implement · Claude Code") and the Task the run serves, code and title. Clicking the code opens the Task in the browser. The workflow's name follows.

  • The card shows the command's latest output line, stdout or stderr, as it arrives. A command that has printed nothing for a minute or more reads "no output for 12 min" in place of "Waiting for output...".

  • The raw command (["bash","-s","--",…]) and the output tail moved behind a Command disclosure that stays open while the panel refreshes.

  • History rows name the step and the Task, or the workflow. Commands without either keep their command text so they remain identifiable.

  • The server's run panel leads the run's lineage with the Task it serves, linked, for anyone who can read that Task. A running step that streams output names its latest line and how long ago it arrived ("last output 3 minutes ago"), or "no output since start".

  • Needs the next desktop build; the server sends the new fields to every client.

  • Keyboard focus stays on the Task link or Command disclosure during tray refreshes.

  • A device command parked as awaiting input keeps showing its latest output and output time while it runs. Reconnects keep surviving commands' latest output and timestamp, and the disclosure shows complete bounded command text.

Project updates over MCP apply the lead Team

An MCP or workflow Project update now applies lead_team, parent and owner, or refuses with the reason, instead of reporting updated without changing anything.

  • upsert on a Project applies lead_team (a Team slug or UUID), parent (a project slug or UUID, or none or null to detach) and owner (a workspace member's email). Before, these fields were accepted, dropped, and the call still answered updated. The workflow upsert node dropped them the same way and now applies them too, or fails naming the field.
  • A new Project is owned by whoever creates it: owner on a create takes only your own email, and another member's is refused with a pointer to update the owner afterwards.
  • Changing the lead Team moves the Project to that Team's space and keeps the previous lead as a contributor. It needs an admin role in the Project's current space, or owning the Project, plus write access to the new Team.
  • A ref that matches nothing you can see, or is empty, is refused and names the field, for example lead_team: no Team you can read matches 'ops'. Nothing is written.
  • archived and refs are no longer accepted as Project data. Over MCP an update that carries archived is refused by name, and the reply says a Project is archived or restored in the web app (no MCP tool archives one). A workflow update that carries it fails with use_project_archive_lifecycle.
  • Sending a column name gets a hint: lead_team_id is answered with "Use lead_team (not lead_team_id)", and the same for owner_id and parent_id.
  • access with action: move on a Project that you may not move now says a Project moves by changing its lead Team and what that takes. Before, it gave the generic content-move rule.

Permission changes keep device commands running

Changing someone's team or workspace role no longer disconnects their device or fails its running steps.

Adding someone to a team, or changing their team or workspace role, used to disconnect their desktop app. Every device step running on it failed as a disconnect, even when the change only widened their access. The device now re-checks its access and stays connected, and running commands deliver their results as usual.

When the device's owner loses access to the workspace (their membership is suspended or removed), its running commands stop. The step fails with "Stopped: the device's access changed during the command; whether it already had an effect is unknown." and the code device_access_revoked, instead of reporting a disconnect. The desktop app stops those commands on your machine at once; an older app stops a long command it kept running across a dropped connection only when its reconnect is refused. A command with If unavailable: Queue until available that had not started yet goes back to the queue for another eligible device. Deleting the device, transferring it to another owner or signing it out still closes its connection, and its running steps fail as a disconnect.

Paused runs resume with the same values

A run that pauses and resumes now passes downstream the values a run that never paused passes, and a value it cannot restore stops the step with a clear error.

  • A run that pauses (a wait, an approval) and later resumes hands its downstream steps the values the steps that finished before the pause produced. Before, a value containing a workflow env value came back as [REDACTED] after the pause, so a step that compared it, such as an update guarded on the Task's current metadata, failed with a conflict.
  • Run history is unchanged: step inputs and outputs still show env values and secrets as [REDACTED]. The original values are kept encrypted with the paused run and deleted when it completes, fails or is cancelled.
  • When a resumed step needs an earlier value that cannot be restored (an output over 256 KiB, or more paused data than the run keeps), the step fails with resume_input_incomplete and names the step and output it needed. It no longer receives [REDACTED] or a truncation marker in place of the value.
  • Runs paused before this change resume without the encrypted copy. A step that reads a redacted value from one of them fails with resume_input_incomplete; start those runs again.
  • The output of a long shell step that was itself paused still reaches its downstream steps redacted after the resume.

Create agents and choose a workflow's Run as identity over MCP

An admin-scoped MCP token can now create an agent, and upsert(source:"Workflow") sets which identity a workflow runs as, with the same checks as the app.

  • agent(action:"create", name, handle, description) creates an agent the way the Agents page does. It needs an admin-scoped token and an active human workspace member. The agent is yours and starts in your Private space.
  • upsert(source:"Workflow", ref, data:{runs_as, run_as_agent}) sets the Run as identity: caller, agent or agent_for_caller, with the agent's id or @handle. Send it on its own, without other fields. It needs manage access to the workflow and shows up in the workflow's audit trail.
  • Before a Team workflow can run as a new agent, move or expose the agent to that Team with access(source:"Agent", ref:"@handle"). Otherwise the change is refused as agent_unavailable.
  • Refusals name the reason: private_runs_as_owner, agent_unavailable, agent_required, invalid_runs_as.
  • workflow_inspect(action:"status") and Workflow rows now show the run identity.
  • query(source:"Agent") rows have a fixed shape: id (the agent's user id), handle, name, description, model, owner and placement. They no longer carry the system prompt, LLM connection or token budget.
  • An agent's @handle now matches in any case in access too.
  • guide(topic:"agent.create") and guide(topic:"workflow.settings") describe both.

Large subtree moves finish, and oversized ones are refused by name

Moving a parent Task with about 100 or more descendants to another Team no longer fails with "Internal error" or rollback; trees over the subtree limit (125 Tasks, 75 when the move also changes Project) are refused with subtree_too_large before anything is written.

  • Moving a parent Task and its subtree to another Team (MCP task_planning change_team_subtree, or the task form) used to fail for trees of about 100 Tasks or more. The first attempt returned "Internal error" and a retry returned cycle_operation_failed with reason rollback. Nothing moved.
  • The move now does less than half the database work per Task inside its single transaction: a 125-Task move runs fewer database statements than a 52-Task move did before, the largest move known to have finished.
  • A subtree move carries at most 125 Tasks, or 75 when it also moves the Tasks to another Project. A larger tree is refused at preview with the error type subtree_too_large (in the task form, a message naming both limits), and nothing is written. The limit was 250, but trees of that size could not finish.

Run AI nodes on your Hugging Face account

Connect your Hugging Face token, browse models and serving partners, or enter any model ID with HF routing policies.

Add a Hugging Face account under LLM Provider (BYOK) with a fine-grained token that allows calls to Inference Providers. AI nodes can browse models and serving partners, with tool support, prices, context and latency where available. You can also type a Model ID, including :cheapest, :preferred or :groq routing.

Calls are billed to your HF account; free accounts need purchased credits. Connection verification uses free identity and model-listing checks. PDFs use extracted text, and image attachments show a warning and need an explicit upstream OCR step.

Device steps resume from their result after a deploy

A Run long command or AI Agent step whose device result arrives after a server deploy now resumes the run with that result instead of failing.

A Run long command step, or an AI Agent step on Claude Code, Codex or Copilot, that kept running on your device through a server deploy now resumes the run with its result. Before, the device delivered the result but the step still failed with "The result of the harness turn this step started on the device is not available" (or the same message for the command), and the work was lost. Output the command or agent echoed from the workflow's environment values is still replaced with [REDACTED].

The same fix applies to two other waits that end on a different server, or more than a day after they started:

  • A Wait step reports its real resumed_at time.
  • An Ask a person step whose deadline passes with Then: Resolve with default response passes on its default answer, such as a select's first option. Both that and Skip the step keep the request's approval_id.

Codex reasoning effort and coding-turn command controls

AI Agent steps using Codex can select reasoning effort and deny ordinary git push and gh commands; attached Rollout tools no longer hit a second CLI approval gate.

Codex AI Agent steps now offer Reasoning effort (model default, low, medium or high) and Deny git push and gh, including resumed turns. Denial keeps ordinary commits and local tests available under your selected sandbox. It uses temporary PATH wrappers for cooperating shell calls, not credential isolation: absolute executables and direct API calls can bypass it. Verify it on your device before publishing a workflow that relies on this control.

Attached Rollout tools now use Rollout's own authority and approval checks without a second Codex approval gate declining them. Tools requiring approval on the server still require it.

AI Agent steps that use Rollout tools survive a deploy

An AI Agent step on your device that calls attached Rollout tools now keeps running through a server deploy, and its tool calls keep working.

An AI Agent step on Claude Code, Codex or Copilot that has Rollout tools attached (an SDLC Brief, for example) now keeps running on your device through a server deploy, on desktop app 0.1.3 or newer. Its tool calls keep working: a call that arrives while the server restarts waits until another server takes the step's tools over, then runs with the same Tools, locked settings and approvals as before. When the device finishes, the step resumes with its result and its list of tool calls.

A step with a Tool whose approval is set to Always still waits on the server that started it, so a deploy during that step fails it as before. Cancelling the run ends the step's tool access at once.

A waiting run says what it waits for

A paused run names its wait (a timer, a device, a person or an approval) and when it resumes, in your timezone.

A paused run used to read Awaiting input whatever held it. Now the run header, the step list, the Runs index, a workflow's runs and its Last run name the wait:

  • Waiting for a Wait step, with "Resumes in 12m (04:27 PM)" in your timezone. The run panel also says how long the step waits.
  • Running on device for a long command that started on your device.
  • Needs approval for an approval request or a tool call that needs one.
  • Needs your input for a text or choice question.

A wait that resumes on its own no longer reads as a warning, and the run panel never shows a raw UTC timestamp for it.

Set fields rules can use the fields set above them

In Transform list, each Set fields rule now reads the item as the rules above it left it, so one step can compute a value and use it.

  • In a Set fields step of Transform list, item in each rule is the item as the rules above it left it. After a rule sets total to item.price * item.qty, a later rule in the same step can use item.total > 100. Before, every rule read the incoming item, so a value set earlier in the step read as empty and had to go in a separate step.
  • A field no rule above wrote still reads the incoming value. A field an earlier rule removed reads null.
  • From empty still outputs only the fields the rules set, and Patch item still outputs the incoming item with the rules applied.
  • A rule that copies the whole item now also copies the fields set above it. If a rule copies the whole item after other rules, move it first to keep the item unchanged. Likewise, move a rule above any rule that sets or removes a field it should read as it came in.
  • The value preview under each rule in the editor shows what the rule reads at run time.

Transform list

Tool checks after an update use the updated node definitions

After a Rollout update, saved tools and App tool warnings are checked against the updated node definitions, even while older servers are still shutting down.

  • After an update, saved tools and the tool warnings on Apps are checked by servers running the update. Before, a server of the previous version that was still shutting down could run that check against the old node definitions, so a tool that the update made current could keep reading as needing repair, and an App could show warnings about the old definitions.

Saved tools keep working when a node gains an option or setting

Saved tools, and the apps and agents that use them, stay current when a node they are built on gains an option or an optional setting, and they still accept only the values they were reviewed with.

  • A node update that adds an option to a choice, adds an optional setting or rewords a tool's description no longer marks the saved tools built on it as needing repair. Apps and agents keep calling them without a new review.
  • A tool keeps the choices it was reviewed with. When a node adds an option to a setting the tool lets its caller fill, the caller still sees and may pass only the options that existed at review.
  • A change that removes or renames a setting or option, makes a setting required, or changes what a setting means still asks for a new review of each tool built on that node.
  • Tools that went stale only because a node gained an optional setting read current again.

Workflows can list stale Tools with Query workspace

Query workspace has a Tools source that filters by health, so a workflow can list the Tools a node change left stale and count them exactly.

  • Pick Tools as the source in a Query workspace step to list the governed Tools the run may read. Filter with name, search, status, kind, node_type or health. status:active health:stale lists the active Tools that need a new review because their node changed, and the step's total counts only those.
  • health is current, stale or missing for a Tool that wraps a node (missing when the node no longer exists); a Tool that wraps an MCP tool reports its last catalog check.
  • Every row also carries source_status (current, stale or unverifiable). The Tool's settings and delegations are not returned.
  • MCP query with source:"Tool" takes the same health filter.
  • Tools are not readable from an App. An App Query Tool set to this source fails before it reads anything.
  • Saved Query workspace Tools keep working: adding the Tools option is a compatible change, so they stay on the sources they were reviewed with.

Long commands survive server deploys

A started Run long command step waits for its device without holding a server, and a started queued command is never sent twice.

Once your device reports that a Run long command step has started, the run waits for the result without keeping a server busy. The result resumes the run on whichever server receives it. The run panel shows the step as running on the device, with the time it fails if no result arrives. A step that passes secrets to the command, or runs as an agent tool, keeps the previous behaviour and still fails if its server restarts.

A server deploy drops the device's connection. With desktop app 0.1.2 or later, the command keeps running through that reconnect and its result resumes the run, so a deploy no longer fails the step or stops the command on your laptop. With an older app, the dropped connection stops the command and the step fails with "Device disconnected during command execution." The same happens on any disconnect the app does not recover from. If the device defers the command for local capacity after reporting the start, the command did not run and the step fails, asking you to retry it. Cancelling the run cancels the command on the device.

Commands with If unavailable: Queue until available are no longer sent twice. Once a device reports that a queued command started, or you approved it on the device, a disconnect fails the step as "outcome unknown" instead of handing the command to another device. A queued Run long command that has started is the exception: it parks like a direct one, and a disconnect fails it with "Device disconnected during command execution."

Commands on your devices can use workspace secrets

Run command and Run long command take a Secrets list; each secret reaches the command as an environment variable on the device, and is redacted from run history.

  • Run command and Run long command have a new Secrets setting. List secrets from Settings › Secrets by name, and the command reads each one as an environment variable of the same name, such as $SENTRY_AUTH_TOKEN.
  • The value goes to the device running the command and nowhere else. The approval on the device lists which secrets the command receives; the value is fetched only after the command is approved. Queued commands, approval requests and run history keep only the names and a reference. Output that echoes a value is redacted, on the device and in Rollout.
  • A secret that doesn't exist fails the step before anything is sent, and the error names it. A step called from MCP or an App without a workflow run can't use secrets.
  • A secret named after a variable the shell uses to run code, such as PATH or BASH_ENV, can't be passed; rename it.
  • This needs Rollout Client 0.1.2 or newer. A step aimed at an older client fails before anything is sent and says which version it needs. Commands without secrets run as before.

Client workflow nodes

A Claude Code step that waited on background work keeps its answer

An AI Agent step on Claude Code that started a background command or a Monitor no longer fails as Output rejected when the agent answers again after that work finishes; the step keeps the answer from its last turn.

Claude Code doesn't exit as soon as it answers if it still has background work running, such as a test run started in the background or a Monitor watch. When that work finishes, it takes one more turn in the same session and answers again. Its final answer is that last one.

An AI Agent step on Claude Code used to treat a second answer as a broken turn and fail with Output rejected (harness_output_invalid), discarding work the agent had already finished and committed. The step now completes with the last answer:

  • Every answer in the run has to be a success. If any of them failed, even one in the middle, the step still fails with Output rejected, and it still reports the session so you can resume it.
  • All answers have to come from the session the step started or resumed. A different session fails the step.
  • The follow-up turn still takes time. If the step's timeout stops the agent before it answers again, the step fails and the first answer is not kept.
  • The turns count and cost come from the last answer.

Codex and GitHub Copilot steps are unchanged: each turn still has to end with exactly one result. No desktop client update is needed.

AI Agent

Cancelling a run stops a device command it just sent

A run cancelled while a step is sending its command to a Rollout Client now stops the command on the device and ends the step at once, instead of waiting out the step timeout.

  • Run command, Run long command and an AI Agent running on one of your devices could miss a run cancellation that landed while the step was still sending its command. The device kept running the command and the step waited out its whole timeout. Now the step hears the cancellation however early it lands: the device gets a cancel for the command and the step ends with Command cancelled by user.
  • This covers both If unavailable settings. A queued command that is delivered while its run is being cancelled is stopped the same way.
  • A step that starts after its run was already cancelled sends nothing to any device and queues nothing.
  • No desktop client update is needed.

Client workflow nodes

Agent turns survive server deploys

An AI Agent step on Claude Code, Codex or Copilot keeps running on your device through a server deploy and resumes the run with its result.

An AI Agent step that runs Claude Code, Codex or Copilot on a registered device, with no Rollout tools attached, now waits for its device without keeping a server busy once the device reports that the turn started. A server deploy or restart no longer fails the step or stops the CLI on your laptop: the device's result resumes the run on whichever server receives it, with the same answer and Harness session reference an uninterrupted turn returns.

The step's timeout still applies. A result that arrives after it fails the step with client_command_timeout, and the error keeps the session reference, so the next step can continue the work.

This needs desktop app 0.1.3 or later, which reports the start only after it has fetched the turn's prompt and files. With an older app, and for turns with Rollout tools attached, turns on an SSH target and AI Agent steps inside an App, the step keeps the previous behaviour and fails if its server restarts.

Filter activity by author handle or email; a bad id no longer matches everything

Activity user_id: takes a handle, email or UUID, and a filter value that names nothing now returns nothing with a warning instead of every row.

  • Activity user_id: takes a handle, an email in any case, or a UUID, like Task assignee:. @me names you, and @unassigned names the activities no person performed, such as automation notes. The query bar's User chip now picks several people and agents.
  • user_id: with a handle or email nobody has returns no activity and a warning, "No match for '…' in user_id". Before, it returned every comment, so a workflow that checked who wrote a comment accepted anyone's. An empty value returns nothing and warns "Empty value for user_id matches nothing".
  • -user_id:<someone> keeps everyone else's activity and the activity with no author.
  • Any id filter given something that is not an id now matches nothing; with - in front it matches everything. This covers resource_id:, run and step id:, and hops such as project.owner:. Before, resource_id:RPD-123 returned every row. The query node's resource: filter on Activity takes the resource's UUID; the MCP query tool still accepts a code such as RPD-123 there.

A node runs once with a list unless you ask for each item

A list wired into a node now arrives whole. To run a node once per item, set For each item to Each item; existing workflows that relied on the old default were updated to keep running per item.

  • A list wired into a node arrives as one list, and the node runs once. A Query whose filter reads records[0] now sees the first record instead of running once per record and wrapping its results in another list. Until now Query workspace, HTTP request, Run command, AI agent, Save to workspace, and the Telegram, Jira, Gmail and Google Drive actions ran once per item of any list they received, without saying so.
  • To run a node once per item, open its Execution settings and set For each item to Each item. Each output then becomes a list with one value per item, the port popover shows its type as list<…>, and the node card shows an Each item badge. Items at once, Delay between items, Max Iterations and On item failure still pace and bound the items.
  • A list wired into an input that takes one value needs the node to run once per item. On the canvas the wire stays and the node shows a problem that says to set For each item to Each item; Publish refuses the workflow until you do. A node that cannot run per item refuses the wire.
  • Workflows saved before this change keep their behaviour: every node of those types that is fed by a wire, or holds a list in one of its settings, was set to Each item, in drafts, draft history, published versions, past runs and saved workflow templates. Most wired nodes now show Each item, including ones fed only single values: they run exactly as before, and you can switch them to Whole list. The Auto choice is gone.
  • An AI agent Tool or an App that passes a list to one of these nodes now runs it once with the whole list.

Workflow finished trigger: choose how many times a loop may repeat

Choose how many times a loop may repeat; a run stopped by the limit now says so.

  • A Workflow finished trigger has a new Loop limit: how many times its workflow may run in one chain of runs that start each other, counting the first. It stays 3 unless you change it, and goes up to 50.
  • When the limit stops a loop, the finished run shows which workflow it did not start, how many times that workflow already ran and its limit. Before, the loop just stopped.
  • Raising the limit applies to finishes after you Publish. It does not restart runs the limit already stopped.

Fetch a list of tasks with id:in

A known set of tasks comes back in one query with id:in:RPD-1693,RPD-1694, and the retired code: and number: keys now point you to id.

  • id:in:RPD-1693,RPD-1694,1693 returns those tasks in one call. It takes task codes (TASK-N for a task with no project), bare task numbers and UUIDs, mixed in one list. Numbers are unique in a workspace, so no project filter is needed.
  • The code: and number: keys from the 2026-09-25 entry were renamed to id: on 2026-09-26 and now answer Unknown field. That error, under MCP query with strict:true, in the query node and in Table widget validation, now ends with "did you mean 'id'?", and the warning a non-strict query returns says the same.
  • The other retired keys name their replacement too: planning_team: points to team:, planning_team_under: to team_under:, and a Record q: to search:.
  • A typo in a key gets the closest valid key under strict:true as well, where the error used to name only the unknown key.

Stale App tools lead to one repair

A stale App's alert, its validation report and a refused rebind now point to the single Repair attached tools review.

When a node definition moves under an App's tools, the App's alert now names Repair attached tools in the App's Tools settings, which reviews every stale tool in one approval and updates the Draft. Agents get the same route: each stale tool in app action:validate carries a ready entry for one consumer repair, and a rebind that cannot succeed says so and names that repair instead of only listing field errors.

A refused secret setting now shows the reference shape it expects, {"$secret":"NAME"}.

Production errors identify the deployed build

Browser and server errors share the deployed Git SHA, and each production deploy reports its commits, timing and private source maps to Sentry.

Browser errors now carry the same release as server errors: the Git SHA of the deployed image. Each production deployment reports that release to Sentry with its commits, deploy start and finish times and a link to the CI run. Source maps from the exact build go to Sentry privately, so browser errors show original source lines, while the served application carries no source maps.

Reporting runs beside deployment, never inside it. If Sentry is unavailable the report fails visibly and the release still ships. Browser tracing, replay and request/DOM breadcrumbs remain disabled.

Runs that skip every action finish as No-op

A run that skips every action now finishes as No-op, and a Workflow finished trigger can ignore it.

  • A note, a disabled node or a branch the fired trigger can't reach no longer keeps a run at OK. When the trigger and a false If are all that ran, the run finishes as No-op.
  • An action the run reached that never reported a result still counts as work, so the run stays OK.
  • Pick OK, With warnings and With errors in a Workflow finished trigger's Outcomes to stop it starting after a run that did nothing.

AI agents can run workflows through their tools

An AI agent step can call a Run workflow tool attached to it, and the workflow starts with the agent's arguments.

An AI agent step in a workflow can now call a tool built on Run workflow. The workflow the tool names starts with the agent's typed arguments, such as customer_id, and the agent gets back what its return step produced. The run counts as a child of the agent's run and runs the release the tool names, with the same access and recursion limit a Run workflow step in that workflow would have. Only a tool attached to that agent step can start one. A required input the tool's reviewed copy does not have yet fails with the workflow's own message, such as 'region' is required, and no run starts; sync the tool from its workflow to add it.

Calling a Run workflow tool any other way, including MCP invoke, is still refused with a message that says so. Start a workflow from MCP with workflow_run.

A coding-agent tool on a device says which setting it refused

Configuring or invoking an AI Agent tool that runs Claude Code, Codex or Copilot on a device now names the setting that was wrong, the agent can run for up to 30 minutes in a workflow, and Copilot's visible tools can be narrowed to the ones you list.

Setting up an AI Agent tool that runs Claude Code, Codex or GitHub Copilot on a registered device used to fail with Invalid target. or Target not found. and nothing else. Configure and invoke now answer with the setting at fault and why:

JSON
{
  "error": "Invalid tool settings",
  "errors": [
    {"path": "/presets/device_id", "message": "That device does not offer the agent_harness capability (the AI Agent permission; turn it on in the desktop client's permissions). Pin a device that has it."}
  ]
}
  • A device without the AI Agent permission is refused at device_id, and the message says where to turn it on.
  • A device id that matches nothing you can use says to take the id from the device picker. The identifier the desktop client shows is a different value.
  • A tool that leaves the device unpinned is refused at device_selection. Before, it got a message about a malformed protected reference.
  • A connection-bound tool's refusals name its connection setting the same way.

As before, a refusal never lists the devices or connections you could pick instead. A device that doesn't exist and one you can't manage get the same message.

A coding agent's timeout now goes up to 1800 seconds instead of 600 in a workflow run. That's the limit the desktop client already applies to agent commands, so no client update is needed. Other device commands keep 600. A call from an App is still cut at 5 minutes, approval wait included; run a longer agent through a workflow the App starts. The AI Agent step's default budget grows with it, from 21 to 41 minutes, for every harness: a hung step without its own timeout runs that long before it is stopped.

Copilot has a new Available machine tools setting. List shell, for example, and the model sees only the shell tool. Rollout still never passes --allow-all-tools, so the allowed-tools list stays the only set of commands that run without asking.

An agent step's execution output no longer carries the raw console stream. For Copilot that stream is the whole JSON event log, which could push a long session past the 200 KB tool result limit. The reply is in output.text, and execution keeps the exit code, duration, a byte count and digest of the output, and the session id for a follow-up turn.

Apps

Live device output stays masked across servers

Secrets echoed in live device output are masked even when the device is connected to a different server than the one running the workflow.

  • Live output, status messages and heartbeats from a device are scrubbed with the secret set of the server that runs the workflow, wherever the device is connected.
  • When that set can't be confirmed, viewers see the redaction marker instead of the raw text.
  • A run that resumes or retries on another server keeps masking the secrets its earlier attempt used.
  • While servers are being updated, run errors and device output written in that window can show the redaction marker in place of their text.

The Rollout Client drops results it can't deliver after 24 hours

Undelivered command results age out of the desktop outbox after 24 hours, so they can no longer fill it and block every later result.

The Rollout Client keeps each command result in a local outbox until the server acknowledges it, and replays the outbox on every reconnect. Results the server refused, such as those from device tools called outside a workflow before the 2026-09-25 server fix, stayed there for good. At 256 of them the client could no longer save any result and every device tool timed out again.

Results older than 24 hours are now dropped from the outbox, including while the client keeps running. A refused result is kept until then, because the stored result is what stops a redelivered command from running twice.

A server cancellation for a command that already finished is now logged as such, instead of as an attempt to cancel an unknown task.

Declared outputs can read a parsed output

A declared output can read a field of another declared output above it, such as stdout parsed as JSON, and dragging such a field onto an input now carries its value.

A declared output can now name a declared output above it as its source. A shell step that parses stdout as JSON in a json output can declare rows reading json at rows, and runs pass the parsed list downstream. Since 2026-10-02 saving or running such a workflow was refused with an invalid source, and those workflows run again. An output reading one declared below it, or itself, is still refused, and the error lists the node's ports and the outputs above it that it could read. The source picker in the Data tab offers the outputs above each entry beside the node's own ports.

Dragging a field out of a parsed output onto an input now reads it from that output. Before, the new output read the raw text at that path and passed an empty value.

Automation notes on Tasks render their Markdown

Run reports that workflows post on a Task or other resource now show headings, bold text, lists, code blocks, tables and links instead of the raw Markdown characters.

  • An automation note's body is rendered as Markdown in the activity feed, the same way comments are. **bold**, ## headings, lists, fenced code, pipe tables and links come out formatted rather than as literal symbols.
  • A single line break inside a paragraph still shows as a line break, so plain notes such as "Exit code 0" followed by a branch name keep their layout.
  • Notes already on a Task render the new way the next time the feed loads. Nothing needs to be re-posted.
  • HTML in a note is still shown as text, and unsafe links are dropped. A body the renderer can't read falls back to plain text rather than disappearing.

Apps can read the result of a long workflow run

An app that starts a workflow can read what the run returned, or why it failed, after the 2-minute wait ends.

An app that starts a workflow waits at most 2 minutes for it. A run that took longer used to reach the app as a run id and a status, with no way to get what the run returned. Attach a Read app workflow result tool to the app and pass it that run id: it returns the run's status, the result of its return step once it finished, and the failure reason when it failed.

The tool reads only runs the same app started. Any other run id, including a run another app started, is refused as not found. You can set an optional wait of up to 2 minutes on the tool so one call keeps checking a run that is still going.

An app that runs as its agent reads its runs only when that agent is a member of the space holding the workflow. If the agent reaches the workflow only because it was shared with it, the app can start the run but reads it back as not found. An app that runs as its agent on behalf of the signed-in person needs both the agent and that person to be members of the space.

Apps can show what a long agent Tool call is doing

An app that calls an AI agent Tool can now show live progress, when the Tool's operator turns it on.

An app that called an AI agent Tool used to show a spinner until the agent finished, with no way to tell a busy agent from one waiting on an approval. Turn on Stream progress to the calling app on the agent Tool and the app is told, while the call runs, which tools the agent calls, whether each one succeeded, the end of each finished reply and when it is waiting for an approval. Apps receive these as progress events through rollout.onEvent.

Progress is off by default and only the Tool's operator can turn it on. It never includes tool arguments or results. Reply text is sent only after the Tool's output checks have passed or rewritten it, cut to the last 280 characters, with secrets removed. Progress is limited to 60 events per minute, counted separately from change events, so a busy agent never holds back the change events that refresh the app's data.

An agent running on a device through Claude Code, Codex or Copilot CLI reports only the Rollout tools it calls and approval waits. Progress isn't available yet for workflows an app starts or for shared links and page embeds.

Agents can set up custom Task fields for a project

The MCP object tool now creates a field group with its fields in one call and binds it to Tasks, Projects, Objectives or Documents, or to the Tasks of one project.

  • object(action:"create", kind:"field_group", name, fields:[...]) creates a field group and its fields together. If one field is refused, nothing is created and the error names that field.
  • bind attaches a group to a target type. With project it covers only that project's Tasks. binding_update with enabled:false hides the group's fields again. The reply lists each field's key for upsert(source:"Task", data:{shared_fields:{...}}).
  • update and the field_* actions work on a group's ref too, and the Task list's columns, filters and sorting pick up the change immediately.
  • The same people can do this as in Settings: workspace owners and admins, and for a project binding, admins of the project's lead team.
  • There is no link field type yet. Store a pull request or other URL in a text field.
  • guide(topic:"object.field_groups") describes the actions.

An agent's handoff can update the Task's fields in the same step

Agent update now sets Task fields together with the agent's result and handoff.

  • Save to workspace → Activity → Agent update has a new Task fields input. A Task agent can set fields such as a phase or who the Task is waiting on in the same step that saves its result and hands the Task to the next assignee.
  • The fields and the rest of the update are saved together or not at all. An unknown field, a read-only field or a value of the wrong type refuses the whole update, the error names the field, and nothing is saved.
  • Only fields that apply to the Task's own project can be set.

Typed outputs from Run workflow

A Run workflow step copies the outputs its workflow's return steps declare as typed ports, and says when the workflow changed them.

The outputs a workflow's return steps declare are now its output contract. Picking that workflow in a Run workflow step, from the inspector or over MCP, copies each output onto the step as a typed port, so the next step wires to total directly instead of reading it out of result. With several return steps each port is named after its step. Copied outputs are read-only, and outputs you add yourself are kept when the copy is updated. When the workflow later changes what it takes or returns, the step's Contract setting shows it and offers Sync from workflow. A workflow you cannot open is never copied.

Workflow inputs a task or a Repeat workflow can't fill

Task routes, publishing and Repeat workflow refuse a required workflow input that nothing would ever send.

A task starts its workflow with the task itself, which can't fill a required workflow input that has no default. Every change that would leave an enabled task route on such a Manual start is now refused, naming the inputs, whether it comes from the task workflow form, the route's on switch or MCP. Publishing or restoring a release that would add such an input under an enabled route is refused too: the Publish review lists the routes and keeps Publish disabled, and MCP workflow_release names them. Give the input a default, make it optional or turn the route off, then publish. Turning a route off always works.

Repeat workflow sends each run only its state and the run number. Choosing a workflow for it that requires any other input with no default is now refused when you pick it, in the inspector or over MCP, naming the inputs, instead of failing when the loop first runs.

Workflow inputs over MCP, Run workflow and agent tools

MCP returns what a workflow takes and returns, Run workflow copies its inputs as typed ports, and tools on Run workflow declare them as typed arguments.

MCP workflow_inspect now returns a workflow's contract with status and release: a JSON Schema of the inputs its Manual start declares, one of the outputs its return steps declare, and a digest. An agent reads what to send in input_data from contract.inputs before it starts a run, and the error for a refused start points there. Only a workflow the caller can open returns one.

A Run workflow step now copies the workflow's declared inputs as well as its outputs. Each input is a typed port on the step showing whether it is required and its default; a value wired into it fills that input ahead of the same key in the step's input object. A required input left out fails the step with the workflow's own message, such as 'customer_id' is required, and no run starts.

A tool on Run workflow declares each copied input as its own typed argument, so customer_id is a required text argument instead of a key to guess inside input. The tool keeps the copy it was reviewed with when the workflow changes; Tool setup shows the change and offers Sync from workflow, which sends the tool back to review. Existing Run workflow tools need one re-review, because their settings now carry the workflow's contract. Calling a Run workflow tool, from an agent or from MCP invoke, does not start the workflow yet: the call is refused with a message that says so instead of an unrelated error. Start a workflow from MCP with workflow_run.

Run asks for a workflow's inputs

Run now and Test with inputs show a form for the inputs a Manual start declares, with file uploads for attachment inputs.

Run now in the Workflows list now opens a form when the workflow's Manual start declares inputs, instead of starting with an empty input that a required input refused. Each input gets a field for its type, prefilled with its default: text, numbers, a switch, a list of allowed values, one value per line for a list of text, and JSON for objects. An input typed Attachment takes a file you upload, stored as an attachment in your workspace, and the run receives a reference to it.

A refused run names the problem under each field and keeps what you typed, so a missing customer id is one fix away instead of a flash to read. A workflow whose Manual start declares no inputs still starts on the click.

In the editor, Test with inputs… shows the same form for a Manual start, with Edit as JSON to type or paste the input as one object and switch back. The form stays open until the test run starts, and it opens with the values you used last.

Workflow inputs on Manual start

Manual start declares the inputs a run starts with, and a start that does not meet them is refused before the run exists.

Manual start now has a Workflow inputs list: each input has a name, a type, an optional default and allowed values, and can be required. Every input is its own port on Manual start, so the next step wires to it directly. Before a run is created its input is checked against them: a missing input takes its default, and a missing required input, a value of the wrong type or a key no input declares refuses the start, naming every field, with no run created. MCP, editor Test, Run workflow, Repeat workflow and app run tools all report those fields. Fields dragged from Manual start's ports stay extracted values under their own collapsed list and are not inputs. A task route can no longer use a Manual start with a required input that has no default, and Manual start's output no longer includes the node's own settings, such as its label.

One editor for declared inputs and outputs

Declared inputs and outputs share one editor, in the node inspector and in Tool setup.

Declared inputs and outputs now share one editor in the node inspector and in Tool setup. Every list can add, remove and reorder rows, set allowed values and defaults, import and export a JSON Schema, pin the structure of the last run, save a schema as a shape and test a sample, for inputs as well as outputs. On mismatch shows the policy each entry actually runs at, and choosing Warn keeps Warn. A row with an error shows it on the control at fault and is saved once it is fixed. A port's info popover on the canvas shows its description, whether it is required and its default.

One contract for declared node inputs and outputs

Declared node inputs and outputs follow one contract that is checked when they are saved and when a node runs.

Declared node inputs and outputs now follow one contract. Saving a declared input or output with an unknown type, a schema that contradicts its type, a repeated id or a default that does not fit is refused, and the error names the entry. A node enforces each declared input and output's required flag, its type and its allowed values: at a strict policy a bad value fails the node, at a warn policy it is recorded as a step warning. A missing value takes the entry's default. MCP workflow_edit can now declare node inputs with inputs and add_inputs, beside outputs and add_outputs.

Fewer reads for Task agent decisions

Task agent checkpoints and dispatch use fewer database reads when the initiating human also owns the binding.

Task agent decisions avoid checking the same human's authority twice within one decision. When the initiating human owns the binding, admission uses eight fewer database queries. Different initiating humans still need their own live permission check, and revoked access is checked again on the next decision. Task, agent, binding, release and final-dispatch protections remain unchanged.

Faster sRGB image-to-PDF conversion

Large unprofiled sRGB images avoid a redundant color-profile conversion.

Already-sRGB images without an embedded ICC profile no longer take an unnecessary color-profile roundtrip when converted to PDF. Embedded profiles and other color spaces still receive explicit sRGB conversion using the --export-profile CLI option supported by the release image. Page sizing, JPEG quality, white transparency background and native resource limits are unchanged.

Retire client wait timers before continuing

Client command and cancellation waits fully retire timer messages that race with a result.

Client command, browser and cancellation-receipt waits now finish retiring a timer message that races with a result before continuing to the next wait. Already-consumed deadline messages do not cause an additional wait. Execution budgets, cancellation grace periods, receipt validation and returned results are unchanged.

Keep board filters when opening hidden tasks

A board column's more link retains the board's project and other filters.

Opening the hidden tasks in a board column now keeps the board's project, priority and other filters. The link selects that column's status and switches to the table without broadening the result set. Production page and column limits are unchanged.

Status alternatives inside OR groups are preserved too. For example, a board filtered by status:open OR priority:high keeps all matching tasks in the selected column when opening its more link; it no longer silently requires those tasks to also have high priority. Nested and negated status alternatives keep their original meaning, while tasks from other columns stay excluded.

Build Apps with icons and dates faster

App builds avoid repeating large library traversal without shrinking the available libraries.

Apps importing icons or date functions no longer make the offline compiler open thousands of library modules on every build. The reviewed library catalog keeps all public exports, shared date defaults and per-App tree shaking. Compiler permissions are unchanged. Running releases retain their original bytes; the updated catalog is used on the next publish.

Keep date Apps small

Apps importing one date locale or function no longer include unused locale factories and parsers.

Apps importing a single date-fns locale or function again discard unused locale factories and parser constructors. Catalog generation verifies their initialization is side-effect-free before restoring the tree-shaking annotations. All library exports, date defaults and shared default-locale identity remain available. Existing releases keep their bytes; the corrected catalog applies on the next publish.

Find, repair and retire Tools

Tools now show source health and retained usage, with reviewed repairs and recoverable cleanup.

The Tools page searches the complete inventory and filters by source health, usage, retention and archive state. Tool details explain their purpose, origin, source changes, replacement history and retained consumers. Remote connection checks distinguish changed or missing tools from authentication and availability problems.

Apps and workflows can prepare one repair review for selected tools, including nested configurations, changed settings and target access. Approval creates the reviewed replacements and updates the Draft together. Publishing remains a separate decision. Standalone replacements use the same review, and new remote configurations keep readable names.

Unused consumer-owned configurations retire after a seven-day grace period; Keep for reuse preserves intentional reusable tools. Retired configurations can be restored as drafts, with old approvals and revoked access kept closed. Health-check failures never retire a tool automatically.

Tool Activity includes calls from every entrypoint and a clear configuration diagnosis when a saved Query setup fails before execution.

Nested lists stay in task descriptions

Task descriptions written from Markdown retain nested lists and continuation text instead of silently dropping them.

Writing or updating a task description from Markdown now preserves child lists, checkboxes, ordered-list starting numbers and continuation paragraphs. Reading the description back keeps the same hierarchy, including every nested sibling.

This also fixes the shared entity rich-text converter used by other description fields. Text already dropped by an earlier write must be restored from its original source.

Pin Apps directly to Home and the sidebar

Open Apps from Home, the sidebar or Favorites without creating a Page around them.

Apps can now appear directly on Home and in the sidebar. Open an App and choose Place, or use Place in navigation in its management menu. Choose an existing shared audience, then add a Home tab or sidebar entry. Labels and icons can be customized using the same controls as Pages.

Use the star beside an App's name to add it to your personal Favorites.

Home keeps its tabs while you use an App, including links within the App. Pages and Document-backed Pages keep working alongside App tabs. Sharing stays with the App: placement never grants access, and navigation updates when access is removed or an App is archived.

Templates read what is wired in, shown as named chips

A {{ }} reference now reads only the step's wired inputs, the trigger and workflow settings; picking an earlier step's value wires it in, and references show as chips such as profile › email.

Text settings that take {{ }} values have a new editor. A reference shows as a chip named like prose (profile › email) instead of an address such as nodes.start_30zq.output.email; hovering a chip shows where the value comes from and a sample, and a reference that cannot resolve turns red.

Type {{, or press a field's {} button, to open the value picker. It lists the step's inputs, trigger (what the run started with, for every step the trigger reaches), what earlier steps produce, and the workflow's settings. Picking a value from an earlier step that is not wired in yet adds the edge, so every value a step reads is a wire you can see on the canvas. Dropping a field dragged out of an output's value tree on a setting does the same.

A setting can no longer address another step directly with {{nodes.<id>.…}}. Such a reference is listed under the step's problems while you edit, and Publish refuses it: wire the step in and read its input instead.

Expressions & Templating

See every request an integration step sent

A step that calls a provider gets a Calls tab listing each request with its status and time, its error lists the details it carries, and the node's About lists the requests before you run it.

Some integration steps do one job in more than one request. Change status in Jira reads the issue's transitions before it moves the issue; Reply to email reads the original message and your address before it sends; Search emails reads each message it found. The run view now shows them, for every Jira, Google and GitHub step that calls the provider's API.

Calls. A step that called a provider has a Calls tab after Output. Each request is a row: the method, the URL, the status, how long it took and what it was for. Open a row to see its query, the body it sent and, when it failed, what the provider answered. A request the step did not need is listed as skipped. A step that runs once per item lists every item's requests, numbered by item, and a request sent once for each email in a list says which one ("3 of 25"). A request the step expected to come back empty-handed, such as an email deleted since it was listed, is marked "left out" rather than failed. Credentials are never recorded.

Errors. The Error tab names an error's type in words, such as "Transition not available" rather than "Error", and lists what the error carries: the transitions the issue does offer, the field that was missing, the item that failed.

Before a run. The (i) next to a node's name in the inspector now explains every node, and for an integration node it lists the requests a run will send and the access it asks for.

Leaving a run returns to the release you opened

A workflow page opened on a release now returns to that release, read-only, after you look at one of its runs, instead of opening the editable main Draft.

Open a workflow on an exact release (?release=<id>), look at one of its runs, then go back to the editor: the canvas shows that release again, read-only, labelled as before. It used to switch to the main Draft and make it editable, so the next change could land on a Draft you had not chosen. Pages opened on a branch or on the main Draft still return to that Draft, with any changes made while you were away.

Workflows

Recovery checks use your current permissions

Checking a recovery proposal, and repeating a submission that already applied, now use the same current Task and workflow permissions that applying uses.

  • Check this run in Review recovery is refused when applying would be refused for permissions: the Task was unassigned from its agent, you or the agent lost access to it, or the task route moved to another workflow and no matching release is selected in the form. Before, the check could still show the proposal in those cases.
  • A repeated submission after a lost response still reports the result already recorded, but only while you still hold the Task and can still open the recovery workflow. Otherwise it is refused and nothing changes.
  • End execution is unchanged. An owner whose route was withdrawn can still end the attempt with the usual settlement evidence.

Task workflows

Edit a branch Draft over MCP against the revision you inspected

workflow_edit now writes a branch Draft when its expected guard names that branch, with the same stale-source refusal as the main Draft. The guard decides which Draft is written.

workflow_edit used to refuse any guard naming a branch Draft, so a branch could only be changed in the editor. It now writes the Draft the guard names:

  • Read the branch with workflow_inspect(action: "source", selector: {"kind": "branch", "id": ...}) and send the expected_source it returns as expected. The batch applies to that branch's Draft, and the response carries the guard for the next edit of the same branch.
  • The guard is compared with the branch row inside the write transaction. A branch that moved since you read it is refused with stale_source and nothing is written, including after an edit that restored its earlier bytes.
  • A branch guard never writes the main Draft. An unknown branch, a branch of another workflow and an archived branch are refused as not found.
  • Edit authority is checked on the workflow in the same transaction; a reader holding a correct guard is still refused.
  • A branch edit reaches production only through workflow_release(action: "publish", branch_id: ...).

Workflow tools

Filter tasks by code or number

Task queries accept code:in:RPD-1,RPD-2 and number:in:1,2, so a known list of tasks comes back in one call.

Since 2026-09-26 these keys are spelled id:, for example id:in:RPD-1693,RPD-1694; see Fetch a list of tasks with id:in.

Task filters now include code and number:

  • code:RPD-123 or code:in:RPD-1693,RPD-1694 matches tasks by the code shown in the UI. The prefix must be the task's current project key, and TASK-N names a task with no project, the same as ref. A code with the wrong prefix matches nothing, and so does a malformed one.
  • number:in:1693,1694 matches by the task number alone. Numbers are unique in a workspace, so the prefix is not needed.

Both work in the task list filter bar, MCP query (including strict:true), saved views and the query node.

New 404, error and maintenance pages

Missing pages, server errors and upgrades now show a small workflow run that explains what happened, instead of a plain line of text.

A link to a page that doesn't exist used to show only "Not Found", and a server error showed "Internal Server Error". Both now show a short workflow run drawn like the workflow editor: a missing page is a step that was never there, and a server error is a step that failed. Each page has a way back to your workspace, and the error page has a retry.

The page shown during an upgrade uses the same design. It shows the release in progress, with traffic paused and the database migrating, and your existing work is preserved as before.

The pages follow your system's light or dark setting, and the animation stops when reduced motion is on.

The query node's Object setting now filters by object

Setting Object on a Record query restricts results to that object, and the object_fields output is removed.

On a rollout.query node or Capability reading Record, the Object setting now restricts the results to that object, exactly like an object:<slug> term in the query. Before, it only chose which schema to use for the object_fields output, so object: metric with number:1 returned record number 1 of every object.

A query that names a different object than the setting now fails with a message naming both, instead of quietly returning nothing.

The object_fields output is removed. It repeated the first record's values a second time, which counted twice against the tool result size limit, and it read as empty when the first record belonged to another object. Use records[0].data instead.

MCP upsert refuses task and project fields it would have dropped

upsert(Task) and upsert(Project) name any data key their command does not accept instead of reporting success without it, and task relations accept a slug or task code.

upsert(source:"Task", data:{project:"…", parent:"RPD-488"}) used to report created while quietly dropping project and parent, so the task landed with no project and no parent. Task and Project writes over MCP now refuse a data key their command does not accept, name it, and suggest the field that was probably meant (project_id, not project; status, not task_status_id). Nothing is written.

Task writes also accept a human identity for their relations, on every surface: project_id and milestone_id take a slug and parent_id takes a task code such as RPD-488. An identity that does not resolve fails with the field name, instead of a bare "Not found.".

API Request can prefix a secret header with Bearer or Token

The secret-header authentication on http.request has a Scheme choice, so a token can be stored raw and sent as "Bearer <token>".

The Secret header authentication on the API Request node and its Tools used to send the secret exactly as stored, so a bearer token had to be saved as Bearer abc123. That tied the secret to one header shape and made rotation error-prone.

There is now a Scheme choice next to the header name: none (send as stored, the default), Bearer or Token. With a scheme set, store the raw token and the request sends Bearer <token>. Secrets stored with the prefix keep working with the scheme left empty.

This adds a field to the reviewed http.request contract, so existing sealed http.request Tools must be re-sealed before their next call. Tools that opted into automatic migration are rebound on their own.

Device tools called outside a workflow return their results again

A Rollout Client shell tool run through MCP invoke or an app widget no longer times out after the device finished, and a slow call now returns its invocation id instead of a timeout.

A device-delegated tool, such as a rollout.client.shell Capability, called through MCP invoke or from an app widget ran on the device but never reported back. The device finished the command and kept the result in its outbox. The server refused that result because the call had no workflow run, so the caller waited out the 60-second tool limit and got a timeout.

Every device dispatch now registers which device may answer it, whether or not a workflow run is involved, so the result arrives and the call returns it. Live output from a call without a run is not streamed anywhere, as before.

A call that is still running after 25 seconds now returns its invocation_id with state running, and keeps executing. Follow it with invoke(action:"status"). Previously the caller hit a client timeout and had no id to follow up with.

The Rollout Client also logs the reason when the server refuses a command result, instead of keeping it in the outbox silently.

Apps whose tool calls are refused now show as degraded

When a tool refuses a published app's call because its arguments no longer match the tool, the app's tool status turns degraded and the workspace is alerted, instead of reading ok.

Renaming the EntityRecord query source to Record broke apps that still sent the old name, while app validate and the app's tool status both said everything was fine. The tools themselves still verified; it was the calls from the app's code that no longer matched.

An app's tool status now has a fourth value, degraded. It is set when a tool refuses a call from the published app because the arguments do not match the tool's current contract, and it names the tool alias and the reason, for example source must be one of: …. The workspace alert channel gets one alert per publication. Publishing the corrected app clears it.

Only calls made by signed-in workspace members count, so a visitor to a public app cannot mark it degraded by sending bad arguments.

The node changelog now also records the EntityRecord → Record and entity_type: → object: rename as a breaking change for arguments an app, agent or MCP caller supplies. A rebind cannot repair those; the app's code has to change.

A smaller MCP tool surface, with manuals on demand

The MCP server now exposes 26 tools instead of 52, grouped by verb, and moves long authoring rules into a guide tool the assistant reads only when it needs them.

Every tool description is loaded into the assistant's context on every request, so a large surface cost context before any work began. The Rollout MCP server now exposes 26 tools instead of 52, and the long authoring rules that used to sit in descriptions now live in guide, which the assistant reads only when a task needs them. Tool descriptions and error messages name the guide topic to read next.

Tools are now grouped by what they do rather than by resource:

  • Reads: query covers every list and lookup, including dashboards, saved views, labels, cycles, channels, secret names and Capabilities, alongside search, workspace_context, guide and attachment_url.
  • Writes across resources: upsert for records (now including workflows, saved views and labels, with an expected guard and dry_run validation), archive for recoverable archive and restore, purge for permanent deletion, access for sharing, link for relationships and label for tagging.
  • Resource tools: workflow_inspect, workflow_edit, workflow_release, workflow_run and node_types; dashboard; app, capability and invoke; task_planning, task_config, cycle_schedule and record_schema; team and member for administration.

Every tool now follows the same conventions: the primary resource is ref, the optimistic guard from your last read is expected, dry_run validates a write without making it, source always names a resource type, every write reply echoes its action, and a parameter the action does not read is refused instead of ignored.

Read-only deployments keep workflow inspection, Capability listings, the Capability impact inventory and every resource's audiences, which are now read through query instead of from inside write tools. Each source keeps its own scope and permission checks. One scope changed: listing and reading Capabilities now needs only a read-scoped token, and which Capabilities a caller can see is unchanged.

Workflow inspection now redacts environment values and service credentials for every caller, including in release envelopes. Dashboard replies no longer carry policy.can_read, next_offset or the catalog zone fields; the MCP Integration page lists each dropped field and what to read instead.

Assistants and saved prompts that name the old tools need the new names. The MCP Integration page lists every current tool.

MCP Integration

Run tools directly from MCP, inline or presigned

The new invoke tool runs a reviewed tool or a built-in node in one call, and presigns large payloads so they bypass the model context.

Agents can now run a tool directly through the MCP invoke tool: an existing reviewed tool, one call to a built-in node, or an App source update. Small calls pass their arguments inline and get the result in the reply.

For a large App source bundle, record batch or export, presign: true returns a one-use token that expires in ten minutes plus a ready request: URL, headers, the argument schema and a curl command that keeps the token out of the process list. The bytes travel over HTTP, never through the model context.

A node or App target creates a single-use tool that never appears in Resources → Tools or any picker and is retired an hour after its call ends. Calls with side effects, including every App source update, wait for the requesting user's approval either way; the request and the approval card show the same short binding code. Read-only calls run at once.

invoke status reports the approval deadline, why a call closed without running, and returns small results inline. invoke cancel withdraws a call that has not run. Approved calls that could not be dispatched within 15 minutes now close with a reason instead of waiting indefinitely.

MCP Integration · Security

Approve agent and workflow requests from the desktop app

Every approval you request now appears in Rollout Desktop with Approve and Deny, matched to your agent's call by a short code.

Rollout Desktop now shows server approvals next to on-device command consent. When your agent's invoke call, an App tool call, a workflow approval step, or an MCP-authored tool activation needs a decision, the request appears on the desktop app connected to that workspace, with a system notification. You see every request you started yourself and every request Rollout asked you to review. Approve or Deny on the card, or open it on the web.

Agent requests carry the same short binding code the agent received, so you can tell concurrent requests apart. The server checks your current permissions on every decision and records it as made in the desktop app. Approving a server request never runs anything on your device.

Update Rollout Desktop to get server approvals; older versions keep receiving device consent only.

Desktop app · MCP Integration

Rollout Desktop 0.1.1 shows what happened this session

The desktop app keeps a timeline of your approvals and finished runs since launch, and its popover now fits its content.

Rollout Desktop 0.1.1 adds a This session timeline to Activity. Every approval or rejection you make in the app, for commands on this device and for server requests such as an agent's invoke call, appears next to every finished run, newest first, with a one-line summary of runs and decisions by outcome. Server decisions show the request's binding code. Reconnecting after sleep or a network drop no longer clears the list; switching workspaces shows that workspace's activity. The timeline covers the time since the app launched and is not stored after it quits.

The tray popover now sizes itself to its content: compact when nothing is pending, taller as approvals and runs arrive, scrolling once it reaches most of the screen height.

Install 0.1.1 from the latest desktop release; the app does not update itself yet.

Desktop app

Capabilities are now called Tools

The governed, reviewed actions that Apps, workflows and agents call are named Tools everywhere, from the page at /tools to the MCP tool and query sources.

A reviewed, model-callable configuration is now a Tool in every place it appears. The name matches what the product already showed in App settings and the AI node's tool list, so one concept no longer has two names.

What changed:

  • The Tools page moved from /resources/tools to /tools. The old address no longer resolves.
  • The MCP tool capability is now tool. Its guide topics are tool.lifecycle, tool.templates and tool.template, the query sources are Tool and ToolImpact, and archive takes source:"Tool".
  • Tool references stored by Apps and AI nodes use the key tool_id ({"tool_id": "<uuid>", "name": "<local_call_name>"}). Existing Apps, workflows, pages and credential contracts were rewritten in place.
  • invoke names a reviewed Tool with tool instead of capability, and the one-time transport endpoints are /api/tenants/:tenant_id/tool-invocations and /tool-results.
  • Tool error codes are renamed to match, for example tool_not_current and tool_source_stale. capability_reference_not_found keeps its name: it reports a connection, device, volume or secret reference, not a Tool.

Device capabilities, deployment capabilities and permission checks keep their names: they describe what a device, a deployment or a role can do, not a Tool.

One inbox for workflow input and App tool approvals

Workflow prompts and App tool requests now share durable approval evidence and a pending approvals inbox.

Workflow input and App tool approval requests now appear in a shared pending approvals inbox. A response records the exact request, typed answer, reviewer, and trusted interactive channel. App approvals continue only when the current App, Capability, credential, and request authority still match. Workflow timeouts, skipped steps, and defaults cannot approve a tool call.

The inbox shows requests only within the recipient's current workflow access or App and Capability manager access. Approval history keeps prior outcomes, including older decisions whose interactive channel cannot be verified. Review context remains available to authorized workflow reviewers through an encrypted request. Historical text and choice answers awaiting resume are preserved; older effect approvals without verified human origin require a new approval and fail the affected run explicitly.

Create and update workspace records through one Upsert action

Workflow and MCP writes use one source picker and explicit record selectors, with sparse updates and guarded Document content.

The workflow editor now has one Upsert step for ordinary Tasks, Projects, Objectives, Milestones, Key Results, custom records, Documents, and supported Activities. The MCP server exposes the same write choice as upsert; query remains the read surface. Separate create and update actions have been removed.

Choose the source once, then provide the fields to write. Leaving both selectors out creates a record. ref updates only that exact existing record and fails if it cannot be reached. upsert_key is an opaque, durable identity scoped to the workspace and source: the first call creates, and later calls patch that same record. Supplying both selectors is refused. Updates keep omitted fields; explicit false, zero, empty values, and permitted null remain meaningful.

Custom-record syncs can pass explicit per-item keys instead of relying on hidden business-field matching. A Document body replacement requires the content digest returned by a read, so a stale automation cannot overwrite a newer collaborative edit. Activity writes stay limited to supported authored comments and notes; audit events and publication or linking actions keep their specialized commands.

Saved current workflows and governed tools using the old actions require the reviewed local transition before they run under this catalog. Historical run snapshots and archived flows retain their original evidence.

Workflow nodes · MCP tools

Choose an Upsert entity in one picker

The Upsert workflow editor now shows one entity choice and refreshes its record fields when that choice changes.

The Upsert workflow step now lists Tasks, Projects, Objectives, Milestones, Key Results, Documents, Activities, and your writable custom record types in one picker. Selecting a different entity refreshes the fields below it and removes incompatible field connections. Existing configured nodes open with their saved entity selected.

Review MCP-authored tools and send large Capability calls securely

Approve unattended tool activation in Tools settings and send exact large JSON calls with one-use tokens.

Capabilities authored through MCP now default to approval on every call. If an author explicitly chooses unattended calls, the tool stays a draft until a current manager approves its exact contract in Resources → Tools. The workspace admin can disable this approval route in Settings → Security & governance. The same owner can approve their own draft in the browser; an MCP client cannot answer that review on the owner's behalf.

For an active tool with large JSON input, manage_capability can issue a short-lived, one-use token bound to the exact request bytes. The caller posts the body once, checks the returned Invocation ID when work is pending, and uses a separate one-use token to download the full completed result. The transport keeps the tool's current credential, delegation and approval rules; an uncertain external outcome is held for reconciliation instead of replayed. App source changes still require a separate publish step.

MCP Integration · Security

Switching a record type cleans up unmatched inputs

Create and Update Record steps now remove wires and empty values that the newly selected record type cannot use.

When you change a Create or Update Record step to another record type, its connected inputs now follow that choice immediately. A wire to a field the new type cannot consume is removed from the saved workflow, while compatible whole-record and shared-field wires stay connected. Empty Task title and body values no longer show as stray saved fields after switching to a custom record. Meaningful saved values remain visible so you can review them.

Workflows

Record metadata controls now follow one field definition

Repeated Document status and Workflow name controls share their presentation without replacing their specialized editors.

Document status choices now look and behave the same in Details, tables, and the document header. Publishing through any of those surfaces first saves the current collaborative body, creates the version snapshot from that saved body, and promotes a pending draft in one transaction. Workflow and tool updates can still change metadata or body content together with status; the published version records the final content from that same update.

Workflow names now use the same input presentation on desktop and mobile while retaining the existing draft autosave, stale-write handling, and system workflow restrictions. Rich document bodies, the workflow graph, access controls, hierarchy operations, and other specialized editors keep their existing owners.

API Request accepts responses larger than 200 KB when you tell it to

The 200 KB response limit is a node setting you can raise to 4 MB, and the error now tells you what the limit was and how far it goes.

Some APIs return a page that cannot be made smaller: a project list with no paging, a report whose page size the server ignores. Until now the API Request node refused any response body over 200 KB, and the error offered nothing to change. The limit is now Max response body under Response options. It still defaults to 200 KB, and you can raise it to 4 MB on the node where you need it. The error names the limit that applied and the ceiling it can be raised to.

Two things to know. A request that reaches a private service through a connectivity binding is capped at 700 KB; the error says so when that is what stopped it. And a Capability built from this node, the kind an app or an agent calls as a tool, keeps the 200 KB default, because a tool call's whole result is bounded to that size after it runs. When an app needs a large response reduced to a few fields, run a workflow from the app and let its API Request node do the reading.

API Request node

Editing one field of a record no longer depends on the other fields

A record with rich-text content accepts a change to a single field again, and stored content the editor produced is read back correctly.

Updating one field of a custom record used to re-check every other field in it. On a record holding rich text that was good enough to save but no longer matches what the editor writes today, that turned an unrelated edit into an error — changing a status from the record page, from an agent, or from a workflow's Update record step all failed the same way. Fields you don't send are now left exactly as stored, and only what you actually change is checked.

Two things that made records unreadable are fixed alongside it. A link pasted into a rich-text field carried a leftover styling attribute that the server refused, which blanked the whole field on every surface that showed it: the record page, previews, search and Markdown exports. New content drops the attribute, and a migration repairs what was already saved — in record fields, task and project descriptions, documents and their version history, comments, posts and notes. The value a read returns can also be sent straight back in the next write; agents and integrations no longer have to reshape it first.

Custom entities

Ask a query for one field inside a record instead of the whole record

Field projection now accepts a path like data.external_id, and a custom record answers to title on every surface that reads it.

Reading custom records back was an all-or-nothing choice. Every value you define on a record type lives inside one data object, and the fields parameter only understood top-level names, so asking for data returned every custom field of every row. Twenty records with a few long text fields came back at over 100 KB, which is close to the ceiling an app tool call is allowed to return at all, and agents were paying that cost to read one identifier.

A field name can now be a path. fields: ["id", "number", "data.external_id"] returns exactly those, rebuilding only the branch you named and leaving the sibling values behind. The same syntax works in the Query Data workflow step's Select Fields and Exclude Fields settings, which already accepted it, so a query written for one surface reads the same on the other. A path that matches nothing in a list read is still reported back to you rather than dropped in silence.

A record's primary value also answers to one name everywhere now. The workflow steps that read and write records emit title alongside primary_text, which is what the query tool and saved-view reads have always returned, so a graph that asks for title no longer fails with an unknown-field error. Nothing that already reads primary_text changes, and excluding either name still drops the value itself rather than leaving a copy behind. Those steps also hand back a record's slug and its status now, so a branch can test them without a second read.

Custom entities

An app tells you when its tools stop working

Apps now carry a tool-health status, the workspace can be alerted when one breaks, and repairing a tool keeps its id instead of forcing a rebuild of everything that uses it.

When a built-in tool's definition changes, every configured version of it stops verifying and the apps and agents using it refuse to run. Until now nothing said so. The app page showed the failure to whoever happened to open it, and that was the only place it appeared — no status anywhere, no notification, nothing that re-checked apps after a release.

Reading an app now returns tools_status: ok, stale (a tool's definition moved) or invalid (a tool was archived, removed, or is no longer active), with the local tool names affected. It is re-checked for every published app after each release, so the answer is there before anyone asks. Turn on App tools that stopped verifying in workspace alert settings and a broken app is emailed or sent to Telegram once, rather than found by a viewer.

Repairing a tool no longer costs a rebuild. manage_capability action:rebind re-checks a tool against the current definition and keeps its id; until now it refused every tool configured through the current authoring path, which left replacing the tool and republishing each app that used it as the only repair. It now works on those too, and only when the current definition still accepts the exact settings that were reviewed — so every app and agent already pointing at the tool keeps working with no re-linking and no republish. A change that would move a preset or a slot is still refused, and that one needs a replacement you read first.

A tool can also be set to follow its node definition, and then that repair happens on its own when a release moves the definition compatibly. It is off by default and stays that way unless you turn it on per tool: a tool can change what it does without changing the settings it accepts, and following it is a decision about a specific tool, not a safe default.

The tool library also separates the two things that were both called "stale": the lifecycle you set on a tool, and a definition that moved underneath one you never touched.

Apps

A refused tool setup names the setting that was wrong

Configuring a tool over MCP no longer answers "Invalid contract." with no detail, and a hand-written settings document no longer has to restate the keys the node already defines.

Configuring a tool through manage_capability action:"configure" used to fail with three words: Invalid contract. Nothing said which setting was refused, and nothing documented what the settings object had to contain, so the only way forward was to copy the template output wholesale and change it in place. Writing the object by hand usually failed for a reason no one could see: an internal field_policy_version key that nothing defaulted.

Those keys now come from the node itself. field_policy_version, slots, presets, hidden_fields and tool_name are filled in when you leave them out, so a configure call carries the fixed values you actually chose and its approval contract, and nothing else. A version you do write that is not the current one is still refused rather than upgraded, because that field exists precisely to stop an older tool's caller-fillable settings being reread under today's rules.

When settings are refused, the reply now carries one entry per offending key, each with the path to it and what is wrong:

JSON
{
  "error": "Invalid tool settings",
  "persisted": false,
  "errors": [
    {"path": "/presets/entity_type", "message": "Set entity_type to the record type this tool writes."},
    {"path": "/slots/url", "message": "url is both a caller slot and a fixed preset. Keep it in exactly one."}
  ]
}

This is the same shape validate_dashboard and manage_app action:"validate" already use. Every action that reviews a settings document answers this way: configure, copy, migrate, create_node, update and activate.

A {"$secret":"NAME"} marker written somewhere it does not belong now says so. It used to be reported as a secret that did not exist or was not shared with you, which sent you off to share a secret that was already shared, and the retry failed the same way.

Two things those messages deliberately will not tell you. A fixed value pointing at a secret, connection or device you cannot reach gets one message, word for word identical to the one for a reference that does not exist anywhere, so a rejected configure can never be used to find out what a workspace holds. And a value rejected against a list of permitted options reports only that it is not permitted, never the list.

MCP tools

Keep an unsent reply when you change the activity filter

Switching between All, Agents and Comments keeps a reply the new view still shows.

A reply you are writing now survives a change of activity filter, as long as the comment you are replying to is still shown by the view you switch to. A comment that appears in both All and Agents keeps its composer, its text and its parent across the switch.

A filter that does not show that comment still ends reply mode, and Cancel reply still returns you to the main composer. Drafts remain in the current browser editor and are not saved across page reloads or navigation.

Task comments

Query Data can read an admitted task's context, and verify a result it is given

Query Data now has an operation setting — the ordinary records query, one admitted task execution's context, or one exact step result checked against what is actually stored. The separate Task Agent Context node is gone.

Two reads that used to need their own plumbing are now operations on the node you already use.

Admitted task context. The Task Agent Context node is gone; Query Data does it, with Operation set to the admitted task context. Give it the execution id, get back admitted, context, execution_id and version — the same values, from the same authorized read. An execution that is not currently admitted for the caller still refuses.

Verified step result. Point Query Data at the reference a step record carries and it returns that exact result — after re-reading the step under your own access and rebuilding the reference from what is stored. Every identity and both payload digests have to match. A reference to a step you cannot see, one whose stored value was capped or redacted, and one that names a different result all refuse the same way; none of them returns a different row or an empty success. Comparing references by hand in a workflow was the old way to do this, and it is easy to get subtly wrong.

Existing Query Data nodes are untouched: no operation means the records query, with its filters, pages, counts and aggregation exactly as before.

The operation is a setting, not an input. A value arriving from the graph, or an argument an agent model chose, cannot switch the read — and when the node is saved as a tool, the operation is fixed by whoever configured it. Every operation runs under the same authority the node always used, so naming one reaches nothing new.

For workflow authors: rollout.task_agent.context is removed. Move those nodes to rollout.query with operation: task_context; execution_id and all four outputs keep their names. A special operation performs a fixed lookup, so a source, filter, include, limit or sort left on the node is ignored — fields and exclude still narrow the response, after the verification rather than before it. source is now an optional port, because only the records operation reads one; a records query without a source still fails.

Query Data

Project Tasks tabs show their label once

Project headers now show one Tasks label beside the existing truthful task count.

Project headers now show the Tasks tab name once beside its task count. The tab keeps the same destination and navigation behavior, and does not show a count until project statistics are available.

One node writes to a feed, whether it is a note or an agent's reply

Create Activity now has an operation setting — a system note, or the admitted agent's own reply in its task thread. The separate Task Agent Comment node is gone.

A workflow that wanted to write into a task's thread had two nodes to choose between, and the choice was not about what you were writing — it was about who was writing it. Create Activity wrote an automation note. Task Agent Comment wrote the agent's own reply. Same destination, two nodes.

Create Activity now has an Operation setting:

  • System note (the default) — the automation's own entry, with no author. Exactly what the node has always done.
  • Task comment as the admitted agent — the agent's reply in the task thread, posted once per stable reply key.

Existing Create Activity nodes are untouched: no operation means System note.

The setting is configuration, not an input you can wire. A value arriving from the graph, or an argument an agent model chose, cannot turn a note into a comment — and when the node is saved as a tool, the operation is fixed by whoever configured it. A comment still needs the agent's real admitted execution: there is no author without one, and the refusal never quietly degrades into an anonymous note.

For workflow authors: rollout.task_agent.comment is removed. Move those nodes to rollout.activity.create with operation: comment. The task goes in resource_id (kind task), the reply text in body_text — a structured document still goes in body — and execution_id, effect_key and parent_id keep their names. A comment operation refuses a supplied activity type: comment.created and comment.replied come from the thread. Replaying the same effect key returns the reply already written, including its original text, so a retry never edits what it already posted.

Task workflows

Filtering by label no longer depends on the icon a label stores

A label whose icon is not one of the built-in sets keeps its name and color in the filter picker instead of breaking the page.

Labels carry an optional icon. A label created with an icon name outside the two built-in sets used to break every surface that listed it: opening Add filter → Labels, or loading a URL that already filters by label, returned an error page even when the label you were filtering by had no icon at all.

Those pickers now show the label with its name, color swatch, group and selected state, and leave the glyph off when the stored name is not one we can draw. The collapsed filter chip follows the same rule. Labels with a supported icon are unchanged, and no stored label was modified.

Labels

A task's agent work now leaves a record, not just a status

Admitted turns, settled checkpoints, silent failures, held executions and owner recoveries each write one short entry in the task thread, and an agent can close its turn with a comment that commits together with its checkpoint.

Until now a task's agent work was only visible as current state: if a turn started and died, or an execution was held because the assignment moved, the thread said nothing and you had to open the technical details to find out. Those moments are now ordinary entries in the task's activity feed, under Updates.

One short entry per thing that actually happened:

  • agent work was scheduled (scheduled, not started — it may still be waiting for capacity),
  • an update was saved, and whether it is ready, waiting, complete or needs attention,
  • the run stopped without saving an update, failed after saving one, or left a result nobody can read,
  • earlier work has not confirmed it finished, and later, that waiting for it ran out,
  • the assignment or access went away and the work is held,
  • the task was closed while input was still queued,
  • new input could not be queued,
  • you resumed, applied a recovery proposal, or ended the work.

Each entry says only what actually happened. Scheduling a turn is not a running provider, so that entry carries no status badge. Unconfirmed earlier work is not necessarily a device, so it is not described as one. Applying a recovery proposal that ends the work does not claim it resumed.

Repeats do not pile up. A wake-up that finds the same situation, a duplicated source event, a settling poll or a replayed recovery all land on the entry already written. A genuinely new run or a new version gets its own.

Each entry is a fixed sentence plus the turn it belongs to. Nothing from the checkpoint, the provider transcript, the session, the worktree, the device or an error body is in it, and it does not name the workflow behind the task — someone who can read the task but not that workflow sees the fact and nothing more. When the runtime records a failure it does so as itself, so an agent whose access was just revoked cannot suppress the record of that.

For workflow authors: Task Agent Checkpoint has a new comment input, an object of {"body": text or rich text, "parent_id": optional comment to reply to}. Wire your role's closing narrative into it and it commits in the same transaction as the checkpoint, the consumed input, the guarded metadata namespace and the handoff — one commit, or none. That comment becomes the turn's receipt, so no separate entry repeats it, and the node returns its activity_id. Stop pairing a Task Agent Comment node with a checkpoint for the closing message. Leave the input unwired when a turn has nothing to say: a wired but blank or malformed comment refuses the whole turn rather than settling without the narrative it promised.

Editing such a comment rewrites the text, never the turn it settled, and deleting it keeps that link on the tombstone.

A note on delivery: the entry is written durably with the transition. The live push that refreshes an open page is best effort — if it is missed, reloading always shows the committed entries.

Task workflows

Decompose Task and Task Follow-Up are ordinary task nodes now

Both nodes moved to the rollout.task namespace. Their behavior is unchanged — the names now say what was always true, that a workflow does not need an agent to use them.

Decompose Task and Task Follow-Up were named as though only an agent could use them. They never were: the command behind each one has always accepted an ordinary workflow run acting on a task it may write, and has always demanded real proof from an agent run. Only the node names said otherwise.

They now sit beside Change Task Planning Team in the ordinary task namespace:

  • rollout.task_agent.decompose → rollout.task.decompose
  • rollout.task_agent.follow_up → rollout.task.follow_up

Nothing else changed. Children and their dependencies are still created in one transaction, the parent still waits for every child and keeps its own description, and repeating an accepted plan still returns the same tasks. A follow-up is still a related sibling that never blocks the task it came from, still files once per origin key, and still refuses an agent assignee — filing a finding must not dispatch the run that files the next one.

For an ordinary run, execution_id is simply the replay anchor that makes a retry safe. For an agent run it is the admitted execution, and it is checked against the task: a failed check refuses the node rather than quietly continuing as the workflow itself.

For workflow authors: the old IDs are removed with no alias. Point saved nodes at the new ones; every input, output and error is the same.

Task workflows

A refused task handoff says which field is wrong

When a checkpoint's handoff is rejected, the run error names the field that failed instead of carrying the whole proposed change.

  • A task workflow's checkpoint whose handoff is rejected — an assignee the agent may not hand the task to, for example — now reports the failing field and its message: assignee_id: must be able to view this task.
  • The proposed task data stays out of the run error: no brief, no task metadata, no checkpoint state, no comment body, no model report.

Task workflows

Agent work moves into the task conversation

A task's current agent state is now one compact line above its activity thread, with the release, run, session and recovery controls behind a Details disclosure instead of a separate panel.

The Agent work panel has left the details sidebar. A task that a configured agent holds now states its current state where the conversation is: one compact line above the activity thread naming the workflow, whether it is working, waiting or needs attention, and how much input is queued for it. That line stays put when you switch between All, Comments and Updates, so waiting work is visible without hunting for it.

Everything technical is behind Details on that line: the pinned release, the latest run, the recorded provider session, worktree, model and device, older enrollments, and the accountable owner's recovery controls. The disclosure is a normal keyboard-reachable button, and closing it puts the detail away rather than moving it somewhere else. Opening or refreshing it leaves your draft, your reply target and the selected filter exactly as they were.

Nothing about who may see what changed. Someone who can read the task but not the workflow behind it still gets the honest "you do not have access" placeholder and no run links, no session, no worktree — and the compact line claims no state it cannot read. Recovery still requires the same settlement evidence, the same exact checkpoint version and the same current authority; replying to the thread never applies it. Closing the disclosure drops an open recovery check, because a check describes one named run against the checkpoint that was saved when it ran.

The checkpoint summary is written once, in the details, and no longer repeated in a second place.

Clicking a task row still shows its agent state without leaving the list: the task preview panel now opens with the activity feed between Details and Links, so the same compact line is there. If you have customised that panel it stays exactly as you arranged it — add the Activity widget yourself, or follow the task link for the full conversation.

Still to come: durable per-turn records — started, waiting, settled or failed — written as ordinary activities so a silent turn still leaves an inspectable outcome in the thread. This release moves the presentation; it does not yet add those entries.

Task workflows

Resumed provider sessions are bound to the connection that created them

The desktop client now records which server, tenant, device, provider and directory owns each Claude or Codex conversation, and refuses any resume that does not match.

A Claude or Codex session UUID is a bearer name. Until now the device checked that a resume named a real UUID and an existing absolute directory, and compared the returned identity only after the turn had run. Anything able to put a UUID in a checkpoint could therefore ask an installed CLI to continue that conversation in a directory of its choosing.

The desktop client now keeps its own record of which authenticated origin owns which conversation: the canonical server URL, the tenant, the device id, the provider and the canonical working directory. A resume is admitted only against an exact existing binding, and the check runs before the dispatch that starts any process for the turn, Codex's review config probe included. An unknown, foreign, contradictory or unreadable reference fails the command with a message that names no other origin or directory.

Only the device's own observation of a running turn writes a binding. A checkpoint field or a reported identity cannot, and the binding is on disk before the result naming the session leaves the device, interrupted and failed turns included. A binding that cannot be written fails the turn and withholds the session instead of reporting an identity the next resume would refuse.

The directory is matched as a filesystem object rather than a pathname: an equivalent symlinked alias resumes, and a directory removed and recreated at the same path does not. A device and inode pair cannot make that distinction on its own, because ext4 hands a freed inode number straight back to the next directory created, so the replacement presents the same pair. What the binding records beside the path is evidence of the directory's own allocation: its birth time (statx STATX_BTIME on Linux, st_birthtime on macOS) and, where the filesystem offers one, the inode generation ext4, XFS and Btrfs redraw whenever an inode is allocated. The generation is what holds when the replacement is instant; the birth time is what holds on a filesystem with no generation.

This makes the guarantee depend on the filesystem. A directory that can supply neither witness is refused outright, fresh turns included, rather than bound to an inode number the filesystem recycles. That covers ext3, an ext4 formatted with 128-byte inodes, kernels older than 4.11 and most network mounts. Reconnecting to the same workspace, and restarting the client, both keep every binding; changing workspace, server, device, provider or directory cannot import a conversation.

Conversations started before this release are not adopted. They have no binding, so resuming one is refused and the recovery is a deliberate fresh session. The checkpoints that name them are left untouched.

Expressions can measure a value in bytes

The new byte_len(s) returns a string's UTF-8 byte size, so a workflow that has to stay inside a byte limit can check it directly instead of counting characters or a Base64 encoding.

  • byte_len(s) is available everywhere expressions are: Transform nodes, conditions, and {{ ... }} spans. It returns how many bytes the string occupies as UTF-8.
  • len(s) is unchanged and still counts graphemes, which is what a reader sees. The two agree on ASCII and disagree on everything else: len("é") is 1 and byte_len("é") is 2.
  • This matters wherever the limit is stated in bytes. The task-execution panel, for example, drops a recorded provider_session value longer than 4096 bytes, so byte_len(value) <= 4096 is the check that matches the rule. Counting characters passes values that are then dropped, and measuring a Base64 encoding to get back to bytes is arithmetic you no longer need.
  • Non-string input returns null, as the other string helpers do, so a comparison against a budget cannot read "not a string" as "fits". byte_len is also the one string function with no input size cap: the oversized value is exactly the one worth measuring.

Expressions and data

Clearing a release pin on a Subflow or Loop now sticks

Blanking Release (vN) or Release ID removes it instead of saving an empty value, and clearing the last one while Specific release is selected now explains what to do about it.

A Subflow or Loop set to Release Source → Specific release takes two optional pins: Release (vN) and Release ID. Clearing one of them did not work. The editor saved an empty value and kept the setting, so the field came back the next time you opened the node, and on a node pinned only by Release ID the save was refused outright and the old value reappeared on screen.

Blanking either field now removes it. The other pin and every unrelated setting on the node are untouched, and the field is still empty after a refresh. Which fields behave this way is a per-field decision, so a blank you typed into an ordinary text setting is still saved as the empty value you meant.

Clearing the last remaining pin while Specific release is selected is still refused, because a node pinned to a specific release with no release named has nothing to run. What changed is the message: instead of "Capability reference not found" it now tells you to enter a Release (vN) or Release ID, or to set Release Source back to Current. Your saved setting is left as it was, and the release mode is never switched for you.

Clearing a pin is not destructive: putting the value back restores it exactly, with nothing left over from the clear. Rollout has no settings history of its own, though, so there is no in-app undo to step back through once you move on.

Clearer widget failures in release verification

Widgets expose their load state as a stable attribute, and a LiveView wait that times out reports what the page was doing.

Every widget instance now carries its load state (loading, error, empty, hidden or ready) in a data-widget-state attribute, and the relationships widget marks an empty result. The rendered page is unchanged; until now those states were distinguishable only by their wording.

Release verification reads that hook. A wait on a widget gives up the moment its load reports a failure, or returns no data at all, instead of running out its deadline. A wait that does time out reports the LiveView's status, mailbox depth and stack trace next to the part of the page that did render, and reports it even when the LiveView has stopped answering renders, which is the case that report exists for. The Document rename check is back to its original five-second bound and now measures the broadcast, the reload and the patch separately. A source check rejects element-scoped render_async/2, which never scoped the wait it appeared to scope.

Agents can file what they find without stalling the work they were given

A new Task Follow-Up node records discovered work as a linked, non-blocking Task, filed once per origin key, and what an agent writes into a Task thread or a follow-up no longer carries injected credentials.

An agent working a Task often notices something real that is not the Task: a node that drops its input on retry, a query that scans the whole table. Until now there was nowhere sound to put it. Creating a Task outright duplicated it whenever the run was retried, and the one idempotent option — a child plan — makes the source Task wait for every child it creates, which parks the delivery the observation was a side note to.

The new Task Follow-Up node files one Task per stable origin key, joined to its source by a plain relationship rather than a dependency. The source keeps running. Repeating the same key returns the Task already filed instead of filing a second one; the same key with different content is refused rather than quietly overwriting what is there. However a run's previous attempt ended — crash, timeout, lost answer — retrying it files one ticket, not two.

Two runs are a different question, and the platform does not answer it. Each run gets its own origin keys, so two agents that notice the same thing file two follow-ups. Recognizing that as one finding means reading the existing Tasks first, which is a recipe's job.

A follow-up that has since been archived, moved to another Project or unlinked is reported for reconciliation rather than recreated: a run cannot tell a deliberate retirement from a lost write, so it stops and says which record is stale.

One limit is the platform's: a run may file 10 follow-ups, and past that the node refuses. And a follow-up cannot be assigned to an agent — an agent-assigned Task starts its own run immediately, which is how a run that reports findings turns into a run that dispatches the runs that report the next ones. Follow-ups arrive unassigned and unstarted, for a person to route.

Separately, what an agent writes is now redacted before it is stored, both in a Task thread reply and in a follow-up's title and description. A secret that reached the node's input used to be written through as templated. Both now run the same fail-closed pass that step evidence, streamed output and the Activity node already used: registered run credentials are masked, and if the credential registry cannot answer, the content is stored masked rather than raw. The other workflow write nodes do not run this pass yet, so a credential templated into rollout.entity.create or rollout.document.create still lands in the row exactly as written.

See which agent has your Task comment, and whether it has read it

Each comment in a Task thread now shows the agent role it reached and whether that role is still waiting to read it or already has.

A comment you post on a Task that a configured agent holds now carries its own delivery state in the thread: Waiting for the role that has not read it yet, or Read by the role whose turn consumed it. The role is named by its agent and, when you can open it, the workflow that agent runs.

Reassigning the Task moves an unread comment to whoever takes over, and the thread follows it: the badge names the new role, never the one that passed it on. That holds however often the Task changes hands, including when it comes back to a role that was handed the comment earlier and passed it on without reading it. A comment several agents were addressed in shows one badge per role, so you can tell which of them has answered.

The Agent work panel counts unread comments separately from the task updates queued beside them. "2 task updates, 1 unread comment" is now what it says, rather than one number standing for both.

Input handed to a turn that stopped before it recorded a result is unread again, and follows the Task with everything else. Previously it stayed with the turn that never answered it, where nobody was going to pick it up.

Task workflows

Address a configured agent in a Task comment

A Task comment can now name another configured agent, which opens an advisory turn with that agent without moving the Task.

A Task comment that names a configured agent is delivered to that agent instead of to whoever currently holds the Task. Asking one role a question no longer interrupts another, and a comment that names nobody continues to the current assignee exactly as before. One comment can name several agents; each gets the comment in its own turn and its own session.

Addressing resolves against the Project's configured routes and the author's own current eligibility: an agent routed on another Project, a disabled or archived route, an agent the author could not assign, or an id that names nothing is dropped rather than assumed. The comment records who it actually reached, and create_activity reports the same list back as addressed_agents.

Naming an agent grants it nothing beyond the turn. It does not reassign the Task, does not widen what its own route already allowed, and does not start a second writer: an advisory turn waits behind unfinished work on the Task. An agent's own reply never dispatches another agent, whatever it names.

Handing a Task on still withdraws whoever was holding it, including an agent you consulted first and assigned later, and its unread comments go to the agent taking over. An agent you only consulted keeps its own thread and its own unread comments until you close its route.

The comment composer has no agent picker yet, so this is reachable from clients that submit a structured mention, including the MCP create_activity tool.

Read an exact workflow result, and check it is the one you were handed

Subflow emits re-resolvable evidence for the step behind its result, queries can address one exact step or a bounded batch of them, and a skipped sibling step no longer stands in for a completed one.

A node id names a node in a graph, not one execution of it. A child run can hold several step rows for the same node id: fan-out and iteration write one row per member, and a node on an inactive branch is recorded as skipped alongside the member that ran. Subflow and Loop read the return node's outputs by node id, and which of those rows they got back depended on storage order.

They now read the completed row. A skipped row carries a skip diagnostic rather than a produced value and is never substituted for one, so a return node whose completed sibling exists returns that result instead of an empty map. A return node that only skipped returns null for its entry, which says it produced nothing.

When a return node has more than one completed row in the same child run, the call fails with ambiguous_producer and names the node. There is no rule that picks one of several real results, and the previous behavior discarded the rest without saying so. A subflow or loop whose return node fans out needs a single collecting node marked as the return instead.

Subflow now emits that resolution as evidence. Alongside result and results, which keep their shape and their node-id keying, reference and references name the run, the workflow, the executed release, the exact step row and that row's own node id and type, plus a digest of the step's persisted inputs and outputs. A Map used as a return node is labelled as the Map it is, not as the provider whose value it forwarded.

The digest covers what an authorized read returns, after redaction and the output budget have applied. A value that was capped or redacted anywhere inside it carries no digest at all, so a bounded preview is never presented as the value itself. A reference is a lookup key and nothing more: resolving it re-reads the row under the reader's own permissions, so no field in a payload can invent provenance, and holding one authorizes nothing.

Queries can now address a step. id:<step-uuid> names one exact step row and id:in:<a>,<b> resolves a bounded set in a single query, under the same authority the source already applied: every step read joins through its tenant-qualified parent run and checks workflow read permission separately. A reader without that permission gets an empty result, which is also what a made-up id gets.

A step read that includes inputs or outputs now says whether that payload is complete. Persisted payloads pass through redaction and the output budget, so a returned value can be missing bytes it once had; until now it came back looking like the whole thing. The verdict travels with the payload even when you narrow a read to specific fields, because a capped value returned on its own reads exactly like a whole one. Include workflow_run alongside both payloads and the read also returns the step's reference, re-derived from the stored row.

Two references are compared by the new reference_matches(a, b) expression, usable anywhere {{ }} templates and Transform expressions are: a subflow's emitted reference and a later query read of the same step either name the same stored result or they do not. It is not the same as comparing the two objects yourself. Both sides are checked for shape first, so a hand-built map never matches, and two references whose values were capped or redacted do not match each other either, because neither proves anything about what it names. reference_complete(r) asks that narrower question on its own.

A malformed step or run id returns nothing instead of matching every row you can see. id:in:step-123 is not a request for the whole page.

See which run produced a step, in the same query

Query Data can now return the identity of the run that executed a step — which workflow, which published release, and whether it was a real run or a debug one — without a second lookup.

  • Querying Workflow Step Runs, add workflow_run to include. Each step now carries the run that executed it: its id, workflow, released snapshot, source, status, outcome, run mode, run type and whether the run covered only part of the flow.
  • That is what tells a real production run apart from a debug, replay or partial one, so a workflow checking its own history can require the exact release it expects rather than trusting a step that happens to match.
  • The run's flow, inputs, results and credentials are never included. If a step's run is unavailable, the field is simply absent rather than a blank run.
  • Without the include, nothing changes: step results stay compact, and inputs / outputs remain their own opt-in.
  • Querying Workflow Runs directly now also returns the released snapshot, the source the run started from and whether it ran a partial flow.

Query Data

Pipe one uploaded file into many commands

Run Command can take its standard input from an uploaded workspace file, so several commands share one authored body instead of each carrying its own copy.

  • Run Command and Run Long Command gained a stdin_source input. Point it at an uploaded workspace file and its exact bytes become that command's standard input, so eight operations running the same driver point at one body instead of carrying eight copies of it.
  • Changing the body means uploading a new file. Every command still pointing at the old one keeps the bytes it was authored against.
  • Name the file in Shared Standard Input in the command's settings, as {"id": "<attachment id>", "content_digest": "sha256:<64 hex>"}, or wire the stdin_source input on the canvas from an upstream node that emits the reference — a Code node building rollout.attachmentRef({ id, content_digest }), for instance. There is no file picker yet: no browse dialog, and no display of the file's name, size or version beside the setting.
  • Pin the bytes with content_digest on the reference — sha256: followed by 64 hex characters. A pinned command refuses to run if the file it reads back is not the file it was written against.
  • A file uploaded through the browser carries no stored digest, and nothing in Rollout shows you one yet, so such a file must be pinned with a digest you compute yourself (shasum -a 256 <file>) before a command will accept it. A file that arrived through the API, an integration or a workspace transfer is stored by its content and needs no pin.
  • The reference is a name, not a permission. Before anything reaches the device the file is re-read under the run's current access: another workspace's file, a deleted one, one the run has lost access to, a body over the 1 MiB standard input limit, one that is not text, and one whose digest does not verify each fail the step naming the field and never the content.
  • A file someone attached to a chat message is data, not program source, and is never resolved here.
  • Wire either stdin or stdin_source, not both, and set either Standard Input or Shared Standard Input, not both: two standard inputs on one command fails the step rather than quietly picking one. A wired source wins over an authored one. Like the approval message, the source is operator-fixed: it is never offered to an agent or an App as something the caller may fill in.
  • Upload the source as a file rather than writing it in a Document. Rich text trims and reflows what it stores, so a program read back from a Document is not guaranteed to be the program that was written.

Client workflow nodes

A run's exact source, without opening the editor

Workflow run results now name the release or the Draft that produced them, and separate a test run on main from one on a branch.

  • Querying Workflow Runs returns the source a run executed: the released snapshot and its name, the branch, the source kind, the run type and whether it covered only part of the flow. The editor already showed this on every run chip; now a query, a workflow reading its own history and the MCP tools see the same thing.
  • branch_id is what tells two Draft runs apart. A selected-node test on the main Draft and one on a branch Draft are different evidence and used to look identical after the fact.
  • Filter on it: branch:<id> returns one branch's runs, branch:main the main-Draft ones, branch:!<id> everything else including main. release: and flow_source: filter the rest of the identity, and runs sort by source_revision.
  • Add branch to preloads to get the branch's name alongside its id. Without it the id is still there; nothing does a per-row fetch to name a branch, and the preload itself loads the branch's identity only — never its graphs.
  • Runs from before branches existed keep an empty branch and release name, and read as unknown rather than as main.

Query Data

A run that has not started anything now says so

A live run whose first node has not begun showed only Running and a start time. The run view now states that no node has started running yet, that it will start on its own, and how long it may wait before it fails.

  • A workflow run can be live without having executed anything. Until now the run view showed Running and a Started time, which read like work in progress.
  • The run header now says No node has started running yet for exactly that state, along with the fact that the run starts on its own once the runtime picks it up. There is nothing to retry, and retrying would only add a second run waiting behind the first.
  • It also states the deadline. Waiting spends the run's own timeout (30 minutes unless the workflow sets another), and a run that has still started nothing by then fails instead of waiting longer.
  • The message is deliberately silent about the cause. Several different waits produce the same row today, and naming one of them would be a guess.
  • Nothing changed about scheduling, about when a run starts, or about that deadline. Only the run view was silent about them.

Workflow runs

Find the runs waiting for input in run history

The run-history status filters now cover every state a run can be in, so a run waiting for input is no longer hidden by every toggle and reachable by none.

  • The status filters in the run-history sidebar offered Running, Completed, Failed and Cancelled. A run awaiting input matched none of them, so picking any filter hid it and no filter brought it back.
  • Awaiting input and Queued are now toggles of their own, alongside the four that were already there.
  • Nothing is filtered by default: with no toggle selected, run history still shows every run, as before.

Runs record which Draft revision they executed

A run started from a Draft now keeps the revision it ran, so two tests of the same Draft taken at different moments are distinguishable afterwards.

  • A Draft keeps changing while you test it. Every run already froze the exact graph it executed, but a Draft edited and then edited back produced two runs with identical graphs and no way to tell which came first.
  • Runs started from the main Draft or a branch Draft now record that Draft's revision, and the run header shows it: Main Draft · rev 7.
  • Querying runs returns the same source_revision, so a workflow reading its own history, or an audit, can name the version a result came from.
  • Releases are immutable and have no revision; runs recorded before this change have an unknown one. Both show the source alone rather than claiming a revision.

Debug workflow runs

Copy to Draft from a run names the Draft it replaces

The run panel's Copy to Draft confirmation now says which Draft it would overwrite — the main Draft or a named branch Draft — like the release picker already did.

  • Copying a run's graph into the Draft replaces whichever Draft you have selected. The confirmation said "the current Draft", which named neither, so a copy aimed at a branch's unpublished work read exactly like a copy aimed at main.
  • It now names the destination before you commit, matching the picker entry and the message you get after the write.
  • The write itself is unchanged: same destination, same permissions, same effect on the Current Release and the Running/Paused state (none).

Debug workflow runs

A client step now says which device problem stopped it

The four ways a Run Command, Claude Code or Codex step can fail to reach a device each carry their own error code, so a workflow can branch on an offline device instead of matching the message text.

  • No eligible device connected, a named device that is offline, a device this workflow or user may not use, and a device that cannot run the requested capability are four different recoveries. They now arrive as four codes — no_device_available, device_not_found, device_not_available, device_not_capable — instead of one generic failure.
  • A step that continues on failure can branch on nodes.<step>.error.code, so an offline laptop can be waited out while a capability mismatch stops the run. The messages are unchanged.
  • The failed step in the run view carries the same label rather than a generic error: No device, Device offline, Device not allowed or Device cannot run this.
  • This matches what Browser Automation already reported and now applies to Run Command, Run Long Command, Claude Code and Codex.

Client workflow nodes

Tune a role's step from Agent settings

Each step of an agent's role recipe now has a Tune action that edits that step's declared settings in a Draft of the running release — a prompt, a command, a timeout — then shows what publishing that Draft would change and lets you publish or roll back, without opening the graph editor.

  • Change a prompt where you read it. Tune on any step of the Role recipe shows that step's editable settings with their saved values. Change one, save it, and the recipe on screen updates to what the Draft now runs.
  • It edits a Draft, never the release. Tuning opens an authoring Draft named for the release you are looking at, and returns to the same Draft next time instead of making another one. The Current release keeps running your tasks until that Draft is published. Each release gets its own tuning Draft, so the one you published stays in the workflow editor's branch list until you archive it there.
  • The panel says which source it is reading. The release and its id before tuning; the Draft name and revision after, with a link straight into the editor at that Draft.
  • A step's instruction document reads by name. When a step names a document by slug or id, the recipe shows that document's title and links to it instead of printing the raw reference. A document you cannot read stays unnamed.
  • Not everything is editable here, on purpose. Credentials, the ids that point at another resource, device targets and structured editors stay in the workflow editor. A setting supplied by a wired input is shown locked, because the wire wins when the step runs.
  • See what publishing would change, before publishing it. Review changes lists what differs between your Draft and the release that is running, step by step and value by value. Publishing is offered there and nowhere else, next to what it actually does: it moves the Current release for every task, trigger and caller of that workflow, while executions already admitted keep the release they were pinned to. If you change your mind, restore the release that was Current a moment ago; your Draft keeps its changes either way.
  • A save that loses a race writes nothing. If the Draft changed while you were editing, the panel says so, keeps what you typed and lets you save it again against the Draft as it now stands.

Task workflows for agents

A node test says which nodes reach outside the run

Previews name every scheduled node that would call a provider, run a command or touch the workspace, and a test can refuse to start when any of them is in scope.

Testing one node or one reachable subgraph runs the real nodes, so anything in scope that calls a provider, runs a client command, makes a request, reads or writes the workspace, writes a checkpoint or starts a child run does it for real. The preview now says exactly which nodes those are, in the editor dialog and in preview_node_test under effects.fixture_required.

The editor's warning used to read the node's declared side-effect class, which describes whether a retry is safe rather than whether the node stays inside the run. A subgraph of workspace reads declares no side effects at all and showed no warning. The dialog now names the nodes instead, and says so plainly when every scheduled node is self-contained.

The dialog also carries a "Refuse if any node reaches outside this run" checkbox, and test_node takes the same thing as inert: true. Either one refuses the test, naming those nodes, and nothing is started: no run, no step, no job. Supplying a stand-in outcome for one of them is not available yet, so the option either runs a wholly self-contained scope or refuses. Left cleared, the route behaves exactly as before.

A Markdown table written into a document stays a table

Documents created or updated from Markdown keep pipe tables as real tables. Until now the rows collapsed into one paragraph of pipes and dashes, with no error to say so.

  • Sending content_markdown with a GFM pipe table — through the MCP create_document / update_document tools, a workflow node, or any other write surface — now produces an actual table in the document: a header row, one row per line, and editable cells.
  • Previously the whole table arrived as a single paragraph with its pipes and dashes run together, and nothing reported the loss. The only way to notice was to read the document back. Guides and runbooks written that way lost their tables silently.
  • Cell content keeps its formatting: links, inline code, bold and italic all survive. An empty cell stays an empty cell, and the :---: alignment row sets each column's alignment in the editor.
  • Reading a document back as Markdown gives you a table again. Alignment is the one thing that does not come back out — the rendered Markdown always writes a plain --- separator row.
  • A paragraph that merely contains pipe characters, and a fenced code block showing table syntax, are untouched. Only a real pipe table with its separator row becomes a table.
  • Markdown images are still refused, inside a table cell as anywhere else: an image has to be an uploaded attachment rather than an address the writer supplies. The document is left exactly as it was when that happens.

Documents

Publishing a large branching workflow no longer stalls

Saving or publishing a workflow whose branches split and rejoin used to get slower and slower as the graph grew, until the request gave up. Validation now takes the same single pass regardless of how many routes through the graph exist.

  • The loop check that runs on every save and publish walked every possible route through a workflow instead of every connection. Branches that split and rejoin multiply routes fast, so a graph of a few dozen nodes could carry billions of them. One 32-node workflow needed 10.9 million steps to answer a question that takes 131, and its publish ran out of time after 15 seconds.
  • The check now visits each node and each connection once, so its cost grows with the number of connections you drew rather than with the number of routes they imply.
  • Nothing about which workflows are accepted changed. Loops are still rejected with the same message, including a node wired back to itself and a loop in a group of nodes nothing else reaches. Connections pointing at a node that no longer exists still report that node by name, and a loop that runs through one is still reported as a loop.
  • The timeout we traced happened during validation, before anything was written, so that attempt left the workflow exactly as it was. A publish can time out for other reasons at other points, though, so check your draft and your published releases before retrying one rather than assuming nothing was saved.

Building workflows

Read Document answers for a large document instead of failing

A document too big for a step's stored evidence now returns its identity, version, digest, size and a bounded preview, with complete=false, rather than failing the step.

  • Read Document used to fail the step when a document's content was larger than a step's evidence budget. It now returns what it can: the document, slug, title, version evidence, content_digest, content_text_bytes and a 4 KiB content_preview.
  • complete tells the two apart. It is true when the body itself is there, and false for the reference form, where content_json, content_markdown and content_text are empty.
  • The body's fields are empty rather than shortened, on purpose: a preview identifies content, it never stands in for it. Nothing downstream can treat a partial document as the whole one.
  • Nothing changed for a document that already fit, and the evidence limit itself is unchanged.
  • To work with a large body, select a version small enough to carry, split the document, or use the preview and digest to decide what to read next.

Read Document

Edit a workflow graph against the version you actually inspected

Semantic graph edits now carry the exact source, revision and digest the caller read. A plan built on an older graph is refused with a typed conflict and nothing is written, instead of overwriting whatever landed in between.

  • workflow_operations flow edits take expected_source: the destination you read, its revision and its graph digest. Until now the tool re-read the workflow immediately before writing, so its lock only covered its own read-to-write window. A batch planned against a graph you inspected ten minutes ago was applied over whatever had been saved since.
  • Send {"source": {"kind": "main_draft"}, "source_revision": <int>, "source_digest": "sha256:..."}. If either value has moved, the call is refused with stale_source and nothing is written. Re-read, rebuild the batch against the current graph and retry.
  • The revision is what makes an edit-and-revert detectable: a graph returned to its earlier bytes has the same digest but a higher revision, and a plan bound to the older one is still refused.
  • Copy the whole expected_source object a read returns. get_flow returns one, inspect_source returns one for a main_draft source, and every successful edit returns the one the next edit needs, so a chain of coupled batches costs one read rather than one per write.
  • The guard is required for any workflow that already has a graph. A blank workflow has no earlier observation to invalidate and can be built without one; the first edit after that is guarded.
  • Unknown keys are refused rather than ignored, inside the guard and inside each operation object. A misspelled or invented guard field can no longer be dropped and read back as applied.
  • Flow edits return a bounded changes summary (which nodes moved and which paths within them, with long values previewed and secrets shown as markers) plus the resulting source identity. It is bounded in nodes, in changed paths per node, and in bytes; an entry past the byte budget is reported as its node id plus detail_omitted. The full graph is still returned when the response fits the bound and named for a follow-up inspect_source when it does not.
  • A guard naming a branch Draft or a release is refused with the owning path named: branch Drafts are edited in the editor and published with {"op": "publish", "branch_id": ...}, and releases are immutable.
  • A guarded graph write is one transaction over one workflow. Writes that also touch a Document, a capability binding or any other domain are separate commits with their own recovery, and are not advertised as one graph transaction.

Workflow tools · Node settings

Update one namespace of a task's metadata without overwriting anyone else's

Workflows can now change a single top-level metadata namespace on a task, guarded against the value they read. A concurrent write to a different namespace survives, and a stale expectation is refused instead of quietly winning.

  • Update Record accepts metadata_namespace: replace exactly one top-level namespace of a task's metadata and leave every other one alone. Reading the whole blob, merging your part and sending it back used to erase whatever another workflow committed in between.
  • The change is compared against the task as it stands at the moment of the write. Send the value you read as expected; if it has changed since, the update is refused and nothing is written — not the metadata, and not the other fields you sent with it. Re-read the namespace and try again.
  • Omit expected to require the namespace to be absent, which is how a workflow claims one for the first time. An explicit null is a different state from an absent namespace, and the two never match each other.
  • A task workflow's checkpoint accepts the same guarded change, so recording a result, handing the task on and saving the reference that goes with it are one commit. If the guard fails, the turn is refused whole: no version bump, no reassignment, no consumed input.
  • Task Agent Context now includes the task's metadata, so a role can read what it needs without a separate query step. Project the parts you actually use into a prompt rather than passing the whole map through.
  • Creating a record has no earlier value to compare against, so the guarded change is refused there and says so. Seed the namespace with ordinary metadata at creation, then guard it on later updates.

Task workflows

A failed coding step now shows the session it left behind

The run view lists the provider session, device, working directory, model, request, exit code and duration a failed Claude Code, Codex or shell command recorded, with the identifiers ready to copy.

  • A client command that timed out, was cancelled, failed on the provider, or returned output the declared fields rejected already recorded where its work went. The failed step now shows it, under Recovery details: the provider session, device, working directory, model, request ID, exit code and duration.
  • The session, device, working directory and request each carry a copy button, so an abandoned Claude Code or Codex conversation can be reattached by hand instead of being read out of a step's raw error.
  • The four client failures also read as themselves on the failed step, which now carries the failure's own label: Command timed out, Command cancelled, Command failed or Output rejected, rather than a generic error.
  • Facts the turn never produced are left out rather than shown blank or stale, so a command that collected no session says nothing about one. Failures with a different shape — a pod that ran out of memory, an exec error — are unchanged and show no recovery list.
  • Limits: this shows what was already recorded and adds nothing new. A command queued through Queue Until Available still collects no session when it times out, and the list is identity only — no output, cost or turn counts. Seeing a session here is not settlement: confirm the device before resuming or assigning another writer.

Client workflow nodes

Device settings now states how much work a device takes at once

The Device settings page inside the desktop app shows the 8-job local ceiling and the one-task-implementor fence, and says that a full device queues work rather than failing it. Both limits already applied; nothing about them was visible.

  • Device settings in the desktop app window has a new Concurrent jobs section. It shows the two limits a device already enforces: 8 jobs at once, shared by shell, Claude Code, Codex and browser commands, and one task implementor at a time.
  • It also states what happens when a device is full: the command returns to the queue and is delivered when a slot frees. It is not failed. The workflow step waiting on it keeps its own timeout, so a device that stays full long enough will still time that step out.
  • Nothing changed about how work is scheduled. These limits were already in force; the page was simply silent about them, which made a busy device look like a broken one.
  • Neither limit is configurable, and the section deliberately offers no control. There is no separate read-only allowance: a Claude Code session and a one-line shell command occupy identical slots.

Desktop app

A custom-field payload that cannot be stored is now refused instead of dropped

Workflow nodes and MCP tools used to silently discard a malformed custom_fields payload and write the record anyway. The write is now refused, and every surface answers the same way a direct one does.

  • Create Record, Update Record and the MCP task, project, document and objective tools no longer massage custom_fields on their way in. Whatever you send reaches the same validation the form uses, so one payload gets one answer whichever surface sends it.
  • A custom_fields that is not an object is now an error. A template that rendered to a string, or a list where an object was meant, used to be thrown away — the task or project was created without its custom fields and the run reported success. Now nothing is written and the step says why. If a workflow of yours has been quietly losing custom fields this way, it will start failing instead; fix the expression that builds the object.
  • A key the workspace has no field for is refused by name. Workflow steps and MCP tools now say which key they rejected instead of just "custom_fields is not a permitted custom field". A key that is not text at all is refused the same way rather than crashing the step. A crashed step used to be retried as if it were a temporary fault, burning the retry budget on a payload that could never succeed.
  • Sending null is unchanged on both Create Record and Update Record: it means "not supplied", the record is written without touching custom fields. Send an empty object to write custom fields with nothing in them.
  • Two spellings of the same key in one payload are refused rather than one of them winning at random.
  • Values are unchanged. Dates, select options, user references and structured fields are cast exactly as before.

Workflow nodes

A null sent between nodes now arrives instead of disappearing

When a node sends null on a connected output, the receiving node gets it. Until now that null was indistinguishable from sending nothing, so the receiving node quietly used its default instead.

  • A connected input can be in three states, and they are now distinct: not connected (the node uses its configured value), connected and sent a value including null (the node receives it and decides what it means), and connected but the upstream node never produced that output (the node's own default applies again).
  • Previously an upstream node that ran and sent null looked exactly like one that produced nothing, so the receiving node fell back to its default. A guard or option deliberately sent as null could vanish and let the rest of the step commit as though nothing had been asked for.
  • If a workflow of yours sends null to mean "use the default", change it to omit that output instead — build the object without the key rather than with a null value. Omitting is now the only way to say "I am not sending this".
  • Merging several branches into one input keeps a null contribution alongside the real values, whichever order the connections were made in. Ordinary list merging is unchanged.
  • Branches switched off by a gate are unchanged: an input fed only by skipped nodes still reads as empty rather than failing, and a live branch feeding the same input still wins.
  • Connections into a node's run-after / branch header are unchanged too. Those carry a signal rather than a value, so a null arriving there still means "this branch did not fire" and the node is skipped. Only ordinary data connections deliver a null to the node itself.
  • Leaving a field out of an object now really leaves it out. When a node takes one of its outputs from a field of another output — a Map or Transform result, most often — a field the pipeline never set (or unset) leaves that output unsent instead of sending null. Combined with the change above, that is what makes "do not send this" expressible at all: build the object without the key. A field explicitly set to null is still sent as null.

Expressions and data

A client command's own output is readable again

Codex shell output reaches the live run view as readable evidence instead of an escaped JSON line, a Claude turn keeps the transcript its answer came from, and a step whose data was too large to retain now says so.

  • A Codex shell command now streams the way a Claude tool call already did: one line naming the command, then what the command actually printed, kept verbatim with its blank lines and indentation. Until now the whole provider event arrived as a single escaped JSON blob and the run view trimmed it line by line, so a test run's own report was effectively unreadable.
  • The line that follows a command states its terminal status and exit code, and names each empty case separately: the command produced no output, the provider reported no output field, or the provider's capture appears truncated. Silence is no longer ambiguous.
  • A Claude Code or Codex step keeps the transcript its answer came from, in a new transcript output. The tool results a turn produced — the test runs, the builds, the greps — used to be gone from the record the moment the provider summarized them; for Codex they never reached it at all, since its answer is read from a capture file. result and stdout still hold the answer, unchanged, so nothing that reads them has to move.
  • Client command steps gained six outputs describing the bytes they returned: output_stream (which output was measured), output_produced_bytes, output_bytes, output_digest, output_complete and output_lossy. The device measures them over the bytes it captured, and the server re-verifies the digest against what arrived before recording it; a claim that does not verify is dropped whole rather than stored unverified. Absent fields mean the runtime captured no stream to measure — a browser command returns a serialized result, and an interrupted command reports identity only.
  • Output that is not text is never certified as complete. A command printing binary is carried as a lossy copy, and the result says so instead of digesting altered bytes as if they were the command's own.
  • A client step whose output is short of what the command produced says so on its step line — "output 128.0 KiB of 1.3 MiB" — rather than leaving a bounded transcript to read like a whole one. Every client node carries the notice, the shell node included. A complete or unmeasured output carries none.
  • A step whose inputs or outputs exceeded the 256 KiB record limit now reads Outputs incomplete, states how many bytes the step carried against how many survive in the record, names the limit that was crossed, and shows the retained head. Until now that record rendered as anonymous original_bytes / max_bytes / preview rows with nothing to say what had happened to the data. The notice is explicit that the bound is the record's own, and points at the step line for what the command itself returned.
  • A step record no longer loses everything to one oversized value. The 256 KiB limit now applies to each output on its own before the whole record, and values that are jointly over it are shortened largest-first, so a huge transcript gives way while the answer, exit code, session and byte counts stay readable.
  • The live output panel states its own bounds — the last 200 events, six hours, chunks over 256 KiB dropped — beside the events it kept, so a partial or emptied buffer is no longer read as the whole of what a command produced.

Client workflow nodes

Send a whole program to a client command through standard input

Run Command and Run Long Command take an optional Standard Input that is piped to the process and closed, so a script larger than one argument can travel beside its own literal arguments.

  • Run Command and Run Long Command have a new Standard Input setting and matching input. Its text is piped to the command and the pipe is then closed, so python3 -, bash -s, patch and cat see the whole value and a normal end of input.
  • This is the way to send content larger than a single argument can carry. One argument is capped at 128,000 bytes; standard input is capped at 1 MiB. Put the interpreter and its arguments in Literal Arguments (argv) and the program in Standard Input.
  • The typed value is program source, not a template. It is sent verbatim: not trimmed, never parsed by a shell, and never template-resolved, so a {{ name }} or {{ .Values.image }} inside a script stays exactly those characters. Command keeps resolving templates as it always has.
  • Wire the stdin input to supply dynamic bytes instead; a wired value wins over the typed source, and wiring an explicitly empty one gives the command a pipe that closes immediately — what a reader waiting on end of input needs.
  • Leaving both unset changes nothing. No pipe is opened and the command keeps the standard input it has always had.
  • A value the device would refuse is refused before the command is sent: anything that is not text, and anything over 1 MiB. The step fails naming the field and its size, and nothing is silently truncated.
  • A command that exits or stops reading before the input is delivered now fails the step with an explicit message. A half-written program is not reported as a clean run. A command that had already finished keeps its real exit code, stdout and stderr; one still running is ended immediately, so the step fails in seconds instead of waiting out its whole timeout.
  • The device's approval card shows the input under Exact action, with its byte size. When the command is python3 -, the program on the pipe is the action, and approving the invocation alone would approve nothing.
  • stdin stays operator-fixed in every tool grant until you expose it on purpose, and a widget grant cannot expose it at all.
  • Requires an updated Rollout Client. An older one ignores the field and runs the command with no input, so a program waiting on it waits out the timeout.

Client workflow nodes

A client command the device cannot accept now fails immediately

A command refused by a device's own payload limits returns a terminal rejection naming the refused field, instead of leaving the step to wait out its whole timeout.

  • A Rollout Client checks every command against its local limits — argument size, standard-input size, path lengths — before it starts a process. Until now a command that failed those checks was logged on the device and dropped, so the workflow step waited out its entire timeout for a process that had never started.
  • The device now answers. The step fails immediately with Command rejected (invalid_command_payload): … and the name of the field that was refused. The refused content itself is never sent back.
  • The answer only happens on the connection that owns the request: the device must have finished authenticating, and the command must carry a well-formed request id. The workspace comes from that authenticated connection, never from the refused command. Anything else is still logged and ignored.
  • A command the device cannot read at all is answered the same way, as long as it named the request — a step should not wait out its timeout because a field arrived with the wrong type.
  • The rejection travels the same durable path as any other result, so it survives a reconnect and is not duplicated on redelivery. A request that has already finished keeps its own result; a late unreadable redelivery cannot overwrite it.
  • Requires an updated Rollout Client. An older one still drops the command silently.

Client workflow nodes

A task checkpoint says when it lost the guard, not just that it failed

When a guarded metadata change loses a race, the checkpoint now fails with its own error code. A workflow can recognise that one case and save the work it already has, instead of treating every refusal alike.

  • A task workflow's checkpoint that carries a guarded metadata_namespace change now fails with the distinct code task_agent_checkpoint_metadata_conflict when the namespace moved since it was read. Every other refusal keeps the existing task_agent_checkpoint code.
  • The error names the namespace that moved. It never repeats the stored or expected value, so run errors stay free of workspace data.
  • Nothing about the refusal changed: the turn still rolls back whole. No version bump, no state, no consumed input, no wake-up, no status change and no reassignment.
  • That is what makes the code useful. Because the claimed version is still current, an error branch can save the work the turn already produced as a plain blocked checkpoint at that same version, with no metadata change, no reassignment and no task status change, keeping a provider session and its counters instead of losing them. It is an ordinary checkpoint and is checked like one.
  • It does not settle the conflict. Whoever wrote the namespace in between owns it now, so its value has to be reconciled before another task write is proposed. Copying the committed value into expected and repeating the same handoff automatically is the one thing to avoid.
  • The other refusals stay one code on purpose. A stale fence, lost execution authority, a protected namespace and a malformed intent are not retryable, and a branch that told them apart would only be a blanket retry.

Task workflows

Check a recovery proposal before applying it

Review recovery can now resolve a named recovery run and show what applying it would do, including which checkpoint fields the replacement would drop, before anything is applied.

  • Check this run in Review recovery resolves the recovery run you named and reports what it would do. Nothing is applied, resumed or saved by checking it.
  • The check shows the workflow and release that produced the proposal, when that run finished, the summary it declared, a digest of its contents, and the checkpoint version it was computed for.
  • Applying a proposal replaces the saved checkpoint wholesale, so the check lists the checkpoint fields it would drop, change, add and keep. Field names and counts only; saved values stay out of the browser.
  • A run that cannot be applied cannot be checked either, and for the same reason. The check is the refusal you would get from applying it.
  • The check is advisory. The saved checkpoint can still move before you apply, and applying refuses when it has.
  • A proposal has to come from a published release of a workflow you can still open, and the receipt records that workflow and release alongside the run.
  • Naming a different run clears the check, so the panel always describes the run that would be applied.
  • Applying the same run again after a lost response reports the result already recorded instead of refusing, and never applies it twice.

Task workflows

Waiting work no longer borrows the word Queued

A task execution that has not started yet reads Not started, the Code node's per-node cap is now called Parallel executions, and a run's status is named the same way in the sidebar as everywhere else.

  • On a task, the Agent work panel showed Queued for an execution that had not been picked up yet, next to a workflow run that could also read Queued for an unrelated reason. The execution now reads Not started. Nothing about dispatch changed; the two states are simply no longer spelled the same.
  • The Code node setting Max Concurrent Runs is now Parallel executions. It never capped workflow runs: it caps how many executions of that one node may run at the same time in the workflow. The saved value, its range (1–10) and the enforcement are unchanged.
  • The run list in the workflow editor sidebar named run statuses from its own copy of the mapping, which had drifted. A suspended run badged Suspended there while the run view and the status filter both called it Awaiting input, so filtering by a name showed rows labelled something else. The sidebar now takes both the name and the badge tone from the same place as the run view, and a suspended run is toned as waiting rather than as nothing in particular.
  • Queued is now reserved for a workflow run held back by a capacity limit. Nothing produces that status yet: an over-cap run is refused rather than queued today, so the word appears only as a filter option. Reserving it now keeps the next release from having to rename something.

Code node settings

Trace a cancelled verification query to its connection

A verification check can capture the connection's own shutdown reason, its timings and the statement that was running, and a bulk-insert fixture no longer leaves the planner guessing.

PostgreSQL reports every cancelled statement with the same wording, and the database driver sends a cancel for any lost connection, so a verification run that lost one had nothing to distinguish an overrun checkout from an owner that went away. A check can now be wrapped so that, when it fails, it prints the connection's own shutdown reason, the backend serving the call, per-query timings, and the statement that was running with the parameters it was issued with. That statement can then be planned again exactly as it ran.

This is per-check instrumentation, not a change to how verification runs: a check nobody wrapped still fails with the bare cancellation. The run that prompted this has not happened again, so what cancelled it is still unknown.

The capability-picker check that prompted it was also slow for a reason worth fixing: its fixture writes several hundred rows that the query planner has no statistics for, which turned a bounded page into six seconds of nested-loop work and left a wide window for the cancellation to land in. Analysing those tables costs under ten milliseconds and returns the check to the plan a real database would choose, and the statistics are taken back down afterwards so no later check plans against them. The row budget, tenant filtering and paging the check asserts are unchanged.

A busy device waits for a slot instead of failing the step

A client command that arrives when the device is already running its maximum number of local tasks is now deferred and re-sent, rather than failed as a rejected command.

  • A Rollout Client runs at most 8 local commands at once. Until now, the ninth was answered as a rejected command, so a step failed on a machine that was simply full — indistinguishable from a real provider failure, and it spent a retry on the way.
  • A full device now reports a deferral. The command is not settled: it waits, it is re-sent every few seconds, and it starts as soon as a slot frees up. The wait never consumes a failure retry.
  • This applies to both If No Device Available settings, and to every client node including Browser Automation. A busy device is not an unavailable one, so choosing Fail does not turn a full machine into an immediate failure any more.
  • The wait comes out of the command's own Timeout. The moment a device defers it, the clock then running becomes a ceiling: waiting for a slot, sitting on the device's approval prompt and the run that eventually starts all end there. Set Timeout to cover the work and the wait you are willing to spend on a busy machine.
  • Approving a deferred command approves it once. The device keeps your decision across re-sends instead of prompting again every few seconds, and drops it when the connection ends or the app restarts.
  • With Queue Until Available, the command goes back to the workspace queue while it waits and the next attempt prefers a device that has not just deferred it, so it moves to an idle machine rather than queueing behind a full one. A Fail dispatch has no queue to return to and keeps waiting on the device it picked, as does a Specific device target.
  • If the timeout does expire while waiting, the step says the device deferred the command for local capacity and it never started. There is no exit code and no session to reconcile.
  • Requires an updated Rollout Client. An older one still reports a busy device as a rejected command and the step fails as it does today.

Client workflow nodes

List and cut workflow branches outside the editor

Agents and integrations can now see a workflow's authoring branches and cut a new one from an exact source, instead of needing the browser for the one step in the middle.

  • workflow_operations gained list_branches: every live branch of a workflow as identity only — id, name, revision, whether it has unpublished Draft work — plus the main Draft's revision. Read access is enough.
  • Exact-source inspection and selected-node tests already accepted a branch id, but nothing outside the editor could produce one for a branch that had never published. Now they can.
  • create_branch cuts a branch from a source you name: a release (by id, v3, or current), another branch's Draft, or the main Draft. A release is re-resolved on the server, so the branch starts from that release exactly as published.
  • The answer names the source the branch was actually cut from, resolved: ask for current and you get back that release's id, because Current moves on the next publish and the word alone cannot say which release you branched from a week later.
  • Branching from a Draft you just read? Pass its revision and a Draft that moved in between is refused instead of quietly seeding a graph you never looked at.
  • Cutting a branch moves nothing else: no existing Draft, no other branch, and no published release. It switches nothing and runs nothing, and it needs write access.

MCP tools

Agent work names the session a turn recorded

Where a turn recorded them, a task's Agent work panel shows the provider session, worktree, model and bound device, so what a resume carries forward is visible before you press it.

  • Where the agent recorded them, the Agent work panel on a task now lists the provider session, worktree and model, plus the device its task route is bound to. The session and worktree are copyable, so an abandoned Claude Code or Codex conversation can be reattached by hand.
  • Review recovery says what Resume preserves in the same place as the button: the checkpoint, the recorded session and worktree, and the pending task comments. Whether the next provider turn continues that session or starts a fresh one is the workflow's decision, not the panel's.
  • A turn that recorded no session says nothing about one rather than showing the previous turn's. A checkpoint replaces the saved state, so a turn that does not carry the association forward genuinely no longer has it.
  • Nothing else about the checkpoint is shown, and none of it is visible to someone who can read the task but not the workflow behind it.
  • For workflow authors: record the association under provider_session in the checkpoint state (session_id, working_directory and model). Anything else under that key is ignored. It is read, never validated or enforced.
  • Limits: the panel reports what a workflow chose to record, and no shipped workflow records this key yet. Until your workflow content echoes it forward, the panel stays quiet about the session and shows only the bound device.

Task workflows

A timed-out coding command now reports where its work went

When a Claude Code or Codex command on a connected device runs past its timeout, the server cancels it, waits up to 35 seconds for the device's answer, and records the session, model, device and request in the step error.

  • A Claude Code or Codex command running on a connected device (If No Device Available → Fail Immediately) that exceeds its Timeout is sent a single cancellation, and the server then holds that exact device and request open for up to 35 seconds to collect the device's answer.
  • What the device reports in that window lands in the step error: the observed session and model, the device, the working directory, the request ID, and any exit code and duration. Output, transcripts, cost and turn counts are still excluded, and values that are missing, mistyped or oversized are omitted.
  • The step still fails with its timeout. A late “completed” answer does not turn it into a success, and the node's own result handling never runs on it. If nothing arrives, the error carries the request, device and working directory for manual reconciliation; no session, model or exit is invented.
  • The 35 seconds are a ceiling, not a delay: the answer ends the wait, and so do cancelling the run, losing the device and stopping the step. Unrelated device traffic cannot extend it. Stopping the step also lets the existing safety cleanup send its own cancellation, so the device can see a second cancel for that request.
  • Only a command whose start is known is waited for: one that needed no approval, or one the device reported as executing. A command still sitting on an approval prompt is not, and an executing report never restarts the command's own clock.
  • Limits: this is not settlement, and it does not authorise another writer to start — confirm the device before resuming. Commands queued through Queue Until Available are unchanged. Nothing is collected after a server restart, for a run that has already ended, or after those 35 seconds; the device still keeps the receipt, but no step is listening. Not yet proven end to end on an installed device inside a live workflow.

Client workflow nodes

Keep task handoffs queued until the previous work settles

Reassigning a task to another device now respects unfinished child runs and uncertain client commands.

Task handoffs wait for unfinished work on the same task even when the next agent uses another device. Settlement includes Subflow and Loop children.

A server timeout or cancellation no longer counts as confirmation that the client stopped. Uncertain direct commands also retain the claim. After the visible settling wait, the owner can inspect the device and use Task recovery to confirm settlement for that exact turn. Later turns need their own evidence.

Task workflows

An interrupted coding command still tells you which session it ran

A Claude Code or Codex command that times out, is cancelled or is interrupted now reports the session and model the provider announced, so the conversation the work went into can be found and reconciled.

  • A timed-out or cancelled Claude Code or Codex command used to report nothing but the failure, losing the session the work had already gone into. It now reports the session and model the provider announced before the interruption.
  • Only the provider's own announcements count: Claude's session envelope and reported model usage, Codex's thread start, and the model named in Codex's recognizable startup banner. Text the model or a tool wrote is never read as identity, and the session or model you configured is never echoed back as if the device had observed it.
  • An explicitly unusable, oversized, conflicting, or mismatched session claim removes the recovery session from the receipt. Events without an identity claim preserve earlier observations. A Codex command without a recognizable startup banner reports no model.
  • The receipt is identity, not a result: no output, no cost, no turn count and no success. A cancelled command now reports no exit code instead of the placeholder -1 it used to invent.
  • Limits: this is not settlement and does not authorise another writer to start. The device stores the receipt durably and resends it after reconnect. Server-side collection now exists for exactly one case: a Claude Code or Codex command running on a connected device that hits its own timeout, where the server cancels the device and waits up to 35 seconds for the receipt. A queued command, a run that has already ended, a server restart, and anything arriving later than those 35 seconds still collect nothing. End-to-end proof on an installed client is still open.

Client workflow nodes

Rejected client output keeps recovery details

When a Claude Code or Codex command returns output your declared fields reject, the node now fails with the same session, device, working directory, exit code and duration a failed command reports.

  • Invalid JSON, missing required fields and wrong types under Outputs → Model produces now preserve recovery details alongside the validation error: the observed session, device, working directory, exit code and duration. Missing or malformed values are omitted.
  • Rejected output remains rejected. Its text and generated report are excluded from the error details, and model-written values cannot replace the observed session identity.
  • Reconcile the prior command before resuming. Recovery metadata does not establish that it is safe to launch another turn.

Client workflow nodes

Claude Code continues the exact session you asked for

Claude Code continuation requires the provider's session UUID and an absolute existing working directory, the finished turn must return that same session, and a turn that reached the provider keeps its own outcome.

  • Claude Code continuation now matches Codex Exec. The session_id input must be the provider's own session UUID and Working Directory must be an absolute path that exists on the device; anything else is refused before the CLI starts, rather than running as some other turn.
  • The continued turn must report the same session back. If it returns a different session ID, or none, the node fails and keeps the real exit code, the returned session, cost, turn count and result text for reconciliation.
  • A Claude Code or Codex turn that reached the provider keeps its own outcome. A provider error, a nonzero exit code, or output from a command the agent ran no longer overwrites that outcome with a "CLI not installed" message; the install message now appears only when the CLI is actually missing from the device. Stderr noise on its own does not fail a successful turn.
  • Fresh turns are unchanged and still run without a session ID or a working directory.
  • Requires an updated Rollout Client. Check the session ID a recovered phase returns before treating its work as the continuation you asked for.

Client workflow nodes

Update existing nodes in place during version zero

Pre-release node contracts can evolve without creating duplicate versioned nodes.

During version 0, existing nodes keep their definition IDs when their contracts or behavior changes. A changed contract requires updating the catalog lock and affected workflows and capability bindings. Creating duplicate versioned nodes is unnecessary. The temporary Claude-specific exception has been removed in favor of this application-wide policy.

Catalog and lock validation, persisted identities, ownership and runtime permission checks remain enforced. Published tool-contract retention begins at application version 1.0.

Claude Code is one node again

The separate rollout.client.claude_code_v2 definition is withdrawn; Claude Fable 5.1, the family aliases and the custom model ID now belong to rollout.client.claude_code, which is offered in the palette again.

  • There is one Claude Code node, rollout.client.claude_code. It is offered in the palette again and carries the full model list: the runtime default, Claude Fable 5.1 (claude-fable-5-1), the fable, opus, sonnet and haiku aliases, and Custom model ID.
  • Yesterday's note asked you to replace an existing Claude Code node to reach the new models. That is no longer necessary. Existing nodes gained the wider model list in place, keep the alias they saved, and resolve it exactly as before: a node saved with opus still dispatches --model opus.
  • The short-lived rollout.client.claude_code_v2 definition is removed. It was never used by a workflow run.
  • Nothing else changes: session continuity, tool allow/deny lists, device authorization, timeouts and the no-fallback default are untouched.

Client workflow nodes

A read-only permission mode for Claude Code

The Claude Code node can ask the device to run a session with only the built-in read tools, plan mode, no MCP servers and no project hooks. It is a restriction the agent runs under, not a sandbox around it.

  • Claude Code has a new Permission Mode option under Options. It stays on Default, so every existing node keeps behaving exactly as it does today. Choose Read-only for research, review and analysis phases.
  • On Read-only the device builds the restriction itself, from its own fixed list: the session gets the built-in Read, Glob and Grep tools and nothing else, Write, Edit, NotebookEdit, Bash, PowerShell and every MCP tool are denied, no MCP server or Chrome integration starts, hooks from the project's and your own settings files are turned off for that run, and the CLI starts in plan mode. Nothing in the node's own configuration can widen that list.
  • If the node's Allowed Tools names anything outside Read, Glob and Grep, the command is refused rather than quietly narrowed, so the run you get is the run you described.
  • What this does not give you: it is not a sandbox. The boundary is enforced by the Claude Code process, not by the operating system, so it does not survive a machine whose managed policy settings install hooks, which run commands with no tool call and cannot be turned off from outside. Nothing measures whether the restriction actually took effect on the device. Read-only also does not confine reads to the working directory.
  • Because of that, a Read-only Claude Code command is still budgeted as a writing command. Only Codex's --sandbox read-only, which the operating system enforces and the device verifies with a probe before running, earns the cheaper read-only budget.
  • Requires an updated Rollout Client. An older device ignores the setting and runs the session unrestricted.

Client workflow nodes

Branch from a release, name the Draft you replace, and read a run's exact source

Cut a new branch straight from a displayed release, see which Draft a Copy to Draft will overwrite before you confirm it, and read on every run whether it came from a release, the main Draft or a branch Draft, and whether it tested one node, a subgraph or the whole workflow.

  • New branch from a release. While viewing a release, the workflow picker offers a branch cut from that release. The release is resolved by id on the server, so what lands in the branch is the release exactly as published. The main Draft, the branch Drafts and the published pin are untouched.
  • Copy to Draft names its destination. The picker entry, the confirmation and the resulting message all say which Draft is being replaced, main or a named branch. The write is unchanged; what changed is that you can see what it will overwrite before you confirm.
  • Runs say where they came from. A run now carries its exact source: the release name, Main Draft, or Branch "<name>" Draft. Editor-sourced runs used to read as an anonymous "Test run" whether they came from main or from a branch.
  • Runs say what they are evidence of. Every run states whether it executed a selected node, a subgraph replay or the full workflow. A complete run is labelled as one instead of being the case with no badge.

Debug workflow runs · Node settings

Inspect and test exact workflow sources from the node settings

Select a release, a branch, or the Draft, inspect a node exactly as stored with complete long fields, and test that node or its reachable subgraph on that exact source with an explicit preview and Start. The same is available to semantic-tool callers through workflow_operations.

  • Inspect source in the node settings shows the selected node as stored in the displayed release, branch, or Draft, compared with the Current release and the main Draft. Long fields load in bounded ranges on demand; secret fields, secret references, credential sidecars and environment values stay hidden. Read access is enough.
  • Test selected node and Test reachable subgraph preview the exact source, scope, inputs, missing accounts and side effects before an explicit Start test. The run is admitted only if the source, projection, environment, credential contract and inputs still match the preview; the editor stays on the same source and paused workflows stay paused.
  • A Start test pressed just before an editor connection loss leaves an account-scoped reminder in this browser (up to 8 per workflow); the next time you prepare a test it is listed as an attempt with an unknown outcome. Nothing is retried automatically; check the Runs history.
  • workflow_operations gains inspect_source (read), preview_node_test and test_node (write) with the same bounds and refusals.
  • Fixed: clicking a node on a displayed release (or any read-only canvas) now opens its settings; previously the selection was dropped and undone.
  • Fixed: Choose Inputs submits the JSON as typed; previously the typed text could be ignored and an empty object used.

Node settings · Debug workflow runs

Hand a task to the next agent as part of finishing a turn

A task workflow can now record its result and reassign the task in one step, so a handoff never half-happens. Owner input that no turn has read follows the task to whoever holds it next.

  • A task workflow's checkpoint accepts Hand off to. The turn's result and the reassignment commit together: you never see a finished turn still assigned to the previous agent, or a reassigned task whose turn was lost.
  • Handing off does not close the task. A role finishing its responsibility is not the delivery finishing. A handoff can return it to an open status such as To Do together with the next assignee; completed and cancelled statuses are refused.
  • A comment you sent while one agent held the task now follows the task to the next agent if no turn read it. Input a turn already consumed stays with that turn's evidence.
  • Closing a task while your input is still queued holds that input instead of discarding it. Reopen or reassign the task to continue.
  • Work waits for the device to confirm the previous command actually stopped, not just for the workflow run to end, and says so while it waits.

Task workflows

Table row delete confirmation names the row

The row actions menu now asks "Delete “Launch”?" instead of "Delete this item?".

The inline delete confirmation in a table's row menu now names the row it will delete, using the same identity the menu's accessible name already shows — the row's title, name, number or ID. Long names wrap and stay inside the menu. The two-step Delete → Cancel/Confirm interaction is unchanged.

Parallel nodes replaces Max concurrency

The workflow execution setting that limits how many nodes run at once is now called Parallel nodes, and its help text states the real behavior. Leaving it blank has always used a default of 10, never unlimited.

  • Max concurrency in a workflow's Execution settings is now Parallel nodes. The setting, its saved value and the runtime behavior are unchanged; only the name and the help text moved.
  • The help text said blank meant unlimited. It never did. A blank value uses the default of 10 nodes at a time, which is what the executor has always applied. The placeholder now shows 10 for the same reason.
  • Semantic-tool callers see the same correction: the defaults.max_concurrency description in create_workflow and update_workflow now says an unset value means 10.
  • If you left the field blank expecting no limit, your runs were already capped at 10 parallel nodes. Set an explicit number if you want a different cap.

Workflow execution

End an agent execution that has nothing left to resume

Task recovery now offers End execution beside Resume agent work. It releases the device an exhausted attempt still holds, keeps the checkpoint, provider session and pending comments, and leaves the task's own status alone.

  • End execution appears in Review recovery on a blocked execution whose latest run has ended. Use it when the attempt is exhausted, or when its routing has been withdrawn and there is nothing left to resume.
  • It requires the same evidence as resuming: describe what you checked and confirm the previous command has stopped and its external effects are accounted for.
  • The saved checkpoint, provider session, counters, pinned release and pending task comments are preserved. The device claim is released so queued work can start.
  • Ending an execution records that one attempt stopped. It does not mark the task complete and does not change the task's status.

Task workflows

Clearing an optional node setting now sticks

Clearing an optional workflow node setting removed it from the editor but left the old value in the saved draft, so it came back on reload. The cleared key is now removed where the draft is written.

  • Clearing an optional node setting from a picker that offers a clear action (a workflow target, a connection, a secret, a device), or blanking an inherited image or working directory, removes the value from the saved Draft. Previously the editor showed the field cleared while the Draft kept the old value, which reappeared on the next reload.
  • Blanking a free-text setting does not clear it. A Subflow or Loop "Release (vN)" or "Release ID" saves the empty value and keeps the key, and blanking the only Release a node is pinned to is refused outright. To unpin a node, set its Release Source back to Current.
  • Only the key you cleared is removed. Sibling settings, including ones changed at the same time, are preserved.
  • Applying a Template clears a setting only where the Template itself carries an explicitly cleared value. Settings the Template does not mention keep whatever the node already had.
  • This can change how an existing workflow runs if a setting has been showing as blank while a stale value was still saved — check the node before your next publish.

Node settings

Claude Code nodes can select Fable 5.1 or any supported model ID

Claude Code adds Claude Fable 5.1, the fable alias and a validated custom model ID to its Model setting.

  • Select Claude Fable 5.1 (claude-fable-5-1) or the fable alias in a Claude Code node's Model setting, next to the default, Opus, Sonnet and Haiku choices.
  • Choose Custom model ID to pass any model name or alias the installed Claude Code CLI accepts. The ID is checked when the workflow is saved and again before dispatch; a Custom selection without an ID does not run.
  • Existing Claude Code nodes keep the alias they saved, session continuity, tool allow/deny lists, device authorization, timeouts and the no-fallback default. Nothing is rewritten or retargeted.

This note originally announced the wider model list as a second definition, rollout.client.claude_code_v2, and said existing nodes had to be replaced to reach it. That split was withdrawn on 2026-09-10, and existing nodes gained the wider model list in place. See "Claude Code is one node again".

Client workflow nodes

Apply a verified replacement checkpoint from Task recovery

When a recovery workflow has produced a verified replacement checkpoint, Review recovery can now adopt it by naming that run. The checkpoint is read from the run itself, and the receipt records which run was applied.

  • Apply recovery proposal joins Resume agent work and End execution in Review recovery. Use it when a separate recovery workflow you ran has produced a checkpoint that should replace the saved one, instead of reaching for an out-of-app reconciliation.
  • Name the completed run that produced the replacement. The checkpoint is read from that run's own recorded result, never from the browser, so what lands on the execution is exactly what the workflow returned.
  • The same evidence as resuming is required: describe what you checked and confirm the previous command has stopped and its external effects are accounted for.
  • A run refuses unless you started it, it finished, it belongs to this execution, and it was produced for the checkpoint that is saved right now. If the checkpoint has moved since, run the recovery workflow again.
  • The pinned release, pending task comments and the task's own status are kept. The receipt records the run applied, a digest of what it contained and the version it was applied for.
  • Applying a proposal resumes the work. It does not record that any of the workflow's own checks passed; the resumed run still has to run them.

Task workflows

Read an agent's role recipe from its Task workflow setup

Agent settings now shows what the selected workflow's Current release runs from the chosen Start node — each step's instructions, runtime and device, saved settings and where it goes next — without opening the graph.

  • The route, in order. Under Setup checks, a Role recipe lists the steps the Current release runs from the selected Start node, numbered in execution order, each one saying what it goes to next and on which output.
  • The settings each step saves. Instructions and scripts, the runtime target and device, the node's own settings and any execution behavior it overrides are read straight from the node manifests in that release. A workflow of your own projects the same way; nothing is special-cased by node id or role name.
  • Nothing it cannot resolve is guessed at. A nested workflow is listed and named as unresolved rather than opened, an unavailable node type says so, secret fields are never shown, and long routes are summarized to their first steps.
  • Reads Current, changes nothing. The recipe follows the same immutable Current release the setup checks already read, refreshes with Refresh checks, and the workflow editor stays the place to change any of it.

Task workflows for agents

Navigate and tune workflows more easily

Ref switching frames the selected graph, and group actions stay accessible above crossing wires.

Switching to a different workflow branch or release now fits its nodes in the canvas, so a smaller graph no longer appears blank after viewing a larger one. Editing settings, arranging nodes, and selecting the same branch keep your current view.

Select an expanded group to use Collapse and Tidy in the toolbar. These controls stay readable when zoomed out and clickable when wires cross the group header. Expand focuses the group above neighboring compact cards. After opening a member’s settings, the containing group’s Collapse group control stays available; collapsing returns selection to the group.

Task recovery also shows the retained workflow release explicitly, such as “Keep v3”.

Workflow editor

Keep group controls in view after fitting

Fit View leaves room for the floating toolbar above tall workflow groups.

After expanding a tall group, Fit view now leaves room above the graph for the floating toolbar. You can open a member’s settings and click Collapse group without the control slipping beneath the page header.

The same clearance applies when opening a workflow or switching branches and releases. Saved node positions stay unchanged.

Workflow editor

Report the execution workspace in workflow actor details

Manual Start actor details use the run's workspace when you switch workspaces.

When you run a workflow outside your default workspace, Manual Start now reports the execution workspace in triggered_by.tenant_id and, when enabled, context.user.tenant_id. Your actor ID and email stay the same.

Workflow permissions and runs without a triggering user keep their existing behavior.

Workflow triggers

More reliable release verification

Release verification uses completed sidebar hydration, distinct fixture keys, and a more efficient tenant-isolation scan.

Release tests now capture sidebar queries through the completed run handoff. Hierarchy test fixtures use distinct valid project keys to avoid repeated collision checks during setup. Existing authorization assertions, query budgets, and verification deadlines remain in place.

Tenant-isolation architecture checks now collect piped calls and public APIs in one source-tree traversal, preserving the complete repository scan.

Keep concurrent release tests from sharing an HTTP port

CI test servers use separate ports when workflow runs share a runner.

Concurrent CI runs now receive separate HTTP ports, avoiding startup failures when two runs use the same test partition on one host. Browser tests follow the port assigned to their server. Local test ports keep their existing values.

Configure and inspect task agent workflows

Published entry choices, device checks and Task-local execution recovery make agent workflows easier to adjust.

  • Choose a published Start node when configuring an agent's Project workflow. Inspect its release, device connection and required capabilities; unavailable saved selections stay visible for correction.
  • Open Agent work in Task details to see the workflow summary, pinned release, latest run and pending input. Refresh the display without leaving the Task.
  • Recover settled blocked work with an accountable-owner evidence check. Resuming preserves the saved checkpoint and pending comments; moving to a newer published release is an explicit choice.
  • Keep execution details behind the original workflow's permissions, including after the agent's Project route changes.

Task workflows

Keep typing while Task changes save

Status, priority and assignee saves preserve unsent Task comments and replies.

Changing a Task's status, priority or assignee keeps the comment or reply you are writing, including text entered before the save finishes. The activity feed still refreshes to show the change. Posting clears the submitted draft after it succeeds.

Task comments

Keep child workflows available across Task continuations

Completed Task turns no longer consume the nesting budget for child workflows.

Task workflows can continue through checkpoints and recovery without counting earlier turns as nested child workflows. Run history stays connected. Subflow and Loop keep their existing nesting limit and cycle protection, and actions still require current Task permissions.

Task workflows

Keep comment drafts while editing a Task

Task text autosaves and incoming activity preserve an unsent comment.

You can edit a Task's title or description without losing the comment you are writing. Incoming activity also keeps the draft in place. Posting successfully clears the submitted editor; a rejected post leaves the text available.

Reply mode now offers Cancel reply when its target is no longer displayed. Drafts remain in the current browser editor and are not saved across page reloads or navigation.

Task comments

Keep the assignee selected when creating a Task

New Tasks retain the person or agent selected in the creation dialog.

Choosing a person or agent in Create task now survives description edits and saves with the Task. This also applies when adding a sub-task.

Creating Tasks

Keep defaults when creating several Tasks

Successive Task forms retain their default type, status and project team.

Create several Tasks or subtasks from the same page without reloading. Each new form selects its default type and status and loads the project's planning team. Catalog refreshes continue to preserve the draft you are editing.

Creating Tasks

Keep typing after choosing a value

A closing picker keeps focus in the field you started editing.

After choosing an assignee or another picker value, start typing in the next field without the closing picker pulling focus back to its button. Keyboard dismissal still returns focus to the trigger when focus needs to be restored.

Avoid an unnecessary check while starting Task workflows

Manual Start passes admitted input forward without repeating permission checks reserved for actions.

Manual Start now passes admitted input and run details forward without repeating the Task permission check used before actions. This reduces work inside Start's short execution budget, including in child workflows. Actions still check current permissions before they run, and cancellation keeps its existing behavior.

Workflow triggers

Keep release build cleanup independent of application loading

Clean rebuilds remove integration artifacts even when application modules are unavailable.

Retrying a release build no longer fails during integration cleanup when the application catalog module is unavailable. The compiler removes its generated index, shards and manifest without touching source files. Normal compilation and release checks still run afterward.

Exact task lookup in workflows

Query Data can find a task by its UUID while respecting its access permissions.

Use id:<task-uuid> with the Task source to retrieve an exact task. Include its project and select id and code to pass a compact ticket identity to later workflow steps. UUID lists and exclusions are supported; malformed IDs cannot turn these filters into a broad task query.

Empty editable date, text, and number cells show a placeholder dash

An unset date, text, or number field in a custom-entity table now renders "—" instead of the column name.

An editable date, text, or number cell with no value renders the same "—" placeholder every read-only cell uses. Previously it could show the column's name (for example "Balance As Of") as if that were the stored value. The column name still appears as the control's accessible name and hover prompt.

Isolated cluster verification

Cluster tests keep working when another CI job on the same host finishes.

Distributed release checks now own their node-discovery state. Cleanup from a neighboring CI job cannot remove a shared registry while another check is starting a node. Tests continue to use real network connections, bounded peer resources and the existing verification deadlines.

Keep workflow output in order after reloading

Buffered workflow output now preserves the newest window when chunks span multiple seconds or servers.

  • Restore workflow output in the same order as live updates when reopening a run, including output buffered on different servers.
  • Keep the newest output when the view reaches its event or byte limit.

Workflow runs

Read nested error details in recovery branches

Recovery expressions can read nested failure details during execution.

Recovery branches now receive consistently named nested error fields. This keeps details such as a provider session ID available to subsequent steps when a command stops before completing its output.

Node execution settings

Assign existing Tasks to agents from details and lists

Task details and bulk assignment include eligible agents, and selected names remain visible after reopening.

  • Find and select eligible agents in an existing Task's Assignee picker, using the same Project and visibility checks as the Task form.
  • Keep agent names when reopening a Task, including read-only views. Private profiles stay hidden and internal agent addresses are never shown as labels.
  • Assign selected Tasks to an agent from the list. Each Task keeps its own Project access checks, with denied assignments reported individually.

Task workflows

Task assignments connect to published agent workflows

Named agents gain Project-specific Task workflows, continuous Task-thread input, stable child plans and versioned Document reads.

  • Configure a Project's Task assignments from an agent's Task workflows settings, selecting an existing published workflow and optional execution device.
  • Keep authorized human comments and agent replies in the same Task thread. Continuing work retains its published workflow release and checks current assignment and permissions.
  • Create child Tasks and dependencies atomically with Decompose Task; repeating the same accepted plan returns the same children.
  • Reuse instructions from workspace Documents with Read Document, including an optional immutable version, complete content and revision evidence.
  • Author development recipes in workspace Workflows, Documents and Templates. The former built-in development recipes leave the global catalog; existing tenant-owned copies remain available.
  • Preserve exclusive device ownership after an uncertain failed run until its owner reconciles the effects. Work waiting for dependencies releases the device only after its prior run has ended.
  • Save and publish workflows with error branches for explicit failure recovery.

Task workflows · Documents

Search dropdowns independently

Searching an assignee, project or milestone no longer loses the query to another dropdown in the same form.

Search each dropdown independently when editing a Task or another form with multiple pickers. Typing a search does not save the surrounding form. Your current selection stays visible while matching options are filtered using the existing access checks.

The query also survives result updates after blur. Dropdowns that stay mounted recover their search when the connection returns; remounted controls start fresh.

Open selection action pickers reliably

Actions such as Assign to now show their choices immediately, and Back returns to the previous screen.

After selecting Tasks, choose Assign to… in the Actions palette to see available assignees. Opening the picker does not change the selected Tasks. Escape or the breadcrumb returns to the previous palette screen without choosing an option.

Run bounded long commands on your device

A separate Run Long Command node supports foreground commands up to 90 minutes with explicit device permission.

Use Run Long Command for a foreground build, test suite or other local command that needs more than ten minutes. It supports a finite limit up to 90 minutes and keeps the existing command output, approval and cancellation controls.

Install the updated desktop app and enable Long shell commands separately. Existing shell permission does not enable the new capability. Workflow and server timeout settings must also cover the requested duration. See the client workflow guide for setup and recovery.

Coding phases keep session context and validate review results

Client workflows gain explicit Codex continuation, fresh structured review, and clearer bounded execution and recovery behavior.

  • Continue related Claude Code or Codex work with an explicit session ID in the assigned worktree, using the provider CLI installed and signed in on the device.
  • Start independent Codex reviews with fresh read-only context. Failed turns, nonzero exits, and malformed structured output cannot become clean reviews.
  • Keep the five-minute command default and ten-minute phase cap. Continue longer work through explicit sessions. Cancellation and disconnect require checking prior effects before retrying.
  • Keep execution concurrency leases valid when the database session uses a timezone other than UTC.

Production validation of the complete autonomous SDLC pilot is pending.

Client workflow nodes · Desktop app

Claude phase failures retain recovery context

Turn-limit failures keep their provider reason and session identity, while blanket MCP denials prevent inherited server startup.

  • See Claude's specific terminal failure reason, including a reached turn limit, while retaining the actual process exit code.
  • Recover a failed client phase from captured session, device, and working directory details without treating an incomplete report as successful.
  • Denying every MCP tool with mcp__* now prevents inherited Claude MCP servers and Chrome integration from starting for that command. Subscription login and saved sessions keep their existing behavior.

Client workflow nodes

Dashboards became programmable Pages

The dashboard and Page authoring boundaries now share one widget model for people, LiveView surfaces, and MCP clients.

  • Chart, stat, table, feed, and rich-text widgets use the same Page composition.
  • MCP clients can validate, create, and edit dashboards with revision-aware operations.
  • Saved Views remain reusable query inputs rather than a second dashboard format.

Dashboard docs · Pages and publishing

Workflow credentials got a fail-closed boundary

Secrets, runtime injection, run output, and operator evidence now meet at one explicit security boundary.

  • Named secrets are write-only and use envelope encryption at rest.
  • Engine-injected values and their Base64 forms are redacted before persistence or broadcast.
  • If the run-secret registry cannot answer, string output is suppressed instead of passed through.

Security overview · Secret handling

Human gates became durable run state

A workflow can suspend at an input or approval, release compute, and resume the same run after an operator responds.

  • Boolean approvals, single choices, multiple choices, and free-text input share one gate.
  • Suspended runs resume from the waiting step rather than restarting the workflow.
  • Responses remain attached to the run and step history for later review.

Human input and approvals · Debugging runs

Build the next release process with us

Join the launch list for product updates, or add a founder-led Design Partner engagement to Business.

Prefer to talk it through? Talk to the founder