How I run 15 projects with Claude Code without losing the thread

A signal box interior with rows of mechanical levers, each connected to a different track, one lever pulled forward, in flat editorial shapes.
Illustration generated with AI (Flux 1.1 Pro).

Fifteen projects, one person. The obvious failure mode is that you spend your day switching between them, and by evening you have touched six and finished none.

So I do not switch. I open a terminal in whichever project I am in and type two words: order backlog. Claude Code reads that project’s queue, sorts it by priority, and starts talking to me about the one thing that matters most. That is my whole interface.

Behind those two words sits a system I built over the past few weeks, and this post is the architecture of it. Where work comes from, how it gets classified, what runs while I sleep, and the parts I refuse to automate no matter how tempting it gets. Here is the whole thing in one picture first, because it is much easier to see than to describe.

The whole thing on one page

Work enters from four sources. An email I send myself, a request I make inside a working session, an error report found by my assistant session, and merge conflicts thrown back by the system itself. Email is the only source that cannot go straight in. It lands in a drop box which checks the logic of the request and scans for dangerous verbs such as delete, transfer or cancel. Anything that came from email is forced to wait for me, no matter how it was marked. Every fifteen minutes the drop box is emptied into one order file per project. Claude Code then classifies each order, and the main question is whether it is small and well defined enough to be finished in a single unattended run. Too big goes to the dialogue pile, anything needing a human click becomes a decision, the rest becomes autonomous. Autonomous orders are picked up by a dispatcher every thirty minutes and run in a fresh git worktree created outside every repository, under three cost brakes and a limit of three attempts, starting on the cheapest model and climbing a rung only after a failure. If the merge is clean and the tests pass, the order closes. If it conflicts, the conflict becomes a new order and the loop starts again. After three failed attempts the order is marked incomplete and never starts itself again. On the dialogue side I type order backlog in a project, the system finds the most important open order, and presents it in a fixed shape: bird's eye view of where it sits, what is at stake, one recommended proposal with reasons, and two or three alternatives. I accept, pick an alternative, or write my own instruction. Then it builds, tests, deploys, tests again on production, closes the order and moves straight to the next one.

The rest of this post walks through that picture, one stage at a time.

Where orders come from

An order is a block of Markdown in a file. One file per project. That is the entire data model.

No database, no ticket system, no board with columns. I tried a proper tool for this years ago and gave up on it, because every one of them wants you to maintain the tool. Markdown does not want anything from me.

Work arrives from four directions.

I email myself. Something occurs to me while I am out. One line to my own address, no subject worth mentioning. This is the entry point I use most, because the phone is the only machine I always have on me.

I am working in a project and say so. Mid-session, something comes up that I do not want to handle right now. I say “file an order for this project: the upload box stutters when scrolling”, and the session writes it. Or the opposite case: I sit down in a project, think about everything still to do, and each item becomes an order.

My assistant finds it. A separate Claude Code session processes my inbox. When it hits an error report and can tell which project it belongs to, it files an order there.

A failed merge produces one. More on that below, because it is the loop that makes the whole thing self-correcting.

The drop box, and why mail does not go straight in

This is the part I thought about longest, and it is the one I would get right before anything else.

A mail I send myself does not become an order. It lands in a drop box first. Every fifteen minutes a small job on my Mac Studio empties that drop box into the project queues.

Why the detour? Prompt injection. My email address is public. Anyone can write to it.

Think about what that means for a moment. If mail text became executable work directly, a stranger could send me a polite message asking to delete a production domain, and my own system would file it as a properly formatted order and hand it to an agent with commit rights. Nobody would have to break in. They would just have to write.

So the drop box reads for sense, not just for format. Does what this text asks for make any sense at all? On top of that runs a scan for verbs with teeth: delete, drop, truncate, transfer, pay, cancel, shut down.

Anything that trips it is forced to needs me present. Not blocked, mind you. Legitimate orders say exactly those words all the time. “Delete the old backups” is a perfectly ordinary request. It simply never happens while nobody is watching.

The rule underneath is stricter than the keyword list, and it is the one I would hand to anyone building something similar: text that arrived by email never starts an unattended run. Not even when it is marked as approved and harmless. Origin outranks classification. A message from outside can ask for work. It cannot authorise it.

How the system decides what runs without me

Every order carries a field saying how it may be handled. Three values:

## ORDER <id>
status: approved
art: autonomous | dialogue | decision

autonomous runs unattended. dialogue waits for a session with me in it. decision is mine alone to click: payment switches, domain purchases, anything public.

The interesting question is who fills that field in. Claude Code does, at the moment the order is written, and the call it has to make is mostly about size. Is this small enough and clear enough to finish in one unattended run? Too big goes to the dialogue pile automatically. The system is allowed to decide that it cannot decide, which is a feature I like more the longer I use it.

If nothing is specified, the answer is dialogue. Fail safe, in the direction that hurts less. An order sitting around too long costs me waiting time. An order running unattended that should not have costs me production.

The autonomous path

Every thirty minutes a dispatcher wakes up, takes the top approved autonomous order, and runs it. Not in my repository. In a fresh git worktree, created outside every repo, on its own branch.

That detail is not decoration. It is the entire reason this can run while I work, because there is a good chance I am sitting in that same project at that same moment. The worktree gives the agent its own complete checkout, and my open files never notice a thing.

When it finishes, the work has to come back. If the merge is clean and the tests pass, it lands and the order is closed. If it conflicts, the system does not guess and does not force anything. The conflict becomes a new order in that project, waiting for me. Its failure mode is to write a ticket about itself, and I can live with that much better than with a system that improvises.

Three brakes, because the meter is running

I pay 200 euros a month for Claude Code. Agents that start themselves are, in financial terms, a machine that spends money while I sleep, and I come from a part of Germany where that thought keeps you awake. So there are three independent brakes.

A cap per run. Every worktree gets a hard dollar ceiling. It dies at the wall rather than running away.

A daily ceiling for the automation as a whole. Computed from the run logs. When the day’s total is reached, the dispatcher stops starting new work.

A limit on how many run at once. Two or three at a time, no more. It is not about CPU, it is about the account. I had to correct this number downwards once already. In the beginning I allowed four in parallel, which emptied my quota faster than I could read the dashboard. By the time I noticed, the month was a good deal shorter than planned. Two feels right today. Three is what I am aiming for once I trust the rest of the machinery a bit further.

There is a fourth one that I like more than the other three: an order gets at most three attempts. After that it is marked incomplete and never starts again on its own. It waits for my hand. A system that retries forever will eventually find a way to retry expensively.

And a small refinement I did not expect to matter as much as it does: runs start on the cheap model and only climb a rung after failing. Most orders are finished by the cheapest thing that could possibly work.

The other path: working through a project with me

The dialogue orders are where my actual days go, and the interface to them is those two words from the beginning.

I go into one of my roughly fifteen project directories and type order backlog. Claude Code lists that project’s orders, sorted by priority, and immediately starts on the top one. It presents it in a fixed shape, which turned out to matter more than I expected:

  1. Bird’s eye. One sentence on where this sits inside the project. Not the task, the context.
  2. The detail. One sentence on what it actually is.
  3. A concrete proposal with a recommendation, plus two or three alternatives, each with a reason.

Then I do one of three things: accept, pick an alternative, or write “let us do it differently, like this”. It builds, tests, deploys, tests again on the production server, marks the order done, and moves to the next one. I walk through my projects, and in each one the work rolls.

The fixed shape matters because it removes the part I am worst at: reading an order I wrote two weeks ago, in a project I have not opened in ten days, and working out what past me was thinking. Past me is not a reliable colleague. He writes terse notes and leaves.

Now I read three sentences and a recommendation, and I am back in context in about fifteen seconds.

One more thing I can say in a project: any general questions about the orders here? It collects everything it is unsure about across the whole queue. I answer all of it in one sitting, and then it runs on alone for a long stretch.

Batched questions instead of an interruption every ten minutes. Small change, enormous difference.

The one repository that may look everywhere

Normal projects are walled off from each other. A session in project A does not touch project B’s orders, ever. One writer per repository, enforced by a hook.

I did not build that rule out of tidiness. Two parallel sessions once wrote to the same shared config file, each read it, each changed its own line, each wrote the whole thing back. Last writer won, and one session’s work vanished without a trace. Classic read-modify-write, except I had not been thinking of my agents as concurrent processes at all. They are.

