When I shipped KittyClaw two weeks ago, the tool did one thing: serve as a board. The Claude agents ran alongside — first by hand, then via a dispatcher.mjs: a Node script polling KittyClaw's API, triggering the right agent based on who was assigned to which ticket.

The dispatcher worked great. It orchestrated Aekan's 13 agents for weeks. But it was an external process: one more node dispatcher.mjs to launch, a state file (dispatch-state.json) to keep in sync, logs to dig up in .agents/channel/debug.log, a config to copy-paste across projects in JS.

Today, the dispatcher doesn't exist anymore. Orchestration lives inside KittyClaw. I run dotnet run on KittyClaw, nothing else. Aekan's 13 agents still run — but the infra that drives them is now a first-class citizen of the board.

This shift from "dispatcher on the side" to "dispatcher inside the board" is small in lines of code, but it completely changes what the tool is. And how I work.


Before: two processes to run, two places to look

The old setup was three stacked layers:

  1. KittyClaw — the board, with its UI and REST API.
  2. dispatcher.mjs — a separate Node script in the project's .agents/channel/, launched manually in a terminal.
  3. Claude Code — the agents themselves, launched by the dispatcher.

It worked. But every project had its own dispatcher.mjs, usually forked from Aekan and hand-adapted. Patterns duplicated: 30s polling, code lock, evaluator debounce, daily budget. Adding a feature (say boardIdle or subTicketStatus) meant re-coding it in every dispatcher, or accepting that one project had it and others didn't.

And visually, orchestration was invisible from the board. To see an agent's live activity, I'd pop a terminal, tail -f the dispatcher log, cross-reference with the board. Two places, two vocabularies.

The board didn't know there was a dispatcher. The dispatcher showed nothing on the board. They talked through the API and a JSON file — fully functional, but decoupled to the point of not knowing each other.


The click: the dispatcher belonged inside KittyClaw

What pushed me over was the pile-up of small repeated frictions. Every new project, I duplicated dispatcher.mjs. Every useful feature (like Lain's CEO wake on idle board), I'd ask myself "do I back-port it to Aekan?". Every bug, "which of the three dispatchers is running this one?".

And above all: KittyClaw already had all the info. Tickets, assignments, columns, members flagged as agents, history. The dispatcher only re-read what the board already knew, to decide what to launch. Duplicated reasoning, not data.

If it's repetitive across projects, it belongs in the engine. If the board already knows the state, it's the best-placed thing to react.


After: the board is the orchestrator

The new workflow is one step:

  1. I create a ticket on the board, assigned to @programmer.

That's it. Thirty seconds later, KittyClaw sees the ticket in the Todo column with assignee programmer, moves it to InProgress, and launches Claude Code with the programmer.md skill and the ticket context. Outputs stream into a live run panel. When the agent finishes, the ticket is ready for review.

What makes this workflow possible is an automations.json file in the project workspace:

{
  "trigger": { "type": "ticketInColumn", "columns": ["Todo", "InProgress"],
               "assigneeSlug": "programmer", "seconds": 30 },
  "actions": [
    { "type": "moveTicketStatus", "to": "InProgress" },
    { "type": "runClaudeSkill", "skillFile": "skills/programmer.md",
      "concurrencyGroup": "code", "maxTurns": 200 }
  ]
}

No magical engine. It's a 30s poll that reads the board, matches a pattern, and launches a claude process with the right skill and context. But once it's in place, I'm no longer in the loop. I become a supervisor.


What changes mentally

The time saved is real — no more switching, no more sessions to locate, no more commands to retype. But the real shift is elsewhere.

With the external dispatcher, I'd already moved past one-on-one chat. The board + dispatcher formed a running team. But the whole thing was fragmented: I watched the board to decide, a terminal to see what agents were doing, logs to debug. Three views for one system.

Now, the board is the system. I see global state, I assign, I let the infra dispatch, I watch streaming runs from the ticket itself. On Aekan, 13 agents run like this — including a documentalist that wakes on every commit, a code-janitor that sweeps every day at 3am, and an evaluator that checks quality whenever a ticket hits Done.

I no longer manage conversations. I manage a queue.

This metaphor shift looks trivial but runs deep. You can't hold 13 simultaneous conversations in your head. You can easily supervise a 50-task queue if the tool shows you what matters.


What stays on me

I read too many threads about "AI will do everything for me", so let me be clear: what matters is still what I do.

  • Deciding what's worth doing.
  • Writing a ticket clear enough for the agent to understand.
  • Reviewing what comes out, accepting or pushing back.
  • Spotting patterns worth automating.
  • Sculpting the tool when it rubs.

What integration removes is exactly what had no added value: maintaining one dispatcher per project, correlating three views, manually back-porting a feature from one project to another. What it leaves is all the rest — which is precisely the interesting work.


Why this lives in the board and not elsewhere

One could imagine a separate tool: a dedicated orchestrator that reads Jira/Linear tickets and launches agents. I had that hesitation moment. But the board already knows who's an agent, who's human, the state of tickets, who's blocked, who's ready for review. Pulling that info into another tool duplicates a source of truth — and creates two places to keep in sync.

Putting orchestration in the board is recognizing that the board is already the execution plan. All that was missing was the executor.

Experience-wise: when an agent runs, stream events (tool calls, file edits, tokens burned) land in a panel that opens from the ticket. No separate tab, no separate dashboard. The board is the dashboard.


What integration unlocks

Some automations already existed inside dispatcher.mjsdocumentalist on commit, evaluator on Done transition, daily code-janitor. What integration into KittyClaw changes isn't their existence, it's their reach:

  • One feature = all projects. When I added boardIdle for Lain's CEO wake, Aekan and HolybotsRisingApps got it for free. With three separate dispatchers, I'd have back-ported by hand.
  • Centralized daily budget. cost-log.jsonl is read by the single engine, the threshold (dailyBudgetUsd: 70) blocks everything non-CEO once crossed. Doing this across three independent dispatchers would have meant three implementations kept in sync.
  • Hot reload. POST /api/projects/{slug}/automations/reload — I change a field in automations.json, it's live. No Node process restart.
  • Unified observability. Every run is an engine object, accessible via API, streamed into the ticket's panel. No more tail -f on three log files.

The right way to put it: the same behaviors, but as infra instead of scripts.


What's next

The next post dives into the technical anatomy: what exactly happens between the moment I create a ticket and the moment Claude starts working. What context gets injected, how sessions persist across runs, how concurrency groups keep two agents from stepping on the same files.

But the deep lesson is already here: a board isn't a tracking tool. It's an execution plan that was waiting to be plugged in.


The code

Everything is on GitHub:

github.com/Ekioo/KittyClaw

If you're building custom tooling around your agents, or want to discuss this approach, join me on Discord.

Join the Discord