Skip to content
UseAgent star-knot markUseAgent
Esc
navigateopen⌘Jpreview
On this page

Runs, threads, and commands

The units of work. A command starts a run, a run is one turn, and a thread is the conversation that ties runs together.

These four terms describe how work is scoped and made durable. They are backend truth: the frontend renders them but never invents them.

Run lifecycle: acceptRunCommand accepts a durable command, the worker claims it, a sandbox is acquired, the engine runs one turn, steps and provider events land in Postgres, finalizeRun commits the terminal state, and a reply re-enters the same door with parent_run_id

The run lifecycle: every channel enters through one durable command door, the Postgres event log is the source of truth, and a reply re-enters with parent_run_id.

Organization

The tenant boundary. Resources such as secrets, skills, knowledge, runs, and integrations belong to exactly one organization. A user is different: membership is many-to-many, so one user can belong to several organizations and acts under one active organization per session (backend/src/db/auth-schema.ts). Org scoping is enforced by the backend auth layer and the database, not by the client.

Thread

One continuing conversation. Replies reuse the thread’s history, its sandbox, and its working directory. Threading is server-side: a reply stores the raw user prompt only, and the backend composes the engine’s context preamble from recent turns. Prior turns are never stuffed into a stored prompt.

Run

One agent turn inside a thread, from an accepted command to a terminal result. The runs list returns thread roots; a single thread is fetched whole when you open it.

Child sessions

An agent can spawn child work in-run through the child_session_create, child_session_list, child_session_events, and child_session_gather gateway tools (backend/src/knowledge/gateway/child-session-tools.ts). Each child is a queued serial turn on the same thread: at most one command per thread is in flight at a time (backend/src/commands/dispatch.ts), so children run one after another, never as a parallel process tree. The timeline renders their progress through the child.started, child.updated, and child.completed canonical events.

Command

The durable record of a product mutation. There are exactly two durable command kinds (backend/src/commands/repo.ts): run.create enqueues a turn, and a reply or resume is simply a new run.create turn on the same thread carrying parent_run_id; run.cancel is the durable record of a user stop request. Commands are the single door: the web app (runs/routes.ts), Slack (slack/events.ts), and scheduled automations (schedules/fire.ts) all enter through the same acceptRunCommand lane.

A command may carry a per-organization idempotency key. When a key is present, a retried submission observes the original command instead of starting duplicate work, and a reused key with a different payload fingerprint is rejected with a 409 rather than silently rerun (backend/src/db/schema.ts). Without a key the submission is still a durable command row, just not deduplicated.

Step

A run’s timeline is written in two lanes.

Durable steps are coarse timeline items in the steps table. A step’s kind is one of command, file, task, or done, with a label, an optional chip, and optional structured code_json (backend/src/db/schema.ts).

Canonical events carry everything else a timeline reader sees. They are provider-neutral (one discriminated union covers every engine, packages/agent-harness/src/canonical.ts) and are persisted in canonical_events before they are published, with an immutable deliverySeq cursor, so a reconnect replays exactly the rows a live subscriber saw (backend/src/runs/canonical-events.ts). The kinds a timeline reader sees include:

Canonical event group Examples
Messages and reasoning message.started/delta/completed, reasoning.delta/completed
Tools and plans tool.started/progress/completed, plan.updated
Files and artifacts file.changed, artifact.created, artifact.delivered
Questions and approvals question.requested/resolved, approval.requested/resolved
Child sessions child.started/updated/completed
Usage usage.updated

Because the event log is the source of truth, the two lanes together fully describe a run and can be replayed. The UI reduces them into the session timeline.

Was this page helpful?