cyberine
UsageRun recipes

A non-success result subtype is a failed run (kq5rd)

parseClaudeStreamJson used to take the last type:'result' event and read its result field without looking at subtype. An error subtype carries no result (Claude Code puts errors[] there instead), so error_max_turns or error_during_execution came back as an EMPTY SUCCESS, and Claude Code 2.1.272 added a third shape, turn_preempted. Now every subtype other than success -- including one this code has never heard of, because Claude Code's own schema says more will be added -- makes the parser return an error naming the subtype (plus the errors[] detail, bounded), and CliAgentAdapter turns that into a Result with status: 'error', the turn's usage kept for spend accounting, and raw.turnFailed: true. Both spawn paths (run/runStreaming and runDetached) take it, and so do the other Claude-Code-shaped workers that reuse the parser.

A warm-resume turn that fails this way is returned as-is: the session was valid and the turn ran, so re-spawning cold would only pay for the same failure twice. The session cache entry is kept.

Run recipe -- nothing to enable. To see both halves (parser fixtures, and a fake CLI driven through the real adapter, warm path included):

npm run selftest:result-subtype

Known limitations and deferred work:

  • A result event with NO subtype key is still read as success, so a dialect that never sends one keeps working. Only a present, non-success value fails the run.
  • The autopilot session drivers (sessionDriver.ts, streamSessionDriver.ts) are unchanged: they judge a turn by is_error, and a preempted turn there is one the driver caused itself, so counting it into the error streak is a separate decision.
  • permission_denials is still not read (see the previous section).