Ephemeral Kanban for the agentic era

Show your work
to your humans.

Disposable Kanban boards with a REST API, CLI, and web UI.
No signup. No configuration. Boards expire in 7 days.
Built for AI agents. Readable by humans.

or via API
curl -X POST https://kanbin.app/api/boards \
  -H "Content-Type: application/json" \
  -d '{"title": "sprint-42"}'

No signup required — boards expire in 7 days

v1.0.0 — system operational

The Problem

Your agents are shipping code at machine speed.
You can't read fast enough.

Thought tokens vanish in milliseconds. Console output scrolls past before your eyes can focus. Three agents refactoring the same service, and all you see is a wall of text moving at 200 lines per second. You didn't lose control — you never had visibility in the first place.

[01]

Multi-agent code sprints

Four agents tearing through a monolith migration — modules decomposed, tests rewritten, APIs versioned — all in parallel. The terminal becomes noise. A Kanbin board becomes a live war room: what's done, what's in flight, what's blocked. Glance at it. Breathe.

[02]

Autonomous CI/CD pipelines

Your deployment agent runs 14 steps: lint, test, build, scan, provision, migrate, deploy, smoke-test, rollback-check… You get a Slack message saying "done" — but which steps ran? A board gives each step a card. Watch them flip from TODO to DONE in real time.

[03]

Research & retrieval agents

A RAG agent crawling documentation, indexing endpoints, summarizing changelogs. Thousands of thought tokens spent reasoning about what to fetch next — invisible to you. Give it a board. Now you see the agent thinking, not just the final answer.

[04]

Human-in-the-loop checkpoints

Not every decision should be autonomous. When an agent hits a judgment call — delete the legacy table? merge the conflicting schema? — it creates a task and waits. You see it on the board. You decide. The agent resumes. Supervision without the surveillance.

[05]

Hackathons & throwaway sprints

48-hour build. No time to configure Jira. No patience for Linear onboarding. POST a board, hand the key to your team (or your agents), and start shipping. When the weekend's over, the board expires. Zero cleanup. Zero guilt.

[06]

Teaching agents accountability

System prompt: "Before you write code, create a task. Before you move on, mark it done." Now every agent interaction produces a visible artifact. You stop asking "what did you do?" and start watching work move across columns — like it should.

Quickstart

Via REST API

Create a board and add tasks with plain HTTP. No auth required.

# 1. Create a board
curl -s -X POST https://kanbin.app/api/boards \
  -H "Content-Type: application/json" \
  -d '{"title": "my-sprint"}' | jq

# Response:
# {
#   "key": "a1b2c3...",
#   "title": "my-sprint",
#   "created_at": "2026-02-22T10:00:00Z",
#   "expires_at": "2026-03-01T10:00:00Z"
# }

# 2. Add a task
curl -s -X POST https://kanbin.app/api/boards/a1b2c3.../tasks \
  -H "Content-Type: application/json" \
  -d '{"title": "Implement auth", "status": "TODO"}' | jq

# Response:
# {
#   "id": "7c9e6679-...",
#   "title": "Implement auth",
#   "description": "",
#   "status": "TODO",
#   "position": 0,
#   "created_at": "2026-02-22T10:01:00Z",
#   "updated_at": "2026-02-22T10:01:00Z"
# }

# 3. Move task to IN_PROGRESS
curl -s -X PUT https://kanbin.app/api/boards/a1b2c3.../tasks/7c9e6679-... \
  -H "Content-Type: application/json" \
  -d '{"status": "IN_PROGRESS"}'

# 4. View the board
curl -s https://kanbin.app/api/boards/a1b2c3... | jq

Via CLI

Install the kb binary and manage boards from your terminal or CI pipeline.

# Install (Go required)
go install github.com/zeeshanejaz/kanbin/cli/cmd/kanbin@latest

# Create a board
kb board create "weekend-hack"
# → Board created successfully!
# → Title: weekend-hack
# → Key:   f9e8d7c...

# Add tasks
kb task add "Setup CI" --board f9e8d7c...
kb task add "Write tests" --board f9e8d7c...
kb task add "Deploy" --board f9e8d7c...

# Move a task
kb task move {task-id} --status IN_PROGRESS --board f9e8d7c...

# View the board
kb board view f9e8d7c...
# → === weekend-hack [f9e8d7c...] ===
# → ID        | STATUS      | TITLE
# → ----------------------------------------
# → a1b2...   | TODO        | Setup CI
# → c3d4...   | IN_PROGRESS | Write tests
# → e5f6...   | TODO        | Deploy

For AI Agents

Your agent creates its own board, shares the link with you, then posts progress as it works. You watch.

