Skip to main content

orun agent

orun agent runs coding agents inside your standards: each session starts from a sealed brief built from the repository's declarations, and its tools are filtered by the policy its agent type declares. It is the command-line face of the agent runtime. An agent type is a markdown file under agents/ — YAML capability frontmatter over a persona body — sealed into the content-addressed object store as an AgentTypeSnapshot. A session is one run of one type: a frozen brief (the base literacy this binary ships, the type's persona, the task contract, the affected set) handed to a driver, whose events stream into an append-only session log that is sealed and replayable. The runtime never hands a driver a raw credential; it hands over the brief and an MCP config filtered through the type's tool policy.

Run bare, orun agent opens the cockpit on its Agents surface; --next opens the cockpit v2 Agents surface instead.

orun agent # the interactive Agents surface (--next for cockpit v2)
orun agent lint [dir]
orun agent import [dir] [--id-only]
orun agent show <name>[@sha256:…]
orun agent context [--seal] # orun agent context id
orun agent run --type <type> [--task KEY --spec <slug>] [--driver <id>] [--dry-run] [--detach] [--json]
orun agent ps
orun agent attach <sessionId>
orun agent kill <sessionId> [--force]
orun agent replay <sessionId>[@sha256:…]
orun agent drivers
orun agent doctor
orun agent serve [--driver <id>] [--session <id>] [--type <type>] [--task KEY]

Every subcommand that reads or writes the object store works against the workspace's .orun/ directory, so run it from the repository root (or a subdirectory of it).

Agent types​

An agent type file has two halves in one document. The frontmatter is the policy contract: name, kind: agent-type, apiVersion: orun.io/v1, harness (a driver id), model, optional runtime tuning (effort, temperature, maxTokens, contextBudget), autonomyDefault, tools (allow, ask, deny — deny-by-default), mayAffect component globs, optional secrets.use, a mandatory owner, and an optional extends. The schema is closed: an unknown key fails the lint. The body is the persona, stored verbatim as a content-addressed blob. Everything in the file is identity — retuning the model or widening mayAffect seals a new version.

The binary ships three types — bootstrapper, implementer, and orchestrator — as embedded fallbacks. A file at agents/<name>.md in the workspace always wins over the shipped copy of the same name.

lint​

Validates every *.md under dir (default agents) without writing. A file with no frontmatter, or whose kind is not agent-type, is skipped with a notice, never an error. Errors (missing owner, empty persona, an unknown frontmatter key, a bad apiVersion) are printed one per line and the command exits non-zero.

$ orun agent lint
agents/implementer.md: ok: agent-type "implementer" (harness claude-code, model claude-opus-4-8, owner sourceplane/team/platform)
agents/notes.md: notice: no frontmatter — not an agent type, skipped

import​

Seals every valid type under dir (default agents) into the object store and moves refs/agents/types/<name>/latest to the new snapshot. The persona becomes a body blob; the binary's base literacy is pinned through extends unless the file pins a custom literacy explicitly (name@id). Import is idempotent: an unchanged file re-seals to the same id. Lint errors block the whole import.

FlagMeaning
--id-onlyPrint only <id> <name> lines, for scripting.
$ orun agent import
sealed sha256:3f9c… implementer (refs/agents/types/implementer/latest)
sealed sha256:a01e… orchestrator (refs/agents/types/orchestrator/latest)

show​

Resolves a type by name (through refs/agents/types/<name>/latest) or by an explicit @sha256:… pin and prints the sealed envelope and persona from content alone — the offline read-back of import.

$ orun agent show implementer
agent-type implementer @ sha256:3f9c…
harness claude-code · model claude-opus-4-8
owner sourceplane/team/platform
autonomy assist
extends sha256:…
tools allow=[…] ask=[…] deny=[*]

# Implementer
…

context​

Prints the versioned base literacy every agent type extends instead of restating — the layer of orun understanding that ships with this binary (base-orun-literacy@v2) and is pinned into every brief by content hash.

FlagMeaning
--sealAlso store the literacy as a content-addressed blob and pin refs/agents/literacy/v2. Needs an object store (orun plan first).

orun agent context id prints the literacy's content id without writing anything, as <id> base-orun-literacy@v2.

Drivers​

A driver is the seam between the runtime and a coding agent: it is launched with a brief and an MCP config path, and emits a normalized event stream (message, tool call, tool result, approval requested, artifact, cost, error, done). Three drivers are registered:

