Sandbox
@antopolskiy/kanban-md

Kanban CLI and TUI for agent task boards

kanban-md keeps work in Markdown task files and lets agents claim, move, and finish tasks from the terminal. It pairs a single-binary CLI with a live TUI, plus agent skills and context files, so a project can run with shared board state instead of repeated prompts.

215 stars27 forksGoUpdated 24d ago
Who it's for

Builders who want Claude Code, Codex, or other agents to share a file-based task board and work in parallel.

What it delivers

You can coordinate multiple agents on one Kanban board without manual handoffs or task clashes.

What it does

Atomic task claiming

`pick --claim` finds the next available task, claims it, and can move it in one step.

File-based task storage

Each task lives as a Markdown file with YAML frontmatter, so humans and agents can read and edit it directly.

Multi-agent safety

Claims act like cooperative locks, with expiration and checks that help prevent agents from working the same task at once.

CLI and TUI board views

Use the command line for batch work and `kanban-md tui` for an interactive terminal board that refreshes from disk.

Installable agent skills

The repo ships skills that teach agents how to use the board and follow the workflow.

Context export

`kanban-md context` writes a board summary into files like `AGENTS.md` or `CLAUDE.md`.

Board workflow commands

Commands cover init, create, list, show, edit, move, handoff, archive, delete, board, metrics, log, and config.

Self-healing IDs and links

The CLI detects and repairs duplicate IDs, filename/frontmatter mismatches, and invalid parent or dependency cycles.

How to get it

  1. 1Install the tool
    brew install antopolskiy/tap/kanban-md
  2. 2Go to your project directory and create a board there
    kanban-md init
  3. 3Install skills for your agents
    # install skills locally in this project -- I prefer this
    kanban-md skill install 
    
    # install skills globally (home directory)
    kanban-md skill install --global
  4. 4Create tickets manually, or ask your agents do it for you
    kanban-md add "Set up CI pipeline" --priority high
    kanban-md add "Fix login bug" --priority critical
    
    claude "add ticket: there is a bug on the login page when the user enters an invalid email address"
  5. 5Kick off /kanban-based-development skill in a single agent and observe how it behaves.…
    kanban-md tui
  6. 6Run
    brew install antopolskiy/tap/kanban-md

README

kanban-md

CI Release Go Version Latest Release codecov Go Reference Go Report Card License: MIT

An agents-first file-based Kanban. Built for multi-agent workflows to allow AI agents work in parallel without clashing. Ultra-fast single binary CLI. Agent skills included. Lean and future-proof: no database, no server, no SaaS — just files.

Demo

How to use it

kanban-md is a flexible tool, and you can use it in many ways. Here is one of the ways I use it in my own projects:

  1. Install the tool
brew install antopolskiy/tap/kanban-md
  1. Go to your project directory and create a board there
kanban-md init

This will create a kanban/ directory and a config.yml file. I also usually add it to .gitignore.

  1. Install skills for your agents
# install skills locally in this project -- I prefer this
kanban-md skill install 

# install skills globally (home directory)
kanban-md skill install --global
  1. Create tickets manually, or ask your agents do it for you
kanban-md add "Set up CI pipeline" --priority high
kanban-md add "Fix login bug" --priority critical

claude "add ticket: there is a bug on the login page when the user enters an invalid email address"
  1. Kick off /kanban-based-development skill in a single agent and observe how it behaves. It should claim a task, create a worktree, implement, test, commit, release the claim and mark the task as done. When confident, kick off the skill in multiple agents -- they will work in parallel without clashing. You should see the progress in the TUI.
kanban-md tui
  1. Adjust the local skill / AGENTS.md to steer the agents in a way that would make sense for this project.

Why kanban-md?

Project management tools are designed for humans clicking buttons. kanban-md is designed for AI agents running commands and human supervision.

  • Agents-first. Token-efficient output formats (--compact), atomic claim-and-move operations (pick --claim), and installable agent skills that teach agents how to use the board — out of the box.
  • Multi-agent safe. Claims provide cooperative locking so multiple agents can work the same board without stepping on each other. Claims expire automatically, and the pick command atomically finds, claims, and moves the next available task.
  • Self-healing task IDs. Commands automatically detect duplicate IDs, filename/frontmatter ID mismatches, and next_id drift, then repair them before proceeding.
  • Plain files. Every task is a Markdown file. Agents, humans, scripts, and grep all work equally well. No API tokens, no authentication, no rate limits.
  • Zero dependencies at runtime. A single static binary. No database, no server, no config service.
  • Skills included. Pre-written skills for using the CLI tool and a multi-agent development workflow. Installable via kanban-md skill install.
  • TUI for observation. A full interactive terminal board with keyboard navigation. It auto-refreshes when task files change on disk.
