A custom Kanban board that drives autonomous Claude Code agents via GitHub Actions. Drag a card between columns, and agents handle planning, implementation, and review automatically.
# Clone and configure
git clone https://github.com/board2agent/b2a.git
cd b2a
cp .env.example .env
# Edit .env with your GitHub PAT, owner, and repo
# Start the board
docker compose up
# Open http://localhost:3000┌─────────┐ ┌──────────┐ ┌─────────────┐ ┌────────┐ ┌──────┐
│ Todo │───>│ Planning │───>│ In Progress │───>│ Review │───>│ Done │
│ │ │ (Opus) │ │ (Sonnet) │ │(Sonnet)│ │ │
└─────────┘ └──────────┘ └─────────────┘ └────────┘ └──────┘
human agent agent agent
drags plans codes reviews
│
├──> approve -> Done
└──> reject -> In Progress
- You drag a card from Todo to Planning
- The board applies
status:planninglabel via GitHub API - GitHub Actions fires the unified workflow
- The workflow reads
.b2a/pipeline.ymlto find the right prompt and model - Claude agent runs, does its work, swaps labels to advance the pipeline
- The board polls GitHub and updates automatically
| Component | Purpose |
|---|---|
board/ |
Next.js Kanban board (Docker Compose) |
.b2a/pipeline.yml |
Pipeline config — stages, prompts, models |
.github/workflows/b2a-agent.yml |
Single unified workflow for all stages |
GitHub Projects projects_v2_item doesn't work as an Actions trigger (despite being documented). Labels on issues (issues: [labeled]) are the reliable alternative. The board abstracts this away — you just drag cards.
The pipeline is defined in .b2a/pipeline.yml:
pipeline:
- id: planning
label: "status:planning"
color: "#0052CC"
model: "claude-opus-4-6"
next: "status:in-progress"
prompt: |
You are the planning agent...
- id: in-progress
label: "status:in-progress"
color: "#E36209"
model: "claude-sonnet-4-6"
circuit_breaker: 3
prompt: |
You are the implementation agent...Adding a new stage = adding an entry to this file. No workflow changes needed.
To connect a GitHub repository to the b2a pipeline, complete these steps:
Go to github.com/apps/claude and install it on the organization or account that owns the target repo. Grant it access to the specific repo (or all repos).
This links the agent to your Claude subscription (no API key needed).
- Run
claude setup-tokenin your terminal to generate an OAuth token - Go to the repo's Settings → Secrets and variables → Actions → New repository secret
- Name:
CLAUDE_CODE_OAUTH_TOKEN, Value: the token from step 1
Click "Onboard Repo" in the board UI (http://localhost:3000). This automatically creates:
- Labels:
status:planning(blue),status:in-progress(orange),status:review(purple),status:done(green),status:blocked(red) - Pipeline config:
.b2a/pipeline.yml— defines stages, prompts, models, and transitions - Workflow:
.github/workflows/b2a-agent.yml— single unified workflow that reads the pipeline config
Alternatively, you can create these manually by copying from this repo.
Set your .env file (in board/) to point at the target repo:
GITHUB_TOKEN=ghp_your_pat
GITHUB_OWNER=your-org
GITHUB_REPO=your-repo
- Create an issue in the target repo
- Drag it from Todo to Planning on the board
- Check that the
status:planninglabel appears on the issue - Check that the
b2a Agentworkflow fires in the repo's Actions tab
If the review agent rejects implementation 3+ times, the card automatically moves to Blocked for human intervention. This prevents infinite agent loops.
| Column | Color | Label |
|---|---|---|
| Todo | Grey | (none) |
| Planning | Blue | status:planning |
| In Progress | Orange | status:in-progress |
| Review | Purple | status:review |
| Done | Green | status:done |
| Blocked | Red | status:blocked |
- Docker Desktop
- GitHub Personal Access Token (see below)
CLAUDE_CODE_OAUTH_TOKENsecret on the target repo (runclaude setup-tokento generate)
The board needs a PAT to interact with issues, labels, and repo contents.
- Go to GitHub Settings → Developer settings → Personal access tokens (classic) or Fine-grained tokens (newer)
- Generate a new token with the required permissions below
- Copy it into your
.envfile asGITHUB_TOKEN
Classic PAT:
reposcope (full control of private repositories) — covers issues, labels, and contents
If the repo is public and you don't need the onboard feature, public_repo alone is sufficient.
Fine-grained PAT:
| Permission | Access | Used For |
|---|---|---|
| Issues | Read and Write | Reading issues, applying/removing labels, posting comments |
| Contents | Read and Write | Creating pipeline config and workflow files (onboard feature) |
# Run with hot reload (uses docker-compose.override.yml)
docker compose up
# Or run natively
cd board
npm install
npm run dev