Use the crumbs CLI to manage tasks, bugs, features, and ideas tracked as plain Markdown files in a .crumbs/ store. Use this skill when the user asks to create, list, show, update, close, delete, link, search, export, or time-track crumbs items — or asks what to work on next. Also use when asked to initialize a crumbs store in a project. crumbs is already installed; run it directly, no cargo run needed.
Flat-folder Markdown task tracker. Each item is a .md file with YAML frontmatter. A index.csv is the read cache, rebuilt after every write. No daemon, no database.
Store lives in .crumbs/ (local, auto-detected from cwd) or the platform global store:
~/Library/Application Support/crumbs~/.local/share/crumbs%APPDATA%\crumbs--dir <path> explicit override--global → platform global store (see above).crumbs/ under cwd (auto-detected)crumbs init # local store, prompts for prefix
crumbs init --prefix myp # skip prompt
crumbs init --global # global store (prefix suggestion: "glob")
crumbs create 'Fix login bug' --type bug --priority 1 --tags auth
crumbs create 'Auth redesign' --message 'Covers OAuth and sessions' --due 2026-04-01
crumbs c 'Quick idea' # shorthand
Title is a positional argument on create — there is no --title flag. (--title is only available on update.)
Use single quotes to avoid shell expansion of !, $, etc.
crumbs list # open + in_progress + blocked + deferred
crumbs list --all
crumbs list --status blocked
crumbs list --status open --priority 0
crumbs list --tag project/auth
crumbs list --type bug # filter by type (task, bug, feature, epic, idea)
crumbs list --phase phase-1 # filter by phase label
crumbs list --verbose # show first two body lines beneath each item
crumbs list --sort priority # sort by: id (default), priority, status, title, type, due, created, updated, phase
crumbs next # highest-priority actionable item (skips deferred with future until date)
crumbs show cr-x7q # IDs are case-insensitive
crumbs show cr-x7q cr-y8r cr-z9s # show multiple items
crumbs stats
crumbs search "login"
crumbs update cr-x7q --title 'New title'
crumbs update cr-x7q --status in_progress
crumbs update cr-x7q --priority 0 --tags auth,urgent
crumbs update cr-x7q --message 'Now includes OAuth flow'
crumbs update cr-x7q --append 'See PR #99' # appends with [date] prefix
crumbs update cr-x7q --due 2026-04-01
crumbs update cr-x7q --clear-due
crumbs update cr-x7q --depends cr-abc,cr-xyz
crumbs update cr-x7q --type bug
crumbs update cr-x7q --points 5
crumbs update cr-x7q --clear-points
crumbs update cr-x7q --phase phase-1
crumbs update cr-x7q --phase 2026-Q2
crumbs update cr-x7q --clear-phase
Omit the ID and supply one or more --filter-* flags to update every matching item in one shot:
crumbs update --filter-tag sprint/3 --priority 1 # raise priority for a whole sprint
crumbs update --filter-status open --filter-phase phase-1 --phase phase-2 # re-phase items
crumbs update --filter-tag done --status in_progress # change status in bulk
crumbs update --filter-priority 4 --filter-tag backlog --dry-run # preview first
crumbs update --filter-tag sprint/3 --priority 0 --yes # skip confirmation
Filter flags (all optional, AND-combined):
| Flag | Description |
|---|---|
--filter-status <STATUS> | match by status |
--filter-tag <TAGS> | comma-separated tags, AND semantics |
--filter-priority <N> | match by priority |
--filter-type <TYPE> | match by item type |
--filter-phase <PHASE> | match by phase |
--filter-all | include closed items in scope (requires another filter flag) |
--filter-* flag is required (empty/whitespace values are ignored)--filter-all alone does not trigger bulk mode — pair it with another filter--yes--dry-run / -n prints what would change without writing anythingcrumbs append cr-x7q 'Quick note' # shorthand for update --append; alias: a
crumbs a cr-x7q 'Quick note'
crumbs block cr-x7q cr-y8r,cr-z9s # cr-x7q blocks targets; targets get blocked status
crumbs block cr-x7q cr-y8r --remove # unlink; targets reopen if nothing else blocks them
crumbs block cr-x7q # mark cr-x7q itself as blocked (no link)
crumbs defer cr-x7q # set status to deferred
crumbs defer cr-x7q --until 2026-04-01 # defer with a wake-up date; resurfaces in next
crumbs defer cr-x7q --reopen # reopen a deferred item
crumbs move cr-x7q --to /path/to/other/.crumbs # move to another store (new ID assigned)
crumbs move cr-x7q --to global # move to the global store
crumbs pull glob-x7q --from global # pull from global into current store
crumbs pull glob-x7q --from /path/to/.crumbs # pull from a specific store
move and pull always assign a new ID in the destination store.
crumbs batch-create --from items.json # JSON array of item specs
crumbs batch-create --from items.yaml # YAML array (.yaml or .yml)
crumbs batch-create --from data.txt --format json # override inferred format
generate-tasks | crumbs batch-create --from - --format json # stdin pipe
crumbs batch-create --from - --format yaml << 'EOF' # heredoc
- title: Fix login bug
type: bug
priority: 1
- title: Update docs
EOF
Input is a JSON or YAML array of item specs. Only title is required; all other fields are optional and default to the same values as crumbs create with no flags. Format is inferred from the file extension (.json → json, .yaml/.yml → yaml); --format overrides or is required when the extension is unrecognised. For stdin (-), --format is always required. On macOS/Linux, end stdin input with Ctrl-D. All IDs are generated fresh and are unique across the batch and the store. reindex runs once at the end.
| Field | Required | Notes |
|---|---|---|
title | yes | |
type | no | default: task |
priority | no | default: 2 (normal) |
tags | no | array of strings |
message | no | body text |
dependencies | no | array of IDs |
due | no | YYYY-MM-DD |
story_points | no | Fibonacci integer |
phase | no | free-form label |
crumbs import --file export.json # format inferred from .json extension
crumbs import --file export.csv # format inferred from .csv extension
crumbs import --file data.bin --format json # explicit format override
Imports item records from a JSON or CSV file. JSON preserves all fields including the markdown body; CSV round-trips only the CSV columns (no body text — use JSON for full-fidelity imports). This is the inverse of crumbs export. Format is inferred from .json or .csv; --format is required for any other extension. Errors immediately if any item's ID already exists in the store, or if the file contains duplicate IDs. TOON import is not supported (use JSON for round-trips). reindex runs once at the end.
crumbs link cr-x7q blocks cr-y8r # bidirectional; sets cr-y8r to blocked
crumbs link cr-x7q blocks cr-y8r,cr-z9s # multiple targets
crumbs link cr-x7q blocked-by cr-z9s
crumbs link cr-x7q blocks cr-y8r --remove # unlink; restores open if unblocked
crumbs start cr-x7q # append [start] entry, set in_progress
crumbs start cr-x7q -m 'Investigating root cause'
crumbs stop cr-x7q # append [stop] with elapsed time
crumbs stop cr-x7q -m 'Fixed, needs review'
crumbs show cr-x7q # shows "Total tracked: Xh Ym Zs"
Start/stop entries are plain lines in the markdown body, interleaved with any notes added via --append. A typical item body looks like:
[2026-03-08] Reproduced locally.
[start] 2026-03-08 09:00:00 Investigating root cause
[2026-03-08] Found the bug in main.js line 401.
[stop] 2026-03-08 09:47:12 47m 12s Fixed, needs review
crumbs start errors with "Already started at HH:MM:SS" if an unmatched [start] exists.
crumbs close cr-x7q # prompts for reason interactively (TTY only)
crumbs close cr-x7q --reason "fixed in PR #42"
crumbs delete cr-x7q
crumbs clean # purge all closed items
Closing an item with an active timer automatically stops the timer first and writes a [stop] entry before setting status: closed.
Omit the ID and supply one or more filter flags to close every matching item at once:
crumbs close --tag done # close all items tagged "done"
crumbs close --tag sprint/3 --reason "sprint done" # with a shared close reason
crumbs close --phase phase-1 --dry-run # preview before acting
crumbs close --tag done --yes # skip confirmation
crumbs close --phase phase-1 --all # include already-closed in scope
Filter flags (all optional, AND-combined):
| Flag | Description |
|---|---|
--status <STATUS> | match by status |
--tag <TAGS> | comma-separated tags, AND semantics |
--priority <N> | match by priority |
--type <TYPE> | match by item type |
--phase <PHASE> | match by phase |
--all / -a | include closed items in scope (requires another filter flag) |
--dry-run / -n prints what would be closed without writing anything--yes / -y skips the confirmation promptcrumbs export # JSON to stdout
crumbs export --format csv
crumbs export --format toon # token-efficient for LLMs
crumbs export --format json --output items.json
crumbs export --output # → crumbs_export.json (default filename)
crumbs export --format csv --output # → crumbs_export.csv
crumbs body cr-x7q # inline TUI editor: line 1 = title, rest = body; Ctrl-S saves, Esc exits
crumbs edit cr-x7q # opens full .md file in $EDITOR; reindexes on exit
crumbs reindex # rebuild index.csv manually
| Field | Values |
|---|---|
status | open, in_progress, blocked (⊘), deferred (◷), closed |
type | task, bug, feature, epic, idea |
priority | 0=critical, 1=high, 2=normal, 3=low, 4=backlog |
tags | comma-separated, e.g. project/auth,urgent |
due | YYYY-MM-DD |
dependencies | comma-separated IDs |
blocks / blocked_by | set via link or block command |
story_points | optional integer; conventional Fibonacci values: 1, 2, 3, 5, 8, 13, 21 |
phase | free-form label, e.g. phase-1, 2026-Q2; always written to frontmatter (as '' when unset) |
Timer entries live in the markdown body alongside other notes:
| Line | Format |
|---|---|
| Start | [start] YYYY-MM-DD HH:MM:SS [optional comment] |
| Stop | [stop] YYYY-MM-DD HH:MM:SS Xh Ym Zs [optional comment] |
crumbs show sums all matched pairs and prints Total tracked: Xh Ym Zs.
CR-X7Q == cr-x7qcrumbs show x7q expands to {prefix}-x7qcrumbs show accepts multiple IDs: crumbs show x7q y8r z9slink blocks and block update both items atomically and set blocked status on targetsopen on targets when no other blockers remain--tags and --depends on update replace the existing list (not append)crumbs list output format: icon id [Px] [phase] [type] title [tags] due:… [Nsp] — phase badge is padded to the widest phase in the current view; unphased items show spaces to match that width; when no items have a phase, [] is shown--tag on list uses AND semantics: --tag alpha,beta returns only items that have both tags; empty parts are ignored--append 'text' adds to the body with a [YYYY-MM-DD] timestamp prefix; --message 'text' replaces it:shortcode: in body text (message, append, timer comments) is expanded to Unicode at write time — e.g. :tada: → 🎉, :bug: → 🐛, :+1: → 👍; unknown shortcodes pass through unchangedcrumbs defer --until <date> sets the due date; crumbs next skips deferred items with a future until date and skips items whose blocked_by items are still opencrumbs start / crumbs stop append timer entries to the body; crumbs show sums elapsed time as "Total tracked"my-task-cr-x7q.md.crumbs/ can be committed to git for full historymove/pull reassign a new ID using the destination store's prefix; import --file preserves the original ID"global" as the path for --to / --from to refer to the global storebatch-create generates fresh IDs for all items; existing IDs in the store are never reused within the batch