The Rules Are Downstream of the Work
The original was written on day 40. This revision is day 105.
Sediment
Four lines in my CLAUDE.md tell me, in my own voice, not to leave loose ends, not to cross repo boundaries, and not to contaminate ~/Projects with worktrees. The worktrees belong inside their own repositories.
I did not write that file and then start following it. Claude Code wrote it by writing down how I had already been talking for forty days.
"Loose ends" shows up in my transcripts on April 29, twice, about a hundred seconds apart. It lands in CLAUDE.md on May 18. Twenty-day lag.
"Crossing boundaries" is what I said on May 3, after Claude edited the wrong repo while I was working in another one. The worktree rule that fixed it gets written down on May 20. Seventeen-day lag.
"Don't contaminate ~/Projects" was a verbatim May 20 pushback. The rule landed the same day, reworded. The phrase changed. The scar survived.
And the file kept taking on layers. On May 31, the day before I first wrote this, a git worktree move clause got added to that same worktree rule. I said then that the file was not finished. It is still not finished.
Sixty-five days later, that file is 208 lines: ten sections, forty-eight bullets. Every one of the original four lines is still in it, and the worktree rule still carries the move clause I added the night before I called the file unfinished.
The rules are not something I decided on and imposed on the work. They are sediment: laid down a grain at a time, by the work, over weeks, never in one sitting. That is the part the word carries that "downstream" does not. Sediment takes time. You cannot deposit a layer you have not lived through.
The file looks like a constitution and reads like one, but it was never written that way. It piled up.
That runs against most of what gets written about Claude Code, which usually says to think hard about your rules first and write a careful constitution before you start. I tried that. I have the failed earlier CLAUDE.md drafts to prove it: vague, wishful, ignored by the model, and rightly ignored, because I had not earned the right to write them yet.
I did not know what a loose end was until I had left a hundred of them.
I did not know what crossing a boundary cost until Claude crossed one and lost me an hour.
What the Next Sixty-Five Days Deposited
The layers since are dated in the file, because I started dating them.
June 26: warn once, then act. One flag naming the risk and what I plan to do, then the smart default. A flag you already answered never comes back unless the facts changed.
June 28: a secret printing into a local transcript on this machine is not an incident. No rotation theater, no masking machinery, no derail. Git and external exposure stay absolute.
June 30: past 70% of the weekly usage window, talk less. Past 80%, stop fanning out.
July 25: mechanical fan-out runs on cheap models. Session-tier models are reserved for judgment.
Each of those is the same shape as the first four. Something cost me time. I said so, in a sentence I would not have thought to write in advance. It got written down.
Rules That Name an Absence
Then two on August 1 that are a different kind of layer.
A gap list handed to me opened with "[medium] No automated tests exist anywhere in the repo." The model made that the headline, reworked the server so it could be tested, and ran a seven-agent workflow that wrote 104 tests across five files. Then it launched a second workflow to revise them. I stopped it mid-run: "Don't be building some huge test suite. I have a command for building out the acceptable level of test suites for these apps. I'm not trying to waste too many expensive tokens on that. Tell the base claude.md this isn't a gap."
The first draft of that rule over-corrected into "no tests," so I corrected the correction: "I didn't say I didn't want tests, but when tests are being added...use my command so it's right sized." The rule is not anti-test. It is about who sizes the suite.
Same day, different repo, same shape: "this is a prototype. Stop throwing CI/CD on local prototype tools... So when adding the pipelines I should be asked if CI/CD is necessary. If you can infer this is one of my local tools then don't even flagg CI/CD as a gap." I had already waved off the deploy half of that same audit earlier in the session. "this is a sandbox app, the deployment stutuff shouldn't be considered a gap." That was the signal the model should have turned into a general rule on the spot, and didn't.
The typos stay in. That is the register the rule was born in.
Both rules say the same thing: the hole is on purpose, and reporting it as a gap is the error.
You cannot write that rule in advance. Before the work, "no tests" and "no CI" genuinely look like gaps. They look like gaps to any competent reviewer, which is exactly why an agent keeps finding them. The only thing that turns a hole into a deliberate shape is having lived in it long enough to know you dug it on purpose.
The constitution you write up front can tell an agent what to build. Only sediment can tell it what to leave alone.
Code to Spec
The same thing happened at the tool layer.
On April 28, I wrote a Python script called harvest_cc.py: 1,168 lines that walked ~/.claude/, parsed session JSONL, applied mapping tables, and saved everything to SQLite with idempotent upserts.
It worked.
Two weeks later, on May 12, I rewrote it as an 84-line slash command.
The slash command does not contain the logic. It is a spec that tells the agent to do the extraction with the tools it already has.
That move, from code to spec, is probably the cleanest signal in the whole first window. I could not have written the spec first. The spec is what was left after I had done the work by hand and learned which parts of it the agent could be trusted with.
The 1,168 lines were not wasted. They were the cost of learning what to hand off.
Two honest updates. The command is still exactly 84 lines. And the script did not die. It is still on disk, now 1,238 lines, last touched May 27, two weeks after the spec was supposed to have replaced it. Sediment does not delete the layer underneath it.
The same pattern showed up one size larger. Between July 3 and July 5 I wrote nine autonomous cross-repo sweep skills: reconciling WIP, security, licenses, dead links, test backfill, deploy health, config drift, changelogs, brand scrub. Nine separate things that each turned out to need a ledger, a one-unit-per-iteration loop, a detect-before-act gate, and a resume-safe contract. So the shared engine got pulled out into autonomous-sweep-core, and all nine now cite it.
Same migration, one level up. Write the concrete thing nine times, extract the spec afterward. I could not have written autonomous-sweep-core first either.
The Harness, Eating Its Own Tail
Then there is the harness itself: the slash commands, skills, and MCP servers I keep in ~/.claude. Forty-four commands, twenty-two skills, four agents, as of this morning.
None of it was designed up front. Each command was promoted out of real work, one at a time. Almost always, I drafted it away from the work on purpose. When I hit something worth turning into a tool, I back out of the repo I am in and write the tool from ~/Projects, so building the tool does not muddy the session that produced the need for it.
And the harness is built out of itself.
The first thing I made was prompt-improver, using skill-builder, before I really knew what I was doing. Then prompt-improver became the tool I drafted almost every later command through.
port-collision-scan came from handing prompt-improver the entire generate-port-registry command and asking for the one-shot version.
The hardening series borrows its shape from cleanup-repo, front-door-security, and shipit.
harness-audit is told, in its own genesis prompt, to reuse lowhangingfruit and cleanup-repo and point them inward.
New tools made from old tools, drafted by the oldest tool I had.
The newest one closes the circle further than I expected. On July 25 I wrote a skill called preference-recalcification, whose only job is to maintain the sediment. Its instructions point at an essay in my docs folder as required reading before it touches the provenance rules. A tool in the harness now cites a piece of writing about the harness as a source of authority over the harness.
That is what I mean when I say the harness is downstream of itself. Not a backup restoring a backup. A toolchain that bootstrapped on its own output.
Who Wrote This Layer
Here is the thing I did not see coming on day 40.
Sediment does not check credentials. Anything that settles becomes a layer. And for most of June, the thing depositing layers into my rules and my roadmaps was not always me.
An agent proposes a constraint in a plan. I say "y." The constraint gets written into a roadmap. A later session reads the roadmap and cites it back to me as decided. Nobody lied. But three documents repeating one origin is not three confirmations, and my "y" approved the intent of a plan, not every line inside it.
So the July 25 layer is a rule about layers. Anything the model inferred rather than something I decided gets a greppable CLAUDE-ORIGIN tag right where it sits. Requirements now carry a provenance class: user-ratified, user-mentioned, bulk-approved, agent-originated. The last three never round up to the first. Silence is not ratification. A "decided, do not relitigate" label binds only if a decision entry exists that actually weighed alternatives. Inheriting a stack is not deciding a stack. Those tags now exist in twelve files across five repos, alongside nine ROADMAP.md and nine DECISIONS.md files carrying the same discipline.
There is a second half to that rule that took one more failure to earn. On July 26 the model wrote a paragraph explaining why my new decision superseded a proposal from an old agent packet. Careful, well-reasoned, and wrong. Arguing against text I never ratified gives it the standing of a live alternative that was weighed and beaten. That is exactly the status it never had. My reply is in the file verbatim: "I literally never cared about the decay layer."
That failure happened inside the document written to obey the rule. Which is the most honest thing in my CLAUDE.md, and the reason it stayed in.
The other thing I did not see coming: a model upgrade is a personnel change nobody announces. Rules written for an earlier model held together because that model filled in the gaps for me. The newer one litigates the letter. My own words, from the transcript that produced the recalcification skill: "it gets better at litigating, the preference must be calcified by the new litigator in language he will respect."
So on July 25 the enforcing model restated my keystone rules in its own voice, at the rigor it would later hold them to. Every rule's scar is quoted verbatim from the session record. The file now carries a note saying so. From "Close loose ends" through "Agent tangents," the "I" is the model, and I am third person.
My rules are written in someone else's first person. That is not a metaphor about ownership. It is the only version the enforcer reliably obeys.
Four Layers
Four layers now, same basic shape.
My coding standards are downstream of my mistakes.
My tools are downstream of my scripts.
My harness is built out of its own commands, drafted by the first tool I wrote.
And my rules about where rules come from are downstream of rules that came from nowhere.
At every level, the thing that looks upstream is actually downstream of the work that produced it.
And this only matters because I am not working alone.
Specific Enough to Constrain
This is the part that does not carry over cleanly from solo work.
When you write code alone, the constraints can live in your head. The rules you write down are notes to yourself across time. They can be vague, because you are the one reading them and you fill in the missing half.
When you work with an agent, the rules have to live in a file the agent reads. Vague does not survive that handoff. The rule has to be specific enough to actually change what the model does.
"Be careful with deletions" does nothing. The model cannot act on it. A new hire probably could not either.
"A one-word approval to a multi-option menu is not durable consent" works, because it names the exact shape of a failure I had already lived through.
You cannot write the second sentence until you have lived the failure.
The first sentence is the kind of thing you can write before the work starts, and it is worth about what you paid for it.
That is why the rules can only be sediment. The rule you write up front is too vague to constrain. The only thing that makes a rule specific enough to bind an agent is the failure that taught you its shape.
You cannot deposit that layer early.
And a rule specific enough to bind one model is not automatically specific enough to bind the next one. That is a maintenance cost nobody mentions in the guides. The sediment has to be re-cut in the new enforcer's language, or it quietly stops loading.
The Good CLAUDE.md
So write your rules.
Just know what they are.
The ones you write before you start are scaffolding: cheap, vague, disposable.
The rules that matter are the ones you write in the third week, in your own annoyed voice, after the model has done the wrong thing for the fifth time in a way you can finally name.
The ones that matter most are the ones you write in the fourteenth week, about the rules themselves, after you find a constraint in your own file that you never actually agreed to.
If you are starting out with Claude Code, and you have read the guides, and you wrote a careful CLAUDE.md, and the model is still doing things you do not want, you are not behind.
You are exactly on time.
The good CLAUDE.md is the one you have not earned yet. Fifteen weeks in, mine still is.
-- Justin Higgins. Software Engineer, Midwest. A hundred and five days pair-programming with an agent. The failures still write the rules; now the rules say which failures were mine.
Companion pieces: The Work Looks Like Nothing - why the session log is the first place judgment ever got recorded. Everything Looks Like Everything - the instrument that was measuring nothing.
Reactions, disagreements, war stories: jchigg2000.dev@gmail.com