Skip to content

A running coding loop is opaque over MCP — coding_timeline is written during the run and no MCP tool reads it #581

Description

@serge-ivo

A live coding run is opaque over MCP, and the data it needs is already being written

Owner's ask, recorded by their own agent as feedback fd60c895-bc18-4ee3-b4f1-de9b351ad4f7
(2026-08-15 02:19, instance bd43f4de-ef35-4051-bdec-43f8571414a1, status:"open") and repeated
directly to me on 2026-08-15:

expose a live, per-step trace of a loop run to the owner — each iteration's tool calls with
arguments and results, and streaming or incremental output — through the same MCP surface that
starts the run. agent_trace exists for chat turns; loop runs need the equivalent, queryable
while the run is still in flight
, not just after it ends.

What an external MCP client can see today, while a run is running

Tool What it gives Gap
coding_loop_status / check_instance_loop status, iteration, lastProgressAt, detail (only once finished) No steps, no tool calls, no output
coding_session_capture last pane text + runState A rolling terminal buffer, not a record; needs the session id
agent_trace source:"coding" act.consequential rows, and errors only via lib/coding-failure.ts:341 on a classified failure Nothing per-step; a run that stalls writes nothing
instance_activity chat-session events only Feedback: "shows nothing at all from loop runs, so during a run it looks idle even though work is happening"

Measured consequence in #580: a run whose engine died at step 1 reported running for 4.35 hours,
and the only place the truth existed was the pane.

The data is already recorded — it just has no MCP reader

coding_timeline (migration 0023, append-only, seq-ordered) is written during the run.
workers/api/src/routes/coding.ts:416 is explicit:

/** Persist a system/status message to the coding timeline (loop events, errors). */

There is an API route — GET /:instanceId/coding/sessions/:sessionId/timeline
(routes/coding.ts:430) — backed by loadTimeline in lib/coding-timeline.ts.

$ grep -rl 'coding_timeline' workers/mcp/src/
(no matches)

Thirteen coding tools on the MCP surface and none of them reads it. This is the same absence
#527 names for the finished-run case. #527 and this issue are one tool apart: a
seq-cursored reader answers both, because "audit a finished run" and "watch a running one" differ
only in whether you keep asking.

Design

One tool, cursor-paged the way instance_messages now is after #566:

coding_timeline(instance_id, session_id?, since_seq?, limit?) → { events[], nextSeq, hasMore, runState }

Payload-size constraint, learned the hard way today

#569 measured list_instance_tools at 66,042 B in production — over the 64 KiB wire limit — after
a guard passed at ~54 KB, because jsonText pretty-printed after the assertion. #578 is open
on the same tool 433 B over on its opt-in path. A timeline reader is unbounded by nature, so:

  1. limit must have a real default and the response must be measured on the deployed tool, not
    on the API body.
  2. Terminal snapshots are the bulk. Consider returning them by reference or truncated-with-a-count
    rather than inline, and state the decision.

Acceptance criteria

  1. An MCP client can read a coding run's per-step record while the run is in flight, without
    knowing a session id in advance.
  2. since_seq returns only newer events; repeated polling with the returned cursor never
    re-delivers or skips. A test drives two overlapping pages and asserts disjointness, as instance_messages returns nextCursor and hasMore: true and has no cursor input — every message older than the first page is unreachable over MCP #566's
    fix does.
  3. The response distinguishes no new events because idle/dead from no new events because a step
    is long
    .
  4. Response size asserted against the wire limit, measured at the layer the client receives, with
    the denominator stated per ADR 0002.
  5. A finished coding run is unauditable over MCP — 13 coding tools, none reads coding_timeline, and coding_session_capture answers an ended session with an empty pane #527's finished-run audit case is satisfied by the same tool, or the issue states why it needs a
    second one.
  6. A test reproduces A run whose engine died at step 1 reported 'running' for 4.35 hours with a fresh lastProgressAt, and wrote nothing to the trace #580's case: engine dies at step 1, and the timeline read shows the terminal
    error rather than silence.

Verified vs inferred

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions