analyze-arcs
Skill11 starsChanged 2 months agoMITView on GitHub
Measure the Claude Code pipeline sessions since a date — master transcripts, their subagents/*.jsonl, and the codex-challenge logs — and report the numbers plus the mechanical doctrine violations. Invoke on "analyze the sessions", "how did the last arcs go", "evaluate the pipeline", "/analyze-arcs <since-date>", or before any kit change that claims to fix a pipeline problem.
In this repository4 other files it gives its agents.
- global/CLAUDE.mdCLAUDE.md
- agent-teamsSkill
- feature-workflowSkill
- stack-updateSkill
The file
We split this skill into the rules it gives an agent
1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 125
Every transcript field the analyzer reads is observed, not documented: "The entry format is internal to Claude Code and changes between …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Analyze arcs
The scripts are read-only. Times in the report are UTC; transcripts are under
~/.claude/projects/<project>/<session>.jsonl with subagent transcripts beside them in
<session>/subagents/. The master transcript is a partial record: owner↔subagent messages
and everything a subagent did live only in the subagent files, so never judge an agent from
the master's view of it.
Procedure
- Version diff first.
claude --versionagainst the stamp in the kit'sdocs/references.md; if they differ, read the changelog between them before blaming the doctrine for a harness change. Run the measurement into the session scratchpad:
python3 ~/.claude/skills/analyze-arcs/scripts/analyze.py --since YYYY-MM-DD --out <scratchpad>/arcs/report.mdOne section per session id: copies of a transcript under several project directories are reported once, from the largest (then the lexicographically last directory), and the header counts the
<id>.jsonlcopies skipped. A set-aside<id>.orphaned-…jsonlcopy, a previous transcript of the session, never beats a live<id>.jsonlwhatever the sizes; it is read only for an id with no<id>.jsonl, and the header counts set-aside copies on their own line. Per session: span, models, Claude Code version, peak context, subagent roster (type, pin, turns, minutes, KB, model actually seen), everycodex-challenge.shlaunch with its range,--out, run minutes and verdict size, every gate with how long it waited, pushes, killed background tasks. Then the flags — mechanical checks only:- unpinned
Agentspawn, or a pin off the doctrine tier (plan-reviewer unpinned — it inherits the session's model, team-revieweropus, executors, fixers and triagesonnetunless the plan marks a step Opus or a same-mechanism fixer round calls for it) with whether the prompt states a reason (a reason keyword, or "Opus" followed within 20 characters, in its sentence, bybecauseor a colon) - named spawn (delivery rerouted to the mailbox)
codex-challenge.shrun in the foreground;--outoutside the session scratchpad- master
Edit/Writeon a product file afterfeature-workflowloaded — or a Bash command that changed one, read from the harness's own changed-file record (bashEditDiff.changedFileson the tool result; 2.1.269+). The auto-mode prompt steers edits through Bash, so the Edit/Write check alone is blind. "Bash writes: not recorded" means no Bash result carried abashEditDiffrecord (one that lists no file, such as a lonesharedorunavailable, still counts): Claude Code before 2.1.269; a permission mode other than auto andbypassPermissions, the only two that record by default (bashEditDiffEnabled: truein user or managed settings records in every mode); or no Bash command in the session changed a file (read-only commands carry no diff). Gaps in the record: a command that exits non-zero gets no record even when it changed files, and arun_in_backgroundcommand gets none either; a record markedunavailable("Set when the diff is incomplete or couldn't be taken") orskipped(a git command that moves the working tree takes no diff) can list fewer paths than changed, or none; at most 200 paths are listed; files Git ignores and files in submodules are never listed. The record is best effort and also lists files git moved or another process wrote while the command ran, so two exclusions run after both scans (an excluded path counts nowhere: not in this flag, not in the first master edit or the missing-call-line check, not as the end of a plan-mode span): a path is dropped when a subagent of the same session wrote that exact path while the call ran (the two tool_use-to-tool_result windows overlap; a subagent write with no result, or an errored one, drops nothing); every path of a command that cannot write a file by hand is dropped — each segment is acd, agitcall from a closed subcommand list (those that move files git owns, such asmergeandcheckout, and those that write no working-tree file, such aslogandcommit;rm,mv,clean,config,applyandamstay counted), or a read filter (head,tail,cut,wc,grep,rg,tr,cat,echo,printf,true,ls,column,jq,sort), with no option or leading assignment that names a file to write or a program to run (--output,rebase --exec,git -c,sort -o,rg --pre); no operator redirects output to a file or starts a background job, and each$(...)or backtick inside passes the same test. The lists are closed: any other command (sed,tee,uniq), or text that does not parse, stays counted. A path that survives from a record the harness markedshared(another Bash call ran in the repository at the same time) gets(shared)on its flag line. Plan files,docs/prompts/,docs/reviews/,docs/todos/, handoff docs, the TODO/tech-debt index,/tmp/and build artifacts are not product files - master
Readof a product file, or a Bash read command (cat/head/tail/less/sed/grep/rgparsed from the command text — the harness records writes only, never reads) inside a plan-mode span (anEnterPlanModewhose call was not denied, to theExitPlanModethat was itself approved — checked only in thetool_resultlinked to thatExitPlanModecall bytool_use_id, so the approval string appearing elsewhere, e.g. in a Read of this script's own source, is not a false close; a rejected exit does not end the span either). When no approved exit ever follows — including a Shift+Tab exit, which leaves noExitPlanModecall at all — the span ends at the first proven-successful product-file edit after it (an Edit/Write/MultiEdit/NotebookEdit whose owntool_resultwas not an error, or a Bash write the harness'sbashEditDiff.changedFilesrecord shows and the exclusions above keep; the harness blocks product edits while still in plan mode, so one proves plan mode had already ended — except in an interactive terminal session with bypass permissions available, where Claude Code does not enforce plan mode's blocks and an edit can run during planning, so the span can end too early there), or end of transcript if there's no such edit either. The command text goes through a quote-aware tokenizer, not a regex: segments split on unquoted&&/||/|/;/newline, operands come fromshlex, each option's value is consumed with it (head -n 5 freadsfonly), redirections are not operands (2>/dev/null; a<fredirect is a read), and forgrep/rg/sedthe first operand is the pattern or script unless-e/-f/--regexp=/--expression=already gave it. A bare recursive search with no path (rg needle) reads.. Same exemptions as the Edit/Write check. Gaps: a read inside a heredoc, apython3 -script, or behind an unexpanded variable (cat $f) is invisible — nothing tokenizes those; a segment with unbalanced quotes claims nothing; acd dir && cat frelative path is reported as written, not resolved against thecd; a session that entered plan mode via Shift+Tab has noEnterPlanModecall and is not windowed at all;product_file()normalizes the path, then exempts any path containing/.claude, so a product repo's own.claude/files are invisible to this flag ExitPlanModeorAskUserQuestionthat waited more than an hour, or was never answeredfeature-workflowloaded with no one-shot/pipeline call line before it; product edits with no call line at all- subagents that died on an API error before doing work; subagents that hit their turn cap
--semanticupgrades the reason-stated and one-shot/pipeline-call-line checks above to a typed judgment from the local-only semantic layer (jev.py/semantic.py), expected at~/.claude/local/analyze-arcs/. Without it, the command's output and network use are unchanged.- unpinned
- Read the timelines at the flagged times. A flag is a place to look, not a verdict:
works on a master or a subagent file; thenpython3 ~/.claude/skills/analyze-arcs/scripts/timeline.py <session>.jsonl <scratchpad>/arcs/<name>.txtawk/grepthe time window. Read the subagent transcript for any spawn whose roster row looks off (long, huge, capped, wrong model). - The judgment findings the script cannot make — check them by hand every time: a verification step that proved only the negative path (curl, unit suites) before a deploy; a review escape (what codex rounds missed and why); whether a long gate wait was a legitimate taste gate or a delegated approval the master should not have blocked on; whether an off-tier pin's stated reason holds; whether a relaunch or respawn was warranted by the agent's own timestamps.
- Report with the numbers, held vs failed, ranked by cost. Every doctrine change proposed from it goes as before/after text through "would removing this line cause mistakes?", and the measured evidence goes into a memory note so the next run has a baseline.
Limits
--min-kb 150 skips small sessions unless they spawned subagents; lower it to see one-shots.
Codex run minutes come from the log file's birth and modification times, so a run whose
--out was reused or deleted reads ?. Spawn rows are matched to subagent transcripts by
order of start time; a spawn that died before writing a transcript shifts the rows after it —
compare the model seen column with the pin when that happens.
Summing tokens by hand: Claude Code writes one JSONL line per content block, each repeating the
response's usage, so count each message id once. In subagent transcript lines whose version is
below 2.1.307, output_tokens holds a stream-start value, not the final count: turns, context size
and cache reads are reliable there, output is not.
Every transcript field the analyzer reads is observed, not documented: "The entry format is internal to
Claude Code and changes between versions" (the bashEditDiff fields are documented as hook input, not
as transcript entries). After an upgrade, check a count that falls to zero against a raw transcript
before reading it as a quiet week.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

