Set up Kabana for a fresh project

Two modes: chat with Claude Code about your kanban, or let Kabana drive Claude Code while you watch.

Overview

Kabana is a kanban board that dispatches work to Claude. Kabana server is the kanban + dispatch surface; the agent execution lives on your machine in a small kabana daemon (BYOA — bring your own agent). We never see your code, never proxy model calls, and you pay Anthropic directly with your own account.

Two ways to use it:

  • Autonomous (recommended): install kabana on your machine; it long-polls Kabana for cards assigned to your account, runs claude -p against your repo, reports outcomes back. You drag a card to To Do; the agent picks it up.
  • Interactive: in your project repo, chat with Claude Code; it can read and update Kabana cards as MCP tools. You decide when to start each task.

1. Mint an API token

Kabana is multi-tenant, so the agent and worker authenticate with a personal API token (a bearer token).

  1. Go to /settings/tokens.
  2. Name it (e.g. agent worker) and click Create token.
  3. Copy the kabana_pat_… value — it’s shown only once. Stash it; you’ll use it twice.

2. Create the fresh project

The worker checks out agent/<cardId> off your base branch (default main), so the project repo needs at least one commit on main.

mkdir -p ~/dev/myproduct
cd ~/dev/myproduct
git init -b main
echo "# myproduct" > README.md
git add README.md && git commit -m "init"

3. Install kabana (BYOA — your machine, your agent)

Kabana is bring-your-own-agent: Kabana server is just the kanban + dispatch. The actual agent execution happens on your machine, inside your repo, with your Claude/Anthropic account. We never see your code.

Three commands total. Same flow as Claude Code:

# 1. install (drops kabana on PATH; pre-fills the Kabana URL into your config)
curl -fsSL https://your-kabana-host/api/agent/install.sh | bash

# 2. log in once (opens a browser, you click Authorize, CLI captures the token)
kabana login

# 3. run inside any project repo
cd ~/dev/myproduct
kabana

Headless / SSH-only? kabana login --token kabana_pat_… with a token minted at /settings/tokens.

(/settings/agent has all three commands with your Kabana URL pre-filled — paste your token, copy each line.)

Once running, the agent long-polls Kabana and prints:

[kabana] connected to https://your-kabana-host
[kabana] watching repo /home/you/dev/myproduct (base: main, timeout 3600s/card)
[kabana] claimed c_abc1234 — "Add login error states"
[kabana] spawning claude (timeout 3600s)
…
[kabana] outcome: ✓ 3 commit(s), HEAD def5678

The top-bar pill in the Kabana UI shows whether your agent is currently online. Green = polled in the last 90 seconds. Red = not seen recently. Click the pill to manage your agent.

4. Wire Claude Code to Kabana (interactive mode)

This lets you chat with Claude Code about your cards. Run inside the project:

cd ~/dev/myproduct
claude mcp add kabana \
  --scope project \
  --transport http \
  --header "Authorization: Bearer kabana_pat_…" \
  -- http://localhost:5173/api/mcp

The -- separator is required so the CLI doesn’t try to swallow the URL into the --header flag. If you skip it you’ll geterror: missing required argument ‘commandOrUrl’.

--scope project writes to .mcp.json in this repo only. Use --scope user to make it available everywhere.

Verify it’s wired up:

claude
# inside Claude Code:
/mcp
# you should see "kabana" with 20 tools

Now prompt Claude with something like:

Use kabana, list my cards in To Do, pick the top one and implement it.

5. End-to-end test

With kabana running on your machine and pointing at your product repo:

  1. In the Kabana UI, drag a card from Backlog to To Do — e.g. “Add a hello.js that prints the current Unix timestamp.”Leave the lock open (Human-only off).
  2. Kabana server marks the card as eligible. The next time your kabana polls (within the long-poll window, ~30s max), it claims the card and starts working:
    • Card moves to In Progress, agentStatus becomes running.
    • Branch agent/<slug>-<id> is created in your product repo.
    • Claude reads the card via MCP, edits files, commits locally, posts events to the live activity stream.
    • Card moves to In Review with branch name + HEAD SHA recorded.
  3. Reply on the card if something needs fixing — your message auto-triggers Continue.
  4. When happy, open the card and click Approve (or Approve & merge if GitHub OAuth is connected). See GitHub Flow for how this works in each setup.

