Claude Code added 33 fields and 4 line types to your local logs in eight days

I read the JSONL under ~/.claude/projects for a living, more or less, so I diff the field names every time Claude Code updates. It updates every couple of days. Between 2.1.237 (Aug 21) and 2.1.251 (Aug 28): four new line types, 33 new fields. 2.1.237 => turnCompanion on user lines 2.1.241 => bridge-session line type, system.url 2.1.246 => cost-state line type, three artifact-* types 2.1.247 => queueSkipAttachments on user lines 2.1.250 => reason on queue operations 2.1.251 => truncatedAfterOutput on assistant lines The one most people will want is cost-state. It writes the dollar cost of the session to disk, with per model usage, API duration, lines added and removed. Two things to know before you build on it: it's written at exit, so 83 of my 97 sessions on 2.1.251 don't have one at all, and totalDuration counts how long the terminal stayed open, not how long anything ran. Also new is output_tokens_details.thinking_tokens, which splits your output tokens into reasoning and answer. On my machine thinking is 42.6% of all output tokens, across 13,836 calls. If you go measuring this yourself, watch out that the usage block repeats identically on every line belonging to the same API call, 1.75 lines per call here. Summing per line got me 48.6%. Deduplicating by requestId got the 42.6%. Now the part I actually came here to post about, because it isn't in that table and a field-name diff will never put it there. Two things broke my parser this month and neither one was a new field. First: since 2.1.237, a slash command defined by a .md file carries origin: {kind: "human"} on its user line. Zero of 52 such lines had an origin up to 2.1.234, then 25 of 25 from 2.1.237 on. Built-ins like /clear, /model and /usage carry nothing in either era, 0 of 586. My code checked that field before it checked the shape of the command, so from one release to the next every custom command started getting filed as an ordinary prompt. Nothing was added anywhere. An existing field just began carrying a value it had never carried. Second, and this is the one that hurt: 2.1.251 stopped writing stop_reason: "end_turn" on the lines of a subagent's own transcript. 0 of 29 subagent transcripts on 2.1.251 have it. 202 of 207 do, across the fifteen releases before that. I was pulling the subagent's returned answer off exactly that marker, so the share of subagents whose output I could show went from 83-100% per release to zero. A subagent that ran six minutes displayed as having returned nothing, with its duration, its token counts and its tool calls all sitting there correct right next to it. The text was there the whole time. Only the marker naming it went away, which is why my field-name diff slept straight through it. What I use now doesn't need a marker: the answer is the last text block with no tool call after it. It agrees with end_turn 202 times out of 202 wherever end_turn existed, and it puts 2.1.251 at 76% instead of zero. Not higher because it selects rather than accepts. 241 of the 253 subagents in my corpus have exactly one block that survives it, and the remaining 12 end on a tool call, which is a subagent that never answered. Two other things quietly stopped happening in the same window. These are features, not schema, so take the numbers as local to me. The Agent tool's run_in_background parameter shows up 100 times on my machine up to 2.1.233 (84 false, 16 true) and in none of the 39 Agent calls from 2.1.245 on, which is why the inline subagent result is gone. TaskCreate appears in 5 sessions up to 2.1.231 and in 0 of the 611 sessions I have between 2.1.239 and 2.1.251. Absence in one person's logs obviously isn't proof of removal. If you still see either, say so. Last one, and it looked like nothing when it turned up. atis-latch arrived in 2.1.235 and I have 2,578 lines of it, every one carrying a single field whose value is the empty string. Running strings over the CLI binary explains it: the value goes back to the API as an x-cc-atis request header, it comes from server-provided client data rather than from anything on your machine, and it's latched per conversation next to the sticky beta headers, so a fork or a resume keeps sending the same one. When the server never sends a value, Claude Code latches the empty string, which is all I have ever had. It sits behind a feature gate too, so your mileage will vary. If yours is non-empty I'd genuinely like to see it. (I keep this diff running because I built a thing that reads these logs live and a schema change breaks it silently: github.com/duqaXxX/seedeep. None of the above needs it, just jq and the files already on your disk.)

添加评论
点赞收藏
点踩分享查看原文
评论
?
参与讨论