Ever asked a coding agent a question, watched it run a few tool calls… and then it just stops without ever answering you? That's a harness-loop failure. Step through the agent loop below and flip the "forgets to reply" bug on to see exactly where it breaks.
A CLI agent is a while-loop around an LLM API call. Each iteration: send conversation + tool results → model returns either tool calls or text → harness executes tools, appends results, loops again. The loop only ends when the model emits a plain text message with no tool calls.
The model must learn that text output = message to the human. If a model was trained mostly on autonomous long-horizon tasks, it may treat a question as a task: gather info via tools, conclude internally, then emit an empty or stop response — never routing the answer back as text. To the user it looks like silence.
Harness ends turn when: (a) model returns no tool calls, or (b) max iterations hit. If the model returns zero tool calls AND zero text, most harnesses still end the turn — silently. Robust harnesses detect this and inject a nudge: "You must respond to the user now."
Practical prompts that force a reply: "Answer in chat, don't just use tools", or end with "then summarize your findings to me." Explicitly naming the deliverable ("reply with a 3-line answer") anchors the model's final text emission.
The loop illustration has five named nodes: user, model, tools, result and reply. Six directed links connect them. Tool output returns from result to model, while a final reply travels from model through reply back to user. At fifty pixels per item the node bar is two hundred fifty and link bar three hundred. This is a Three.js diagram of a predefined story. The model and tools labels do not represent actual provider requests, file reads or shell execution. The script defines sixteen callback steps and two named tool actions: read file then grep. The read file message assigns twelve hundred four lines, and grep reports a missing zod dependency. Neither action accesses a file. At twenty pixels per callback sixteen measures three hundred twenty, while at one hundred pixels per action the two tool calls measure two hundred. Callback travel steps are animation stages rather than model turns, and a fixed packet interpolation increment determines motion rather than measured inference latency. The failure toggle changes callback fourteen to an empty response and logs that a turn ends without text or tool calls. In the normal branch the last callbacks route a text reply through the reply node to user. One final response is the observable outcome; two tool messages alone do not supply it. At one hundred pixels per count two tool actions measure two hundred and one final reply one hundred. Three.js construction occurs before button listeners. With its external dependency aborted locally, stepping and running remain inert, so offline preservation of the original blank stage is distinct from actual loop operation.