kanban-md tui

Interactive TUI

Installation

Homebrew (macOS/Linux)

brew install antopolskiy/tap/kanban-md

Go

go install github.com/antopolskiy/kanban-md/cmd/kanban-md@latest

Homebrew also installs kbmd as a shorthand alias for kanban-md.

Binary downloads

Pre-built binaries for macOS, Linux, and Windows are available on the Releases page.

Quick start

Note: normally, you wouldn't run the CLI commands directly. Your agents will do that for you.

# Initialize a board in the current directory
kanban-md init --name "My Project"

# Create some tasks
kanban-md create "Set up CI pipeline" --priority high --tags devops
kanban-md create "Write API docs" --assignee alice --due 2026-03-01
kanban-md create "Fix login bug" --status todo --priority critical

# List all tasks
kanban-md list

# Filter and sort, highest priority first
kanban-md list --status todo,in-progress --sort priority

# Move a task forward
kanban-md move 3 in-progress
kanban-md move 3 --next

# Edit a task
kanban-md edit 2 --add-tag documentation --body "Cover all REST endpoints"

# View task details
kanban-md show 1

# Done with a task
kanban-md move 1 done

# Or delete it
kanban-md delete 3 --yes

How it works

Running kanban-md init creates a kanban/ directory:

kanban/
  config.yml
  tasks/
    001-set-up-ci-pipeline.md
    002-write-api-docs.md
    003-fix-login-bug.md

Each task file is standard Markdown with YAML frontmatter:

---
id: 1
title: Set up CI pipeline
status: backlog
priority: high
created: 2026-02-07T10:30:00Z
updated: 2026-02-07T10:30:00Z
tags:
  - devops
---

Optional body with more detail, context, or notes.

The config.yml tracks board settings:

version: 3
board:
  name: My Project
tasks_dir: tasks
statuses:
  - backlog
  - todo
  - name: in-progress
    require_claim: true
  - name: review
    require_claim: true
  - done
  - archived
priorities:
  - low
  - medium
  - high
  - critical
wip_limits:
  in-progress: 3
  review: 2
classes:
  - name: expedite
    wip_limit: 1
    bypass_column_wip: true
  - name: fixed-date
  - name: standard
  - name: intangible
claim_timeout: 1h
defaults:
  status: backlog
  priority: medium
  class: standard
next_id: 4

Commands

init

Create a new kanban board.

kanban-md init [--name NAME] [--statuses s1,s2,s3] [--wip-limit status:N]
FlagDescription
--nameBoard name (defaults to parent directory name)
--statusesComma-separated status list (default: backlog,todo,in-progress,review,done,archived)
--wip-limitWIP limit per status (format: status:N, repeatable)

After creating a board, kanban-md prompts to add the board directory (for example, kanban/) to .gitignore:

  • If .gitignore exists in the board directory parent, the entry is appended.
  • If .gitignore does not exist, it is created with the board directory entry.

create

Create a new task. Aliases: add. Title can be provided as a positional argument or via --title.

kanban-md create "My task" [FLAGS]
kanban-md create --title "My task" --description "Details here" [FLAGS]
FlagDefaultDescription
--titleTask title (alternative to positional argument)
--statusbacklogInitial status
--prioritymediumPriority level
--assigneePerson assigned
--tagsComma-separated tags
--dueDue date (YYYY-MM-DD)
--estimateTime estimate (e.g. 4h, 2d)
--classstandardClass of service (expedite, fixed-date, standard, intangible)
--parentParent task ID
--depends-onDependency task IDs (comma-separated)
--bodyTask description (alias: --description)

list

List tasks with filtering and sorting. Aliases: ls.

kanban-md list [FLAGS]
FlagDefaultDescription
--statusFilter by status (comma-separated)
--priorityFilter by priority (comma-separated)
--assigneeFilter by assignee
--tagFilter by tag
-s, --searchSearch tasks by title, body, or tags (case-insensitive)
--blockedfalseShow only blocked tasks
--not-blockedfalseShow only non-blocked tasks
--parentFilter by parent task ID
--unblockedfalseShow only tasks with all dependencies satisfied (missing dependency IDs are treated as satisfied)
--unclaimedfalseShow only unclaimed or expired-claim tasks
--claimed-byFilter by claimant name
--classFilter by class of service
--archivedfalseShow only archived tasks
--group-byGroup results by field (assignee, tag, class, priority, status)
--sortidSort by: id, title, status, priority, created, updated, due
-r, --reversefalseReverse sort order
-n, --limit0Max results (0 = unlimited)

