Skip to content

External-Agent Lanes

External-agent lanes — race the real agents

Section titled “External-agent lanes — race the real agents”

Chimera’s mission is controlled comparison. The multiplexer already races several Chimera scaffolds (presets, loops, models) on one task. External lanes close the loop: a lane whose driver spawns a real third-party coding-agent CLI as a subprocess, translated into the same event stream every Chimera lane emits. Now you can race the actual upstream agents against Chimera — or against each other — under identical tasks and workspace isolation, with the same scoreboard, telemetry, and cohort artifact.

Terminal window
set -a; source .env; set +a # model credentials for the Chimera lane
# race the claude CLI against glm-5.2, isolated worktree each:
chimera code --tui --models ext:claude,glm-5.2[1m]

ext:<profile> is a lane like any other: its own git worktree, its own pane, its own row on the scoreboard. Its file writes show in the Ctrl+R diff and persist in the cohort — resumable with --resume / /cohorts.

An external lane is ext:<profile-name>. It takes no preset or loop axis (those are Chimera-scaffold knobs; the external tool runs its own way), so ext:claude:minimal is an error on purpose. Mix freely with Chimera lanes:

Terminal window
chimera code --tui --models ext:claude,glm-5.2,glm-5.1:explore
# └ external ┘ └───── Chimera lanes ─────┘

A profile says how to run one CLI. One ships built in — claude, the claude CLI (--print --output-format stream-json), which this repo already integrates against. Everything else is your own config, under [external_agents.<name>] tables in ~/.chimera/config.toml (the same file every Chimera CLI reads; $CHIMERA_CONFIG_HOME is honored):

[external_agents.myagent]
# {task} (required) is replaced with the task text; {workdir} with the lane
# worktree path. The subprocess always runs with cwd = the lane worktree.
command = ["myagent", "--prompt", "{task}"]
protocol = "stream-json" # or "text"; default "stream-json"
env = ["MYAGENT_API_KEY"] # optional: subprocess sees ONLY these (+ PATH,
# HOME, TERM, …). Omit to inherit your full env.
timeout = 600 # seconds; default 900. On expiry: SIGTERM.

Profile names are your data — name them whatever you like. Reference one with ext:myagent. An unknown or malformed profile fails loudly at launch, naming the known profiles.

ProtocolInputTelemetry
stream-jsonnewline-delimited JSON events (the claude CLI’s stream-json vocabulary)real — cost, tokens, and step count parsed from the final result line
textplain stdouthonest zeros — no cost/step data exists; the lane says so with a system note. Wall-clock time is still real.

Each JSON line maps to loop events the pane renders:

stream-json lineBecomes
system / inita “external agent ready” note
assistant msg — thinking blockthinking_chunk (collapsed reasoning)
assistant msg — text blockassistant_chunk (streamed prose) + a committing assistant event carrying that step’s token usage
assistant msg — tool_use blocktool_use (a real tool call in the pane + sidebar)
user msg — tool_result blocktool_result paired with its call
resultfolded into the lane’s single terminal result (cost, usage, steps, reason)
non-JSON linesurfaced verbatim as a dim system note (never silently dropped)

What external lanes expose — and the honest limits

Section titled “What external lanes expose — and the honest limits”
  • Isolation is identical. External lanes get a git worktree from the same base commit as every other lane, so their diffs are clean and comparable, and nothing they write touches your real tree.
  • Telemetry varies by protocol. stream-json gives real cost/tokens/steps; text gives honest zeros (with a note) and real wall-clock. Chimera never fabricates a number it did not observe.
  • No steering, no follow-up queue. A mid-run message cannot reach a --print-style CLI. Steering an external lane emits a polite system note (“steering is not supported — message not delivered”) instead of pretending or crashing.
  • Conversation memory is the tool’s own. Each turn is a fresh CLI invocation. Chimera reconstructs a minimal user/assistant history for the cohort artifact and resume display; it does not replay prior turns into the external tool unless that tool persists its own session.
  • Cost is real money. An external lane runs the real agent under your own login/credentials. Keep race tasks small.

An external lane persists exactly like a Chimera lane: the manifest records its profile (as model ext:<profile>, preset external) and telemetry; its transcript, produced diff, and minimal history are written to the cohort directory. Resuming (--resume <id>, /resume, or the /cohorts picker) rebuilds the lane from its profile on a fresh worktree with the saved diff re-applied, restores its telemetry so the scoreboard keeps accumulating, and lets it run another turn.

The driver is usable without the TUI — it satisfies the same chimera.assembly.driver.DriverProtocol the multiplexer drives:

import asyncio
from chimera.assembly.external_driver import ExternalAgentDriver, resolve_external_profile
from chimera.core.loop_events import LoopEventType
async def main():
driver = ExternalAgentDriver(resolve_external_profile("claude"), workdir="/tmp/lane-a")
async for ev in driver.send("create hello.txt containing hi"):
if ev.type is LoopEventType.result:
print(ev.data.reason, ev.data.cost_usd, ev.data.turn_count)
asyncio.run(main())

send() streams LoopEvents ending in exactly one result; cancel() terminates the process group cleanly (SIGTERM first, kill only after a grace window). See the multiplexer guide (docs/guides/tui.md) for the full racing surface.