skip to content
Jobs

The Chat Pane Learns to Reply

Joining a fully built but isolated chat backend to the running engine, so a typed message finally gets an answer.

Gantry sprints
Joining a fully built but isolated chat backend to the running engine, so a typed message finally gets an answer.

Gantry runs a chat pane beside a build: an engineer can type a message to an assistant while the run works. The trouble was that the pane accepted a message, showed it, and then went silent — no reply ever came back. Everything needed to answer had already been written and tested on its own: the code that runs one conversational turn against a model, the stored transcript that remembers the conversation across turns, the router that reads incoming commands, and the front-end code that knows how to draw a reply. They had been built one step ahead of the thing meant to use them, and never joined up. This job did the joining. It inserted the router at the exact point where the front-end talks to the engine, stood up the assistant beside the running build, and carried its reply back out to the screen — so that typing a message now produces an answer, while a run nobody talks to behaves exactly as it did before.

Build

A single sprint that was pure wiring: the machinery all existed and was already tested apart, so the run's difficulty was concentrated onto one genuinely new piece — the event fan-out that earlier work had explicitly deferred to exactly this step.

The brief for this job is unusually explicit about what it is not. Every backend component — the turn runner, the persisted transcript, the command router, the run-scoped tool host, the front-end's reply rendering — already existed and already carried its own tests, landed a step ahead of the consumer that would use them. What remained was to place the router at the one point where the front-end's command channel meets the engine's prompt handler. Framing the job this way is itself the decomposition's claim: by landing and proving each part in isolation first, the earlier milestone left this step with almost nothing to invent, only to connect. The done-criteria lean on exactly that — the new tests reuse a scripted stand-in that already existed for the model, and drive a message through to assert the reply events and a transcript entry appear, rather than testing any component that is new here.

The one place the difficulty had not already been dissolved is called out in the brief as the deferred piece now due. The tool host needs to watch the engine's live event stream, to see when a prompt it issued gets resolved, while the front-end also holds that same stream — and no way to feed both existed. A comment in the code had explicitly postponed how events fan out to both a front-end and a brain to this transport work. That fan-out is the real content of the sprint; everything around it was already proven.

The run reflects the cut. The sprint executed once, passed its gate, and passed review — no repair, no retry, no re-plan. For a run that stays green throughout, the question worth asking is whether the boundaries were drawn so the difficulty was gone before the step began, and here the answer is yes by construction: the risky, testable parts were finished earlier, and this step was left small enough that a fresh agent could carry it whole, having to invent only the fan-out the earlier work had left for it.

Feature

Before this job the assistant pane could send but never receive. Afterward one router owns the front-end channel, forwards prompt answers untouched, and hands chat messages to an assistant running alongside the build, with an event fan-out feeding its tool host.

Before this job, a message typed into the assistant pane went nowhere. The channel from the front-end fed straight into the engine's prompt handler, which knew how to resolve a pending question but had no notion of a free-form chat message, so anything that was not a prompt answer was simply dropped.

The design puts a router in sole ownership of that front-end channel. A prompt answer is forwarded downstream untouched, so the existing question-and-answer paths resolve exactly as before; a chat message is peeled off and handed to an assistant console standing beside the build loop, which runs one turn and streams its reply back onto the same event stream the screen already reads. Because the assistant's tool host must also watch that stream — to notice when a prompt it issued gets resolved — the job added a fan-out that copies the engine's events to both the front-end and the host without either starving the other. A run that receives no message constructs no console and emits no chat events at all.

Standing in the tree today, the design holds but has been folded into larger successors. The build entrypoint this job edited is now a whole module directory, and the router lives there as a named function that still splits the front-end channel and copies the events out. The brain the job wired in has since been renamed the assistant throughout, and its standalone module absorbed into that rename; the chat console module itself remains, with most of its wiring still present. The capability the job delivered — type a message during a run and get a reply — is still there and still documented in the console module's own header, now described as tying several sprints' worth of backend into one running whole.

unavailable sessions
unavailable context
20,427 in / 128,034 out tokens
$13.32 cost
0 x 1 milestones x sprints
unavailable edits
unavailable commands
34m duration
unavailable roles
0 x 0 fixes x replans
- harness