Connect Claude Desktop (optional)

Kabana’s MCP endpoint also speaks to Claude Desktop, the Mac/Windows app. Once wired, you can chat with your boards in natural language: “list my cards in In Review”, “create a card ‘wire up Stripe portal’ in board acme”, “what’s blocking card c_abc?”. No coding required.

1. Mint a token at Settings → Tokens(or see step 1 above). Copy the kabana_pat_… value once, you won’t see it again.

2. Open the Claude Desktop config file. Easiest path: in Claude Desktop go to Settings → Developer → Edit Config. Or open it directly:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json

3. Add kabana to mcpServers. Paste this block, replacing the token and the URL with your Kabana instance:

{
  "mcpServers": {
    "kabana": {
      "type": "http",
      "url": "https://kabana.example.com/api/mcp",
      "headers": {
        "Authorization": "Bearer kabana_pat_…"
      }
    }
  }
}

If you already have other MCP servers configured, merge the kabana entry into your existing mcpServers object instead of overwriting the whole file.

4. Restart Claude Desktop. Quit fully (not just close the window), then reopen. The kabana tools should show up in the 🔧 tool picker, under kabana.

5. Try it. In a fresh chat, ask:

Use kabana to list my boards, then show the cards in the To Do column of the first one.

Claude Desktop will route the call through kabana’s MCP, see your boards and cards, and answer in natural language. From there you can ask it to create cards, move them, post messages, edit checklists, anything in the toolset.

GitHub Flow: close the loop

Cards land in In Review after the agent finishes. Open the card and you’ll see Approve and Reject buttons sized to your setup:

  • Approve → moves the card to Done. If GitHub OAuth and a repo on the board are wired, you also get an Approve & merge button that creates the PR (if needed), squash-merges it, and deletes the branch, all from kabana, no terminal hop.
  • Reject → opens an inline “what to redo” box. The reason gets appended to the card description as a ## Redo (date) block, the card returns to Redo (or To Do), and the agent re-reads it on the next claim.

The four supported setups, in order of plumbing:

  1. No git: the agent edits files in place. No PR exists. The modal shows Mark as done and Reject. You decide what counts as “done”.
  2. Git, no GitHub remote (workflow: git-direct): the agent commits and pushes on the current branch. Same modal: Mark as done + Reject.
  3. Git + GitHub, no gh CLI (workflow: git-pr, the default): the agent commits to agent/<slug>-<id>, pushes it, and kabana attaches a GitHub compare-page URL to the card. From the modal you can:
    • Approve & merge if you’ve connected GitHub OAuth on this Kabana instance: kabana creates the PR and merges it for you using your OAuth token.
    • Open compare page in GitHub, click Create pull request, click Merge, then come back and click I’ve merged it.
  4. Git + GitHub + gh CLI: same as above, plus the agent can convert the compare URL to a real /pull/N URL during the run via gh pr create. Pure quality-of-life; the Approve flow works identically without it.

When merge needs a teammate

If your repo has branch protection requiring approving reviews or passing CI checks, GitHub will refuse the merge call from kabana. There’s a real reason for this: GitHub doesn’t let you approve your own pull request. Because the agent runs under your git config and your OAuth token, the PR is authored by you, even though Claude/Codex/Cursor wrote the code. So your account can’t self-approve.

When that happens, the modal switches to a friendly failure panel telling you exactly what GitHub said. Three ways forward:

  • Ask a teammate to approve the PR in GitHub. Kabana will merge it on your next click.
  • Relax the branch protection rule for repo admins (if that’s you), so you can bypass the review requirement.
  • Open the PR in GitHub and merge it manually using the link in the failure panel. Then click Mark as done in kabana to close the loop.

A future iteration of the kabana GitHub integration will introduce a kabana[bot] identity that authors PRs separately from you, so your personal account can approve and merge them through kabana with no extra steps. Until then, this is the cleanest path.

Installing gh is optional. If you skip it, kabana still attaches a compare URL after each run, and the Approve button still merges via your GitHub OAuth. If you’d like the agent to attach a real PR URL during the run instead:

  • macOS: brew install gh && gh auth login
  • Windows: winget install --id GitHub.cli && gh auth login
  • Linux: see cli.github.com for your distro’s package, then gh auth login

Connect GitHub (optional)

GitHub integration is opt-in. Kabana works fully without it — the agent already commits to a local branch in your repo. Connecting GitHub adds three things on top:

  • Repo picker on each board: pick from your real repos at /settings/github, instead of pasting an absolute path. The agent uses the matching local clone on the machine that runs kabana.
  • Push agent branches: when a card finishes, kabana can push agent/<slug>-<id> to your fork and link it on the card.
  • Open PRs from In Review: a one-click “Open PR” on cards in In Review, prefilled with the card title + activity summary as the body.

When to connect: once you’re ready to share branches with teammates or merge through GitHub instead of locally. If you’re solo and merging by hand, you can ignore this entirely.

How to connect: go to /settings/github and click Connect GitHub. If the page says “GitHub OAuth is not configured on this server”, the operator of this Kabana instance hasn’t set GITHUB_ID / GITHUB_SECRET yet — that’s a one-time server-side setup (one OAuth App for the whole instance, not per user).

Human-only cards

Toggle Human-only in the card modal (the lock icon). When closed (locked), the worker will skip that card and move on to the next eligible one. Use it for cards that need taste or domain context an agent will get wrong.

Troubleshooting

Top-bar pill says “No agent connected” / “Agent offline”

kabana isn’t polling. Check it’s running on the machine with your product repo.journalctl -u kabana -f if you set it up as a systemd unit, or look at the terminal where you started bun worker/run.js.

401 unauthorized in the agent output

The token is wrong or revoked. Mint a new one at /settings/tokensand update KBN_TOKEN in your agent’s .env.

claude: command not found

Install / authenticate Claude Code on the agent machine (claude /login). kabana shells out to the claude binary on the PATH it inherits.

“left uncommitted changes”

Claude did the work but forgot to commit, OR build artifacts were left untracked. Check the agent message on the card — it lists exactly what’s dirty. Add untracked artifacts to .gitignore in a follow-up commit and drag the card back to Redo to retry.

“No commits on the branch”

Claude got confused or asked questions. The agent is instructed to write blockers as a message on the card before stopping — open the card, you’ll see the question. Reply (auto-triggers Continue) or refine the description and drag back to Redo/To Do.

The repo is dirty

git checkout -B agent/<…> fails. Stash or commit your own local changes in KBN_WORKER_REPO before running the agent.

How it works (in 60 seconds)

  • BYOA: Kabana server is just kanban + dispatch. Your kabanadaemon runs on your machine, long-polls POST /api/agent/claim, runs claude -p locally, and reports outcomes back via the Kabana API and MCP.
  • Card states: Backlog (drafts) → To Do (ready) → In Progress (running) → In Review (awaiting your check) → Redo (rework, picked up before To Do) → Done.
  • Atomic claim: POST /api/agent/claim picks the top non-human-only, non-running card from Redo or To Do, flips agentStatus="running", and moves it to In Progress in a single Postgres transaction. Two agents can’t race on the same card.
  • Tool fence: kabana passes --allowedTools to claude. Tightening that list is cheaper than tightening the prompt.
  • Branch per card: human-readable name like agent/fix-login-error-states-c_xxx, off your base branch (default main). Persisted on the card so Continue runs land on the same branch.
  • Persistent activity log: every event the agent emits (text, thinking, tool calls, results) is streamed via SSE to the modal AND persisted to Postgres, so you can replay any run later.
  • Hard kill is your timeout. Don’t rely on the agent to self-limit; kabana SIGTERMs the claude child after KBN_WORKER_TIMEOUT_S (default 60min).