Repository navigation
chore: audit and trim always-loaded Claude config (post-Opus-5 ablation) #252
Description
Premise
Boris Cherny (Anthropic) reports cutting 80% of Claude Code's system prompt for Opus 5, and recommends users periodically delete their CLAUDE.md, skills, and hooks to see what the model no longer needs. Talk: https://youtu.be/qyPCVqFUyDo · Writeup: https://www.xda-developers.com/your-claude-md-is-probably-wrong-how-anthropics-engineers-structure/
The advice applies to one category only: prompt text that corrects model behavior. It does not apply to context the model cannot derive (project conventions, domain facts, deliberate style rulings, safety constraints).
Sorted by that distinction, the audit finding is lopsided: the project CLAUDE.md files are mostly the good kind; the global file is where the cruft lives.
Always-loaded budget today: global 1,675w + project 900–1,800w + MEMORY.md ~1,314w + 618w of skill descriptions ≈ 6–7k tokens/session. On a 1M window that is not a budget problem. The cost is dilution — ~40 generic instructions make the ~6 load-bearing ones harder to weight. That is the case for cutting; token economy is not.
Phases
-
Phase 0 — Ledger + guardrails. This issue, the attic, the stumble log.
-
Phase 1 — Global
CLAUDE.mdtrim. 1,675w → 1,015w (39%) in one pass. Highest leverage (loads everywhere), lowest risk (nothing safety-critical in it). Merged in chore(claude): trim the global CLAUDE.md and set up the ablation guardrails #253. Observation window opens here. -
[~] Phase 2 — Observation window. Now closes 2026-10-16 (end of day). Extended twice: on 2026-08-12 to 09-26, because travel 08-04 → 09-09 left ~3 days of representative work; and on 2026-09-29 to 10-16, because use stayed light after the return. Log every stumble; no re-adds during the window. → Observation window
-
Phase 3 — Re-add pass. Re-add only what appears in the stumble log more than once, at the narrowest scope that fixes it. Unblocks 2026-10-17.
-
Phase 4 — Responsive-QA → skill. Decide whether the extracted doc becomes a skill with a trigger description. Deferred out of Phase 1 on purpose (see D5). Actionable now (the freeze ended 2026-09-09); not tied to the observation window.
-
Phase 5 —
resolve-issuetrim. 649w → 386w, then 560w (14%) after the fix below. Six narrated steps down to seven non-derivable rules. Merged in chore(claude): trim resolve-issue from six narrated steps to seven rules #254 (2026-08-12). Pulled forward ahead of Phase 2 completion on purpose: Joshua had a real ComixDistro issue about to start, and using it beats reasoning about it. That paid off immediately — see the first stumble below, and D7. -
Phase 6 — Project
CLAUDE.mdtrims. ofreport's hard-wrapped Development Workflow: done (merged in ofreport.com#219). ComixDistro's 3× repeated CI-ordering rationale: done — kept once, in the sign-off step; 1,796w → 1,757w (merged in euroteamoutreach/comix_distro#1096, 2026-10-06). -
Phase 7 — Retire tutorial mode. Policy decided (Q2, answered 2026-08-01). Applied in three PRs, all merged 2026-08-12:
- global file → chore(claude): trim the global CLAUDE.md and set up the ablation guardrails #253 ✅
ofreport.com-hugo→ chore(claude): retire tutorial mode from the development approach ofreport.com#219 ✅ (the stale "explain Hugo concepts")euroteamoutreach.org→ chore(claude): retire tutorial mode from the development approach euroteamoutreach/euroteamoutreach.org#20 ✅ (five bullets → two; dropped "No black boxes", "Incremental progress", "Present options")
Confirmed by grep that no tutorial-mode language exists anywhere in dotfiles, including the PRD starter template, so nothing propagates to future projects. ComixDistro never had any. Both project PRs were branched off
mainrather than committed onto the in-flight branches those repos were sitting on (chore/markdownlint-config-standardization,feat/gh-15-footer); both original branches were restored afterward.
Guardrails (must stay in place for the whole initiative)
| Guardrail | Location |
|---|---|
| Attic — quarantined text, never hard-deleted | claude/.claude/docs/attic-2026-08.md |
| Stumble log — the only evidence admissible in Phase 3 | claude/.claude/docs/stumble-log.md |
| Ledger — phase state, decisions, open questions | this issue |
Decisions
-
D1 — Cut in one pass, not incrementally. You cannot predict which line mattered; you can only observe. Incremental trimming never generates signal because nothing changes enough to notice.
-
D2 — Quarantine, never hard-delete, for the duration. Git already covers recovery; the attic makes "bring it back line by line" a two-second edit instead of an archaeology session.
-
D3 — Re-add at the narrowest scope: skill > project file > global. A line that only matters in one repo must never land in the global file.
-
D4 — Safety-critical project content is exempt from ablation entirely. Not experiments: ETO's memorial page + Fallen Defender/IRS earmarking language, ComixDistro's post-launch QA gate, URL-preservation/no-404s, the MailChimp RSS re-blast warning. A regression there has real-world cost, not just an annoying correction.
-
D5 — Responsive-QA body moves to a doc, with a 3-line trigger left in the global file. It is not cut outright. Rationale: that failure mode is silent —
resize_windowreturns success whileinnerWidthstays wrong, so the overflow check then passes trivially. Ablating it would produce no stumble-log signal, which breaks the entire method. Cost drops ~440w → ~40w with the trigger preserved. -
D6 — Large orchestration skills are out of scope.
autopilot-batch(4,325w),autopilot(3,299w),qa-triage-batchetc. are specifications with safety invariants (worktree isolation, model gating, merge tiers), not behavioral correction, and they are just-in-time loaded — zero cost when unused. Gutting them would be the wrong lesson from the talk. -
D7 — A command correction is not a behavioral correction, and is out of ablation scope. Surfaced by the first stumble (see below). Ablation removes instructions that correct model behavior — "be thorough", "read carefully", "don't forget X" — because current models don't need them. It does not cover a skill that hands over a command which is incomplete for the job it describes: there the instruction introduces the gap rather than merely failing to prevent one, and no amount of model capability closes it, because the model is doing exactly what it was told. Test to tell them apart: if the model followed this line perfectly, would it still get the wrong result? If yes, it is a command bug — fix it, don't trim it.
First stumble — logged and corrected 2026-08-01
The trimmed /resolve-issue ran live on comix_distro #512 and surfaced a real regression on its first outing.
The trim cut Step 1's "extract title, description, labels, and comments" as GENERIC, leaving only gh issue view N — which prints the body but not the comment thread. On #512 the three comments held roughly a third of the actual scope, plus one that superseded an acceptance criterion still written in the body. Following the skill literally would have shipped incomplete work while ticking every AC — a silent, confident miss. That session read the comments anyway, out of habit, which is not something to rely on across sessions or model versions.
Verified against the live CLI before fixing:
| Command | Behavior |
|---|---|
gh issue view N |
body only — no comment content. Header does carry a comments: N count, but in a metadata block that is easy to skim past. |
gh issue view N --comments |
comments only — omits title and body, so it is not a drop-in replacement |
Fixed in #254: the fetch step now runs both calls unconditionally, with the rationale inline (the body is the oldest artifact on an issue; comments carry scope added later and decisions that supersede it). Also switched the acceptance-criteria write-back from --body "$var" to a file round-trip with --body-file, which keeps issue bodies containing backticks out of shell parsing — the same reasoning that survived the Q1 test.
Note on the original: it was already self-contradictory — an incomplete command paired with an instruction to extract something that command does not return. The trim did not create the flaw, but it removed the one word that prompted a human or agent to go around it. Recorded honestly in the stumble log as the initiative's first entry.
Open questions — both ANSWERED 2026-08-01
Q1 — Is the Git Commit Protocol still necessary? → Right conclusion, wrong reason.
Tested rather than reasoned about: four --allow-empty commits on a throwaway branch, with Bash(git commit:*) allow-listed and defaultMode: auto.
| Message form | Prompted? | What landed |
|---|---|---|
| double quotes, plain text | no | correct (baseline) |
| double quotes, backticked phrase | no | phrase silently deleted |
double quotes, $(echo INJECTED) |
no | substitution ran and was inlined |
| single quotes, same content | no | exactly correct, both literal |
Zero prompts across all four. The stated rationale is dead — the permission system does not pre-flag substitution ahead of the allow-list.
But the conclusion survives for a better reason, so the section was rewritten, not cut: the shell still performs the substitution, and neither form aborts the commit. That is worse than a permission prompt — a prompt is visible and stops you; a mangled message just ships. The rewrite also documents a newly verified light path (single quotes preserve both literally, for a one-liner with no apostrophe).
Neither predicted outcome ("still needed" / "collapses to one line") was correct. Recorded in the attic under a new FALSIFIED code — the method argument for testing over guessing.
Q2 — Per-project autonomy / tutorial mode → Retire tutorial mode, keep the understanding.
Joshua's ruling: the "explain Hugo concepts" framing that started on ofreport is out of date, and tutorial-mode leanings should go generally. What stays is clarity, transparency, and understanding of the code we write — he wants to follow the logic, not be hand-held as a junior developer, and not be given something so terse the reasoning is hard to follow. He expects this calibration to evolve.
Implemented as "Understanding transfer, not tutoring" in the global file, naming both failure modes rather than one. Rules out: concept tutorials for tech he already ships in production, narrating what the code plainly says, and pausing to offer a choice when one option is clearly right. Explicitly warns against over-correcting into terseness. Discriminator: explain the decision, not the syntax.
Note this is not the same as flipping projects to /autopilot by default — that remains a per-run opt-in. Q2 settled the explanation register, not the supervision boundary.
Confirmed redundancies (Phase 1 evidence)
Now near-verbatim in Claude Code's own system prompt:
Global CLAUDE.md line |
Superseded by |
|---|---|
| "Finish the job" | "Finish the whole task, not just easy parts — report completion only when fully done." |
| "Bias toward action" (head) | "make routine judgment calls yourself, and check in only when different readings would lead to materially different work" |
| "Flag it honestly rather than glossing over it" | "Report outcomes faithfully: if tests fail, say so with the output" |
| "Prefer established patterns over clever abstractions" | "Write code that reads like the surrounding code: match its comment density, naming, and idiom." |
| "Use Context7 (MCP) before implementing…" | the Context7 server's own instructions: "Use even when you think you know the answer — your training data may not reflect recent changes." |
Activity
chore(claude): resolve #252 Q1 and Q2 — rewrite the commit protocol, …
chore(claude): trim resolve-issue from six narrated steps to seven ru…
chore(claude): retire tutorial mode from the development approach (#219)
chore(claude): retire tutorial mode from the development approach (#20)
joshukraine commentedon Aug 12, 2026
Reopened — and why it closed
This issue auto-closed on 2026-08-01 at 16:41, two minutes before #254 was opened. Nothing was actually complete.
The cause: the squash-merge of #253 concatenated its constituent commit subjects into the squash message, one of which read
resolve #252is a GitHub closing keyword, and closing keywords fire from commit messages landing on the default branch. #253's PR body said explicitly "Does not close it — #252 stays open through Phases 2–7." The body was right; the commit subject silently overrode it.Worth recording precisely because it is not an ablation stumble: "Never reference issue numbers in a commit message" survived the Phase 1 trim and is still in the global file. This was a violation of a rule that is on the books, not evidence that a cut line should come back. It does not go in the stumble log.
Phase 2 extended to 2026-09-26
The window opened 2026-08-01 and was set to close 08-15. Joshua left on 2026-08-04 for a trip to the States and returns 2026-09-09, with work volume in between a fraction of normal. So the original window rests on roughly three days of representative work — and the single logged entry came from day one.
Less volume is only half of it. Travel work is a different shape: short sessions and cold re-entry into projects untouched for a week make some stumble classes more likely, while the watch-list items that need long implementation sessions to surface at all — doc drift, large unreviewed diffs — cannot fire. The sample skews in both directions at once, which is worse than merely being small.
New close date allows ~2.5 weeks of normal-volume work after the return. Travel-period entries still count and are still logged; they are now tagged as atypical so Phase 3 can weigh them accordingly.
Two rules added to the stumble log alongside the extension:
Frozen until 2026-09-09: Phase 4 (responsive-QA → skill) and the remaining Phase 6 item (ComixDistro CI-ordering de-dup). Both change live config, and config surgery on a single travelling machine is a bad trade against signal this weak.
Merged today
resolve-issuetrim, 649 → 560wPhases 5 and 7 are now complete. One thing #254's merge fixed that was not on anyone's list: because
~/.claude/skills/resolve-issueis a stow symlink into the working tree, the live skill had been serving the unmerged branch version.masterstill carried the 649-word original with the comment-fetch bug, so anygit checkout master— or a fresh dotfiles setup on another machine during the trip — would have silently reverted to the version that ships incomplete work while ticking every AC. Merging before six weeks of travel closed that gap.chore(claude): trim the global CLAUDE.md and set up the ablation guar…
joshukraine commentedon Sep 21, 2026
Status check 2026-09-21 — plus a new style ruling (not a re-add)
Where the initiative stands, 5 days before the window closes:
/resolve-issuecomment-fetch bug, a D7 command bug, fixed in chore(claude): trim resolve-issue from six narrated steps to seven rules #254 and closed out 2026-08-02. Zero behavioral stumbles in the whole window. Nothing on the watch list (doc drift, commented-out code, mock boundaries, large diffs) ever fired.On current evidence Phase 3's answer is re-add nothing.
New ruling — response register (committed today, bce9545)
Joshua reported weeks-long friction that is not an ablation regression: replies long enough to be hard to digest live, and jargon/idiom standing in for named things — concretely, a Hermes-agent session where "the tripwire we worried about never materialized" referred back to a problem never re-named.
Checked the attic first: nothing about concision was ever cut. The suspected cause is a line Phase 7 added on 2026-08-01 — "Don't over-correct into terseness either — when the reasoning is load-bearing, spell it out" — paired with a "give him the why" instruction carrying no length budget. Together they read as standing permission to expand.
Applied: the anti-terseness clause is out; three bullets replace it —
Why this does not violate the no-changes-during-the-window rule: it is a deliberate style ruling from Joshua, the category this issue's own premise exempts from ablation — not a re-add of quarantined text, and not evidence-driven from the log. Net +104 words on a 1,015-word file.
Quarantined the removed clause in the attic under a new
SUPERSEDEDcode (replaced by a later, deliberate ruling — the line was doing its job, the job changed), and logged the friction in the stumble log. Phase 3 should confirm this, not reopen it.joshukraine commentedon Sep 29, 2026
Phase 2 extended again, now through 2026-10-16
The 9/26 close assumed the ~2.5 weeks after the 9/09 return would be normal-volume work. They weren't: use stayed light. So the zero-stumble result mostly means the trimmed config went largely unexercised, not that it held up. It is not a basis for closing Phase 3.
Stumble log updated accordingly.