A Kanban board where humans and Claude Code / Codex agents collaborate. Two modes:
- Board — create or import a task; an agent picks it up; you chat with it from review → done. Attach files/images to a task — they land in the agent's workspace before the CLI starts.
- Chat — a free-form, multi-agent conversation over a real project directory. @-mention agents into one thread; they collaborate with each other via team tools.
Agents are portable manifests: pick the harness (claude or codex),
optionally pin a model (with a cc-switch
proxy the model dropdown lists exactly what the active provider serves), and
declare marketplace plugins (claude-only) — the runtime that executes a
task is chosen at dispatch time.
Chat mode lives alongside the board (not inside it — conversations have no kanban lifecycle):
- Pick any project directory as the shared workspace; every agent in the thread works in it.
- @-mention an agent to bring it into the conversation. Each (conversation, agent) pair keeps its own claude session, so agents keep independent context across turns. Messages without a mention follow sticky routing — they reach the agent you last talked to.
- Agents get team MCP tools injected per turn:
delegatehands a sub-task to a teammate (scoped to agents already in the conversation),list_teammatesshows who's available. Calls are authenticated with per-turn tokens; the server is the sole token authority. - Before each turn an agent receives a handoff baton — a short catch-up
of what teammates did since its last reply (long entries are spilled in
full to
.handoff/in the workspace). - Conversations track cumulative token/cost spend, accept file uploads, and archive with per-agent JSONL reports.
Chat mode is always on in the desktop/local build. Team servers opt in with
CHAT_ENABLED=true (conversations are isolated per user; each user's turns
run on their own daemon).
A one-page walkthrough of daemon pairing, agent onboarding, the task lifecycle, per-task workspaces, capabilities/plugins, watchers, the protocol, and the server schema (see also runtime-and-flow.md):
| Piece | Tech |
|---|---|
| Server | Go (chi router, email+password auth) |
| Daemon | Go (one binary, pairs with server, spawns claude / codex) |
| Desktop | Wails v3 (macOS app: server + daemon in one process, no login) |
| Frontend | React 18, Vite, Tailwind v4, base-ui + shadcn-style primitives |
| Storage | SQLite (default, pure-Go) or MySQL 8.0 via DB_DRIVER=mysql |
| Wire | REST + WebSocket (server ↔ daemon, server ↔ browser) |
Three pieces: a server (one, central), a daemon on every machine that should run agents, and you in a browser. Or skip all of that and build the desktop app — server + daemon bundled in one macOS app, no login.
- Server host — nothing. The binary embeds the UI; SQLite is pure-Go and
server.dbis created underDATA_DIRon first run. - Daemon host — the
claudeand/orcodexCLI onPATH, already logged in (claude /login/codex login). The daemon spawns these per task/turn. - Building — Go (version in
backend-go/go.mod), Node ≥ 20,make.
Everything has a sensible default — the server boots with none set:
| Var | Default | When you need it |
|---|---|---|
DATA_DIR |
~/.batonboard/data |
Persist the DB somewhere fixed (recommended for deploys) |
SERVER_URL |
http://localhost:8787 |
Your public URL behind a reverse proxy |
PORT / HOST |
8787 / 127.0.0.1 |
Change the listen address |
COOKIE_SECURE |
false |
Set true when served over HTTPS |
CHAT_ENABLED |
false |
Open chat mode on a team server (desktop always has it) |
ENCRYPTION_KEY |
(none) | Encrypts stored integration tokens (Jira/GHE creds) at rest — set on team servers |
DB_DRIVER |
sqlite |
Set mysql + DB_SERVICE_* vars for MySQL 8.0 |
Integrations — set the whole group to enable:
| Var(s) | Enables |
|---|---|
ATLASSIAN_DOMAIN, ATLASSIAN_EMAIL, ATLASSIAN_API_TOKEN |
Jira task import / Jira watcher |
GITHUB_TOKEN |
GitHub Enterprise watcher (pull PRs awaiting your review) |
One double-clickable Open Kanban.app: the server and daemon run in-process
on a loopback port, the SPA is embedded, and there's no login — it's your
single-user local board with chat mode on.
scripts/build-desktop-app.sh # → dist/Open Kanban.app
open "dist/Open Kanban.app"Requirements: macOS 13+, Go, Node ≥ 20, and the claude/codex CLI logged
in. The script builds the SPA, embeds it (-tags embed_ui), compiles the
Wails binary, and ad-hoc signs the bundle (fine locally; distribution needs
Developer ID signing + notarization). Optional: drop a 1024×1024
dist/icon-source.png before building to get a real app icon; stamp a
version with VERSION=0.2.0 scripts/build-desktop-app.sh.
git clone <repo> && cd batonboardDev (three terminals, HMR):
make dev-server # backend on :8787
make dev-frontend # Vite SPA on :5173
make dev-daemon # daemon: auto-pairs in the browser on first run, then runsOpen http://localhost:5173, register with an email + password, approve the
daemon when the browser pops up, and you're on the dashboard. To let the
daemon use a real project dir:
make dev-daemon-config BROWSE_ROOTS=$HOME/Developer/your-project once
before make dev-daemon.
Production binaries:
make server-embed # → backend-go/bin/server (SPA embedded, self-contained)
make build-daemon # → backend-go/bin/daemon
VERSION=v0.1.0 make release # cross-compile all platforms → dist/ + checksumsRun the server behind a TLS reverse proxy with SERVER_URL set to the public
URL and DATA_DIR on a persistent path. On each agent machine:
./daemon run --server https://kanban.example.comThe first run auto-pairs: it opens your browser to approve (you must be
logged in), saves a token to ~/.config/batonboard/credentials.json, then
connects. Later runs just reconnect. Re-pairing the same machine (same
hostname) reuses the same runtime, so its agents stay attached. Multiple
daemons per user are fine (laptop + work box) — each is its own "Runtime".
- Log out and log in with a different account to switch workspaces (data is isolated per user).
- Settings → Danger zone → Reset everything wipes all your data, unpairs
your daemons, and signs you out (type
RESETto confirm).

