Session economy playbook¶
A recurring procedure for reading session logs over time, so the plugin gets cheaper to run and re-does less work.
Every instrument this playbook uses already existed as a one-shot command. The loop was missing. The loop is a cadence, a fixed order, a decision rule per signal, and an append-only stream that makes one round comparable to the last. Without those, each review re-derived its own baseline. The question "did anything we changed help?" had no mechanical answer.
This is maintainer tooling for developing this plugin. It is not shipped. It is not a workflow for people who install dev-team on their own projects.
What this is not¶
Do not use this playbook to answer a question that one instrument already answers on its own:
| Question | Use |
|---|---|
| How much did that run cost? | /cost-report |
| How did that run go, step by step? | /run-report |
| What should we change, based on recent sessions? | /session-review |
| Which agents/routing have gone stale? | /harness-audit |
| Which skills and agents are unused? | /artifact-lifecycle |
| Is autocompact configured for this repo? | Context management |
This playbook is the longitudinal layer over those instruments. Run them in a fixed order on a fixed cadence. Persist the comparable subset. Act on the deltas rather than on any single round's absolute numbers.
Cadence¶
Monthly, and additionally whenever one of these lands:
- a change to the autocompact threshold (ADR 0043);
- a model change (a new default model resizes every window);
- a batch of agent, skill, or hook changes so large that you could not attribute a later regression to it.
Monthly is deliberate rather than weekly. The stream is per-session aggregates. A week of one maintainer's work is too few sessions for a percentage to mean anything. A 2-of-9 blocked rate reads as 22% and is noise. A round that cannot distinguish signal from sample size is worse than no round, because the round invites action on both.
The rounds¶
Run the rounds in this order. The output of each step is input to the next.
1. Refresh the session stream¶
python3 plugins/dev-team/scripts/session_report.py --profile maintainer \
--plugin-root plugins/dev-team \
--append .claude/metrics/session-digest.jsonl
This is the same append that /session-review performs at its step 5. The playbook extracts the append so
a round can refresh the stream without also producing a suggestions report.
The stream holds aggregate counts only, with no file names, prompts, or code.
The stream captures these fields. The last column states what each field is for:
| Group | Fields | Reads as |
|---|---|---|
rework |
repeated_file_edits, repeated_verify_runs, retried_bash_commands, failed_edits, permission_denials, compaction_events |
work done more than once — the thing to drive down |
token |
per-model input/output/cache totals | what it cost |
accuracy |
tool_error_rate, user_correction_turns |
how often the loop went wrong |
gate |
commit_attempts, commit_bypasses, bypass_rate |
whether the gates are being obeyed or routed around |
utilization |
agents_invoked, skills_invoked, never_observed_* |
what is actually used |
2. Read the deltas, not the levels¶
python3 -c "
import json, pathlib
p = pathlib.Path('.claude/metrics/session-digest.jsonl')
rows = [json.loads(l) for l in p.read_text().splitlines() if l.strip()]
print(f'== session-digest: {len(rows)} rounds ==')
for r in rows[-2:]:
print(' ', r.get('recorded_at'), json.dumps(r)[:160])
"
A single round's absolute numbers are close to meaningless, because the corpus changes shape every month. The direction of a metric across rounds, against a change you can name, carries the information.
3. Decide¶
Each signal has one rule. Each rule names the action and, where one exists, the ADR whose revisit trigger the rule discharges.
| Signal | Direction | Action |
|---|---|---|
rework.repeated_file_edits / repeated_verify_runs rising |
worse | Run /session-review for the why. This stream says only that it happened. |
gate.bypass_rate rising |
worse | A gate is being routed around. Fix the gate's cost or its correctness — never its enforcement. |
accuracy.user_correction_turns rising |
worse | Instructions are being misread. Candidate for a CLAUDE.md or skill-prose fix, not a code fix. |
utilization.never_observed_* growing |
drift | Feed to /artifact-lifecycle; a never-invoked artifact still costs registry tokens. |
rework.compaction_events high |
compaction threshold too high, or wrong lever | Lower CLAUDE_AUTOCOMPACT_PCT_OVERRIDE via /setup, or write a /handoff summary before long phases (ADR 0043). |
Change one thing per round. If you make two changes between rounds, the next delta attributes to neither. This is the reason the stream is append-only: a round is evidence only if you can pin it to a known before-state.
4. Write down what changed¶
Append a one-line note to the round's PR or the relevant ADR. Include the date, the one change made, and the metric the change was meant to move. Step 2 of the next round reads for exactly that note.
What this playbook cannot tell you¶
A review procedure that implies more coverage than it has is the same failure as a gate that cannot fail. These are the limits:
- Causation. The stream is observational. A metric that moves after a change is consistent with that change, not proof of it.
- Sample size. The stream records no confidence intervals, and a maintainer's month is a small n. Treat a single round's percentage move as a hypothesis, not a finding.
- Session-total cost. No instrument here bounds what a session spends in
total. Autocompact bounds context occupancy, which is a different
quantity.
hooks/lib/cost_meter.pyis the instrument that measures the other one.