AI coding tools assume single-threaded users
In January, Claude Code was generating so many artifacts that my main project’s docs/ directory was filling up with plans and handoffs from multiple orgs, multiple projects, and multiple dates. I sketched a Hive partition scheme — org/project/dt=YYYY-MM-DD/ — to tame the mess. I never built it.
The plan singleton problem came later and turned out to be worse. Claude Code’s plan mode stores one plan per session. Switch workstreams and the old plan haunts you. Start a new plan and the old one gets destroyed. No amount of directory structure fixes that — the singleton lives inside the session, not on disk. Both problems grow from the same root: AI coding tools assume you’re doing one thing at a time.
The plan that wouldn’t die
Claude Code has a plan mode. You enter it, describe what you want to build, the tool writes a structured plan, you approve it, work happens. When you’re done, you exit plan mode. Simple.
Except I’m never done with just one thing. A typical session for me touches infrastructure Terraform, a client project’s modules, a blog post draft, and a ticket triage pass. Four workstreams, one session. When I finish the Terraform plan and pivot to writing a blog post, the plan from the Terraform work is still there. It resurfaces in suggestions. It haunts the context. I call them zombie plans.
The tool doesn’t know I changed hats. It sees one session, assumes one intent, and keeps trying to be helpful about the last thing I was doing.
One session, one plan, one thread
Plan mode stores a single plan per session in a petnamed file — something like piped-juggling-spark. Enter plan mode again and the tool takes that plan out back and shoots it. The previous plan is gone. Not archived, not versioned, just replaced. I want to see what plans I generated and worked on months and years from now. I share plans with teammates for feedback and approval before implementation starts — the plan is a team artifact, not a private scratchpad. The tool treats them as disposable — one mutable slot, one plan in, one plan out.
This is fine if your sessions are single-purpose: open a terminal, fix a bug, close the terminal. The plan lifecycle matches the session lifecycle.
My sessions aren’t single-purpose. I run six sessions per workday in one repo alone — and that’s one of several active projects. Client work, personal tools, blog sites, each with their own Claude Code sessions, each multiplexed across three or four workstreams within a single session. The session is a workspace, not a task. The plan singleton doesn’t just assume one task per session. It assumes one thread of intent per session.
Every AI coding tool I’ve used makes this assumption. Copilot, Codex, Gemini CLI, Claude Code — they can all juggle multiple files, but they model the user’s intent as a single thread. One problem being solved, one workstream active. The tools don’t have a concept of “which hat am I wearing right now.”
The data engineer’s instinct
My first instinct was to partition. I’m a data engineer — when data from multiple sources lands in one place and you can’t tell which is which, you partition it.
~/.claude/
├── client-a/
│ ├── observability-poc/
│ │ └── dt=2026-01-14/
│ │ ├── handoffs/
│ │ ├── plans/
│ │ └── scratch/
│ └── training/
├── client-b/
│ ├── finops/
│ └── vpn/
├── startup/
│ ├── ml-infra/
│ └── compliance/
The layout uses Hive-style date partitions — one branch per org and project, so that plans live in their own directory, scoped to the workstream that produced them. The zombie plan problem can’t exist when plans are namespaced — there’s no singleton to haunt you because there’s no shared slot to fight over.
I wrote the shell helpers too:
claude_partition() {
local org=$1 project=$2
local today=$(date +%Y-%m-%d)
mkdir -p $CLAUDE_ROOT/$org/$project/dt=$today/{handoffs,plans,scratch}
}
claude_latest() {
ls -d $CLAUDE_ROOT/$1/$2/dt=* 2>/dev/null | sort -r | head -1
}
The idea was that each git worktree could symlink .claude to its partition, and direnv would export CLAUDE_ORG and CLAUDE_PROJECT to tell the tool which workstream was active. Like switching databases in a SQL client — same tool, different context. I never implemented it.
What I built instead
The partitioning schema would have worked for the artifact explosion — Claude Code reads whatever .claude directory is in the project root, and a symlink swap is all it takes. I was treating both problems as storage problems, but only one of them was. The plan singleton didn’t start driving me crazy until later, and by then I’d already built enough workarounds to keep moving.
I stopped using plan mode for plans. Instead I write them directly to markdown files in docs/, named by date and session number. HANDOFF-2026-03-12-session-04.md is unambiguous about when it was written and which session produced it. No singleton. No zombies.
The workflow rules that the tool can’t infer — “confirm before executing,” “approval of a plan means the document is ready, not that implementation should start” — I encode those in CLAUDE.md. The patterns that need to survive across sessions go into skills, because the tool forgets everything between sessions. And I maintain my own state machine for tracking work items: ticket → approval → branch → commits → PR → harvest. Each piece of work has a defined stage, and I tell the tool where we are every time we start.
I use multiple LLMs anyway — they have different personalities, excel at different things, and evolve at different speeds. But it’s undeniable that seeing the same stale plan offered to me over and over again is off-putting enough to make me open a different terminal. Sometimes I start a second Claude instance, or switch to Codex or Gemini, just to get away from the zombie. It keeps one session from drowning in context from another workstream, but it fragments my primary assistant. I end up ferrying context between Claude 1, Claude 2, Codex, and Gemini — copying findings from one into prompts for another, losing continuity every time I cross the boundary.
All of this is scaffolding I built because the tools assume I’m single-threaded.
Three kinds of context
The tools handle what’s happening right now — the conversation, the files open, the recent edits. That context lives in the window and dies when the session ends. They’re good at this part.
What they don’t handle at all is which hat I’m wearing. Am I doing infrastructure work or writing a blog post? Am I in one project’s Terraform or another’s? The answer changes which conventions apply, which files are relevant, which ticket board to check. The tools have no model for this.
And what I’ve learned across all sessions — debugging insights, architectural decisions, team conventions, and past mistakes — that’s what CLAUDE.md files and skills attempt to provide, but it’s static. A snapshot of knowledge baked into config files, not a living memory.
The Hive partitioning schema would have solved the middle problem — the symlink trick works. But it only solves artifact organization. The plan singleton lives inside the session, not on disk.
What the tools could do
AI coding tools need a concept of workstream — a named, switchable context that carries its own plans, its own conventions, and its own history.
Think of it like git worktrees. A worktree gives you a separate working directory with its own branch, its own index, its own state — without disturbing the other worktrees. A workstream switch would do the same thing for AI context: the plan, the relevant files, the applicable conventions, the ticket — all scoped to the workstream, all isolated from the others.
I say “I’m switching to the blog post now” and the tool archives the infrastructure plan, loads the content conventions, and stops suggesting Terraform completions. When I switch back, the infrastructure context is right where I left it.
Every AI coding tool will eventually need this, because the people who get the most value from these tools are exactly the people who context-switch the most.
The workaround that works
Until the tools catch up, the workaround is to stop using plan mode entirely. I write plans directly to files and name them by workstream. Handoff docs serve as session-spanning memory, workflow rules go into CLAUDE.md, and recurring patterns become skills.
It’s more manual than it should be. But it works, and it scales to any number of concurrent workstreams, because files in directories have always been the original partitioning scheme.
The Hive layout was the right idea — I just applied it with markdown files and naming conventions instead of symlinks and direnv. When multiple streams land in one place, you partition them. The tools haven’t learned that yet.