show

Show full details of a task. When the task has direct children, the detail view includes their IDs, statuses, titles, and a terminal/total roll-up. Parent status remains independently managed; the roll-up is informational only.

kanban-md show ID
kanban-md show ID --archived  # include archived children in the roll-up
FlagDescription
--archivedInclude archived direct children (hidden by default)

Children are ordered by task ID, matching the default list --parent order. Human-readable CLI and TUI detail views prefix them with ├─ and └─ tree guides so the parent-child relationship remains visually clear. Tasks with a direct parent show an upward relation such as ↑ Parent #1 [in-progress] Parent title; if the parent file is unavailable, the relationship falls back to its stored task ID. JSON output always contains a children array; compact output adds a children:DONE/TOTAL done annotation only when children are present.

Parent links stay acyclic. create and edit reject a parent that would close a ring, naming the chain it would form:

$ kanban-md edit 2 --parent 1
Error: parent would create a cycle (#2 → #1 → #2)

depends_on is checked the same way, since two tasks that depend on each other can never become unblocked. Both checks run wherever the link is written, so create --parent, edit --parent and edit --add-dep are all covered.

A representative board for trying the CLI and TUI behavior is available in examples/issue-11-demo.

edit

Modify an existing task.

kanban-md edit ID [FLAGS]
kanban-md edit 1,2,3 --priority high  # batch edit
FlagDescription
--titleNew title (renames the file)
--statusNew status
--priorityNew priority
--assigneeNew assignee
--add-tagAdd tags (comma-separated)
--remove-tagRemove tags (comma-separated)
--dueNew due date (YYYY-MM-DD)
--clear-dueRemove due date
--estimateNew time estimate
--bodyNew body text (replaces entire body)
--append-body, -aAppend text to task body
--timestamp, -tPrefix a timestamp line when appending
--startedSet started date (YYYY-MM-DD)
--clear-startedClear started timestamp
--completedSet completed date (YYYY-MM-DD)
--clear-completedClear completed timestamp
--parentSet parent task ID
--clear-parentClear parent
--add-depAdd dependency task IDs (comma-separated)
--remove-depRemove dependency task IDs (comma-separated)
--blockMark task as blocked with reason
--unblockClear blocked state
--claimClaim task for an agent (set claimed_by)
--releaseRelease claim on task
--classSet class of service

move

Change a task's status.

kanban-md move ID [STATUS]
kanban-md move ID --next
kanban-md move ID --prev
kanban-md move 1,2,3 todo          # batch move
FlagDescription
--nextAdvance to next status in the configured order
--prevMove back to previous status
--claimClaim task for an agent

handoff

Hand off a task for review. Moves to review status, appends a note, and optionally blocks/releases.

kanban-md handoff ID --claim NAME [--note TEXT] [--block REASON] [-t] [--release]
FlagDescription
--claimClaim name (required)
--noteHandoff note to append to body
--timestamp, -tPrefix a timestamp line to the note
--blockMark task as blocked with reason
--releaseRelease claim after handoff

delete

Delete a task. Aliases: rm.

kanban-md delete ID [--yes]
kanban-md delete 1,2,3 --yes       # batch delete

Prompts for confirmation in interactive terminals. Use --yes (-y) to skip the prompt (required in non-interactive contexts like scripts). Batch delete always requires --yes.

archive

Soft-delete a task by moving it to the archived status. Archived tasks are hidden from all normal commands (list, board, metrics, context, TUI) but remain on disk.

kanban-md archive ID
kanban-md archive ID --claim agent-1  # archive a task claimed by agent-1
kanban-md archive 1,2,3    # batch archive

To see archived tasks:

kanban-md list --archived
kanban-md list --status archived

board

Show a board summary with task counts per status, WIP utilization, blocked/overdue counts, and priority distribution. Aliases: summary.

kanban-md board
kanban-md board --watch    # live-update on file changes
FlagDefaultDescription
-w, --watchfalseLive-update the board on file changes (Ctrl+C to stop)
--group-byGroup by field (assignee, tag, class, priority, status)

pick

Atomically find and claim the next available task. Designed for multi-agent workflows where agents need exclusive task assignment.

kanban-md pick --claim agent-1
kanban-md pick --claim agent-1 --status todo --move in-progress
kanban-md pick --claim agent-1 --tags backend
kanban-md pick --claim agent-1 --parent 42
kanban-md pick --claim agent-1 --no-body
FlagDefaultDescription
--claim(required)Agent name to claim the task for
--statusall non-terminalSource status(es) to pick from (comma-separated)
--moveAlso move picked task to this status
--tagsOnly pick tasks matching at least one tag
--parentOnly pick tasks that are children of this parent task ID
--no-bodyfalseShow only the pick confirmation line (skip full task details)

By default, pick prints the one-line confirmation and then the full task details (same as show, including body) so agents do not need a follow-up show command.

The pick algorithm selects from unclaimed, unblocked tasks with satisfied dependencies, prioritizing by class of service (expedite > fixed-date > standard > intangible), then by priority within each class. Fixed-date tasks are further sorted by earliest due date.

agent-name

Generate a random two-word name for use with --claim. Uses the system dictionary when available, with a built-in word list as fallback.

kanban-md agent-name
# → quiet-storm

kanban-md pick --claim $(kanban-md agent-name) --status todo --move in-progress

metrics

Show flow metrics: throughput, average lead/cycle time, flow efficiency, and aging work items.

kanban-md metrics [--since YYYY-MM-DD]
FlagDefaultDescription
--sinceOnly include tasks completed after this date

log

Show the activity log of board mutations (create, move, edit, delete, block, unblock).

kanban-md log [FLAGS]
FlagDefaultDescription
--sinceShow entries after this date (YYYY-MM-DD)
--limit0Maximum number of entries (most recent)
--actionFilter by action type (create, move, edit, delete, block, unblock)
--taskFilter by task ID

config

View or modify board configuration.

kanban-md config                       # show all config values
kanban-md config get KEY               # get a single value
kanban-md config set KEY VALUE         # set a writable value

Available keys:

KeyWritableDescription
board.nameyesBoard name
board.descriptionyesBoard description
defaults.statusyesDefault status for new tasks
defaults.priorityyesDefault priority for new tasks
defaults.classyesDefault class of service for new tasks
statusesnoList of statuses
prioritiesnoList of priorities
tasks_dirnoTasks directory name
wip_limitsnoWIP limits per status
claim_timeoutyesClaim expiration duration (e.g. 1h, 30m)
classesnoClass of service definitions
tui.title_linesyesNumber of title lines shown in TUI cards
tui.hide_empty_columnsyesHide columns with zero tasks in TUI
tui.age_thresholdsnoTUI age color thresholds
next_idnoNext task ID
versionnoConfig schema version

context

Generate a markdown summary of the board state for embedding in context files (e.g. CLAUDE.md, AGENTS.md).

kanban-md context                             # print to stdout
kanban-md context --write-to AGENTS.md        # write/update in file
kanban-md context --sections blocked,overdue  # limit sections
kanban-md context --days 14                   # recently completed lookback
FlagDefaultDescription
--write-toWrite context to file (creates or updates in-place)
--sectionsallComma-separated section filter
--days7Recently completed lookback in days

Available section names: in-progress, blocked, overdue, recently-completed.

When using --write-to, the context block is wrapped in HTML comment markers (<!-- BEGIN kanban-md context --> / <!-- END kanban-md context -->). If the file already contains these markers, only the block between them is replaced — all other content is preserved.

Interactive TUI

kanban-md tui opens a full interactive terminal board with keyboard navigation. It auto-refreshes when task files change on disk. If no board exists in the current directory, kanban-md tui can initialize one and then offers to add that board directory to .gitignore.

kanban-md tui             # launch from any directory with a kanban/ board
kanban-md tui --dir PATH  # point to a specific kanban directory
kanban-md tui --hide-empty-columns  # override config and hide empty columns
kanban-md tui --show-empty-columns  # override config and show empty columns
kanban-md tui --mouse      # opt in to mouse navigation
kanban-md tui --narrow     # force the single-column layout at any width

Set tui.hide_empty_columns in config.yml to control the default behavior.

Note: Older releases shipped a standalone kanban-md-tui binary. It has been retired — use kanban-md tui instead.

In create/edit dialogs, text fields support cursor-based editing (←/→, Home/End, Backspace, Delete).

Opening a task with direct children shows the same child list and roll-up as show. Archived children remain hidden in the TUI. A board search controls which cards are visible, but does not hide children from the selected parent's detail view.

Task bodies are rendered as Markdown using the terminal's default foreground for the main text, so they remain readable when a terminal switches between light and dark themes while the TUI is running.

Narrow mode (small terminals)

On terminals too narrow to show every column side by side — a phone over SSH, a split pane — the board automatically switches to a single-column layout. It shows one column at a time, full width, under a two-line header: a tab strip of all columns (the active one highlighted) on top, and the active column's own full name, count, and WIP limit below. Card titles stay readable instead of being crushed to a few characters per column.

Switch columns with /, h/l, or Tab/Shift+Tab. With --mouse, tap a tab to jump straight to that column; tapping a card selects it as usual.

Narrow mode activates automatically once columns can no longer get a usable width. To force or tune it:

kanban-md tui --narrow                         # force narrow mode for this run
kanban-md config set tui.narrow_threshold 80  # persist a custom trigger width

Set tui.narrow_threshold with kanban-md config set (or directly in config.yml) to override the automatic trigger — the board goes narrow below that terminal width. Use 0 for automatic behavior or 1 to effectively disable narrow mode.

Mouse mode

Mouse controls are opt-in, so the normal keyboard-only TUI remains unchanged. Start mouse mode with:

kanban-md tui --mouse
Mouse actionResult
Click a cardSelect the card and synchronize keyboard navigation
Double-click the same card within 500 msOpen its detail view
Click BackReturn to the board
Wheel over a columnActivate that column and move its selection one card
Wheel in a detail viewScroll the task body three lines
Hold a card, drag to another visible column, and releaseMove the task to that status

The entire rendered destination column is a drop target, including its header, cards, and visible empty area. Releasing over the source column or outside a valid column cancels the drag. Keyboard shortcuts continue to work while mouse mode is active, so both input styles can be mixed freely.

The board status line begins with the card count and ? help, followed by the optional mouse indicator and the remaining actions. Shortcut characters are highlighted inside their action labels so the essential hints survive narrow terminal widths.

Status moves made in the TUI preserve an existing task claim. If an unclaimed task enters a require_claim status, the TUI automatically claims it using the local hostname; that claim remains attached if the task later moves elsewhere.

Terminals commonly reserve a modifier such as Shift or Option/Alt to bypass application mouse reporting for native text selection. The exact modifier is terminal-dependent; use the terminal's normal selection shortcut or omit --mouse when native selection is preferred.

Keyboard shortcuts

KeyAction
h / lMove between columns
j / kMove between tasks within a column
EnterView task details
cCreate task in current column
eEdit selected task (same 4-step flow as create)
EOpen the selected task's Markdown file in $VISUAL, then $EDITOR, then vi when available
mMove task to a different status (picker dialog)
n / pMove task to next / previous status
dDelete task (with confirmation)
sCycle the sort field (priority → created → updated → title)
SReverse the sort direction
/Search/filter tasks live. By default matches a case-insensitive substring of the title. Start the query with # to search ticket IDs instead: #12 matches every ID beginning with 12 (e.g. #12, #121), and a trailing space (#12 ) requires an exact match (only #12). Enter keeps the filter, Esc clears it
rRefresh board
?Show help

Files in the repo

Repository payload28 top-level entries
  • .agents
  • .claude
  • .githooks
  • .github
  • .vscode
  • assets
  • cmd
  • docs
  • e2e
  • examples
  • internal
  • site
  • .codex
  • .cursor
  • .gitattributes
  • .gitignore
  • .golangci.yml
  • .goreleaser.yml
  • .markdownlint.yml
  • AGENTS.md
  • CLAUDE.md
  • CODEX.md
  • GEMINI.md
  • go.mod
  • go.sum
  • LICENSE
  • Makefile
  • README.md

Discussion (0)

Ask about usage, or say what you built with it

Sign in to join the discussion.

No comments yet. Be the first to say what this is good for.

More tools

JuliusBrussee/
caveman

🪨 why use many token when few token do trick — Claude Code skill that cuts 65% of tokens by talking like caveman

105k
1 add
MemPalace/
mempalace

The best-benchmarked open-source AI memory system. And it's free.

59k
stablyai/
orca

Orca is the ADE for working with a fleet of parallel agents. Run any coding agent with your own subscription. Available on desktop, mobile and remote runtime.

66k

A cross-platform desktop All-in-One assistant for Claude Code, Codex, OpenCode, OpenClaw, Grok Build & Hermes Agent. Only official website: ccswitch.io

132k

Never stop coding. Free MIT AI gateway: one endpoint, 352 providers (150+ free), 1200+ models Kimi, Claude, GPT, Gemini, GLM, DeepSeek, MiniMax. Works with Claude Code, Codex, Cursor, OpenCode, Cline & Copilot. Quota-aware auto-fallback, RTK+Caveman compression saves 15-95% tokens, MCP/A2A, Desktop/PWA. Built by 550+ contributors

64k
headroomlabs-ai/
headroom

Compress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.

71k