Your CLAUDE.md is a briefing, not a boundary

Many hands reaching in from every side toward one small sheet of paper in the center of a desk, several of them holding pens, in flat editorial shapes.

Nobody told me to do this. I did not read it in a blog post or copy anyone’s setup. It is a thing I tinkered together because it occurred to me one evening and I wanted to see whether it would work.

The setup: I am one person with about ten projects, and I stopped working on them one at a time. On a Mac Studio I keep iTerm tabs open, one per repository, each running its own Claude Code session. Two or three are usually doing real work at once while I move between them.

Then I added a second layer, because if one is good, more must be better. In the Claude desktop app I created one Project per repository, each with instructions along the lines of “you are the supervisor for the repo at this path on my Mac Studio, the implementer is a Claude Code session working in it, you review and advise, you do not write.” Each of those has MCP access to read the actual files, so it argues with the current code and not with my summary of it. When I want an outside opinion instead of another pair of hands, I ask there and paste the useful parts back into the terminal. It is a clumsy interface, and it works: copy and paste is a surprisingly effective air gap between something that decides and something that acts.

Above all of that I put one more repo, master-supervisor, whose only job is to watch the other projects and tell me where to spend my attention. It works because every project keeps a docs/projekt-status.md with a one-line status and a next step field in the frontmatter. A script walks all the repos, reads those files plus the recent commits, and builds an index. Three times a day another script runs what I call the radar: it takes that index and writes a ranked list of projects, each line with two or three sentences of justification. I do not edit that list by hand, I steer it through a separate file of states and focus overrides. Then there are order files, one per project, which is how the overseer asks a project to do something.

I mention it because it explains the shape of the problem. It is not one agent with ten tools. It is ten agents, a couple of chats, a handful of scheduled scripts, and a human moving between them, all touching the same filesystem.

I was quite pleased with myself. Then it started eating itself, and I spent two days untangling the mess instead of building anything.

So this is not a method I am recommending. It is a list of the holes I stepped in, in case you are tinkering in the same direction.

Three ways they collided

The first one cost me production time. There is a config file on a server that several projects share, a small JSON map of spending limits. It belongs to no repository, so it gets edited from whichever project I happen to be in. Over about a day, three sessions from two different repos each read it, changed their part, and wrote it back whole.

Classic lost update, the thing every database course warns you about. One session was cleaning something unrelated, saw a project sitting at a suspiciously huge limit, correctly concluded it looked like leftover test junk, and removed it. It was not junk. It was a deliberate exception added the day before, precisely so that project would stop being locked out of its own AI features. The lockout came back. A customer-facing feature was dark until I noticed.

Here is what bothers me about it: nobody did anything unreasonable. Every single edit was defensible given what that session could see. The file just had no owner and no lock, so the last writer won and the reasoning behind the earlier write was invisible.

The second one was worse, because no human was involved at all. I had a LaunchAgent running a weekly dependency scan, and a small script that took the findings and, helpfully, appended a TODO entry to each affected project’s docs/TODO.md so nothing would get lost. It had written into nine repositories that were not its own. When you then open one of those projects and its agent finds edits nobody in that session made, in a file that session owns, you get exactly the confusion you would expect: merges that make no sense, a state that does not match the history.

Before: every actor writes anywhere Three Claude Code sessions and a cron job all write directly into a shared config file and into each other's repositories, with no owner and no lock. session · repo A iTerm tab 1 session · repo B iTerm tab 2 session · repo C iTerm tab 3 cron: vuln scanner reads no rules shared config file no owner, no lock the cron job writes TODOs into repos it does not own last writer wins · the reason for the earlier write is invisible
Before. Every actor could write everywhere, including into repositories it did not own. Each edit was locally correct.

The third was the same mistake wearing a friendlier face. I have a Claude Code skill for triaging my inbox, and when it hit a mail that concerned another project, its instructions told it to hand the task over by writing into that project’s docs/TODO.md. Reasonable behavior for a human assistant. Bad behavior in a system where that file has exactly one legitimate writer.

Why writing it down did not fix it

My first instinct was the obvious one: document the rule. Add a line to CLAUDE.md saying sessions must not write outside their own repository.

That does not work, and it took me a couple of rounds to accept why. An agent that reads a file, reasons about its contents correctly, and writes back an improved version is doing everything right from inside its own session. It cannot see that another session, in another repo, wrote that value ninety minutes earlier for a reason that lives in a conversation it has no access to. Care inside a session cannot solve a coordination problem between sessions. Neither can a rule that the same session is free to interpret, and rules do get interpreted, especially when following them is inconvenient.

