---
title: "From kanban to harness: when the tracking tool becomes the orchestrator"
description: "KittyClaw started as a board to track my agents. In two weeks, it became what triggers them. A shift small in code, big in consequences."
date: 2026-04-26T10:02:00+02:00
tags: ["KittyClaw", "Tooling", "AI", "Claude Code", "Philosophy"]
---

When I [shipped KittyClaw](/blog/kittyclaw-agent-driven-kanban) 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`](/blog/dispatcher-agent-orchestration): 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:

```json
{
  "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](/projects/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.mjs` — `documentalist` 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](https://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](https://discord.gg/4MVPfw9wTQ)**
