Productive-Session Patterns
What a productive human-driven agent session actually looks like — measured,
then distilled into authoring rules for bots. This is the “what works”
companion to workflow_authoring_pitfalls.md
(“what fails”), and the empirical backing behind ADR-055 (unit-convergent
improve loop) and ADR-057 (axis-driven work-list sweep).
Provenance. Mined from the operator’s local Claude Code transcript archive
(2026-04 → 2026-07): ~2 900 top-level sessions, of which ~1 200 are manual
(human-piloted, across ~15 repositories in several languages/stacks) and
~1 500 are bot-generated (iterion nodes delegating to claude_code — worktree,
dispatcher, and project-store runs). Manual campaign sessions were also read
qualitatively (14 sessions with ≥24 commits each), as were failing and
succeeding bot transcripts. All identifying material stays out of this doc by
design; only shapes and numbers cross over.
1. The measured signature of a productive session
Interactive manual sessions (≥3 human messages, ≥0.5 h active): ~3.3
commits per active hour, sustained. Key shape numbers:
| metric |
manual sessions |
bot sessions (pre-ADR-055/057) |
| commits / active hour |
3.0–3.8 |
0.08 (worktree loops) — 1.1 (dispatcher) |
| read : edit ratio |
0.8–1.0 |
3.5 |
| todo-list events (share of all actions) |
4.6 % |
0.2 % |
| commits with a todo-list refresh in their window |
56.7 % |
13.3 % |
| commits with a test run in their window |
40.7 % |
35.6 % |
| median edits per commit |
3 |
0 |
| time to first commit |
median 46 min (p25 29, p75 84) |
n/a (most never commit) |
| inter-commit gap once cruising |
median 11.9 min (p25 5.9, p75 20.7) |
n/a |
Robustness facts worth designing around:
- Flat endurance. Manual throughput stays ≈3.4 commits/h from 30-minute
sessions to 48-hour campaigns. The pattern scales; context compactions do
not dent it (compacted = simply the long sessions, same commits/h).
- The pattern dominates the model. Productivity varies little across model
families in the corpus; the working shape, not the model tier, is the lever.
- Sub-agents pay. Sessions spawning ≥3 sub-agents run ~26 % more
commits/h than sessions spawning none (exploration offloaded, main context
preserved).
- Steering is front-loaded. Human corrections per hour decrease with
session length (~1.0/h in short sessions → ~0.35/h in very long ones), with
a small end-of-session burst for validation/merge. Once framed, a campaign
runs itself.
2. Campaign invariants (from qualitative reads)
Fourteen high-throughput campaign sessions (≥24 commits each) share eight
structural invariants:
- Parallel-explore opening, then a written plan, then approval — never a
direct fix. Typically several read-only explore/plan agents in parallel,
findings verified against the real code (“load-bearing claims” re-checked),
a plan written to a file, 0–2 scoping questions, explicit go. The first
commit lands ~45 min in; ~18 edits typically precede it.
- Phase 0 is foundation, not feature. The first commit is structural: a
documentation schema, a pure-additive interface that de-risks the later
refactor, a workspace scaffold.
- One repeated work unit: locate the exact insertion points → implement →
build → test → semantic commit (
type(scope): …). Small atomic units
(median 3 edits per commit); validation precedes the commit, not the
reverse.
- The unit of work mirrors the brief. Feature work → one phase;
validation campaign → one subject; review campaign → one finding/MR;
migration → one repo/wave. The operator sets the grain implicitly; the
session sticks to it.
- The todo list is the metronome. It is born from exploration (not
before it), stays dense and moving (re-prioritized, items deferred), and
is refreshed at unit boundaries — 57 % of commits have a todo refresh in
their immediate window.
- Terse steering, standing autonomy. Most human turns are one-token
go/status signals; long messages appear only for the initial brief, a new
sub-mission, or a factual correction. Recurrent batch grant: “do all the
items, one by one, until everything passes”.
- Ritualized closure. Convergence = proven green (tests/CI/e2e) + merge
or handoff + a persistence artifact: memory update, dated bilan,
pitfalls-doc entry, or a gitignored handoff file priming the next session.
Productive sessions never end dry.
- Real execution is the value engine. The deep bugs only surface when the
thing actually runs (a live run, a deployment, a CI pipeline) — never from
reading. Every campaign variant embeds a real-run feedback loop, and the
tightest-loop sessions (CI grinding with pasted logs) are productive with
almost no plan at all: feedback-loop latency substitutes for planning.
Campaign variants: epic (phased plan, heavy todo), review (N parallel
reviewers + explicit false-positive verification, then fan-out into isolated
fixes/MRs), migration (distrust-and-verify knowledge base first, then
repo-by-repo waves with “trap” notes committed as docs), validation (dated
bilans as the primary deliverable), CI-grind (no plan, human pastes failure
logs, minutes-long iteration).
3. Where bot sessions lose (gap analysis)
Reading failing bot transcripts against the manual baseline shows the deficit
is framing, not capability — the failed sessions contain correct, tested
code that simply never lands. The recurring gaps:
- G1 — No materialization stage. Code-writing nodes without a commit step
leave finished work stranded in the worktree. (Fixed for the improve loops
by ADR-055/057’s per-item verified commit; any new code-writing bot must
include an equivalent stage.)
- G2 — No termination contract. Nodes without a required structured
output leave the engine unable to detect completion: the same instruction
gets re-injected, the agent re-does or re-verifies work, and the session is
eventually killed mid-flight with nothing banked. Every node must end on a
machine-checkable output.
- G3 — Redundant re-reading. Failing sessions re-read the same large
files 15+ times (read redundancy ×2) — a symptom of over-broad scope and
lost anchors after failed edits. Narrow the per-item scope instead of
prompting “read less”.
- G4 — Fighting the environment. Large time sinks on unprovisioned
sandboxes (read-only caches, missing toolchains, purged temp dirs). This is
an engine/infra fix, never a prompt fix.
- G5 — Self-exoneration spirals. Without a baseline of pre-existing test
failures, a diligent agent burns its budget proving failures aren’t its own.
Give nodes the baseline as input and explicit permission to skip what they
didn’t break.
- G6 — Frozen upfront plan vs living list. Failing bots create 5–6 coarse
phases upfront and tick them; the productive shape is a dense, re-prioritized
work list. In the corpus the correlation is stark: dense todo ↔ frequent
commits.
- G7 — Contradictory injected instructions. Missions assembled from
successive injections (“produce the plan, do not modify files” … “now
implement it”) confuse the turn loop; a node’s mission must be one coherent
contract.
- G8 — Commit cadence absent from the contract. The one bot session in
the corpus that matched manual throughput (7 real commits/h-equivalent) was
the one whose brief imposed operator-style waves: test → commit → todo
refresh, repeated. Cadence must be in the contract (agent-side) or enforced
deterministically (engine-side).
4. Authoring rules derived (the “do” checklist)
For any bot whose nodes write code, alongside the anti-Goodhart checklist in
workflow_authoring_pitfalls.md:
- Encode the work-list sweep, not open review for whole-codebase change:
determined axis → enumerate concrete sites → transform/verify/commit each →
re-enumerate as the done-oracle (ADR-057).
- One verified commit per work item — match the measured cadence (small
atomic units, ~3 edits/commit, minutes not hours apart). An interrupted run
must have banked every completed item.
- Termination contract on every node: required structured output; the
engine detects completion rather than re-poking.
- Give the fixer the baseline (pre-existing failures, known flakes) plus
explicit skip permission — and bound the “is it mine?” investigation.
- Budget a real opening phase. Manual sessions spend ~45 min
understanding before the first commit; an enumerate/plan node needs an
equivalent whole-repo, adaptive exploration (and it should emit the
work-list from it).
- Prefer a living work list over frozen upfront phases: items get
appended, re-ordered, deferred as the sweep learns.
- Close with a persistence artifact: report, bilan, board update, or
handoff file. A run whose learnings evaporate with the worktree did not
finish.
- Shorten the real-feedback loop before enriching prompts. A tight
run-observe-fix loop outperforms a richer plan (the CI-grind result); in
bot terms: deterministic verify gates close to the change, real runs over
static analysis, fast re-entry after failure.
- Offload exploration to sub-agents where the backend allows it — keep
the main context on the transform, not the search.
- Fix the environment in the engine, not the prompt (G4): provision
toolchains/caches before delegating; an agent fighting its sandbox is an
infra bug report, not a prompt-tuning opportunity.
5. Reproducing the measurements
The mining pipeline (transcript census → per-session metrics → event
timelines → qualitative reads) is deliberately simple: parse the local
~/.claude/projects/**/*.jsonl transcripts, count tool uses by kind, detect
git commit/test invocations in Bash inputs, compute active time by clamping
inter-event gaps, then read the outlier sessions. Anyone can re-run the idea
on their own archive; the scripts are session-scratch, not part of this repo
(and transcript archives must never be committed — they contain private
project material).