Skip to content

docs: halve CLAUDE.md; disclose the release runbook - #450

Merged
lesnik512 merged 1 commit into
mainfrom
docs/compress-claude-md
Aug 31, 2026
Merged

docs: halve CLAUDE.md; disclose the release runbook#450
lesnik512 merged 1 commit into
mainfrom
docs/compress-claude-md

Conversation

@lesnik512

Copy link
Copy Markdown
Member

Why

CLAUDE.md is loaded on every turn, and it ratchets. Size at each commit that touched it:

Date Bytes
2026-03-20 4,562
2026-06-25 8,420 (pre-compaction peak)
2026-06-25 6,203 (#239, "docs: compact CLAUDE.md")
2026-08-30 12,312

It doubled in nine weeks; #449 alone added 39 lines by inlining planning/README.md. Nothing in it
was stale — I re-checked every claim (justfile recipes, asyncio_mode, line-length, select,
--cov-fail-under=100, the validate= deprecation at modern_di/container.py:110, the four
registries, the 12+1 integrations). The problem is that half of it cached a lookup it already points
at, so each rule lived in two or three places and could rot in all but one:

  • The "do not extract a helper" warning appeared three times: CLAUDE.md, the
    resolver_compiler.py module docstring, and test_resolve_costs_exactly_one_resolver_frame_per_node.
  • wiring.py, dependency_graph.py and integrations.py bullets restated their module docstrings
    near-verbatim; scope.py — "Scope enum" — restated the filename.
  • ## Commands named the justfile as source of truth, then copied its recipe comments verbatim.
  • ## Project Overview duplicated CONTEXT.md's opening plus a 13-integration roster that ls docs/integrations/ gives free — a maintenance liability with no decision value.

The file was failing its own admission check ("Can an agent get this by reading modern_di/? → don't
write it").

Design

Two moves: prune the caches, and disclose what only some runs need.

Section Before After
Key files 3,985 1,410
Cutting a release 1,360 0 (→ docs/agents/release.md)
Where a fact goes 1,648 1,324
Commands 736 395
Project Overview 488 404 (absorbs ## Vocabulary, 240 → 0)
Agent skills ×3 519 476
Architecture / Testing / Code Style 2,084 1,576
Total 12,312 6,485

Key files keeps only the five rules a single-file read cannot give: the resolver_compiler frame
budget and its new-provider-type branch, exceptions.py owning every message and glyph, the
shared-vs-per-container registry split, dependency_graph walking WiringPlan.edges, and UNSET as
the shared miss marker. Everything derivable from opening the module is gone.

Cutting a release fires a few times a year and cost every turn; it moves verbatim to
docs/agents/release.md (a tree already excluded from the mkdocs site) behind a one-line pointer.
The INVARIANT: docstring-shape prose now cites tests/test_invariant_census.py, which owns and
enforces that shape, rather than restating it in nine lines.

Two additions rather than cuts. "Prose about mechanism has no home" now names this file as subject
to the same rule — that omission is what let it double. And the "read CONTEXT.md before naming a
concept" trigger from the deleted ## Vocabulary heading moves into Project Overview so the
pointer survives its section.

One factual correction: the old line "Every module under modern_di/ except the package
__init__.py re-exports" reads as though every module is re-exported. __init__.py exports only
Container, Group, Scope, exceptions, integrations, providers. The replacement sentence
makes no such claim.

Non-goals

  • No rule changes. Every convention that survives says what it said; this is deletion and
    relocation, not redesign.
  • No new enforcement. A test that caps CLAUDE.md's size or diffs it against module docstrings
    would stop the ratchet mechanically, but it would fail on legitimate growth and nothing in the repo
    currently gates prose. Left for a follow-up if the file regrows a third time.
  • No changes under modern_di/. Where a bullet was the only home for a fact, the fact stayed in
    CLAUDE.md; nothing was pushed into a new module docstring.
  • docs/agents/release.md is not link-checked, same as the rest of that tree — a gap this PR
    documents in ## Commands rather than closes.

Verification

  • just test-ci — 512 passed, 100.00% line coverage (6030/6030). No Python changed.
  • just lint-ci — ruff format, ruff check, ty all clean.
  • just docs-buildmkdocs --strict builds; docs/agents/ stays excluded from the site.
  • All ten relative link targets in the rewritten file resolve (checked by hand — nothing validates
    root Markdown).
  • Both inbound references still land: docs/adr/0011 cites the registries entry (kept) and
    .github/PULL_REQUEST_TEMPLATE.md cites "Where a fact goes" (kept).

https://claude.ai/code/session_01FdBFyAZ6nntxXwPjy6Xm7p

CLAUDE.md had ratcheted from 4.5 KB to 12.3 KB, with a compaction in June
(#239) undone twice over. Roughly half of it cached lookups it points at:
module docstrings, justfile recipe comments, pyproject settings.

12,312 B -> 6,485 B. Key files keeps only the cross-file rules a single-file
read cannot give; the release runbook moves to docs/agents/release.md behind
a pointer; Vocabulary folds into Project Overview; the three agent-skill
subsections collapse to pointer bullets.

Claude-Session: https://claude.ai/code/session_01FdBFyAZ6nntxXwPjy6Xm7p

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Details
Benchmark suite Current: 0387d0d Previous: 1ea74ee Ratio
benchmarks/test_guard_by_type.py::test_g16_resolve_by_type 3150962.552859924 iter/sec (stddev: 1.1851549894469189e-8) 3150940.0152010303 iter/sec (stddev: 1.0730284239262876e-8) 1.00
benchmarks/test_guard_by_type.py::test_g17_resolve_by_type_large_registry 3145391.77145479 iter/sec (stddev: 1.662659220005772e-8) 3153308.3328560423 iter/sec (stddev: 1.3869427385051052e-8) 1.00
benchmarks/test_guard_cold.py::test_g8_cold_first_resolve 22768.35790854921 iter/sec (stddev: 0.00000493342946672016) 23399.43754533766 iter/sec (stddev: 0.000004615339361367785) 1.03
benchmarks/test_guard_cold.py::test_g8b_cold_first_resolve_cached 17737.516297257764 iter/sec (stddev: 0.000008709434913273287) 18258.21714941566 iter/sec (stddev: 0.000004561489209033697) 1.03
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[1] 464.64508433707266 iter/sec (stddev: 0.00007209321805544171) 471.5927415437599 iter/sec (stddev: 0.00003828250486694024) 1.01
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[2] 444.6321812414162 iter/sec (stddev: 0.0000348048944793266) 434.6057208849211 iter/sec (stddev: 0.00003444426182541086) 0.98
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[4] 382.56145041316813 iter/sec (stddev: 0.00005367517147349876) 392.8902815455737 iter/sec (stddev: 0.00006907908303780609) 1.03
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[1] 2210.362277810931 iter/sec (stddev: 0.00002538488239235447) 2152.947623918151 iter/sec (stddev: 0.000029919818633541512) 0.97
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[2] 1638.052326842746 iter/sec (stddev: 0.0001635689038616069) 1492.0112310139875 iter/sec (stddev: 0.00020718819350787476) 0.91
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[4] 1143.7970935216567 iter/sec (stddev: 0.000037531433569632904) 1094.9387142267738 iter/sec (stddev: 0.00004181430442129771) 0.96
benchmarks/test_guard_lifecycle.py::test_g6_build_child_container 764442.2149950332 iter/sec (stddev: 7.794843731204289e-8) 668555.3578371395 iter/sec (stddev: 3.9276643390822e-7) 0.87
benchmarks/test_guard_lifecycle.py::test_g6b_build_child_container_auto_scope 695509.5763049335 iter/sec (stddev: 3.165619866269698e-8) 687167.058970974 iter/sec (stddev: 8.828710386969566e-8) 0.99
benchmarks/test_guard_lifecycle.py::test_g7_request_lifecycle_batch 2331.820803464456 iter/sec (stddev: 0.000020870851425105612) 2313.7050977670237 iter/sec (stddev: 0.000014377940830019346) 0.99
benchmarks/test_guard_lifecycle.py::test_g7c_event_loop_floor_control 61954.786333179785 iter/sec (stddev: 0.0000019303053477744448) 60846.949201084644 iter/sec (stddev: 0.000002033000360369562) 0.98
benchmarks/test_guard_lifecycle.py::test_g13_teardown_at_scale 46200.90365724546 iter/sec (stddev: 0.0000019529480509890943) 46312.85170228115 iter/sec (stddev: 0.000002737063802782133) 1.00
benchmarks/test_guard_resolve.py::test_g1_transient_resolve 2009919.0510101174 iter/sec (stddev: 2.1246019626869907e-8) 2059021.225734717 iter/sec (stddev: 3.525267068220601e-8) 1.02
benchmarks/test_guard_resolve.py::test_g2_cached_resolve 3549531.511551623 iter/sec (stddev: 8.00971141301041e-9) 3333878.533607576 iter/sec (stddev: 9.155632916007022e-9) 0.94
benchmarks/test_guard_resolve.py::test_g3_deep_chain 756302.7053236016 iter/sec (stddev: 5.04290226160577e-8) 752529.6472224294 iter/sec (stddev: 3.8674659173969325e-8) 1.00
benchmarks/test_guard_resolve.py::test_g4_wide_resolve 407642.0325729634 iter/sec (stddev: 1.0220917369224803e-7) 406897.6392631225 iter/sec (stddev: 1.0525803375112558e-7) 1.00
benchmarks/test_guard_resolve.py::test_g5_cross_scope 1606704.9726527666 iter/sec (stddev: 2.3296986440126478e-8) 1613190.1524936643 iter/sec (stddev: 2.3013119774949782e-8) 1.00
benchmarks/test_guard_resolve.py::test_g9_context_resolve 853256.6995140115 iter/sec (stddev: 3.657450489093486e-8) 834636.1656132308 iter/sec (stddev: 4.6654796970009304e-8) 0.98
benchmarks/test_guard_resolve.py::test_g12_override_active_resolve 502413.07745029044 iter/sec (stddev: 5.4033765793941776e-8) 501884.23653582734 iter/sec (stddev: 7.309233830769732e-8) 1.00
benchmarks/test_guard_resolve.py::test_g18_alias_hop 2402040.004527426 iter/sec (stddev: 1.1352452224393983e-8) 2239116.254855509 iter/sec (stddev: 1.557023081647912e-8) 0.93
benchmarks/test_guard_validate.py::test_g10_validate_deep_chain 27244.44605168503 iter/sec (stddev: 0.000003515150280709954) 27888.9265120092 iter/sec (stddev: 0.0000036969729607802292) 1.02
benchmarks/test_guard_validate.py::test_g11_validate_wide 16955.153612921993 iter/sec (stddev: 0.000004135922902105045) 16748.589320779636 iter/sec (stddev: 0.000004229673015586571) 0.99

This comment was automatically generated by workflow using github-action-benchmark.

@lesnik512
lesnik512 merged commit e87968d into main Aug 31, 2026
9 checks passed
@lesnik512
lesnik512 deleted the docs/compress-claude-md branch August 31, 2026 14:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant