Saying Is Not Doing
On 2026-10-18 the family ran a live acceptance. Each of the five brains other than Claude and GPT took a turn as chief of a fresh Pippa conversation and had to see Coop work through to the end with nothing but the coop tool (track 5, lesson 6). Four turns in, the Kimi chief and the Grok chief each wrote something like "closing #506 ... closed". Neither had called anything, and the todos stayed open.
The models were doing what the replay had taught them. Every vessel replayed prior turns as text: Dad's messages and Pippa's reply texts. The tool calls a reply made were stored right beside it, in messages.tool_uses, and never rode the replay. So in the history the model read, an earlier reply that said "I'll close #505." and then reported the result looked exactly like a reply that only said so. A few turns of that and the lesson is learned: in this conversation, closing is something you say.
Measured Before It Was Fixed
The fix was chosen by measurement. The session rebuilt that exact point offline: the stored history, the engine's prompt and the route's tools, with the tools executed dry. Then it asked for the next turn many times under three kinds of replay.
| Replay | Kimi | Grok |
|---|---|---|
| Text only, as it was | 3 close calls in 16 tries | stopped on "I'll close it" with no call in 7 of 27 |
| A text record of the calls at the head of Dad's next message (the first fix) | helped only partly | did not help |
| The calls replayed in each wire's own call shape | closed 9 of 9 | called 14 of 14 (10 closes, 4 a show first) |
The middle row teaches the most. The first fix, shipped the same morning, described each earlier call in prose ahead of Dad's next turn. The facts were right and the form was wrong. A model trained on tool use learns what calling looks like from the call structure itself, and a paragraph that reports a call is still a paragraph. The text record was replaced the same day.
Each Vessel, Its Own Shape
context/reply_calls.py sits at the seam every vessel already shares, prepare_turn_messages. For each replayed assistant message it reads that reply's stored calls, pairs each call with the answer stored after it, and hands them to the vessel as Message.tool_calls. Each vessel renders them ahead of the reply's text the way its own in-turn loop sends them:
- Codex and Grok:
function_callandfunction_call_outputitems. - Kimi and Ollama: an assistant message carrying
tool_calls, then tool messages. - GLM:
tool_use, thentool_result. - Gemini: a model turn of
functionCallparts, the first carrying a synthetic thought signature because Gemini rejects a call without one, then a turn offunctionResponseparts. - Claude: a
callsfield in its prior-turn JSON, explained in the replay head.
A provider check that day sent real stored histories with replayed calls to Grok, Codex, Kimi, GLM, Gemini and Ollama, and all six took them without an error.
The Details That Keep It Safe
Byte-stable ids. A replayed call needs an id, and a fresh random one would change the history's bytes every turn and throw away the prompt cache from lesson 2. The ids are built from the stored message id (replay_<stem>_<n>), so a replayed turn is the same bytes every time it is replayed.
Bounded. A reply replays its last 12 calls. Inputs and answers are what the turn streamed, and the routes keep at most 500 characters of each; an input cut short of valid JSON travels as {"input_excerpt": ...} instead of as broken JSON. Only a reply with text is replayed at all, as before.
One vocabulary. The Claude vessel reaches the family tools through MCP and stores a call as mcp__coop__coop. An Ollama turn in Master Chief copied that name straight from the replay, called a tool it did not have under that name, and was refused twice. Calls now replay under the family's own name for the tool, coop, whichever vessel made them.