The transcript of a running session is readable while it runs - in the panel, and by the supervisor that has to decide whether to step in.
Changed
-
One transcript renderer, in
src/transcript.ts, behind the panel's/api/transcriptandmilestoner transcript. The page no longer decodes anything; a test asserts it never grows a parser back. A line without a top-leveltypeis not an event, so a plain-text transcript and NDJSON of another shape (codex exec --jsonnests its type undermsg) are passed through exactly as written, which is what keeps every agent watchable. -
The default
agent.argsrun Claude Code with--output-format stream-json --verbose. A headlessclaude -pwith the default text format writes nothing until it exits, so the panel's "watch the live transcript" opened a file that was empty for the whole session. It now fills turn by turn while the session works: an event appears when a turn completes or a tool returns, so a long generation is a still frame rather than a stall. -
Infrastructure classification weighs what the agent produced, not what the transcript file holds. A stream-json session opens with a four-kilobyte
system/inittool inventory and closes with aresultenvelope; counted as evidence those alone clearedtinyTranscriptBytesandcrashTranscriptBytes, which would have charged an attempt for every infrastructure death.readTranscriptEvidencediscounts them, so both thresholds keep their existing calibration and a plain-text transcript from any other agent weighs exactly what it always did. See D-040. -
The init inventory is no longer searched for
infraFailurePatternsorusageLimitPatterns. It lists every installed skill and slash command, so a session could be classified from somebody else's prose. Theresultenvelope still is, but only its words -result,subtypeandapi_error_status- and not the kilobyte of costs, token counts and hex uuids around them, any of which can carry the429pattern.
Added
-
A usage limit the agent reports outright (a
rate_limit_eventwith statusrejected, and its epochresetsAt) is checked before the text patterns and outside thedeathSecondsbound they sit behind, so a quota that ran out mid-session refunds the attempt and waits for the announced reset. Onlyrejectedcounts:allowed_warningmeans the limit is near, not reached, and a session runs straight through it. The last event decides. -
milestoner transcript [--name <file>] [--lines <n>] [--raw]prints what the running session is doing, as prose rather than as its wire format: the agent's own text,>for a tool call and<for its result, cut to 240 characters. Its first line names the session and says whether it is still going, so a transcript quoted in an intervention cannot silently be a finished one;--rawomits it. Read-only, and outside the supervisor's intervention set on purpose - knowing what a session is doing has to be free to be done every cycle. -
The panel follows an open transcript while the session runs, refreshing every 2.5s, and shows the same rendering the command prints. The scroll sticks to the bottom only while the reader is already there, and following stops when the pulse says no session is writing to that file - which also ends the pointless follow of a transcript opened from the attempt history.
-
The bundled supervisor skill reads the transcript every cycle and quotes what it saw when it intervenes. It also no longer claims a transcript proves nothing: liveness and diagnosis are now two separate questions, with the transcript answering only the second. Re-run
milestoner skill install --forceto pick this up - the installer will not overwrite a skill you already have. -
milestoner lintwarns (agent-not-streaming) when aclaudeagent is configured withoutstream-json, which is what an existing.milestoner/config.jsonwritten before this release will be.
Upgrading
- Re-run
milestoner skill install --forceto replace an already-installed supervisor skill; the installer will not overwrite one you already have. - Existing
.milestoner/config.jsonfiles have no streaming flags.milestoner lintwarns (agent-not-streaming), but it is a warning: the run still starts, the panel just stays empty until the args are updated.
Compatibility
Only Claude Code's stream-json is decoded. A line without a top-level type is not an event, so plain-text transcripts and NDJSON of another shape pass through byte for byte and no agent is worse off than before. The per-agent table is in the guide, under Running a different agent.