Your CLAUDE.md was written for a model you no longer run.
A CLAUDE.md has to fit two things: the model that reads it, and the person it speaks for.
Both move. One command re-fits it to both — and never writes a line you didn't pick by number.
Inside Claude Code:
/plugin marketplace add pueding/houserules
/plugin install houserules@houserules
/houserules:fitThat re-fits your CLAUDE.md in both directions and hands you one table. The
three commands below run pieces of it; fit is the one you want by default.
| Command | Fits your CLAUDE.md to | Writes? |
|---|---|---|
fit |
the model and you, reconciled | on your pick |
migrate |
the model that reads it | on your pick |
learn |
how you actually work | on your pick |
test |
— proves a rule works first | never |
/houserules:fit # global file, last 14 days
/houserules:fit ~/.claude/CLAUDE.md # a specific file
/houserules:fit --days 30 # wider session windowRunning migrate and learn separately leaves two problems on your desk, and
both are correctness issues rather than conveniences.
Fit — ~/.claude/CLAUDE.md
188 lines / 8,682 B / ~2,346 tok per session
Model: claude-opus-5 · guide fetched live | Sessions: 14d, 37 sessions, 22 corrections
| # | Lines | What | Source | Verdict | Why |
| -- | ------- | --------------------- | ---------- | ------- | -------------------------------- |
| 1 | 18-29 | "Explain so I can act"| BOTH | REWRITE | rule exists, "tldr" 3x anyway |
| 2 | (new) | Don't edit on analyze | BOTH | ADD | 3x/2 days + guide warns on scope |
| 3 | 89-113 | Sub-agent routing | migrate | DELETE | all 7 agents missing from disk |
| 4 | 63-66 | Scope Control para 1 | learn | KEEP | was marginal; 3 corrections back it |
Reply with the numbers you want:
apply 1,3 test 1,3 apply all apply none
1. The analyses disagree, and the disagreements are the most informative rows.
migrate says delete a rule because the guide says the model handles it
natively; learn says you corrected it anyway, three times, last week.
The session record wins. The guide describes the model's default; your
corrections describe what you needed. A general claim loses to evidence from
your machine. Both sources and the reasoning are shown so you can overrule — and
if the corrections all predate the model change, the row is marked WEAK and
left to you rather than decided.
2. Two write passes corrupt line numbers, invisibly. migrate cites
L89-113 against the file as it exists now. Let learn write first and every
citation is silently wrong. fit collects both analyses before either writes,
then applies once in descending line order.
| Bucket | Meaning |
|---|---|
BOTH |
The guide recommends it and your sessions demand it — one row, two justifications, ranked top |
CONFLICT |
The sources disagree. Both shown, resolved toward your history |
OVERLAP |
Both touch the same lines. One merged edit, never two |
| pass-through | Independent findings |
A real run on a 188-line file produced two BOTH rows, no CONFLICT, and
filtered 15 of 22 corrections as product decisions rather than behavioral rules.
Net effect: +2 lines, −192 bytes — the dead routing table was wide enough to
pay for four new rules.
How conflicts are resolved, and why order matters
On a live conflict the session record wins — with one dated exception. If the
corrections all predate the model change, the guide may now be right and the
rule genuinely obsolete. That row is marked WEAK and left to you rather than
decided either way. Dates are checked, not assumed.
Nothing is resolved silently. Both sources and the reasoning appear in the row, so a resolution you disagree with is one you can see and overrule:
CONFLICT — kept against the guide
guide: "<verbatim quote recommending removal>"
observed: 3 corrections across 2 sessions, most recent 2026-08-04
-> KEEP. The guide describes the default; your sessions describe the exception.
Application order is a correctness property, not a style choice. Edits apply in descending line order, so a row at L63 never shifts the citations of an unapplied row at L89. Pure additions have no line range and go last. One backup, one write pass, one stamp — then the diff and the backup path, plus any rows you skipped named explicitly so the remainder isn't silently lost.
OVERLAP never produces two edits to one range. If both analyses touch the
same lines, they merge into a single replacement satisfying both — otherwise
whichever applied second would clobber the first.
/houserules:migrate ~/.claude/CLAUDE.md # one file
/houserules:migrate ./CLAUDE.md # this project
/houserules:migrate # discover every CLAUDE.mdYour CLAUDE.md was written against one model's behavior. Point it at a different model and it's mis-fitted in both directions:
- Rules that patched a weakness the new model doesn't have aren't neutral — they cost tokens, and some fire twice against behavior it now has natively.
- Behaviors the new model introduced have no rule at all yet. Longer default replies, longer written deliverables, readier delegation.
Migration is not pruning. Anthropic's per-model guide ships a remove this list and an add this list. A run that returns only deletions has done half the job.
Anthropic proved the premise on themselves: when Opus 5 shipped they cut over 80% of Claude Code's own system prompt with no measurable eval loss. Boris Cherny, who created Claude Code:
"Every six months, delete your CLAUDE.md, delete your skills, delete your hooks. Then see what the model does. It might surprise you."
Deleting everything is good advice and terrible ergonomics. Most of your file is genuine preference — how you want to be talked to, your commit conventions, your TDD workflow. No model release makes that obsolete. You want a scalpel.
The biggest finding on a real file wasn't a stale rule — it was a dead one. A 26-line sub-agent routing table, perfectly sensible as prose, pointing at seven agents that were never created:
$ ls ~/.claude/agents/
pm-agent.md
MISSING explorer MISSING implementer MISSING documenter MISSING reviewer
MISSING architect MISSING debugger MISSING security-auditor
Read the file and it looks fine. That's category E — a rule that names a thing gets checked against whether that thing exists. First pass on that file: 348 → 188 lines, ~5,263 → ~2,346 tokens per session.
The categories behind the verdicts
| Category | Verdict | Test | |
|---|---|---|---|
| A | Model-compensation | DELETE | The live guide says to remove it |
| B | Harness duplication | DELETE | Already in the agent's own system prompt |
| C | Ecosystem duplication | DELETE | Owned by an installed skill/plugin/hook |
| D | Internal contradiction | REWRITE | Two rules that cannot both hold |
| E | Unexecutable | DELETE | Names something that does not exist |
| F | Scope misplacement | MOVE | Global rule that is project-conditional |
| G | Genuine preference | KEEP | Describes how you want to work |
| H | Unmet new behavior | ADD | The guide recommends it; your file lacks it |
Category B is one no static tool can do — the agent running the audit can read its own system prompt; a linter can't.
Category D is usually the highest-value finding. Older models averaged
contradictions out; literal-following models resolve them differently every turn.
A real one: "Default to terse" on line 311 and "Be organized, accurate, thorough, and detailed" on line 326 of the same file.
Most CLAUDE.md content is written from imagination — you guessing, in advance, how you'll want to work. This writes it from the record: what you actually asked for, how often, and what you had to say twice.
/houserules:learn # last 14 days
/houserules:learn --days 30
/houserules:learn --project my-appEvery re-steer — "no, use pnpm", "I said don't add comments", "again?" — is a rule the file should already have carried.
The best thing it finds isn't a new rule — it's a failing one. A real example, from a file that already contained, verbatim:
"If I ever have to reply "explain more easily," that round-trip should not have been needed."
and a session record that then contained:
[2026-07-26] "I don't understand what you said. tldr"
[2026-08-04] "It needs to explain more kindly"
[2026-08-04] "btw, why did you explain the log mechanism deeply?"
The rule is read every session and not working — it says how to explain well but never says when to stop. No tool that reads CLAUDE.md alone can find that. It takes the correction history to prove it.
How it survives 1.3 GB of transcripts
~/.claude/projects/ is routinely gigabytes and almost entirely tool-call
records. Nothing raw ever reaches the model.
scripts/mine-sessions.py keeps only promptSource == "typed" — actual human
keystrokes. On a real machine that's 370 prompts out of ~14,000 records over
two weeks. It then flags corrections by cue position and prompt length, not
keyword presence: a strong cue in the first 150 characters, or a prompt under 300
characters. That's what separates no, use pnpm from a 400-word product spec
that happens to quote the word "never".
| Classifier | Flagged | Quality |
|---|---|---|
| Keyword-only | 54 (15%) | product specs, quoted text |
| Position + length | 22 (6%) | genuine corrections |
Standalone and dependency-free — run it without the plugin:
python3 scripts/mine-sessions.py --days 14 [--project SUBSTR] [--all] [--json]It will not bloat your file
Both directions can add and both can rewrite, so run carelessly they'd fight.
learn is deliberately conservative:
- A pattern needs 2+ occurrences across 2+ sessions or 2+ days, whichever
count is higher. The
oris load-bearing: session ids survive resumes, so one id routinely spans a week — counting sessions alone collapses independent occasions and silently drops real patterns. Counting days alone has the mirror failure. - Weaker evidence is shown as
WEAKwith the count — never silently promoted, never silently dropped. - Product decisions and domain arguments are ignored. On a real run 15 of 22 corrections were filtered out as things you were building, not how you want the agent to work.
- Zero proposed rules is a normal result. It says so and stops.
A rule is not right or wrong in isolation. It competes with everything already in the file, and a well-worded rule can lose. You cannot see that by reading.
Measured, on a real machine:
| Same rule, same probe, same model | Result |
|---|---|
"Answer in exactly one short sentence. Never more." appended |
~200 words, headers, bullets — did not fire |
| the same rule substituted for the competing style rules | one sentence — fired |
The appended version lost to the gloss-in-parens and everyday-analogy rules
already in the file — you can watch them firing in its output. That is the
mechanism behind learn's failing-rule finding above. test catches it before
you apply, instead of weeks later.
/houserules:test # after fit, before applyEach rule is A/B'd against a real probe — preferably the verbatim prompt you typed right before complaining. If the rule works, that prompt stops producing the thing you complained about.
| Verdict | Meaning |
|---|---|
| FIRES | Observables move the intended way, consistently |
| PARTIAL | Some clauses land, others don't — the most useful verdict |
| NO EFFECT | The rule is being outcompeted |
| BACKFIRES | Wrong direction |
| INCONCLUSIVE | Arms errored, or a rewrite was tested as an add |
A measured PARTIAL: "Answer in a single short paragraph. No bullet lists, no
headers, no code blocks." took bullets 2 → 0 (−100%) and lines 17 → 11 (−35%),
while words went up 9%. The formatting clause landed, the brevity clause
didn't. One rule, one clause to fix — from deterministic counters, no LLM judge.
Rules that don't land get a sharper draft and one retest. The usual causes, in order: outcompeted by a more specific rule elsewhere (it names the line), abstract ("be concise" has no observable), prohibition without a replacement, or buried.
Why probes are subprocesses, not subagents
A subagent shares the parent session's harness and cannot load a different
CLAUDE.md — so it cannot vary the thing under test. Every probe is a separate
claude -p process with its own harness resolution. They parallelize as
background jobs, so this costs wall-clock, not correctness.
Each probe is a full billable invocation; n=3 across a 7-row table is ~42 runs. The skill states the number before starting so you can cut it, and it won't test on a cheaper model than the one that will read the file — a haiku result doesn't transfer to opus.
Adds and rewrites are different experiments. An add is clean: arm B appends
the rule, the global file is identical in both arms and cancels out, nothing is
written. A rewrite needs the old text gone — appending would test "new on top
of old", the wrong question, which reliably reports NO EFFECT. True substitution
requires --allow-swap, which briefly stands a variant in place of the real
CLAUDE.md (backed up, restored in a finally, refuses to start if a previous run
left one behind). It asks first. Without it, rewrites are reported INCONCLUSIVE
rather than answered wrongly.
A shadow config dir via CLAUDE_CONFIG_DIR does not work — on a live machine
the on-disk credentials are stale and a separate config dir can't refresh them.
This plugin hardcodes zero model facts.
A pruning skill with one model's rules baked in becomes the exact technical debt it exists to delete. Ship Opus 6 and your pruner is itself scar tissue.
So it fetches Anthropic's per-model docs at runtime. They publish a prompting
guide with an explicit "remove this from your prompts" section on every
release — a changelog, on a stable URL pattern.
skills/migrate/references/model-docs.md holds URL patterns. Not model facts.
Nothing in this repo needs updating when a new model ships.
Existing CLAUDE.md tools all optimize one axis: does this file describe the codebase accurately? None ask whether it's fitted to the model reading it, and none look at what actually happened in your sessions.
| Tool | Optimizes for | Model-aware | Session-aware |
|---|---|---|---|
claude-md-improver (official) |
Codebase description | ❌ | ❌ |
revise-claude-md (official) |
Appends session learnings | ❌ | Current session only |
| ClaudeForge | Generation, sync, line caps | ❌ | ❌ |
Anthropic's claude-opus-4-5-migration |
Model IDs, headers, params | ✅ — but excludes CLAUDE.md | ❌ |
| houserules | Fit, both directions | ✅ | ✅ full history |
- Decide for you. It produces the table; you pick numbers. A run that applies changes nobody selected is a bug.
- Hide a conflict. When the guide and your history disagree it shows both sources and its resolution, never a silent pick.
- Treat migration as pruning. Removing without adding leaves the file fitted to the old model. It works both lists.
- Chase a line count. A 400-line CLAUDE.md of real preference is fine.
- Delete on keyword match. "JWT verification" is domain vocabulary. "Run
flutter analyzebefore committing" is an external gate. Both stay. The distinction: self-directed re-checking is scar tissue; a real command producing real output is not. - Propose a rule from one occurrence. Every rule is a permanent tax.
- Write without a backup, or edit before you've approved by number.
- Guess. If the model guide can't be fetched, it says so and marks the audit degraded rather than falling back on remembered facts.
claude-md-improver— is CLAUDE.md accurate about the codebase?/claude-api migrate— are your API calls on the right model ID and params?
Different axes. These two are fit.
MIT