Skip to main content
Draft. This page describes a change that is on staging and not yet in production. It stays out of the navigation until Phase 1 ships. Until then the pages listed at the end describe the product as it runs today.

What changes

Today a conversation with an agent runs one turn per message. A turn ends when the harness finishes, when it has produced no output for a set time, or at a hard duration cap. Anything the agent left running dies with the turn, a question ends the turn, and a deploy roll stops it. With resident processes, a harness agent’s task is one process. It shows as In progress from the first message until the agent itself calls finish_process. While it runs:
  • Every message you send is delivered into the running process. There is no new turn and no re-routing.
  • The agent posts progress notes and asks questions without stopping. The task pill shows the latest note instead of “running”.
  • A process that waits, for you, for a pull request, for a time, parks to disk and holds no capacity. It wakes into the same files, the same git tree and the same conversation.
  • A fleet roll, a scale-in or an executor crash parks the process and resumes it. You see nothing.
This is the default for every external-harness agent. There is no flag and no per-message choice.

The three calls an agent has

The harness already talks to xpander on every run. Three calls carry the model: While work the agent started is still open, finish_process is held: a sub-agent still running, a question card it raised that you have not answered, or a wait it booked. The call records nothing and answers with what is open, so the task stays In progress; the agent finishes once the sub-agent reports, the answer arrives or the wait ends. Asking never stops the task. The question card sits in the activity thread while the agent continues work that does not depend on the answer, or calls wait_for and parks. Answering on the card, or typing a reply, delivers the answer into the process. On Claude Code, if the agent tries to finish while a command it started in the background is still running, the task does not complete. It stays In progress, shown as Working, and the agent is told which commands are still running. The task completes once those commands have finished or been stopped and the agent finishes its work. A command still running after 240 minutes no longer keeps the task open. You do not have to wait: archiving the conversation ends the process, and the background command ends with it. Pressing Stop ends only the agent’s current turn; the task stays In progress.

Task states

You see one status, In progress, for the life of the process. Underneath it a substate tells you what the agent is doing. Three exits exist: Completed when the agent calls finish_process, Stopped when you press Stop, and Failed, which only an operator sets. xpander never fails a process on its own. A process that is never finished asks “still needed?” after a period of idle days and finishes itself with a summary after a longer one; both periods are per-install settings.

Conversations

A sub-task is a process. A conversation is a chain of processes.
  1. The first message in a conversation starts a process on the harness agent.
  2. While that process is live, in any substate including Waiting, every later message is delivered into it. A message to a parked process wakes it.
  3. When the process is Completed or Stopped, the next message starts a new process. The conversation shows both cards, for example “Fix PR 5678” Completed and “Cut the release” In progress.
  4. Parallel work is a new conversation, like another terminal tab. Two processes of one agent get their own working trees and never edit the same files.
The harness session is per conversation, so a finished process’s context carries into the next one. “Now do the release” remembers the pull request it just merged. Omni follows the same rule one level up. Dispatching to a harness agent creates a process; follow-ups become steers into it; the child’s notes and questions appear in Omni’s thread; the result comes back when the child finishes. Omni’s own conversation is never blocked by a week-long child.

What stops happening

Harness differences

Claude Code gets a true hot session from day one: the harness stays open between messages while you are present. Codex and OpenCode run resident with a park after every turn until their multi-turn drivers exist. The experience is the same; the wake is slower.

For operators

  • Only a hot segment holds a fleet slot. Parked processes cost nothing, so hundreds of waiting processes coexist with a small fleet. Autoscaling demand is pending wakes plus hot segments.
  • Parking is presence-based: with nobody in the conversation for a couple of minutes the segment parks. A safety timer sits underneath for a stream that never closed. wait_for parks at once.
  • A process lives on the executor volume that holds its agent’s home directory. A demand floor keeps that executor’s ordinal alive while a process waits on it. Nightly volume snapshots join the infrastructure as code.
  • Credentials are per segment: the turn token is minted at claim and revoked at park. A week-long process never holds a credential for a week. Provider keys never reach the harness, as today.
  • A process pins the harness version it started on. Roll-forward happens at finish or at an explicit park, never mid-flight.
  • Log events per process: process.start, process.park with reason, process.wake with trigger, process.crash, process.finish. A staff page and GET /fleet/processes list every process in the organization with state, volume, executor, age and last update.
  • Billing is per segment: compute from the sandbox at park, tokens per response through the proxy, rolled up per process in the task view.
Defaults proposed in the design and still to be confirmed:

Phases

A message is one turn of the conversation, streamed token by token, and the conversation record keeps the whole thread. See Conversations, tasks and files and the Conversations API.

Still open

Decisions the design asks for:
  • Keep or drop the two “Ask user” display labels in Xpander Chat and the legacy frontend.
  • Confirm the defaults in the table above.
  • Confirm the names tell_user, wait_for, finish_process and start_service.
Risks named in the design:
  • Session growth over weeks. Claude Code compacts on its own; Codex has no compaction on resume and long Codex processes lean on the handoff digest.
  • The volume pin keeps an executor from scaling in while a single process waits on it.
  • Docker inside the sandbox is not available yet.
  • A personal Claude Max subscription cannot be used; API pricing applies.

Pages that change