Sessions that ran Workflow-substrate pipelines read as near-zero subagent spend: analyze_subagents() globs one level only, while Workflow runs log under workflows/wf_*.json (per-agent summary) and subagents/workflows/<runId>/agent-*.jsonl (raw usage). New analyze_workflows() joins both — raw transcripts authoritative (dedup by requestId, as everywhere), summary supplies stage labels and models, label-prefix grouping (impl:3 -> impl), untracked transcripts isolated under '?'. Report gains workflows[] and workflow_totals; totals now include workflow spend. Live check against a real 17-agent workflow run: raw 1.30M vs reported 1.22M (the live counter's known ~7-11% under-tracking). closes #28
10 KiB
name, description
| name | description |
|---|---|
| postmortem | Use after a working session (or a `/boss` run) to grade how well the toolchain and the dispatched agents actually performed, and how many tokens the run spent. Reads the session's own Claude Code transcript + subagent logs + Workflow run logs, aggregates tokens/tool-health deterministically via a helper script, and writes a scored retrospective. Utility skill, user-invoked or orchestrator-invoked at run close; never a pipeline gate. |
postmortem — grade the run
Violating the letter of these rules is violating the spirit.
Overview
Every session leaves a detailed flight recorder behind — the
JSONL transcript under ~/.claude/projects/<slug>/<session>.jsonl,
one sidechain log per dispatched subagent under
<session>/subagents/, and for every Workflow run a per-agent
summary in <session>/workflows/wf_*.json with raw per-agent
transcripts under <session>/subagents/workflows/<runId>/. Nobody
reads it. So the same expensive
habits repeat: a subagent fleet that bounces BLOCKED, a tool
loop with a 30% error rate, a cache-cold run that re-sends the full
input on every turn. This skill turns that recorder into a graded
retrospective: how well did the toolchain work, how effective
were the agents, and how many tokens did it spend.
It is descriptive, not corrective. It produces a report and, where warranted, recommends filing tracker issues — it does not change code, baselines, or the pipeline.
When to Use / Skipping
Invoke:
- After a substantial interactive session, when you want to know where the time and tokens went.
- At the close of a
/bossautonomous run, to grade the orchestrator's dispatch choices. - When a run felt token-heavy or thrashy and you want the numbers.
Not a pipeline phase. Never a hard-gate. It reads logs; it never blocks a cycle.
The Iron Law
NUMBERS COME FROM THE SCRIPT, NEVER FROM MEMORY OR EYEBALLING THE LOG
REPORT TOKENS AS RAW COUNTS — NEVER CONVERT THEM TO A COST OR PRICE
NEVER READ ~/.ionos_token, .credentials.json, OR ANY SECRET FILE INTO CONTEXT
A GRADE WITHOUT A CITED METRIC IS AN OPINION — DROP IT
DEDUP TOKEN USAGE BY requestId — THE SCRIPT DOES THIS; DO NOT RE-SUM THE RAW LOG BY HAND
What the data does and does not contain
Read before interpreting, so the report never overclaims:
- Present: per-request
usage(input / output / cache-creation / cache-read / server-tool counts),model,requestId, timestamps, everytool_usewith its input, everytool_resultwith the authoritativeis_errorflag, skill invocations, slash commands, and a full separate transcript +agentType/descriptionfor each subagent. Workflow runs additionally carry a per-agent summary (stage label, model, a live token counter) inworkflows/wf_*.json; the counter under-tracks vs. the deduped raw transcripts (~11% in the corpus behind issue #28), so the script treats the raw transcripts as authoritative and reports the counter only asreported_total_tokensfor cross-checking. - Absent:
costUSDis alwaysnull;durationMsis alwaysnull. There is no metered cost in the log, so this skill does not compute one — it reports raw token counts (kept split by class: input / output / cache-creation / cache-read, plus atotal_tokenssum). Wall-clock is derived from timestamp deltas and the report says so.
The streamed transcript repeats the same requestId across
several assistant lines with an identical usage object. The
helper script dedups per requestId; never sum the raw lines.
The Process
Step 1 — Run the aggregator
python3 <skill-dir>/scripts/postmortem.py [--session <id>] [--cwd <project>]
Defaults to the newest transcript in the current project's log
dir — i.e. the session you are in (it will be flagged active,
meaning totals are partial). To grade a finished run, pass its
--session <uuid>.
The default log dir is derived from cwd (the path with / replaced
by -), so a session run inside a git worktree resolves to a
different slug than the primary clone, and after exiting a worktree
the default again follows the current cwd. To grade a worktree run
from the primary clone, pass --project-dir ~/.claude/projects/<worktree-slug> (or --file <path> to bypass slug
derivation entirely).
The script emits one JSON object on stdout. That JSON — not the raw log — is your evidence base.
Step 2 — Read the JSON and grade three axes
Grade each axis on the cited numbers. A grade with no number behind it is an opinion; drop it.
- Token spend & efficiency —
totals.total_tokens, the main-vs-subagent split, the token breakdown (output share is the write-heavy signal),cache_hit_ratio(the dominant efficiency lever: below ~0.7 on a long session means cache-cold turns re-sending the full input),server_tools(web_search / web_fetch counts). - Toolchain health —
tools.error_ratioandinterrupted(the authoritativeis_errorsignal), the tool mix (a Read / Edit / Bash imbalance hints at thrashing or re-reading),slash_commandssuch as/compact(context pressure). - Agent effectiveness — per subagent:
terminal_status(DONE/DONE_WITH_CONCERNS/PARTIAL/BLOCKED/NEEDS_CONTEXT/unknown),total_tokens, andrequests. A fleet that burned real tokens to returnBLOCKEDis the headline finding. Compare each agent's token spend to what it delivered. For Workflow runs, grade per stage instead:workflow_totalsand each run'sstagestable (label-prefix grouping, e.g. allimpl:Nunderimpl) show where the run's spend concentrated;agents_untracked > 0flags retried/dropped attempts. Schema-bound workflow stages carry noterminal_status— the workflow script's own aggregation already judged them.
Step 3 — Write the report
Write a Markdown report to the configured destination (see Output destination). Structure it as Output format below. Lead with the scorecard, support every grade with a number from the JSON, and keep the prose tight — this is a retrospective, not a transcript replay.
Step 4 — Surface, don't fix
Translate the sharpest findings into recommendations. Where a
finding is a concrete, trackable defect (a subagent that reliably
bounces BLOCKED, a tool loop with a runaway error rate),
recommend filing it via the issue skill — name it, but do not
file it yourself unless the user asks. This skill ends at the
report.
Output destination
Resolve in this order:
--out <path>if the invoker passed one.- The project's post-mortem directory, if it has one (its CLAUDE.md project facts).
- Default:
docs/postmortems/<session-id-short>-<yyyy-mm-dd>.mdunder the project root, creating the directory if needed.
Also print a ≤200-word summary to the chat so the headline grade and token spend are visible without opening the file.
Output format
# Post-mortem — <session-id-short> (<date>)
**Scorecard**
| Axis | Grade | Headline metric |
|------|-------|-----------------|
| Token spend & efficiency | A–F | <total_tokens> total, cache hit <ratio> |
| Toolchain health | A–F | <error_ratio>, <n> interrupts |
| Agent effectiveness | A–F | <k>/<n> agents DONE, <tokens> on subagents |
**Token spend**
<main vs subagent split; token breakdown by class (input / output /
cache-creation / cache-read); the one class that dominates and why>
**Toolchain**
<tool mix, error ratio + what the errors were, context-pressure
signals like /compact>
**Agents**
<per-subagent line: type — status — <total_tokens> — one-clause
verdict. Omit if no subagents were dispatched.>
**Recommendations**
<≤5 bullets. Each ties to a cited metric. Mark any that warrant
an `issue`.>
_Token counts are raw usage. Wall-clock is derived from timestamp
deltas, not metered._
If the session is flagged active, add one line at the top:
"⚠️ Session still active — figures are partial."
Common Rationalisations
| Excuse | Reality |
|---|---|
| "I'll just skim the transcript and tally the tokens" | The transcript repeats usage per streamed line under a shared requestId. Hand-summing double-counts. Run the script. |
| "Let me convert the tokens to a rough dollar figure" | Don't. There is no metered cost in the log and prices vary by plan; report raw token counts and let the reader price them if they want. |
| "Cache hit ratio of 0.5 is fine" | On a long session it means half the input was re-sent uncached. That is the single biggest efficiency lever — grade it. |
| "All agents returned, so effectiveness is an A" | "Returned" ≠ "succeeded". A BLOCKED agent that burned tens of thousands of tokens is a failure that still spent the budget. Read terminal_status. |
| "Let me also peek at the IONOS token to check the endpoint" | Never. Secret files are out of bounds — see the Iron Law and the user's global rules. |
| "I found a broken agent, I'll fix its prompt now" | Out of scope. This skill reports and recommends; the fix is a separate, tracked change. |
Red Flags — STOP
- Quoting any token number that did not come out of the script's JSON.
- Converting token counts into a cost or dollar figure — report raw counts only.
- Reading any file under
~/.claudeother than the session transcript and its subagent logs — and never any credential or token file. - Editing code, baselines, or pipeline config "while you're in there". Report only.
- Grading an axis with adjectives instead of the cited metric.
Cross-references
- Helper script:
scripts/postmortem.py— the deterministic aggregator. All numbers originate here. - Hand-off target: the
issueskill, when a finding is a trackable defect worth filing. - Report destination (optional): the project's post-mortem directory, if its CLAUDE.md project facts name one.
- Data-source note: this skill reads only the current session's own transcript and subagent logs. It does not crawl other projects or other sessions (single-session by design).