master-supervisor is the exception, and it is where the portfolio view lives. From there I can ask: what is the single most important order across everything I own? If an error report came in overnight from any project, that is what surfaces, regardless of which repository it belongs to.

And I can say “work on it now”. Then it checks something first: is a session already open in that project? If yes, it tells me it cannot work in the main repository directly, takes a worktree instead, and merges when it is done. It assumes I might be sitting in there, because I usually am.

What it costs to build something like this

If you are considering this for yourself, here is what is actually behind it. I counted today.

Shell scripts36, about 9,400 lines
Python5 files, ~350 lines (counting, reporting)
Documentation26 living docs, ~5,600 lines
Instruction files (CLAUDE.md)27 across all projects, ~5,500 lines
Skills (reusable prompts)63
Hooks (fire before and after tool calls)26, ~2,450 lines
Tests on the orchestration itself308
Commits that are real development263 in 22 days
Commits from the machine1,833 (index and ranking refresh on a timer)
Commits that are just bookkeeping706 (approvals, reclassifications, closures)
Unattended runs so far488 logged

Two things stand out when you put it in a table like this.

The first is the ratio. Roughly 9,800 lines of code against 11,100 lines of prose, counting docs and instruction files together. More than half of this system is not code at all. It is written instructions for a language model plus documentation for the one human involved. That surprised me, but in hindsight it should not have. The code only moves files around and starts processes. All the judgement lives in the text.

The second is the tests. 308 of them, on an orchestration layer of 9,400 lines, for a system with exactly one user. That sounds excessive until you remember what the thing does: it starts agents that hold commit rights on fifteen repositories while I am asleep. The tests do not run against the real orders, they run against copies.

One number in that table deserves a warning, because I got it wrong myself first. The repository has about 2,800 commits, and quoting that as build effort would be flattering nonsense. 1,833 of them are the machine talking to itself, because the index and the priority ranking refresh on a timer and every refresh is a commit. Another 706 are bookkeeping: approvals, reclassifications, closures. What is left, the commits that actually changed how the thing works, is 263.

I had written 1,360 in the first draft of this post. It felt about right, which is exactly the problem with numbers that feel about right. Whenever you see a commit count offered as proof of work, ask what else lives in that repository.

There is something I should say about those 263 commits, because it changes what the number means: I did not write a single line of this code myself.

Not one. All of it came out of working with Claude Code, and a good part of it I did not even type. I described what I wanted by talking, using Superwhisper for dictation, and then read, argued with and corrected what came back.

I started programming when I was sixteen. This is the first year of my life in which I have not written code by hand, and I am still not entirely used to saying that out loud. My job in this repository was not typing. It was deciding what should exist, noticing when something was wrong, and saying no often enough. Which, judging by this system, turns out to be most of the work anyway.

As for time, I never tracked it properly, so I can only estimate: somewhere north of a week of full time work, spread across evenings and weekends. Probably more. I would rather give you a rough number than a precise one I made up.

Whether that pays off depends entirely on how many projects you run. At three projects, do not build this. Use a Markdown file per project, it works fine, I did it for a year. Somewhere around eight or ten the arithmetic flips, because the cost of losing track of a project starts to exceed the cost of the machinery.

What this actually gave me

It does not make me faster at writing code. Claude Code had already done that part.

It solved a different problem, and it is the one that really finishes off solo developers running too many things: projects go quiet and nobody notices. Not because they failed, but because nothing in my setup ever raised its hand. A Markdown file will not tell you it has been ignored for three weeks. A queue that sorts fifteen projects by priority will.

The second thing is smaller and I value it more. I no longer decide what to work on by asking myself what I feel like doing, because what I feel like doing is always the project that is going well. Now I type two words and the sorting is done by something that has no moods and no favourites. Out of sight, out of mind is a genuine risk at fifteen projects, and this is the cheapest cure I have found for it.

If you build something similar, build the drop box and the approval gate first. Everything else in this system I have rebuilt at least once. Those two never needed repair, and they are the reason I can sleep while agents hold commit rights.

The whole thing is private and there is no public repository. If enough people want to see it, tell me and I will know it is worth making presentable.

← All posts