DriverWhat it runs
stubAn in-process, deterministic script — no binary, no model, no network. The default for run; an interactive stub run (no --task) serves steers, approvals, and interrupts until a /done steer.
claude-codeThe Claude Code CLI in headless mode. The runtime writes the orun MCP config under .orun/agent-mcp/, filtered through the type's tool policy, pins the type's model, and materializes hosted skills (see orun skills). The default for serve.
bootstrapA product build with no model attached. serve still supervises — heartbeat, relay, sealing — but the body is orun baseline new <id> --local --out <dir> --run-hooks --resume --progress json [--values <file>], with <id>, <dir>, and the values file read from ORUN_BASELINE_ID, ORUN_BASELINE_OUT, and ORUN_BASELINE_VALUES. ORUN_BASELINE_UNTIL adds --until <phase> and ORUN_BASELINE_PHASE adds --phase <phase>, beside --resume; both set is refused before launch, naming both. A build stopped by --until that exits 0 is completed. The driver narrates the build's --progress json stream into the transcript; the build reports its own stream to the platform. It is not steerable: a steer or interrupt is answered with a line saying so, and the child's exit status alone decides the outcome.

orun agent drivers prints the registered ids, one per line. orun agent doctor reports what the live plane needs: the drivers, the MCP tool count orun mcp serve exposes, and whether a claude binary is on PATH (with its version — the driver's wire protocol is pinned by fixtures, so version drift is worth knowing before a session hits it).

$ orun agent doctor
drivers [bootstrap claude-code stub]
mcp tools … (orun mcp serve)
claude /opt/homebrew/bin/claude (… (Claude Code))

run​

Assembles a frozen, content-addressed brief and runs it through the chosen driver, hosting the session locally so heads can attach.

FlagMeaning
--type <type>Agent type: agents/<type>.md, or the shipped copy of that name. Supplies the persona, the tool policy, and the model.
--task <KEY>Task key to implement (for example ORN-142). Without it the run is interactive rather than an implementation run.
--spec <slug>A sealed brief under .orun/specs/<slug>/snapshot.json supplying the task's contract; the brief's content id is computed over the bytes on disk and recorded on the run. With --task, the task must carry a contract in that brief.
--driver <id>Driver id (default stub).
--dry-runSeal and print the brief — id, run kind, task, and the full instructions — without launching.
--detachFork the session body into its own process group and return; attach later with attach. Closing the terminal never kills a detached run.
--jsonJSON output: {briefId, runKind, task} with --dry-run; the run result otherwise.

The command needs an object store (orun plan first). A task run's branch is agent/<KEY>-<type>. Sealing the session as a discoverable, replayable record needs the type to have been sealed — run orun agent import first; without it the run still executes and its segments are stored, but it is not indexed under refs/agents/sessions/<id>.

# See exactly what the agent will be briefed with
orun agent run --type implementer --task ORN-142 --spec orn-142 --dry-run

# Smoke the whole loop with no model
orun agent run --type implementer --task ORN-142 --spec orn-142

# The real thing, left running in the background
orun agent run --type implementer --task ORN-142 --spec orn-142 --driver claude-code --detach

While it runs, the body prints session as_… hosting — attach from another terminal: orun agent attach as_…, then renders each event as a line. At the end:

session as_8f3c2d1e9b7a4c6d (driver claude-code)
brief sha256:…
outcome completed pr=https://github.com/acme/api/pull/412
segments 3 sealed
session sealed sha256:… (refs/agents/sessions/as_8f3c2d1e9b7a4c6d)
replay orun agent replay as_8f3c2d1e9b7a4c6d

Sessions: ps, attach, kill​

A running session is a body; every terminal or console looking at it is a head. The body hosts a socket under .orun/agents/live/, and the live registry beside it is what ps reads.

ps​

Lists live sessions on this machine only — the local registry, with dead bodies swept. Cloud sessions do not appear here; watch those in the console or attach to them by id.

$ orun agent ps
SESSION TYPE TASK STATE AGE PID
as_8f3c2d1e9b7a4c6d implementer ORN-142 running 4m12s 48213

attach: orun agent attach <session> end: orun agent kill <session>

attach​

Attaches this terminal as a head: replays the session's event history, then follows live. Everything you type is a steer — a user turn, attributed and sealed into the session log. Lines starting with / are head commands:

CommandEffect
/approve <requestId> [reason]Answer a pending approval.
/deny <requestId> [reason]Deny it.
/interruptStop the current turn, not the session.
/endGraceful terminal: the body seals and exits.
/detach (or Ctrl+D)Leave; the session keeps running.

Any other slash-word is passed through as conversation, since a driver may have its own.

attach resolves the id locally first. When no local body has that id, it attaches over the cloud relay instead, and for that it needs:

VariableMeaning
ORUN_CLOUD_APIThe api-edge base URL. Required.
ORUN_ORG_IDThe workspace (org_…) id. Required.
ORUN_SESSION_TOKENThe bearer presented to the relay.

The relay endpoint is $ORUN_CLOUD_API/v1/organizations/$ORUN_ORG_ID/agents/sessions/<sessionId>. Without ORUN_CLOUD_API and ORUN_ORG_ID the command fails with no live local session "…", and no cloud attach config. A local and a remote session render identically.

kill​

Ends a session gracefully by dialing its socket and sending the terminal command, so the body seals and exits. If the body is dead or unreachable:

FlagMeaning
--forceKill the body process and sweep its registry entry. Sealed segments up to the last seal survive.

replay​

Resolves a session by id (refs/agents/sessions/<id>) or by an explicit @sha256:… pin and re-renders it from the sealed segment chain alone — deterministic, from the object graph, with no live process.

$ orun agent replay as_8f3c2d1e9b7a4c6d
session as_8f3c2d1e9b7a4c6d @ sha256:…
runKind implementation
agentType sha256:…
brief sha256:…
outcome completed pr=https://github.com/acme/api/pull/412

transcript (17 events):
1 message_agent {"text":"reading brief …"}
2 tool_call {"tool":"catalog_affected","decision":"allow"}
…

serve​

The in-sandbox entrypoint: the same delegation loop as run, with its attach plane pointed at the per-session cloud relay. Event batches dial out to the relay; steers, verdicts, and interrupts dial back. The console and a remote orun agent attach as_… are interchangeable heads over that stream. You do not normally run it by hand — the platform execs it in the sandbox it provisions for a session or a platform baseline build.

FlagMeaning
--driver <id>Driver id (default claude-code). bootstrap for a platform baseline build.
--session <id>Session id (defaults to ORUN_SESSION_ID).
--type <type>Agent type (defaults to ORUN_AGENT_TYPE). Without one, the tool policy is deny-by-default and every tool call is denied.
--task <KEY>Task key (defaults to ORUN_TASK_KEY).

Identity comes from the sandbox environment the control plane injects:

VariableMeaning
ORUN_CLOUD_APIThe api-edge base URL. Also seeded to the harness as ORUN_BACKEND_URL when that is unset, so the orun MCP server and every in-sandbox orun verb find the platform.
ORUN_ORG_IDThe workspace (org_…) id.
ORUN_SESSION_IDThe as_… session id.
ORUN_SESSION_TOKENThe session bearer — the service-principal credential.

All four are required; the first lines on standard error name the binary's version and which of them arrived (the token redacted). A grounded session also carries its repository binding, and serve clones it before the loop starts, creating the task-keyed branch and putting the driver's working directory inside the checkout:

VariableMeaning
ORUN_REPO_REMOTEThe https clone URL. Never carries a credential; git authenticates through orun git-credential, which mints short-lived repo-scoped tokens with the session's own bearer.
ORUN_REPO_FULL_NAMEThe owner/repo full name.
ORUN_REPO_REFThe ref to clone at.

Without ORUN_REPO_REMOTE the session is ungrounded and boots as before. A grounded session that cannot reach its repository fails loudly; it never degrades to ungrounded. The session token is also written to ORUN_TOKEN_FILE on every rotation, so orun verbs the harness spawns authenticate as the live session with no configuration. With --driver bootstrap, a grounded session builds in its clone.

A grounded session other than a baseline build also keeps the checkout's live preview running once the repository declares one and has the code, restarting it if it exits, and reports each change as a preview_changed event (starting, ready, failed with a detail, stopped when the session ends). The servers run without the box's secrets. ORUN_PREVIEW=off turns it off.

Exit codes​

CodeMeaning
0Success.
1Any error: lint errors, no object store, an unknown type or driver, a missing session, a relay or identity failure.