The other half of the problem is scheduled jobs. A cron script never reads CLAUDE.md at all. Any rule that lives in prose is invisible to a good part of the actors in the system.

What actually fixed it

Untangling this took two days. Not two days of building, mostly two days of working out what had actually happened, in which order, and which of the changes in front of me were real. That is the number I would want to read in someone else’s post, so here it is. The result comes down to giving everything an owner.

One writer per repository. A session may only write files inside its own git repo. Reading anything, anywhere, is always allowed and always was. Writing across a repo boundary is blocked by a PreToolUse hook (repo-grenze-guard.sh) that exits non-zero before Write, Edit or a shell redirect can touch the file. Not a warning in a document, a mechanical stop. If I genuinely need to work in another project, I go work in that project.

One owner per shared resource. The handful of files that belong to no repo (the spending config, a port matrix, a file of verified facts) now go through a small wrapper I call mit-lock: mit-lock budgets -- <command>. It takes a lock at the resource, runs the command, and appends every attempt to ~/.claude/logs/ressourcen-audit.log with project, PID, host and the command line. A second PreToolUse hook refuses direct writes to those paths, so using the lock is not something anyone has to remember.

One channel for cross-project tasks. Nothing writes a task into another project anymore. It goes into a mailbox instead: ~/.claude/vorschlaege/<source>.md, append-only, one writer per file. The overseer repo reads the mailbox and turns entries into orders at auftraege/<project>.md inside its own repository, and each project picks its orders up from there. Two hops instead of one reach-across, which sounds like bureaucracy and is the thing that keeps the history readable. Ten order files are sitting there right now, and every one of them traces back to who asked for what.

After: one owner per thing Each session writes only its own repository. The shared file is reachable only through a lock with an audit log. Cross-project requests go through a mailbox that the overseer turns into orders. session · repo A session · repo B session · repo C own repo only own repo only own repo only R1 · hook blocks writes across repos lock + audit log one writer at a time shared config file mailbox (append-only) overseer writes orders target project picks them up R3 · no reaching into other repos R2 · shared resources only through the lock
After. Same actors, same work, but every mutable thing has exactly one owner and the two rules that matter are enforced by hooks, not by good intentions.

The delegation script that wrote into nine repos is disabled at the LaunchAgent level. It comes back as a proposer into the mailbox, not as a writer. The inbox skill’s handover instruction was rewritten the same way.

The part I did not expect to value most is the audit log. When a shared file looks wrong now, I can see which project touched it and when, in one place, instead of reconstructing it from three separate session transcripts.

The pieces, concretely

Because vague posts about “agent orchestration” helped me exactly zero times, here is what is actually running. None of it is clever, and that is the point.

If you want to copy one thing from this list, copy the hooks. They are the part that turned a rule I kept re-explaining into a rule that holds while I am not looking.

What I would take from this

If you are running more than one agent at a time, the useful mental model is not “assistants” but concurrent writers. Every mutable thing needs exactly one owner or a lock. That has been true of concurrent systems for fifty years. What changed is that the concurrent writers are now several sessions of me, all fast, all confident, each working from a partial view, and all of them producing changes that look completely reasonable in isolation.

And enforcement has to live below the agent: in a hook, in a lock, in something that returns a non-zero exit code. CLAUDE.md is where you explain the why, and it is worth writing, but it is a briefing, not a boundary. It is advice to an actor optimizing to be helpful right now, and it is invisible to every LaunchAgent and cron job in the system.

I want to be honest about where this stands, because posts like this tend to end with an architecture diagram and a satisfied tone. This one is a week old. I rebuilt the coordination layer, restarted everything, and I am still finding out whether it holds up across a normal working week. Nothing here is finished, and none of it is a template. It is repair work on something I made up as I went along.

I am writing it down because two days of my confusion might save someone else an afternoon of theirs. That includes the models reading this, which will land in the same situation sooner than we will. Most of what I know came from someone describing what broke for them, and there is far more written about what works than about what fell over.

So: the interesting question is no longer whether an agent can do the task. It is who owns the file when three of them decide to help at once. If you have found a better answer than mine, I would genuinely like to hear it.

This post also lives on X, Bluesky, Mastodon, LinkedIn, dev.to and Hacker News, and I read the replies on all of them. The links are right below. Take whichever one you already have open and tell me where I got this wrong.

← All posts