← Back to Too Good to Share

Too Good to Share / Series

CCSwitchboard

1. What it is, and why I built it

View on GitHub

Why I built it

It exists because of friction. I run several Claude Code instances at once, each in its own terminal tab, some on the host machine and some on the VM, each pointed at a different repo. Alongside them I keep a separate Claude.ai conversation per project, because that is where I actually think and plan. The two halves do not talk to each other, so I was the wire between them. Plan something in a web thread, paste it into the right terminal, wait, then copy the result back into the right web thread so Claude.ai can react to it. Do that across several projects at once and most of the work is bookkeeping: what I had pasted where, which runs I was still waiting on, which finished results still needed feeding back into which conversation.

Underneath that sat a smaller gripe, and it is the one that seeded the whole thing. Terminal tabs are easy to close by accident. The X sits right where you tap to switch tabs, and I had killed plenty of mid-run Claude Code instances by fumbling it. So the first thing I actually built that night had nothing to do with any of this: a one-line Windows Terminal fix to hide the close button. A warm-up. But it put me in the mood to fix the bigger annoyance properly.

What I wanted was plain enough. Kick off Claude Code tasks, and have something send a prompt back into the chat when a task finished, so Claude.ai could read the result and decide what to do next on its own: fire the next job, tell me it is done, or tell me it needs me.

Nothing that already existed did that. I looked. Every one of them was built to run agents, not to keep those agents wired into the conversation I plan in. I weigh them all up properly in the alternatives section further on, so this is only the short version of why none of them scratched the itch:

  • Subagents, the Task tool inside one Claude Code run, fan work out in parallel nicely. But they live inside that one run, and nothing fires them from a chat thread.
  • Agent Teams and multi-agent orchestration frameworks coordinate agents well. They are heavier to stand up, and they still are not driven from the browser conversation. The framework route also usually calls the paid API directly, so heavy use is metered per token rather than covered by a flat plan.
  • Local orchestrators like Conductor, Claude Squad and Gas Town fan work out better than this does. But each one is another place to live in, not a bridge from the chat I already plan in.
  • Hosted cloud agents like Claude Code Web, Jules and Codex Web need no local setup. They are still a separate destination, and they hand me less control over my own VM and machine.
  • CI-driven automation like claude-code-action is good for jobs triggered by repo events. It is not interactive and it is not a conversation, and running it in a pipeline means it bills against the metered API rather than a flat plan, which adds up fast for heavy use.
  • Docker self-host runners give clean isolation, at the cost of more infrastructure to stand up. They usually run on a raw API key, so every token is metered rather than flat-rate. And they still do not dispatch from the chat.

The same thread runs through all of them. They all run agents. None of them keeps the planning conversation and the execution in the same place, so none of them removed the thing that was actually costing me time, which was the copy-paste between the chat and the terminal. They are aimed at a different problem to the one I had.

There is a money angle as well, though it only applies to some of them. CCSwitchboard drives the ordinary Claude Code command-line tool, so every job it runs sits on my flat Claude subscription. A few of the options above bill the metered API by the token instead, the pipeline and Docker routes especially, and calling the API directly like that costs a great deal more than a flat plan once you are putting real volume through it. The rest, the subagents, the local orchestrators and the hosted cloud agents, mostly run on a subscription of some kind too, so there the cost is a wash and only the copy-paste problem separates them from this.

What it is

The one-line version is above: Claude.ai in the browser dispatches a job, a headless Claude Code run executes it on the VM, and the answer comes back into the same conversation without me carrying it across by hand.

That last part is the whole point of the project. A chat thread is turn-based. It cannot wake itself up. It sits there until a human types the next message. Everything CCSwitchboard does serves one idea: give the conversation a way to be woken by something other than me. Once a turn-based thing can be poked from outside when work completes, it can drive real work without me standing over it. The rest of this page is the machinery that does the poking, and there is more of it than you would think.

There are several moving parts. The next section maps them.

Architecture topology: four components each talking only to the relay in the middle
The flat topology: four components, each only ever talking to the relay in the middle, and no component talking to any other directly.
A Rube Goldberg machine, absurdly overcomplicated
This is what I thought too when I started mapping out how it would all work together
The concurrency guard: one repo, one running job, a queue of nothing, and a repo free nudge that wakes the loser to retry
The concurrency guard: one repo, one running job, a queue of nothing, and a "repo free" nudge that wakes the loser to retry.
The lifecycle of a single job: dispatch out to the relay, run and stream, and the result back to the same thread
The lifecycle of a single job: dispatch out to the relay, run and stream, and the result back to the same thread. One loop, out and back.