A harness is the thing that actually runs an agent: its tools, its sandbox, its conversation store, its sign-in. Gimbal sits above it and decides who is asked what, when, and with which context.
Adapters in the box
| Package | Harness | How |
|---|---|---|
gimbal/codex | Codex | Attaches to the machine’s shared codex app-server daemon. |
gimbal/claude | Claude Code | Through the Claude Agent SDK. |
gimbal/agy | Google Antigravity | Through the agy print-mode CLI. |
gimbal/opencode | OpenCode | Through its native session and event interface. |
gimbal/pi | Pi with Diffusion Router | Native Go engine in the Gimbal process, with independent session storage. |
The external harnesses use their own sign-in, configuration, and tools. Pi uses the Router key described below.
For Pi, set DIFFUSION_API_KEY. The headless engine runs inside Gimbal;
no separate Pi, Bun, or Node installation is required.
Select pi/diffusion/<model-id> with gimbal run-prompt --model or a
workflow role flag, for example pi/diffusion/deepseek-4.1-flash-background. Gimbal creates a
separate temporary config and session directory for each session; reasoning
effort is not supported for Pi models.
To find model IDs available to your Router key that support chat and tools:
curl -fsS https://router.diffusion.io/v1/models -H "Authorization: Bearer ${DIFFUSION_API_KEY}" |
jq -r '.data[] | select(.capabilities.openai_chat == true and .capabilities.tools == true) | .id' Prefix a chosen open-weight ID with pi/diffusion/ when binding a role.
Keep Codex work through a lost connection
The promise: when Codex’s connection drops during a task, Gimbal recovers the same work and continues the workflow without repeating completed operations. If it cannot establish safe continuation, it pauses the same live run, explains the problem, and lets the person resume or cancel it.
Scope: an active Codex turn in a workflow. Gimbal’s workflow host and the executor process running that turn stay alive. The connection to Codex’s app-server may break, or that Codex service may stop and restart using its existing native history. The workflow keeps its run, task and worktree; recovery uses the same native thread. Rejoining a surviving turn keeps its turn identity; continuing an interrupted turn may create a follow-up turn on that thread after the person confirms it is safe.
Current status: partly implemented; not yet proven end to end. Source implements reconnection, native-history reconciliation and a paused resume path. Historical checks at Gimbal b6e2c07e simulate these conditions. The test cases named “restart” change fake-daemon state; they do not stop and restart a process. PR630’s saved-result test constructs another daemon object and reads executor evidence; it proves that restoration avoids redispatch, not that an application restarted or unfinished work resumed. The live socket-loss test in source deliberately leaves the Codex daemon running; it is not daemon-restart evidence. No passing record for the journeys below is published here.
This is not a claim that quitting and reopening Gimbal, restarting its workflow host or turn executor, or switching to another agent restores an in-flight workflow. Those require separate lifecycle evidence. Claude Code, Pi, Antigravity and OpenCode need their own recovery claims and checks. The adapter ownership audit remains separate from this user-facing behavior.
How recovery must be witnessed
Use a disposable project and an isolated Codex app-server, never a shared service carrying unrelated work. Start a real multi-stage workflow: accept stage one, have stage two write a unique marker and remain active, then independently validate stage two and reach stage three. Keep the marker, run/task/worktree identities and native thread/turn identities observable.
1. Lose the connection during active work
After observing stage two’s marker, break only the active Codex connection. Witness the connection closing while the Gimbal host, turn executor and Codex daemon remain running. Restore connectivity and observe the surviving turn finish, stage-two validation run, and stage three begin. Stage one is not rerun and the marker is written once. A successful reconnect alone is not a pass.
2. Restart Codex after completion but before delivery
Hold delivery of stage two’s answer until native history shows that the turn completed. Stop the isolated Codex app-server, witness that process exit, then start a new process against the same native history. Record both process identities and confirm that Gimbal’s host and turn executor did not restart. Gimbal must recover the authoritative completed answer and advance through validation to stage three without executing stage two again. Merely reading a prewritten result file does not demonstrate this journey.
3. Restart Codex with unfinished work
After the marker appears but before a final answer exists, stop the isolated Codex app-server and witness its exit. Start a new process using the same history. Gimbal must inspect what survived and must not treat the lost connection as permission to replay the task. If no surviving operation can safely finish, the same live run must visibly pause with an actionable reason. After checking partial work and confirming prior operations have ceased, use its supported resume action. Observe continuation on the same native thread, exactly one marker, independent validation and progress to stage three. A paused state by itself does not prove continuation.
4. Cancel while recovery is paused
Make the Codex service unavailable during stage two and observe bounded recovery attempts followed by the same run pausing. Cancel that run through its supported control, then restore service. Observe cancellation remain cancellation: no resumed assignment, no extra marker and no stage-three work. Record the final native operation state rather than assuming a local process exit proves remote work stopped.
For each journey, publish the exact Gimbal revision/build, Codex version, date, isolated launch command/configuration, run and native identities, injected fault, observed outcome, marker count and validation/next-stage evidence. A restart claim also requires the old process’s exit and the new process’s PID/start identity, plus the identities of components left alive. State whether the turn survived, a completed answer was restored, or an interrupted turn continued. Retain these observations as evaluation evidence; a test name, a second in-memory object or a socket reconnect cannot stand in for a witnessed process restart.
Implementation references: original user-visible failure and intended outcome, Codex recovery source, simulated recovery cases, live connection-loss test, and saved-result characterization.
Binding roles to harnesses
A ModelBinding is a harness adapter, a model, and an effort. A run binds every role its workflow names, so one run can put planning on one vendor and review on another:
gimbal run pyramid-summary ... --document-authoring gemini-3.1-pro:high --editorial-review claude-sonnet-5-5:high The workflow’s source does not change. It named roles. The displayed defaults and available model IDs can change; inspect gimbal run pyramid-summary --help before a large run.
Writing an adapter
type HarnessAdapter interface {
CreateSession(ctx context.Context, model, effort, workdir string) (string, error)
RunTurn(ctx context.Context, sessionID, prompt string, schema json.RawMessage,
onEvent func(AgentEvent) error) (TurnResult, error)
Steer(ctx context.Context, sessionID, message string) (landed bool, err error)
Fork(ctx context.Context, sessionID string) (string, error)
Close(ctx context.Context, sessionID string) error
} The interface is untyped on purpose: a raw JSON Schema goes in, raw JSON comes out, and Generate validates and decodes. Cancelling the context passed to RunTurn is the interrupt. Steer reports whether the message landed in a live turn. Whatever the adapter allocates for a session is released by Close, which the runtime calls when the owning scope ends.
Adapters are responsible for connection maintenance, reconnection, and reconciliation with the native operation. They make observable, responsible best-effort attempts to complete the requested turn while preserving its semantics: keep the session identity and existing work, avoid blind replay and concurrent replacement workers, respect cancellation, and eventually release adapter-owned resources. This does not require a cancellation ledger or retained cleanup lifecycle in the workflow orchestrator. Reconnecting alone is not a successful turn; success requires the native result. Workflow code owns task policy and independent validation.
For a paused Codex turn, inspect the existing work and confirm prior operations have ceased before sending resume with gimbal steer RUN_ID --work-dir /abs/project --session SESSION_ID resume. Use gimbal cancel RUN_ID --work-dir /abs/project to request cancellation of the live run. These controls belong to the live-call recovery scope above; they do not reconstruct a stopped workflow host. The product anti-goal excludes strict orchestrator timing requirements and cancellation-completeness journals.