Skip to content

About

File-based kanban board for autonomous agentic loop. CLI and TUI for multi-agent workflows. Skills included.

Resources

Stars

0 stars

Watchers

0 watching

Forks

 
 

Repository files navigation

kanban-md

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

An agent-first, file-based Kanban board for coordinating AI coding agents and human supervisors. It runs locally as a single binary: no database, server, account, or SaaS dependency.

Demo

How to use it

kanban-md is flexible, but a typical agent-driven setup looks like this:

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

This creates kanban/config.yml and kanban/tasks/. The interactive setup offers to add kanban/ to .gitignore; keep it tracked instead if the board should travel with the repository.

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

# Or install them globally
kanban-md skill install --global
  1. Create tasks manually, or ask an agent to capture them.
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. Start the kanban-based-development skill with one agent. It will claim a task, create an isolated worktree, implement and verify the change, merge it, release the claim, and mark the task done. Once the workflow fits your project, run more agents and supervise their progress in the TUI.
kanban-md tui
  1. Adapt the local skill or AGENTS.md to the repository's own build, review, and release rules.

Why kanban-md?

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

  • Agent-first. Token-efficient output (--compact), a single-step pick/claim/move workflow, structured JSON, and installable skills make the board practical inside non-interactive agent loops.
  • Cooperative multi-agent coordination. Claims reduce duplicate work, can be required by selected columns, and expire automatically when an agent stops renewing them. Claims are coordination leases, not a security or distributed- transaction boundary.
  • 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, Git, and grep can inspect the same source of truth without API credentials.
  • No service dependency. A single binary owns the local workflow; there is no database server, background daemon, or remote configuration 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

Agents can run these commands for you, but the same interface is useful for manual work and scripting.

# 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 soft-delete it by moving it to archived
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.

When kanban-md updates a task, it retains unrecognized YAML frontmatter properties, including exact numeric text, tags, lists, and maps with non-string keys. Anchors, aliases, and nested YAML merges are retained when their bindings stay entirely within these properties. This lets other tools keep their metadata through task edits. By default, additional properties do not appear in table, compact, or JSON output. You can explicitly select scalar values for the property views below. kanban-md's own fields remain authoritative, including fields you clear.

An update refuses before changing the task file if an extra property aliases a canonical field or another anchor that cannot be retained safely. Top-level YAML merges, top-level alias keys, and custom tags on the whole frontmatter mapping also require manual editing before an update. A quoted "<<" property is allowed. Otherwise valid tasks with this metadata remain readable. If startup needs to repair an inconsistent task ID or filename and cannot safely rewrite its metadata, the command fails with an error until you correct the task manually.

kanban-md reserializes its own fields after an update. It does not guarantee comments, indentation, quote style, original key placement, or byte-for-byte formatting.

The config.yml tracks board settings. A newly initialized board currently uses schema version 12:

version: 12
board:
  name: My Project
tasks_dir: tasks
statuses:
  - name: backlog
    show_duration: false
  - name: todo
  - name: in-progress
    require_claim: true
  - name: review
    require_claim: true
  - name: done
    show_duration: false
  - name: archived
    show_duration: false
priorities:
  - lowest
  - low
  - medium
  - high
  - highest
  - critical
defaults:
  status: backlog
  priority: medium
  class: standard
claim_timeout: 1h
classes:
  - name: expedite
    wip_limit: 1
    bypass_column_wip: true
  - name: fixed-date
  - name: standard
  - name: intangible
tui:
  title_lines: 2
  age_thresholds:
    - after: 0s
      color: "242"
    - after: 1h
      color: "34"
    - after: 24h
      color: "226"
    - after: 72h
      color: "208"
    - after: 168h
      color: "196"
next_id: 1