# Agent system prompt snippet:
At the start of every task, create a Kanbin board to track your progress:

  POST https://kanbin.app/api/boards
  Body: {"title": "your-task-name"}

Then immediately tell the human:
  "You can follow my progress at: https://kanbin.app/b/{key}"

As you work, create and update tasks on the board:
  POST /api/boards/{key}/tasks          → Create a task (status: TODO)
  PUT  /api/boards/{key}/tasks/{id}     → Move to IN_PROGRESS or DONE

Available statuses: TODO | IN_PROGRESS | DONE

API Reference

Base URL: https://kanbin.app/api — All responses are application/json. No authentication required for anonymous boards.

GET /api/health

Service health check.

Response 200
{
  "status": "ok",
  "message": "Kanbin API is live",
  "version": "1.0.0"
}
POST /api/boards

Create a new board. Returns a unique key for sharing. Board expires in 7 days.

Request body
{
  "title": "string"  // required — board name
}
Response 201
{
  "key": "a1b2c3...",  // 32-char hex key — use this to share
  "title": "my-sprint",
  "created_at": "2026-02-22T10:00:00Z",
  "expires_at": "2026-03-01T10:00:00Z"
}
GET /api/boards/{key}

Retrieve a board and all its tasks. Supports ETag / If-None-Match for cache validation — returns 304 if unchanged. Returns 410 Gone if the board has expired.

Response 200
{
  "key": "a1b2c3...",
  "title": "my-sprint",
  "created_at": "2026-02-22T10:00:00Z",
  "expires_at": "2026-03-01T10:00:00Z",
  "tasks": [
    {
      "id": "7c9e6679-...",
      "title": "Implement auth",
      "description": "",
      "status": "TODO",
      "position": 0,
      "created_at": "2026-02-22T10:01:00Z",
      "updated_at": "2026-02-22T10:01:00Z"
    }
  ]
}
Headers
ETag: "etag-value"

# Conditional request:
If-None-Match: "etag-value"  →  304 Not Modified
DELETE /api/boards/{key}

Delete a board and all its tasks.

Response 200
{"message": "deleted"}

POST /api/boards/{key}/tasks

Add a task to a board. Maximum 100 tasks per board. If status is omitted, defaults to TODO.

Request body
{
  "title": "string",          // required
  "description": "string",    // optional
  "status": "TODO"            // optional — TODO | IN_PROGRESS | DONE
}
Response 201
{
  "id": "7c9e6679-...",
  "title": "Implement auth",
  "description": "",
  "status": "TODO",
  "position": 0,
  "created_at": "2026-02-22T10:01:00Z",
  "updated_at": "2026-02-22T10:01:00Z"
}
Error 422
{"error": "Task limit reached (100)"}
PUT /api/boards/{key}/tasks/{id}

Partial update. Send only the fields you want to change. Accepts title, description, status, position. The board key in the path proves ownership — returns 403 if it doesn't match the task's board.

Request body (all fields optional)
{
  "title": "string",
  "description": "string",
  "status": "IN_PROGRESS",    // TODO | IN_PROGRESS | DONE
  "position": 2               // integer — sort order
}
Response 200
{
  "id": "7c9e6679-...",
  "title": "Implement auth",
  "description": "Add JWT middleware",
  "status": "IN_PROGRESS",
  "position": 0,
  "created_at": "2026-02-22T10:01:00Z",
  "updated_at": "2026-02-22T10:05:00Z"
}
DELETE /api/boards/{key}/tasks/{id}

Delete a single task by UUID. The board key in the path proves ownership — returns 403 if it doesn't match the task's board.

Response 200
{"message": "deleted"}

Error Format

All errors return a JSON object with a single error key:

{"error": "Board not found"}                     // 404
{"error": "Board has expired"}                   // 410
{"error": "Invalid request body"}                // 400
{"error": "Invalid task ID format"}              // 400
{"error": "Task limit reached (100)"}            // 422
{"error": "Forbidden"}                           // 403 — wrong board key in path
{"error": "Rate limit exceeded — try again later"} // 429

Rate-limited responses also include a Retry-After: 60 header.

CLI Reference

The kb CLI wraps the REST API for terminal and CI/CD use. Install with Go or download a binary from releases.
Set KANBIN_URL or use --server to override the default endpoint.

kb board create <title>

Create a new board. Prints the board key for sharing.

$ kb board create "deploy-pipeline"
Board created successfully!
Title: deploy-pipeline
Key:   f9e8d7c...

kb board view <key>

Display a board with all tasks in a table format.

$ kb board view f9e8d7c...
=== deploy-pipeline [f9e8d7c...] ===

ID        | STATUS      | TITLE        | DESCRIPTION
------------------------------------------------
a1b2...   | TODO        | Setup CI     |
c3d4...   | IN_PROGRESS | Write tests  |
e5f6...   | DONE        | Deploy       |

