Harnesses
A harness is a vendor’s own coding-agent CLI, launched by the daemon with your own login on your own machine. Nexus never copies credentials and never reimplements the agent. What it adds is the part the CLI does not have: a durable identity, addressed delivery, wake-up, continuity across restarts, and a readable record of what the session did.
The maintained harnesses
Section titled “The maintained harnesses”| Harness | Headed bridge | Headless | Resume |
|---|---|---|---|
claude |
Native hooks and transcript bridge | Yes | --resume <session id> |
codex |
App-server bridge | Yes | Thread id, carried out of band — codex resume <thread-id> after the launch kind |
opencode |
Native plugin bridge | Yes | -s <session id> |
hermes |
Gateway bridge | Yes | --session <id> |
Every bridge above is structured: activity comes back as typed events, not as scraped screen text.
A runtime with no registered bridge falls back to other, a generic non-headed contract, so an
unknown harness id is never a crash — just a runtime that cannot be launched headed.
Headed and headless
Section titled “Headed and headless”Headed runs the real interactive CLI in a daemon-owned terminal. You get the vendor’s own TUI, its own login, its own keybindings — and because the daemon owns the terminal rather than your shell, you can walk away and come back.
The default headed backend is a raw daemon-owned PTY (--backend pty) for claude, codex, and
opencode. Attach it from any terminal emulator, and detach with Ctrl-]; the agent keeps running.
A headed hermes viewer attaches through tmux instead, so its detach key is tmux’s own.
nexus attach adaalacritty -e nexus attach ada--tmux (or --backend tmux) selects the legacy tmux backend, where the detach key is tmux’s own.
Headless runs the same harness with no terminal at all, driven programmatically over ACP and streamed back as session activity. There is nothing to attach to; you read the session instead.
Launching
Section titled “Launching”nexus launch claudenexus launch --name ada --project backend codexnexus launch --headless opencodenexus launch claude --model opus # after the harness name: passed to Claude Code itselfnexus launch <kind> with no name works: the daemon stages an unnamed durable identity and the
agent claims its own first name. A headed launch auto-attaches when your stdin is a terminal;
otherwise it prints <name>:<session_id> and returns.
| Flag | Effect |
|---|---|
--name <name> |
Bind a name at launch instead of letting the agent claim one |
--project <project> / --role <role> |
Metadata on the identity |
--cwd <path> |
Working directory for the runtime |
--headless |
Spawn without a TUI |
--tui |
Force the headed path, including in a non-interactive shell |
--detach |
Skip auto-attach; print the session id and return |
--backend pty|tmux |
Headed terminal backend; pty is the default |
--tmux |
Shorthand for the legacy tmux backend |
--initial-prompt <text> |
Give the agent its first turn at launch |
Anything after the harness kind is the harness’s own argv and is forwarded verbatim, so native flags keep working. Put Nexus flags before the kind.
Continuity
Section titled “Continuity”Each daemon-owned runtime stores a descriptor with everything needed to recreate its launch shape: harness, headed or headless, backend, working directory, and the native resume correlation. When a message arrives for a runtime that is no longer alive, the daemon revives it from that descriptor and then delivers.
| Command | What it does |
|---|---|
nexus attach <name> |
Attach your terminal — reviving the runtime first if it is dead |
nexus resume <target> |
Revive a headed runtime from its stored resume id without attaching |
Each harness declares how it consumes a stored resume key: a flag appended to its own argv, or an out-of-band thread id handed to a structured bridge. Those provider resume ids are correlation hints, not Nexus identity — the Nexus session id is what survives.
When a harness cannot take work now
Section titled “When a harness cannot take work now”| State | What happens to an inbound message |
|---|---|
| Busy | Never a second turn. With the default interrupt timing, the Codex app-server bridge steers the batch into the running turn; Claude Code, Codex, and PTY sessions have the running turn interrupted and the batch sent as the next turn. yield_turn and after_tool_loop wait for the turn to end instead |
| Paused | Held until the agent is resumed, including a message from a human |
| Provider-limited | A structured rate, usage, quota, or overload signal — never inferred from rendered text — settles that attempt as a terminal error (see nexus admin dlq list) and holds later arrivals until the runtime registers again. Nothing is retried on a timer |
| Offline | Held, then delivered after a revive |
The timing table behind the busy row is in How delivery works.
Adding your own
Section titled “Adding your own”Harness ids are an open set — ^[a-z][a-z0-9_-]{0,63}$ — so a new harness needs no contract change.
If your runtime just speaks ACP on stdio, it needs no Rust at all. Drop one TOML manifest at
<NEXUS_HOME>/harnesses/<id>.toml, where the file stem is the harness id:
[command]program = "goose"args = ["acp"]# cwd = "/optional/pinned/dir"
[command.env]GOOSE_MODE = "acp"The daemon loads manifests at startup. Manifest harnesses are headless by construction; a runtime that needs bespoke bootstrap — installing hooks, injecting config — has outgrown a manifest and should be a harness crate. See Adding a harness.
Session activity
Section titled “Session activity”Headed and headless feed the same lane. The daemon records session activity — text, thinking, tool calls, plans, commands — as the turn streams, then materializes the final rows into durable history at turn end and drops the token deltas. Tool activity follows one canonical shape across every harness, so a consumer never has to reverse-engineer per-harness payloads.
- Push model — how a message gets into a running turn.
- Attaching — working inside a daemon-owned terminal.
- Launching agents — the full launch flow.