config.yml and tasks/*.md are authoritative. activity.jsonl is a best-effort, bounded audit log, and .lock is a transient coordination file used by operations that must serialize access. Neither is a hidden database. Direct task-file edits remain supported, but commands are the claim-aware mutation path while a task is actively claimed.

Commands

init

Create a new kanban board.

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

After creating a board interactively, kanban-md offers 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]
Flag Default Description
--title Task title (alternative to positional argument)
--status config default Initial status
--priority config default Priority level
--assignee Person assigned
--tags Comma-separated tags
--due Due date (YYYY-MM-DD)
--estimate Time estimate (e.g. 4h, 2d)
--class config default Configured class of service
--parent Parent task ID
--depends-on Dependency task IDs (comma-separated)
--body Task description (alias: --description)
--set-property KEY=LITERAL Set a scalar property; repeat for multiple keys

list

List tasks with filtering and sorting. Aliases: ls.

kanban-md list [FLAGS]
Flag Default Description
--status Filter by status (comma-separated)
--priority Filter by priority (comma-separated)
--assignee Filter by assignee
--tag Filter by tag
-s, --search Search tasks by title, body, or tags (case-insensitive)
--blocked false Show only blocked tasks
--not-blocked false Show only non-blocked tasks
--parent Filter by parent task ID
--unblocked false Show only tasks with all dependencies satisfied (missing dependency IDs are treated as satisfied)
--unclaimed false Show only unclaimed or expired-claim tasks
--claimed-by Filter by claimant name
--class Filter by class of service
--archived false Show only archived tasks
--property KEY=LITERAL Match one exact typed scalar value; repeat to combine with AND
--show-property KEY Include a selected scalar in table, compact or JSON output; repeat for multiple keys
--group-by Group counts by assignee, tag, class, priority, status, or property:KEY
--hide-claimed-column false Hide the CLAIMED column in table output (no effect on --json or --compact); defaults to true if KANBAN_HIDE_CLAIMED_COLUMN is set
--hide-due-column false Hide the DUE column in table output (no effect on --json or --compact); defaults to true if KANBAN_HIDE_DUE_COLUMN is set
--href false Render TITLE as an OSC-8 terminal hyperlink in table output (no effect on --json or --compact); defaults to true if KANBAN_HREF is set
--sort id Sort by: id, title, status, priority, created, updated, due
-r, --reverse false Reverse sort order
-n, --limit 0 Max 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
Flag Description
--archived Include archived direct children (hidden by default)
--show-property KEY Include a selected scalar on the task and its children; repeat for multiple keys

Children are ordered by task ID by default, matching list --parent. Set children.detail_sort: property:reading_order to use a numeric property instead. Finite numbers sort ascending, ties use task ID, and missing or unsuitable values follow in ID order. This changes detail views only, not list, board or pick order. See selected task properties. 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
Flag Description
--title New title (renames the file)
--status New status
--priority New priority
--assignee New assignee
--add-tag Add tags (comma-separated)
--remove-tag Remove tags (comma-separated)
--due New due date (YYYY-MM-DD)
--clear-due Remove due date
--estimate New time estimate
--body New body text (replaces entire body)
--append-body, -a Append text to task body
--timestamp, -t Prefix a timestamp line when appending
--started Set started date (YYYY-MM-DD)
--clear-started Clear started timestamp
--completed Set completed date (YYYY-MM-DD)
--clear-completed Clear completed timestamp
--parent Set parent task ID
--clear-parent Clear parent
--add-dep Add dependency task IDs (comma-separated)
--remove-dep Remove dependency task IDs (comma-separated)
--block Mark task as blocked with reason
--unblock Clear blocked state
--claim Claim task for an agent (set claimed_by)
--release Release claim on task
--class Set class of service
--set-property KEY=LITERAL Set or replace a scalar property; repeat for multiple keys
--clear-property KEY Remove a property, distinct from setting it to null

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
Flag Description
--next Advance to next status in the configured order
--prev Move back to previous status
--claim Claim 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]
Flag Description
--claim Claim name (required)
--note Handoff note to append to body
--timestamp, -t Prefix a timestamp line to the note
--block Mark task as blocked with reason
--release Release claim after handoff

delete

Soft-delete a task by moving it to archived. 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; it is required in non-interactive contexts and for batch deletion. The task file remains on disk and can still be listed with --archived.

archive

Move a task explicitly to the archived status without a confirmation prompt. Archived tasks are hidden from normal commands (list, board, metrics, context, TUI) but remain on disk. Use --claim when archiving a task with an active claim.

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
Flag Default Description
-w, --watch false Live-update the board on file changes (Ctrl+C to stop)
--group-by Group counts by assignee, tag, class, priority, status, or property:KEY

pick

Find and claim the next available task in one operation. Designed for cooperative multi-agent workflows where ownership needs to be visible.

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
Flag Default Description
--claim (required) Agent name to claim the task for
--status all non-terminal One source status to pick from
--move Also move picked task to this status
--tags Only pick tasks matching at least one tag
--parent Only pick tasks that are children of this parent task ID
--no-body false Show 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]
Flag Default Description
--since Only include tasks completed after this date

log

Show the activity log of board mutations. Emitted actions include create, edit, move, delete, block, unblock, claim, release, handoff, and TUI priority changes.

kanban-md log [FLAGS]
Flag Default Description
--since Show entries after this date (YYYY-MM-DD)
--limit 0 Maximum number of entries (most recent)
--action Filter by exact action name
--task Filter 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:

Key Writable Description
board.name yes Board name
board.description yes Board description
defaults.status yes Default status for new tasks
defaults.priority yes Default priority for new tasks
defaults.class yes Default class of service for new tasks
statuses no List of statuses
priorities no List of priorities
tasks_dir no Tasks directory name
wip_limits no WIP limits per status
claim_timeout yes Claim expiration duration (e.g. 1h, 30m)
classes no Class of service definitions
tui.title_lines yes Number of title lines shown in TUI cards
tui.hide_empty_columns yes Hide columns with zero tasks in TUI
tui.narrow_threshold yes Terminal width below which the single-column view is used; 0 is automatic
tui.age_thresholds no TUI age color thresholds
next_id no Next task ID
version no Config 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
Flag Default Description
--write-to Write context to file (creates or updates in-place)
--sections all Comma-separated section filter
--days 7 Recently 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
Flag Description
--hide-empty-columns Hide empty columns for this run, overriding config
--show-empty-columns Show empty columns for this run, overriding config
--mouse Enable mouse navigation and drag-and-drop
--narrow Force the single-column layout at any terminal 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 shows its known ancestor path and the same direct-child list and roll-up as show. Archived ancestors remain visible as context but cannot be opened; archived children remain hidden. Search and level filters control cards, not which active relations you can open in details.

Explore task relations

In details, Tab and Shift+Tab move the relation focus in reading order; Enter opens it. Esc or Backspace takes one step back, restoring your previous task, scroll position and relation focus. q closes the entire chain and returns to the board, keeping its search, level and sort settings. j/k, arrow keys and g/G still scroll the detail content.

Ancestors appear root-first. On a milestone → epic → story path, the first Tab focuses the milestone; Tab, Tab, Enter opens the immediate epic. From that epic, Tab, Enter opens the milestone. Two Esc presses retrace those steps. Missing parent IDs and self/cycle markers remain visible rather than being repaired by navigation.

Focus one hierarchy level

In board mode, v cycles all tasks → the numeric levels present among active tasks → unknown depth, if present → all. Root tasks are L0, their children L1, and so on. Boards with hierarchy show these text labels beside task IDs and the active level[...] in the status line. Flat boards keep their usual cards by default. While typing a search, v is ordinary text.

Levels come from parent links, including archived ancestors, and are not task types or stored fields. Missing/self-parent links use an effective level-zero root; a multi-task cycle and tasks reaching it have L?. The level filter and title/tag/ID search combine with AND. Neither writes task data.

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 action Result
Click a card Select the card and synchronize keyboard navigation
Double-click the same card within 500 ms Open its detail view
Click an active relation row in details Open that task, including wrapped rows
Click Back Take one detail-history step, or return to the board when history is empty
Wheel over a column Activate that column and move its selection one card
Wheel in a detail view Scroll the task body three lines
Hold a card, drag to another visible column, and release Move 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

Key Action
h / l Move between columns
j / k Move between tasks within a column
Enter View task details
c Create task in current column
e Edit selected task (same 4-step flow as create)
E Open the selected task's Markdown file in $VISUAL, then $EDITOR, then vi when available
m Move task to a different status (picker dialog)
n / p Move task to next / previous status
d Soft-delete (archive) task with confirmation
s Cycle the sort field (priority → created → updated → title)
S Reverse the sort direction
/ Search/filter tasks live. Matches a case-insensitive substring of the title or any individual tag, not the body. Start with # for ticket IDs: #12 prefix-matches IDs, #12 exact-matches #12, and bare # matches all. Enter keeps the filter, Esc clears it
v In board mode, cycle exact hierarchy levels; session-only
Tab / Shift+Tab in details Focus relations in reading order
Enter in details Open the focused relation
Esc / Backspace in details Go back one navigation step
r Refresh board
? Show help
q Quit from the board; close the whole detail chain from details
Ctrl+C Quit

Global flags

These work with any command:

Flag Description
--json Force JSON output
--table Force table output (default)
--compact / --oneline Compact one-line-per-record output
--dir Path to kanban directory (overrides auto-detection)
--no-color Disable color output (also respects NO_COLOR env var)

Output format

The default output format is table (human-readable). Use flags to switch:

# Default: table
kanban-md list --status todo

# Compact: one line per task, ideal for AI agents
kanban-md list --compact

# JSON: for scripting and piping
kanban-md list --json | jq '.[].title'

Set the KANBAN_OUTPUT environment variable to change the default: json, table, compact, or oneline.

Override priority: --json/--table/--compact flags > KANBAN_OUTPUT env var > table default.

Configuration

kanban-md discovers its config by walking upward from the current directory, similar to how git finds .git/. This means you can run commands from any subdirectory in your project.

Use --dir to point to a specific board:

kanban-md --dir /path/to/kanban list

Custom statuses

Define your own workflow columns:

kanban-md init --statuses "open,in-progress,blocked,closed"

The order matters — it defines the progression for move --next and move --prev, and the sort order for list --sort status.

Custom priorities

Edit config.yml directly to customize priorities:

priorities:
  - trivial
  - normal
  - urgent
  - showstopper
defaults:
  priority: normal

Priority order runs from lowest to highest. list --sort priority shows the highest configured priority first by default; use --reverse for lowest first.

Hyperlinked titles

list --href (or KANBAN_HREF) renders TITLE as a clickable OSC-8 terminal hyperlink in table output, resolving the link target in this order:

  1. An explicit https:// href property, set with --set-property 'href="https://example.com"'.
  2. Otherwise, the first https:// link found in the task body — either a markdown [text](https://...) target or a bare https:// URL.
  3. Otherwise, the title is rendered plain.

Set --set-property href=false to opt a task out of hyperlinking entirely, including the body fallback.

Each hyperlink carries a per-task OSC-8 id (task-<ID>). Some terminals (kitty, notably) group hover/click highlighting by (id, url); without a distinct id, two tasks sharing the same URL would be highlighted as a single combined link.

http:// targets, in either the href property or the body, are never linked. This follows --no-color/NO_COLOR: disabling color also disables hyperlinks, and has no effect on --json or --compact output. Only the title text itself is clickable; column padding is never part of the link.

Selected task properties

Use your own top-level scalar properties for categories, reading order or other workflow data, without adding a task type or rank to the core model:

kanban-md create "Draft chapter" --parent 1 \
  --set-property kind=chapter --set-property reading_order=20
kanban-md edit 2 --set-property reading_order=10
kanban-md list --property kind=chapter --show-property reading_order
kanban-md list --group-by property:kind
kanban-md show 1 --json --show-property kind --show-property reading_order

Repeat --set-property, --clear-property, --property and --show-property for different keys. Keys are case-sensitive literal names matching [A-Za-z_][A-Za-z0-9_.-]*; a dot is part of the key, not a nested path. Task-owned names such as status, priority, parent, body and file are reserved: use their existing flags. Duplicate keys and simultaneous set/clear of the same key are errors. Multi-task edits retain the normal per-task batch behavior, not an all-or-nothing transaction.

CLI literals support a bare string, a JSON-quoted string, a decimal/scientific number, lowercase true/false, or null. Shell quotes protect the argument; inner JSON quotes choose a string instead of a number or boolean:

kanban-md edit 2 --set-property reading_order=20      # number
kanban-md edit 2 --set-property 'reading_order="20"'  # string, not a numeric order
kanban-md edit 2 --set-property 'note=""'             # empty string
kanban-md edit 2 --set-property note=null            # present null
kanban-md edit 2 --clear-property note               # absent key

The authoring grammar does not evaluate YAML tags, aliases, arrays or maps. Use strict JSON numeric spelling on the CLI: quote 01, +20, .5, 0x10 or 1_000 if you mean text. Reading existing YAML numeric forms is exact, including large values and base-prefixed integers; numeric-looking strings remain strings. Property equality is typed and exact. Repeated filters and ordinary filters combine with AND. Missing and unsupported values never match, including a filter for null.

Edit these optional view settings directly in config.yml:

group_orders:
  property:kind: [milestone, chapter, story, bug]
display:
  compact_fields: [status, property:kind]
tui:
  card_fields: [property:kind]
children:
  detail_sort: property:reading_order

Omit them to retain [status/priority] compact chips, the TUI priority badge and ID-ordered children. Compact/card fields accept one or two distinct choices from status, priority, class or property:KEY; empty and null lists are invalid. Omit the field to use its defaults. Restart an open TUI after changing these config settings; its refresh command reloads tasks, not view settings. Compact fields apply to list, show and pick; other command confirmations keep their existing format. Child detail sort accepts id or one numeric property selector. Config version 12 migration preserves the old effective defaults and does not rewrite tasks.

Group order is a presentation preference, not an enum. Configured values appear first; other strings follow alphabetically, then numbers, booleans and null. Missing or unsupported values share the last (unclassified) group. Scalar group labels are quoted/typed to keep text "20" distinct from number 20. For example, a typo such as chapetr remains visible in the grouped summary; correct it with edit ID --set-property kind=chapter. Grouped output contains counts, not task records, so it cannot be combined with --show-property.

Only list and show accept --show-property. It adds selected columns/tokens to human output and a properties object to each JSON task or child record. Missing keys are omitted, explicit null is present as null, and unsupported values are omitted with a warning. Nested, alias, timestamp, binary, custom-tagged and non-finite values remain preserved but are not selected scalars. Unselected metadata never enters task JSON. Display and sort settings do not select JSON values; use --show-property explicitly.

Human badges use KEY=-- for missing, KEY=? for unsupported and KEY=null for null; strings are quoted. Control characters are escaped and long badge values are shortened. Details show the selected properties that explain the view; JSON keeps their complete supported values when explicitly requested.

Child ordering never changes priority, pick, dependencies, claims or WIP. Zero, negative and fractional numbers are valid; sparse values such as 10, 20, 30 leave room for inserts. Reparenting or clearing a parent retains the property. To reset placement when detaching, clear both in one edit:

kanban-md edit 2 --clear-parent --clear-property reading_order

An explicit property replacement/removal can still refuse if it would leave another retained YAML alias unsafe. The error leaves the task file unchanged and asks for manual frontmatter editing; unrelated values are not rewritten to make the edit succeed.

Shell completions

Generate completions for your shell:

# bash
source <(kanban-md completion bash)

# zsh
kanban-md completion zsh > "${fpath[1]}/_kanban-md"

# fish
kanban-md completion fish | source

# PowerShell
kanban-md completion powershell | Out-String | Invoke-Expression

Agent skills

kanban-md ships with installable skills that teach AI agents how to use the board. Skills are auto-triggered prompt files that give agents command references, decision trees, and workflows — so they manage tasks correctly without you writing custom instructions.

Two skills are included:

Skill Description
kanban-md Command reference, decision trees, and workflows for managing tasks via CLI. Auto-triggered when an agent encounters task-related work.
kanban-based-development Full autonomous development workflow — multi-agent claim semantics, git worktrees for isolation, and a strict status lifecycle (in-progress → review → done).
# Install skills for all detected agents (Claude Code, Codex, Cursor, OpenClaw)
kanban-md skill install

# Check if installed skills are up to date
kanban-md skill check

# Update skills to match current CLI version
kanban-md skill update

# Preview one skill
kanban-md skill show --skill kanban-md

Skills are versioned to match the CLI. When you upgrade kanban-md, skill check tells you if your installed skills are outdated, and skill update brings them in sync.

Multi-agent workflow

kanban-md coordinates concurrent work by multiple agents and humans through cooperative claims and classes of service.

Claims

Claims are cooperative leases: an agent claims a task before working on it, and well-behaved agents exclude tasks with active claims from selection. Claims expire after the configured timeout (default: 1 hour). They reduce collisions, but they are not a security boundary or a transactional distributed lock.

On Unix-like systems, kanban-md also makes actively claimed task files read-only. Commands from the current claimant temporarily unlock the file while updating it, then restore read-only permissions; releasing or expiring the claim makes the file writable again. This protects against accidental direct edits by another process running as the same user, but it is not a security boundary: that user can still change permissions, rename, or delete the file.

Statuses with require_claim: true (default: in-progress and review) enforce that every move or edit includes --claim <name>. This prevents accidental anonymous moves in multi-agent environments.

# Agent picks next available task
kanban-md pick --claim agent-1 --move in-progress

# Move to review (require_claim enforced — must include --claim)
kanban-md move 5 review --claim agent-1

# Agent finishes and releases
kanban-md edit 5 --release
kanban-md move 5 done

# Another agent picks from a specific queue
kanban-md pick --claim agent-2 --status todo --tags backend

Classes of service

Tasks can have a class of service that affects WIP limits and pick priority:

Class Behavior
expedite Bypasses column WIP limits. Has its own board-wide WIP limit (default: 1). Picked first.
fixed-date Picked by earliest due date within its priority tier.
standard Default class. Normal WIP and priority rules.
intangible Picked last. For background/maintenance work.
kanban-md create "Critical hotfix" --class expedite --priority critical
kanban-md create "Q2 deadline feature" --class fixed-date --due 2026-06-30

Swimlanes

Group board or list views by any field to see work distribution:

kanban-md board --group-by assignee     # who is working on what
kanban-md board --group-by class        # class of service breakdown
kanban-md list --group-by tag           # work by tag
kanban-md list --group-by priority      # priority distribution

Design principles

kanban-md provides orthogonal, composable workflow primitives. Development is one use, not the definition of its domain. These principles guide new features and reviews; they are not a claim that every existing implementation meets them.

  1. Compose workflows; make new domain concepts earn their place. Prefer shared capabilities over built-in concepts named after one workflow.
  2. Choose the smallest capability that actually solves the need. Count user effort and maintenance cost; a generic framework is not automatically simpler.
  3. Keep the basic board complete; make workflow policy optional. Extras should impose no required setup or default clutter. Usability and data protection still deserve sensible defaults.
  4. Give each value and action one explicit meaning. Separate task data, relations, views, and policy. Display order must not silently become execution order.
  5. Keep local files authoritative and the core independently useful. Optional integrations must not make ordinary board use depend on accounts or services.
  6. Preserve contracts across interfaces, upgrades, and writers. Keep mutations consistent, agent commands non-interactive, and existing boards compatible.

The project-local principal-owner skill contains the review criteria, tradeoffs, and decision format. It is contributor guidance, not one of the workflow skills installed into users' projects.

Development

# Build
make build

# Build and install to GOPATH/bin
make install

# Run all tests (unit + e2e)
make test

# Run only e2e tests
make test-e2e

# Lint
make lint

# Lint with autofix
make lint-fix

# Full pipeline
make all

License

MIT

About

File-based kanban board for autonomous agentic loop. CLI and TUI for multi-agent workflows. Skills included.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages