API-Docker
view release on metacpan or search on metacpan
.claude/skills/kanban-issues-karr-cli/SKILL.md view on Meta::CPAN
---
name: kanban-issues-karr-cli
description: Use when picking up, claiming, handing off or creating agent tickets with the karr CLI, or when reading a repo's karr board.
---
# karr â Kanban Assignment & Responsibility Registry
Git-native kanban board for multi-agent workflows. Canonical board state lives in
`refs/karr/*`, not in a checked-in `karr/` directory. Commands materialize a
temporary task/config view only while they run.
`--json` is available on every command with an alternate rendering. `--compact`
is not -- exactly nine render one: `board`, `config`, `context`, `dashboard`,
`list`, `log`, `metrics`, `pick`, `show`. Anywhere else it answers
`Unknown option: compact` with the usage and exit 2, rather than accepting the
flag and ignoring it.
## Referring to a karr id
In prose -- commit subjects, card bodies, anywhere the text travels -- a karr id is
written `k12`, never a bare `#12`: GitHub, Gitea and GitLab all resolve `#12` against
*their own* issue 12, which is a different thing or nothing at all. This is karr's
numbering only and says nothing about how the repository's public issue tracker is
referenced -- that is separate, with its own notation.
## Commands
### Initialize
```bash
karr init [--name NAME] [--statuses s1,s2,s3] [--claude-skill] [--new-board]
```
Creates the board refs inside the current Git repository. With
`--claude-skill`, installs this skill to
`.claude/skills/kanban-issues-karr-cli/SKILL.md`.
Before it writes anything, init asks the remote whether this repository already
has a board there: `git clone` does not fetch `refs/karr/*`, so a fresh clone
looks exactly like a repository that never had one. A remote that advertises
`refs/karr/*` means the board exists and is one `karr sync` away, so init
refuses and says so rather than starting a second board beside it. Every other
answer -- no remote, an unreachable one, no answer inside the probe budget --
lets init through, because it has to work offline. Use `--new-board` only when
a clone is really meant to keep its own, independent board: the two will not
sync with each other, and the board-identity guard is what stops them.
### Create task
```bash
karr create "Title" [--status STATUS] [--priority PRIORITY] [--tags t1,t2] [--body TEXT]
karr create --title "Title" --assignee NAME --due 2026-03-15
karr create "Ship it" --depends-on 2,3 # ids of tasks this one depends on; each must exist on this board
karr create "Wait for the fix" --needs other-repo#7 # waits on a card in ANOTHER repository of the fleet
karr create "Fix the thing" --escalated-from home#5 # the card raised in that other repository
```
### List tasks
```bash
karr list # the open cards
karr list --status todo,in-progress # filter by status
karr list --priority high,critical # filter by priority
karr list --tag backend # filter by tag
karr list --class expedite # filter by class of service
karr list --blocked # only the blocked cards
karr list --not-blocked # only the unblocked ones
karr list --archived # the archive, and nothing else
karr list -s "search term" # search title/body/tags
karr list --sort priority --reverse # sort and reverse
karr list --sort priority -n 5 --json # the five most urgent open cards
karr list --claimed-by agent-1 # filter by claim owner
karr list --unclaimed # only what no live claim holds
karr list --compact # one-line output (agent-friendly)
karr list --json # JSON output
```
Finished work is out of `list` by default: the board's final column (`done` on
a default board) and `archived` are shown only when asked for by name
(`--status done`, `--archived`). `--sort` takes `id`, `title`, `status`,
`priority`, `created`, `updated` or `due`, and `priority` sorts most urgent
first. `-n`/`--limit` cuts after filtering **and** after sorting, so
`--sort priority -n 5` is the five most urgent open cards rather than five
arbitrary ones put in order -- that is the "what next" call, instead of pulling
the whole board and cutting it locally.
`--unclaimed` is "what is free right now" -- `claimed_by` unset or empty, or a
claim older than the board's `claim_timeout`. It is the question `karr pick`
answers by *taking* the card, so this is how to see the free work without
touching it, and it uses the very test `pick` uses. It is not the opposite of
`--claimed-by NAME`: that one is an exact match on the field and matches an
expired claim too, so the two overlap on "cards NAME no longer holds" and
passing both is a usage error. Since it asks about the claim and nothing else,
a blocked card nobody holds is still listed -- `--blocked --unclaimed` is a
real triage query.
### Show task
```bash
karr show ID
karr show # most recently updated task
karr show --last 5 # the 5 most recent
.claude/skills/kanban-issues-karr-cli/SKILL.md view on Meta::CPAN
karr context --sections blocked,overdue # filter sections
karr context --days 14 # lookback for recently-completed
karr context --activity-limit 10 # other agents' log entries in Recent Activity
karr context --json # JSON output
karr context --compact # board_name and the four counts, key=value
```
Generates a markdown summary with sections: In Progress, Blocked, Overdue, Recently Completed, Recent Activity (other agents' log entries, newest first, bounded by `--activity-limit`, default 5). `--sections` takes the slugs `in-progress,blocked,over...
### Skill management
```bash
karr skill install # install skill for detected agents
karr skill install --agent claude-code # install for specific agent
karr skill install --global # install globally (~/)
karr skill install --force # force reinstall
karr skill check # check if installed skills are current
karr skill update # update outdated skills
karr skill show # print skill content to stdout
```
Supported agents: `claude-code`, `codex`, `cursor`.
For Docker-wrapped usage, prefer the `raudssus/karr:latest` alias that mounts
the current project at `/work` and uses `/home/karr` as `HOME`, so the image
can drop privileges to the owner of the mounted workspace without breaking
access to Git config or agent skill directories.
### Sync
```bash
karr sync
karr sync --pull
karr sync --push
```
Use this when you want explicit control over board ref exchange with the remote
instead of relying only on the implicit pull/push behavior of mutating
commands.
`karr sync` also carries `refs/karr-foundation/*` â karr-foundation's shared
chain, run logs, question mailbox and design documents â in the same run,
after the board and never on its own. One command on purpose: a separate one
would be a second thing to remember, and a coordination namespace nobody
synced fails quietly. Mutating commands still sync the board only, so this
costs nothing outside an explicitly typed `karr sync`, and a repository
holding nothing under `refs/karr-foundation/` pushes nothing there. Deletions
in that namespace (log retention, a cleared chain) travel like board deletions
do, so a pruned run log does not come back on the next pull.
**A fresh clone fetches the board by itself.** `git clone` does not carry
`refs/karr/*`, so a new checkout holds no board while the whole board sits on
its remote. The read commands (`board`, `list`, `show`, `log`, `context`,
`metrics`, `needs`, and `config show`/`config get`) do not pull as a rule â
only mutating commands do â but where there is nothing under `refs/karr/` at
all and the remote has a board, they fetch it once and answer, with one line
on STDERR (never STDOUT) saying where it came from. Where there is no remote,
or the remote has no board, they still refuse with exit 1 rather than
rendering an empty board: that is the only place `karr init` is the answer. In
a clone whose board is on the remote, `karr init` refuses as well and points
at `karr sync`, so it can no longer start a second, empty board beside the
real one; `karr init --new-board` is the documented way through when an
independent board there really is what you want.
`KARR_NO_AUTO_FETCH=1` switches the fetch off where karr must not touch the
network.
### File view (kanban-md interop)
```bash
karr materialize # refs -> tasks/ + config.yml on disk
karr materialize --force # overwrite git-tracked cards there
karr import --yes # tasks/ on disk -> refs
```
The board lives in `refs/karr/*`. `materialize` writes a file view of it for
grepping or for kanban-md to read; `import` reads such a directory back in.
The `tasks/` directory is always gitignored and is never the source of truth â
losing it costs nothing, editing it costs nothing until you `import`.
`materialize` refuses to write over paths the project itself tracks in git,
which is what `--force` overrides.
### Repair an old board
```bash
karr repair # report what would change
karr repair --yes # migrate
```
Boards written by karr 0.402 or earlier stored UTF-8 double-encoded. Such a
board is detected on read and repaired on the fly, so nothing is broken in the
meantime; this migrates the stored refs once so the workaround stops being
needed. A board created by a later version needs nothing here and says so.
The same command also raises a `started` stamp that precedes its own card's
`created` up to that `created` â karr wrote `started` as a bare date until
ticket #68, which reads as midnight and so lands before a card created later
the same day. A clamped card then asserts zero queue time and no longer
records that its stamp was ever day-granular, so the dry run tells you how
many cards that is before you apply it. It reports, but does not touch,
`completed` stamps with the same day-granular problem.
### Backup and restore
```bash
karr backup > karr-backup.yml
karr restore --yes < karr-backup.yml
```
`restore` is destructive and replaces the entire `refs/karr/*` namespace.
### Destroy
```bash
karr destroy --yes
```
Deletes the entire `refs/karr/*` namespace from the repository and prunes the
remote board state too when a remote is configured. Prefer taking a
`karr backup` first.
### Helper refs
```bash
karr set-refs superpowers/spec/1234.md draft ready
karr set-refs superpowers/spec/1234.md < design.md # multi-line payload
karr get-refs superpowers/spec/1234.md
```
Stores and retrieves helper payloads in Git refs outside protected namespaces
such as `refs/karr/*`, branches, and tags. Use this for shared planning blobs,
agent scratch data, or similar workflow artifacts that should sync through Git
without becoming task cards.
The arguments after the ref are joined with a single space, so they are a
one-line payload. A document goes in on stdin instead â with no content
argument at all, `karr set-refs REF < file` stores the file verbatim and
`karr get-refs REF > file` gives it back unchanged.
### Activity log
```bash
karr log # last 20 entries
karr log --agent swift-fox # filter by agent
karr log --task 5 # filter by task
karr log --last 50 --json # more entries, JSON
karr log --compact # one line per entry, no padding
```
### Flow metrics
```bash
karr metrics # throughput, lead/cycle time, efficiency, aging
karr metrics --since 2026-01-01 # only count tasks completed after this date
karr metrics --compact # one line plus one per aging item
karr metrics --json # JSON output
```
Every figure comes from the `created`/`started`/`completed` stamps on the
cards, not from the activity log. Cards whose stamps cannot carry a
measurement â an unreadable date, a `started` that precedes the card's own
`created`, or a `completed` that precedes that `started` â are left out of the
averages that need them and counted in `unusable_timestamps` (cards, not
stamps), so a low sample count is visible rather than silent.
Lead time is the deliberate exception: a `completed` that precedes its own
`created` is still averaged in, negative and all, because every value it could
be clamped to would be an invention. Such samples are counted separately in
`negative_lead_samples` and named in the closing note, so the average is
qualified instead of cleaned â they are *in* the figure, not missing from it,
which is why they are not in `unusable_timestamps`. They come from boards
written before karr 0.403, which stamped `started`/`completed` as a bare
`YYYY-MM-DD` that reads as midnight; on such a board an average printed to the
hour is finer than the data underneath it.
### Agent name
```bash
NAME=$(karr agent-name) # mint once, reuse everywhere
karr pick --claim "$NAME" --move in-progress
karr handoff ID --claim "$NAME" --note "Implementation complete"
```
Every `karr agent-name` call mints a **new** name and remembers it nowhere, so
`--claim "$(karr agent-name)"` written a second time claims under one name and
hands off under another â while the first claim is live the handoff is refused,
and once it has expired it silently re-stamps the card with a name nobody holds.
Capture the name once into a shell variable and pass that same variable to every
later `--claim`, `--claimed-by` and `log --agent`. If it was never captured, read
it back off the board (`karr show ID` â `Claimed:`, or `karr pick`'s own
`(claimed by NAME)`) rather than minting a fresh one.
## Stored task format
```markdown
id: 1
title: Set up CI pipeline
status: backlog
priority: high
class: standard
created: 2026-03-12T10:00:00Z
updated: 2026-03-12T10:00:00Z
tags:
- devops
- needs:other-repo#7
Optional body with more detail.
```
Cross-board dependencies ride in `tags` (`needs:BOARD#ID`,
`escalated-from:BOARD#ID`) rather than in a frontmatter field of their own:
kanban-md marshals a card from its own struct and would drop an unmodelled key
the first time it writes, while `tags` is modelled on both sides.
Tasks are stored under `refs/karr/tasks/*/data`. During command execution `karr`
materializes the same Markdown shape into a temporary task directory, so this
format still matters when reading or generating tasks programmatically.
## Config refs
```yaml
version: 1
board:
name: My Project
statuses:
- backlog
- todo
- name: in-progress
require_claim: true
- name: review
require_claim: true
- done
( run in 2.909 seconds using v1.01-cache-2.11-cpan-b301d465b3d )