skip to content
Jobs

Delivering Gantry's Tools to Any Harness's Assistant

The conversational assistant reached its run tools only under Claude; this job taught every harness to register them natively.

Gantry milestones
The conversational assistant reached its run tools only under Claude; this job taught every harness to register them natively.

Gantry can run a conversational assistant beside a build — one that reads files and runs commands through gantry's own bridge rather than the coding CLI's native shell. For those tools to appear, gantry has to tell the running CLI where to find them, and it did that by writing a Claude-shaped configuration file into the working directory before every assistant turn. But that file is Claude's format alone, and gantry's default coding CLI is a different one that never reads it. So the default assistant started with none of gantry's tools and quietly fell back to its own shell, which is not what the run intended.

This job moved tool registration into the layer that already knows each CLI's conventions. Gantry now describes the run-scoped servers once, in a form that belongs to no particular CLI, and each supported CLI renders that description into its own native configuration — a written file for some, command-line flags for others. The bridge and the tools it exposes were already working; the gap was purely in how their existence was announced to a CLI that was not Claude.

Build

A single foundation sprint made the neutral registration the source of truth with no change in runtime behavior; per-harness renderer sprints then translated it independently, each a unit-testable pure transformation, leaving the motivating bug deliberately live until the last sprint flipped the driver over.

The cut that made this agent-sized was to treat MCP registration as data the harness renders, mirroring how the system prompt and answer source were already modelled, and to land that data before anything consumed it. The first sprint introduced the neutral server description and threaded an unused field onto the agent spec, and it changed no runtime behavior at all — the old unconditional file-write stayed exactly as it was. That let the foundation be proven in isolation: the source of truth existed and the existing Claude JSON became one rendering of it, with the motivating bug still fully present at the sprint's end.

The renderer sprints then each answered one question — what native form does this CLI want — and nothing else. Claude keeps its written config file; codex bakes command-line flags into its argv; gemini and opencode write their own settings files. Because every renderer is a pure translation from the neutral description to a native form, each could be pinned by a unit test with no live CLI and no change to how any run actually behaved. That is why the run stayed green throughout with no gate sending a sprint back and no review forcing a re-plan: the difficulty was dissolved into independent translations rather than concentrated in one risky integration, and the headline bug was carried, live and untouched, until the final sprint retired the old write and populated the spec field instead.

Where difficulty did concentrate was codex, the default CLI and the actual subject of the bug. Its registration arrives as `-c` overrides whose right-hand side parses as TOML, and a malformed value is silently dropped — which would send the assistant straight back to toolless with nothing red to show for it. That boundary was held by an encoding test that pins the TOML quoting and the args array, rather than trusting a live spawn to notice. The one visible extra event, a second gate on the final sprint, is the merge re-running the suite on the integrated tree; it too passed.

Feature

Gantry's run-scoped tools now reach the assistant under any supported CLI: a CLI-neutral server description rides on the agent spec, and each plugin realizes it as a written config file or as inline flags. The design still stands at HEAD, though the standalone brain-driver source has since folded into the chat wiring.

Before this job, gantry's conversational assistant reached its run tools only when the coding CLI happened to be Claude. Under the default CLI it ran without them, silently, because the only description of those tools was a file that CLI never opens. The registration mechanism assumed one vendor's convention and the assistant paid for it.

The design that answers this is a neutral field on the agent spec listing the stdio servers by name, command, and args, plus a delivery description on each harness's invocation with two shapes: a file the runner writes into the working directory and keeps out of git's index, or nothing to write because the registration is already baked into the argv. Claude writes its conventional config file; codex bakes `-c mcp_servers.*` flags; gemini and opencode write their own native settings files; a one-shot build or review stage carries no registration and stays byte-for-byte identical to before. The driver stopped writing any file directly — it fills the spec field and lets the resolved CLI deliver.

Standing in the tree at HEAD, the design holds. The neutral server type and the delivery description with its file and no-file variants are still in the harness module; each plugin still renders its own native form, and the host exposes the neutral registration and derives the Claude JSON from it rather than hand-building it. The drift to report plainly is that the separate brain-driver source is gone: the conversational-assistant wiring moved into the chat engine, but it still carries the host's neutral registration onto the spec exactly as this job arranged. Most of the lines the job introduced are still present.

unavailable sessions
unavailable context
61,460 in / 144,071 out tokens
$26.74 cost
0 x 5 milestones x sprints
unavailable edits
unavailable commands
1h duration
unavailable roles
0 x 0 fixes x replans
- harness