Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Runner catalog

A runner is an external ACP-speaking agent that jj-acp can spawn. Runners are data, not code: a catalog entry names an executable, its arguments, an environment floor, an MCP transport and an install hint. Adding support for a new agent MUST be a catalog change.

The catalog is tiered so that trust decreases as flexibility increases, matching the model the upstream harness uses and the model @lapismd/ai-host already exposes to Lapis consumers.

TierSourceEditableAuto-install
1Compiled-in defaultsNoNever
2Catalog file supplied by launch configurationNoNever
3Caller-supplied definition in a task or control frameNoNever

No tier may auto-install. Availability is determined by resolving the declared executable, and an unavailable runner reports its install hint rather than attempting a download or executing a shell command.

Requirements

IDRequirement
JAC-AGENT-001A runner MUST be declared as data carrying identifier, label, command, arguments, environment floor, MCP transport and install hint.
JAC-AGENT-002Adding a runner MUST NOT require a code change, an install shell command or a network fetch.
JAC-AGENT-003Reserved harness environment keys MUST be stripped before a definition or caller override is merged, and MUST NOT be settable by any tier.
JAC-AGENT-004A disabled or unknown runner identifier MUST fail resolution and MUST NOT fall back to a default runner.
JAC-AGENT-005Runner identifiers MUST be validated against a fixed pattern and MUST be unique within a resolved catalog.
JAC-AGENT-006The launch environment MUST be assembled from the inherited environment, the definition floor and caller overrides in that precedence order.

Reserved environment

The harness injects identity and correlation variables into a spawned agent so that tools it provides can attribute work correctly. Those names are reserved. A runner definition, a catalog file or a caller-supplied override that sets one is stripped before merge, and the strip is recorded so the operator can see that a definition attempted to claim harness identity.

This is the only place jj-acp performs anything resembling an authorization check, and it is a namespace guard rather than an identity system. There is no keypair, no signature, no token and no peer credential anywhere in this repository. The controlling application decided to run this runner with this environment; jj-acp only refuses to let the runner definition contradict that decision.

Default catalog

The compiled-in tier names the adapters that are already in use elsewhere in the workspace, so an operator who has one of them installed needs no configuration. Identifiers are stable and reserved: a lower tier cannot shadow them.

IdentifierAdapterMCP transport
codex@agentclientprotocol/codex-acpstdio
claudeclaude-agent-acp, legacy claude-code-acpstdio
opencodeopencodestdio
goosegoose acpstdio
cursorcursor-agent acphttp

A runner that speaks ACP over stdio and satisfies the protocol requirements in ACP wire protocol works without being listed here. The catalog exists for discovery and labelling, not as an allowlist.

Implemented surface

ModuleOwns
definitionRunnerDefinition, CommandSpec, McpTransport, identifier and label validation
catalogTiers, collision rules, resolution and listing
defaultsThe compiled-in tier and its reserved identifiers
configCatalog document parsing
environmentReserved-key stripping and three-layer merge
availabilityThe CommandProbe trait, a PATH probe, a fixed probe and availability reports
errorTyped refusal reasons

A candidate argv is a CommandSpec, and a definition may list several in preference order. The first whose executable resolves wins, which is how one definition covers both a current and a legacy adapter command name without inventing two runners.

Resolution refuses rather than substitutes. An unknown identifier and a disabled one are distinct errors, and neither falls back to a default, because silently running a different agent than the one requested would execute untrusted prompt content with capabilities the caller did not choose.

Collisions are refused for the whole batch rather than skipping the offending entry. A catalog file that fails to load therefore cannot produce a quietly smaller runner set than the operator wrote.

CommandProbe is a trait so availability is testable against a synthetic search path. The real probe only tests whether a file exists; it never executes the candidate to see whether it works, because executing an untrusted binary to probe it would be worse than not probing at all.

Environment precedence

The three layers apply in order: the inherited environment, the definition floor, then caller overrides. A later layer replaces an earlier one for the same name, and the first appearance fixes its position so the result is deterministic.

Every layer is stripped of names under the JJ_ACP_TASK_ prefix before merging, and the stripped names are returned so an operator can see that a definition tried to claim harness identity. The harness then adds its own reserved variables through a separate function that no catalog file and no caller override can reach. The prefix is matched rather than an enumerated list, so a future harness variable is covered without a rule change.

Qualification status

The compiled-in entrypoints are declared from the published adapter package names but are not yet qualified against installed adapters. Declaring an argv is not evidence that it launches, which is why the real installed-runner gate is a separate ledger task and why an unqualified default is a convenience rather than a claim.

Qualified entrypoints

The default catalog table above is a convenience, not a claim. This records which entrypoints have actually been launched and spoken to.

IdentifierEntrypointQualified against
cursorcursor-agent acp2026.09.26-dd393fe, two completed turns
codexcodex-acp1.13.1, one completed read-only turn
claudeclaude-agent-acpnot launched
opencodeopencode acpexecutable present, entrypoint unverified
goosegoose acpexecutable present, entrypoint unverified

The codex entry needs a qualification of its own. The codex CLI is not an ACP agent and has no acp subcommand; the ACP surface is a separate adapter package, @agentclientprotocol/codex-acp, which is how ai-host reaches it through acpx. That launcher uses npx -y, which fetches the package into the npm cache on demand and never puts it on PATH. So codex-acp can be present and working on a machine where command -v codex-acp finds nothing, and this harness’s compiled-in declaration resolves only when the binary really is on PATH. A catalog entry naming npx with the adapter in its arguments is the portable form.

opencode and goose report available: true on a machine that has them installed, and that means only that the executable exists. Probing never runs a candidate, because executing an untrusted binary to see whether it works is worse than not probing. Their ACP entrypoints remain unverified.

Public release packaging

The published agent crate includes registry-versioned dependencies and its own README, license and notice. Runner selection, environment precedence and reserved IDs retain their existing contracts.