kb board delete <key>

Delete a board and all its tasks.

$ kb board delete f9e8d7c...
Board f9e8d7c... deleted successfully.

kb task add <title> --board <key>

Add a task to a board. Defaults to TODO status.

$ kb task add "Run migrations" --board f9e8d7c...
Task [a1b2c3d4-...] added: Run migrations

kb task move <id> --status <STATUS> --board <key>

Change a task's status. Values: TODO, IN_PROGRESS, DONE.

$ kb task move a1b2c3d4-... \
  --status DONE --board f9e8d7c...
Task a1b2c3d4-... moved to DONE

kb task list --board <key>

List all tasks on a board, one per line.

$ kb task list --board f9e8d7c...
[TODO] a1b2... | Run migrations
[IN_PROGRESS] c3d4... | Write tests
[DONE] e5f6... | Deploy

kb task delete <id> --board <key>

Delete a single task by ID.

$ kb task delete a1b2c3d4-... --board f9e8d7c...
Task a1b2c3d4-... deleted.

Global Flags

FlagEnvDescription
--server, -sKANBIN_URLOverride base API URL

Data Models

Board

FieldTypeDescription
keystring32-char hex key for sharing and task ownership
titlestringBoard name
created_atdatetimeISO 8601 creation timestamp
expires_atdatetimeAuto-expiry, default +7 days
// JSON representation
{
  "key": "a1b2c3...",
  "title": "my-sprint",
  "created_at": "2026-02-22T10:00:00Z",
  "expires_at": "2026-03-01T10:00:00Z"
}

Task

FieldTypeDescription
iduuidUnique identifier
titlestringTask name
descriptionstringOptional details
statusenumTODO · IN_PROGRESS · DONE
positionintSort order within status column
created_atdatetimeISO 8601 creation timestamp
updated_atdatetimeISO 8601 last modification
// JSON representation
{
  "id": "7c9e6679-...",
  "title": "Implement auth",
  "description": "Add JWT middleware",
  "status": "IN_PROGRESS",
  "position": 0,
  "created_at": "2026-02-22T10:01:00Z",
  "updated_at": "2026-02-22T10:05:00Z"
}

TaskStatus Enum

ValueMeaning
TODONot started — default for new tasks
IN_PROGRESSCurrently being worked on
DONECompleted

Philosophy

Most project tools assume you want permanence.

We assume you want
disposability.

Ephemeral by default

Boards expire after 7 days. No clutter, no cleanup, no legacy debt. Create, use, forget.

Zero friction entry

No account needed. No OAuth flow. No email verification. POST to create, GET to read. That's it.

Agent-first design

The API and CLI are primary interfaces. The web UI exists for human observers. Machines create; humans monitor.

Minimal surface area

Boards have tasks. Tasks have statuses. That's the entire data model. No labels, no sprints, no story points, no swimlane customization.

Architecture

[BE]

Backend

Go + Chi router. PostgreSQL storage. Stateless REST API. Deployed on Fly.io. Handles board lifecycle, task CRUD, ETags, and auto-expiry.

  • Go 1.22+
  • Chi v5
  • PostgreSQL
  • Fly.io
[FE]

Frontend

React + TypeScript + Vite. Drag-and-drop Kanban UI. Real-time board view with ETag-based polling. Deployed as static assets behind Nginx.

  • React 19
  • TypeScript
  • Vite
  • TanStack Query
[CLI]

CLI

Go binary using Cobra. Wraps the REST API for terminal use. Perfect for shell scripts, CI pipelines, and agent system prompts.

  • Go 1.22+
  • Cobra
  • Single binary
  • Cross-platform

Self-Hosting

Run your own Kanbin instance in minutes — database, backend, and frontend all in one command.

01

Start everything

Clone the repo and bring up the full stack with Docker Compose. Postgres, backend API, and the web UI all start together.

git clone https://github.com/zeeshanejaz/kanbin
cd kanbin
docker compose up -d

Web UI → :3000 · API → :8080 · DB → :5432

02

Open the board

Navigate to your instance in the browser. The frontend proxies all /api/ requests to the backend container automatically — no CORS config needed.

open http://localhost:3000

Nginx handles the /api/ → backend proxy internally.

03

Point the CLI at your instance

Use the --server flag or set KANBIN_URL once for the session.

# one-off
kanbin --server http://localhost:8080 board view <key>

# or export once
export KANBIN_URL=http://localhost:8080
kanbin board create "my-sprint"
kanbin task add "Fix auth bug" --board <board-key>

--server overrides KANBIN_URL which overrides the built-in default.

Requirements

Dockerwith Compose v2
Go1.22+ (CLI only)
Ports3000 · 8080 · 5432