A kanban board over fold_db. Cards move through columns; every
change persists in folddb. Modeled on fbrain β a thin Bun/TypeScript client
of the LastDB/FoldDB node (/api/mutation + /api/query) using Mini's
Schema Service-backed app-schema declaration for its private-visibility record
shapes.
Development source of truth is LastGit lastdb:///fkanban; GitHub
EdgeVector/fkanban is a public read-only mirror for clone/browse. See
.lastgit/README.md before opening review artifacts.
Schemas, registered under the fkanban/* app namespace (so they never collide
with fbrain/* or any other app on a shared daemon):
fkanban/Cardβ primary record byslug(includes body)fkanban/Boardβ board metadata byslugfkanban/BoardCardsβ thin membership byboard+sk(list/pickup)fkanban/MilestoneCardsβ thin reverse membership bymilestone+sk
Default columns: backlog β todo β doing β done.
Hot-path card create/update writes BoardCards only for the thin payload
(including milestone and sk). LastDB Mini binds BoardCards and MilestoneCards
as multi-key siblings and folds shared field tips onto the milestone
partition β the app does not dual-write MilestoneCards payload on every
mutation, and does not call protein APIs.
On move / milestone clear / delete, the app retires obsolete MilestoneCards
keys (deletes). Heal (milestone-indexes-heal) may still full dual-write to
repair drift.
Shared field descriptions match between the two layouts so field identity can
align; layout stays distinct so partition markers never co-identity.
See fold docs/app-developers-multi-key-proteins.md and tests
test/protein-primary-membership.test.ts / test/no-protein-reach.test.ts.
Contributing to kanban itself? See AGENTS.md for the build/test/run/dogfood + PR workflow and the non-obvious gotchas.
Just want to use kanban? Skip straight to Prerequisites + Quick start.
kanban initasks Mini to register/resolve thefkanban/*schemas and seeds the default board.
Schema setup has one supported path: kanban init calls Mini's
POST /api/apps/declare-schema. Mini resolves an existing catalog identity or
registers a novel shape with Schema Service, anchors added fields as an
expansion of the prior identity, loads the exact catalog definition, and only
then returns the hash that fkanban may persist. There is no fkanban-side Schema
Service script and no Mini local-mint fallback. Existing rows remain visible
through expansion field mappers; schema changes do not bulk-copy card data.
You need three things before the Quick start, in this order:
1. Bun. kanban is a Bun/TypeScript app, so you need the Bun runtime.
curl -fsSL https://bun.sh/install | bash # or: brew install oven-sh/bun/bun2. The kanban repo. Clone it and install its dependencies β this is where
the Quick start's cd kanban comes from.
git clone https://github.com/EdgeVector/fkanban.git
cd kanban
bun install3. A running folddb node. kanban is a thin client β it needs a running
folddb node to talk to (init defaults to Unix socket ~/.lastdb/data/folddb.sock (local)). Start
one before init in one of two ways:
-
Homebrew (recommended for just using kanban): install folddb from the EdgeVector/homebrew-folddb tap and start the daemon. It serves the Unix socket ~/.lastdb/data/folddb.sock by default β exactly
init's default--node-url.brew install edgevector/folddb/folddb brew services start folddb # background daemon, restarts at login(
folddb daemon startworks too if you'd rather not run it as a service.)You don't need to run
folddb setupfirst:kanban initauto-provisions the node identity on first run against a fresh, unprovisioned node β so a kanban-only user can skip it (handy for headless/SSH/CI: just start a node, thenkanban init, no interactive wizard required).folddb setupremains the way to set up a full folddb identity (24-word recovery phrase, cloud sync) if you want one. -
From the fold monorepo (for fold devs):
cd fold/fold_db_node && ./run.sh --local --dev
Once a node is up, run bun src/cli.ts doctor to confirm it's reachable, then
bun src/cli.ts init to bootstrap the board.
The commands below are written as kanban <cmd>. To make a bare kanban
resolve from any directory, run the one-line installer from the repo root:
cd kanban
bun run install-cli # symlinks kanban/kanban-mcp plus fkanban/fkanban-mcp aliases
kanban doctor # confirms the shim is on PATHinstall-cli auto-picks a writable PATH directory (/usr/local/bin,
~/.local/bin, or ~/bin); pass an explicit one if you prefer
(bun run install-cli ~/bin). If the directory you pass isn't on your
PATH, it links the shims anyway but tells you so (and prints the exact
export PATH=β¦ line to add) rather than falsely claiming success. Under the hood it just symlinks the bundled
bin/kanban wrapper (a tiny bun run src/cli.ts "$@" script, plus a matching
kanban-mcp one, with fkanban and fkanban-mcp aliases kept for compatibility)
β so it's fully local and reversible, nothing is published to
a registry, and the rm β¦ line it prints removes all four shims. Without the shim, run the
CLI as bun run src/cli.ts <cmd> from inside the repo; the two are equivalent.
For long-lived agent machines, use the host-track refresh helper instead of pointing PATH at a workspace checkout:
bin/host-track-refresh
kanban which --json
kanban which --checkPreferred install (Kind B local-safe, host-track apps.json):
~/.host-track/apps/fkanban/current β versions/<oid>
~/.local/bin/{kanban,fkanban,β¦} β β¦/current/bin/β¦
Upgrade with last-stack-safe-upgrade-cli fkanban (or host-track refresh fkanban when wired). which --check accepts both that layout and the legacy
checkout ~/.host-track/fkanban (still used by bin/host-track-refresh on
older machines). Override with FKANBAN_HOST_TRACK_DIR.
Host-track registers this repo under the app ids kanban and fkanban
(same install root). Use host-track status kanban for the registered app
status, and fkanban which --json or ~/.host-track/stamps/fkanban.json to
inspect the live install.
When promoting a host-track build or config that flips an operational default
such as an enforce* guard, post a temporary Situations notice before the
promotion. See Operational Default Flips
for the notice convention.
With the prerequisites in place (Bun installed, repo cloned, bun install run,
a folddb node up), from inside the kanban repo:
bun run install-cli # one-time: put kanban on PATH (see "Install the global shim")
# Bootstrap the node, register/resolve the fkanban schemas, and seed the
# default board. On a fresh bootstrap, `init` ends by printing a "Next steps" block β
# including the `claude mcp add fkanban β¦` command to register the MCP server
# (the form is picked for you based on whether the `kanban` shim is on PATH).
kanban init
# β¦or point at an ephemeral dev node. The CLI's --schema-service-url is recorded
# in config for diagnostics only (it shows in `kanban doctor`); Mini owns the
# required Schema Service registration call.
kanban init \
--node-url http://127.0.0.1:9105 \
--schema-service-url https://y0q3m6vk75.execute-api.us-west-2.amazonaws.com
kanban add ship-login --title "Ship login flow" --tags auth,p1
kanban move ship-login doing
kanban add fix-typo --column todo
kanban list(Haven't installed the shim? Every kanban <cmd> below works as
bun run src/cli.ts <cmd> run from the repo directory.)
If init reports app_schema_declare_unsupported, the node does not expose
Mini's registered app-schema declaration route. Upgrade LastDB/FoldDB to a Mini
build whose /api/apps/declare-schema resolves or registers every proposal
with Schema Service; --schema-service-url is diagnostic because Mini owns the
service call.
Schema synchronization has one executable transport: F-Kanban's node client
calls Mini's POST /api/apps/declare-schema (normally through kanban init).
F-Kanban must not call Schema Service, use the legacy owner-declare route,
accept local_mint, or copy rows as part of a field expansion. The LastGit CI gate runs
bun run check:schema-sync-boundary and rejects those bypasses. An incompatible
key-layout migration is a separately designed and reviewed operation; it is
never inferred from schema synchronization.
If init reports schema_not_writable, the node has a fkanban/* schema that
resolves but isn't writable for all fields β usually an older, narrower
version of the schema (fewer fields than this kanban build expects), sometimes
loaded alongside the current one. init now refuses to adopt such a hash
(it would 400 every subsequent write) and leaves your existing config
untouched, so the board keeps working. The fix is node-side: repair or
upgrade Mini's registered schema declaration path, then re-run kanban init. init
and kanban doctor write-probe the schema hashes before trusting them, so a
stale duplicate can't silently break writes.
Default board (default)
BACKLOG (0)
β
TODO (1)
β’ fix-typo fix-typo
DOING (1)
β’ Ship login flow ship-login #auth #p1
REVIEW (0)
β
DONE (0)
β
| Command | What it does |
|---|---|
kanban init |
bootstrap node + register/resolve schemas + seed default board (idempotent) |
kanban add <slug> |
create/update a card (--title --board --column --assignee --tags --deps --replace-deps --surfaces --priority P0-P3 --milestone <slug> --kind pr|registry|tracker|umbrella|meta|program|capstone|validation --body, or pipe body on stdin) |
kanban mark <slug> <line> |
append one marker line to an existing card body, idempotently (--json) |
kanban move <slug> <column> |
move a card to a column (--from/--expect COL as a compare-and-swap claim guard, --position N, --force as an explicit override for dependency blocks and default/todo pickup-readiness policy) |
kanban dep add <slug> <dep> |
add a dependency edge (card <slug> depends on existing live card <dep>) |
kanban dep rm <slug> <dep> |
remove a dependency edge |
kanban tag add <slug> <tagβ¦> |
add one or more tags to a card, incrementally (keeps the rest) |
kanban tag rm <slug> <tagβ¦> |
remove one or more tags from a card |
kanban list |
render a board as columns, a wide table, or grouped beneath milestone headings (--group-by-milestone); blocked cards show π |
kanban overlap <slug> |
compare a candidate card's surfaces against doing cards in the same repo (exit 2 on declared conflict) |
kanban pickup status |
classify active cards by pickup eligibility and explain why non-ready cards are skipped (--json) |
kanban pickup claim |
atomic next-card claim: priority order + surface-overlap skip + CAS todoβdoing (--worker --prefer-repo --exclude-repo --max-doing --dry-run --json) |
kanban groom stale-blockers |
dry-run/apply cleanup for stale generated blocker metadata (--apply --json) |
kanban hygiene orphan-bun |
dry-run/apply a path-scoped PPID-1 Bun helper reaper for kanban/gstack (--apply --min-age-hours N --pileup-threshold N --json) |
kanban rank |
reorder work cards by priority so pickup works urgent cards first (--board --column, default todo; grouping kinds are skipped) |
kanban search <query> |
find cards by text across slug/title/body/assignee/tags (--board --column --limit N --all --json --full-body) |
kanban show <slug> |
print one card in detail incl. deps + blocked state (--json) |
kanban rm <slug> |
delete a card with fold_db's native tombstone mutation |
kanban board create <slug> |
create/update a board (--title; --columns may be omitted or set to backlog,todo,doing,done) |
kanban board list |
list boards (--json) |
kanban board rm <slug> |
delete a board with native tombstones; always refuses default, and refuses non-default boards with live cards unless --force |
kanban milestone add <slug> |
create/update a first-class outcome milestone (--state --north-star --driver --deps --proof-card --proof-status) |
kanban milestone list |
list the milestone portfolio (--board --state --json) |
kanban milestone show <slug> |
show one milestone's outcome, lifecycle, dependencies, driver, and proof linkage (--json) |
kanban milestone state <slug> <state> |
transition planned|active|blocked|proving|complete|abandoned (--json) |
kanban milestone reconcile <slug> |
report ready child-card frontier, proof state, and actionable lifecycle warnings (--json) |
kanban milestone portfolio |
show milestone North Star, lifecycle, proof, ready frontier, blocker, and warning count (--board --json) |
kanban milestone detail <slug> |
show the outcome, proof, warnings, and child cards grouped by fixed columns (--json) |
kanban milestone groom |
report actionable driver, proof, frontier, lifecycle, and relationship warnings (--board --json) |
kanban migrate area-tags |
one-time cleanup of stale generated area:* tags (--dry-run --json) |
kanban ping |
liveness probe: one cheap node status read, no board read (--json) |
kanban doctor |
health-check config + node + schemas + a query round-trip |
kanban mcp |
start an MCP server over stdio |
Global: --verbose (echo HTTP), --version, --help.
--json works on the write commands too β add, move, dep add/rm,
tag add/rm, rm, board create, and board rm echo the write result as a JSON object instead of a prose
line, so scripts and agents can confirm the outcome machine-readably (e.g.
kanban move ship-login doing --json β {"slug":"ship-login","from":"todo","to":"doing"}).
Use kanban move ship-login doing --from todo when claiming work: if another
writer moved the card first, the command exits non-zero and --json prints
{"error":"claim_conflict","current":"<col>","expected":"todo"} without
moving it.
Milestones are first-class supervisory records between Brain North Stars and
executable cards. They are not tagged cards, never occupy card columns, and can
never be selected by pickup. Cards link to them with --milestone <slug>;
F-Kanban refuses missing milestone references and board/North-Star mismatches.
Milestones are driven and proven while cards remain the atomic pickup work.
Transitions are explicit and proof-gated. Entering proving requires a live
proof card linked back to the same milestone and board. Entering complete
also requires that card to be in the board's terminal column, milestone
proof_status to be passing, and the card body to contain an exact
PROOF: PASS or RESULT: PASS line. Finishing implementation cards alone
never completes the milestone. A failed proof returns to active with
--proof-status failing for fix-forward work. milestone reconcile exposes
the next ready card frontier and warnings without making the milestone pickup
work.
Use milestone portfolio for the cross-outcome view, milestone detail to
groom one outcome and its card frontier, and milestone groom for the health
queue. The ordinary board remains card-native; list --group-by-milestone
adds milestone headings while keeping cards in their fixed columns and puts
unlinked work in a final Unassigned / Operational section. Milestone records
themselves never appear as cards.
list caps each column at 12 cards by default so a long done column
can't flood the terminal; the overflow collapses to a dim β¦ N more (--all)
line (the done/terminal column keeps the most recent cards). --all shows
everything and --limit N sets a custom per-column cap β both apply to text
and --json. Default --json reads, including --column, use the same
12-card-per-column default cap and return single-line body previews with
bodyTruncated; pass --all to return every row, or --full-body /
--full_body for the historical complete card-body JSON surface. --wide
prints one fixed-width row per card with
COLUMN SLUG REPO BASE PR UPDATED TITLE for agent/reconcile scans.
--tag <tag> and --assignee <name> apply exact-match filters to the
listing (contrast the fuzzy substring search below), e.g.
kanban list --tag kanban --column doing.
For hook-safe scripting, list and search also accept repeatable
--field <name> projection. It prints TSV with no header and no JSON:
kanban list --column todo --field slug prints one slug per line, while
kanban list --field slug --field pr prints slug<TAB>pr per card. pr is
the shorthand for the stored pr_url field. Existing filters such as
--board, --column, --tag, --assignee, --limit, and --all still
apply before projection.
search <query> finds cards by a case-insensitive substring across slug,
title, body, assignee, and tags β handy once a board has more cards than fit on
screen. Space-separated terms are AND-matched (kanban search auth p1 needs
both), results span columns/boards and are annotated with [board/column],
and --board / --column scope the search. Like list, the text output caps
the rendered matches at 20 by default so a busy board doesn't flood the
terminal; the overflow collapses to a dim β¦ N more (use --limit N or --all)
line. --all shows every match and --limit N sets a custom cap β both apply
to text and --json. Broad --json reads use the same 20-match default cap
and return single-line body previews with bodyTruncated; pass --all to
return every match, or --full-body / --full_body for the historical
complete-body JSON surface.
default/todo is the pickup lane: a pr card there must carry clean routing
data (Repo: owner/name and Base: branch, or the matching structured
--repo/--base fields) so an agent can clone the repo and start once its
dependencies are done. kanban add and kanban move reject malformed
default-todo cards by default, including inline-commented Repo: headers,
missing base branches, intentional block_status holds, and non-pickup
--kind values. Use --force only as an explicit operator override; otherwise
put human-gated, deferred, tracker, program, capstone, validation, and other
non-pickup work on a parking surface until it is split into concrete PR work.
Use pickup status before grooming or pickup:
kanban pickup status
kanban pickup status --jsonAgents should claim with pickup claim, not hand-roll list β overlap β move:
kanban pickup claim --json --worker last-stack-fkanban-pickup-w2
# dry-run selection only:
kanban pickup claim --dry-run --jsonpickup claim walks pickup-ready todo cards in priority order (P0βP3), skips
surface conflicts with doing cards in the same repo, and CAS-moves the first
winner into doing. Concurrent workers that lose a race get claim_conflict
and the command continues to the next candidate. Idle boards return
{ "claimed": false, "reason": "no-eligible" } with exit 0. JSON responses
include bounded diagnostics.exemplars for non-ready categories so automations
can report concrete blockers without broad board scans.
For automation idle decisions, treat the queue as truly empty only when the claim result is all of:
claimed: falsereason: "no-eligible"scanned_ready: 0skipped: []
If scanned_ready > 0, or skipped contains surface-overlap,
exclude-repo, claim_conflict, or another skip reason, ready work existed but
could not be claimed by this worker. That is queue backpressure or routing
selection, not idle capacity; a pickup routine should report the skip and exit
instead of inventing idle work.
It classifies each active card as pickup-ready,
blocked-on-dependency, human-gated, malformed-routing,
parked/non-work, collision, or stale-metadata. The JSON shape carries the
same counts and per-card reason/suggestion fields for automations.
The conventional human/parking surface is a board named human:
kanban board create human \
--title "Human / parked work" \
--columns todo,waiting,validated,done
kanban add legal-review \
--board human \
--column todo \
--block-status needs_human \
--block-reason "waiting on legal review"Cards on human are visible through kanban list --board human and
kanban board list, but pickup status never treats them as pickup-ready.
Dependencies still work across boards: a default/todo card can depend on a
human-board prerequisite and remains blocked-on-dependency until that
prerequisite reaches the human board's terminal column (done by the convention
above).
Return work to the pickup lane only when the human gate is actually cleared:
kanban add legal-review --board default --column todo \
--block-status none --block-reason ""
kanban rankMigration guidance:
- Move true Tom/human, legal, hardware, product-decision, or validation-evidence
gates to
humanand keep the explicitblock_status/block_reason. - Move deliberately deferred or sequencing-only rows to a parking board, or keep
them out of
default/todowith--block-status deferred. - Mark trackers, programs, capstones, validations, registries, and context rows
with their non-
pr--kind; split out a concreteprcard when code is ready. - Do not auto-clear real human gates. Use
kanban groom stale-blockersto find generated/stale blocker metadata, then review the dry-run before applying safe generated cleanup.
groom stale-blockers is dry-run by default:
kanban groom stale-blockers
kanban groom stale-blockers --applyIt reports stale generated BLOCKED: prose, malformed Repo: header lines,
block status/reason mismatches, stale pickup-area overlap holds, and
human/parking candidates. With --apply, it rewrites only generated boilerplate
and structured fields it can prove stale; ambiguous or real human gates stay as
review-only candidates.
hygiene orphan-bun is dry-run by default and does not talk to the folddb node:
kanban hygiene orphan-bun
kanban hygiene orphan-bun --applyIt only targets PPID-1 Bun processes older than 24 hours whose command path
matches the explicit agent-tooling allowlist: kanban MCP (src/cli.ts mcp or
src/mcp/main.ts), gstack browse server (gstack/.../browse/src/server.ts), or
gstack terminal-agent (gstack/.../browse/src/terminal-agent.ts). It also flags
same-parent Bun pileups above 100 processes so the machine-hygiene loop can
surface Codex-style process explosions without killing by process name.
A card can depend on other cards, including cards on another board such as the
human parking board. It stays π blocked until every dependency reaches
its own board's terminal column, and move refuses to advance a blocked card
into a working column (doing / done) unless you pass --force.
Backlog/todo moves are always allowed.
Cards marked --kind tracker, --kind umbrella, --kind meta,
--kind registry, --kind program, --kind capstone, or --kind validation
are context/grouping cards, not prerequisites: if another card lists one as a
dep, it is treated as satisfied by default and does not block pickup. A parked
human prerequisite that should block downstream implementation should remain a
concrete pr dependency until it reaches the parking board's terminal column.
Deleting/tombstoning a card with live dependents is refused (the policy landed in PR #149) so dependency edges cannot silently turn into missing slugs.
kanban add api --title "Build API"
kanban add ui --title "Build UI" --deps api # ui depends on api
kanban move ui doing # β refused: blocked by "api" (not yet done)
kanban move api done
kanban move ui doing # β unblocked
kanban dep add ui docs # add another edge incrementally
kanban dep rm ui docs # β¦or drop one
kanban add ui --deps "" --replace-deps # explicitly clear all depsEdges are stored in the Card schema's canonical deps array field. They are
not part of the body and they are not user tags, so an agent cannot accidentally
erase or forge a dependency while editing prose or labels. Historical
dep:<slug> tags are still read as a compatibility fallback, but new writes
strip them and persist edges only in deps. Mini local declaration expands the
existing fkanban/Card schema to add deps; no data migration is required.
add --deps and dep add require every dependency slug to resolve to an
existing live card before writing. Generic card updates preserve existing deps
unless --replace-deps is set, so a cleanup call with deps: [] cannot
silently erase real dependency edges. If older data already contains a missing
dep, read paths surface it in missingDeps and treat it as blocking until the
edge is repaired. rm refuses to delete/tombstone a card while any live card
still depends on it, so normal operations cannot create new missing dependency
slugs.
Cards can declare the repo-relative paths or subsystem names they expect to touch. Declare surfaces when filing the card, and update them if the scope grows:
kanban add ship-cli --surfaces "src/cli.ts,src/mcp/**"The same data can live in the body for incremental adoption:
Surfaces: src/cli.ts, src/mcp/**
Run kanban overlap <slug> before picking up or widening a card. It compares
the candidate against doing/review cards with the same repo and prints the
conflicting card slugs plus matched patterns. Declared conflicts exit 2; cards
with missing surfaces only warn and exit 0 so older cards do not block
adoption.
Use kanban mark <slug> "<line>" for routine annotations. kanban add --body
replaces the full body, and refuses a body made only of a newline-joined list of
existing card slugs to catch accidental candidate-list clobbers.
Tags are freeform labels for filtering (kanban list --tag <tag>). There are
two ways to set them, mirroring dependencies exactly:
kanban add ship-login --tags auth,p1 # REPLACES the whole tag list
kanban tag add ship-login blocked # add one tag, keep the rest
kanban tag rm ship-login blocked # drop one tag, keep the rest
kanban tag add ship-login p1 needs-review # add several at once--tags a,b,c on add overwrites the entire list β supplying it drops any tag
not in the new set. tag add/tag rm edit a card's labels incrementally,
so a groomer can add p1 without first reading and re-sending every existing
tag (the same distinction dep add/dep rm have to add --deps). Adding a tag
the card already carries is a no-op; removing one it lacks warns but succeeds.
Reserved tags (dep:<slug> legacy dependency tags, the delete tombstone) are
rejected β use dep add/dep rm and rm for those. Dependency edges live in
the card's separate deps field, not in tags.
A card has an optional priority β P0 (most urgent) β¦ P3 (least). It lets
kanban rank order a column so the fkanban-pickup routine (which works the
lowest position first) picks up the most urgent cards first.
kanban add ship-login --priority P0 # stored as a `p0` tag
kanban rank # reorder the `todo` column by priority
kanban rank --board roadmap --column backlogPriority is read, in precedence order, from (1) a line-anchored
Priority: P<n> header in the card body (most explicit), then (2) a
p0..p3 tag (what --priority writes), else (3) P2 (normal). Priority
still rides on the existing tags array; dependency edges do not.
rank reassigns each work card's position in priority order (ties broken by
created_at, oldest first), leaving gaps (10, 20, 30, β¦) so a card can be
hand-inserted between two without a full re-rank. Context/grouping cards
(registry, tracker, umbrella, meta) are skipped so they do not affect
pickup order. It's idempotent β re-running an already-ranked column writes
nothing β and is the step the board groomer runs after promoting cards into
todo. The priority signal alone does nothing until rank turns it into
position.
Exposes the board as tools (fkanban_list, fkanban_search, fkanban_add,
fkanban_move, fkanban_rank, fkanban_pickup_claim, fkanban_overlap, fkanban_dep_add, fkanban_dep_rm, fkanban_tag_add,
fkanban_tag_rm, fkanban_show,
fkanban_pickup_status,
fkanban_rm, fkanban_board_create, fkanban_board_list, fkanban_board_rm,
fkanban_milestone_add, fkanban_milestone_list, fkanban_milestone_show,
fkanban_milestone_state,
fkanban_milestone_reconcile,
fkanban_milestone_portfolio, fkanban_milestone_detail,
fkanban_milestone_groom,
fkanban_doctor)
so agents can drive β and self-diagnose β the board.
For MCP writes, omit deps on fkanban_add unless you are intentionally
setting dependencies. Existing deps are preserved by default; replacing or
clearing them requires replace_deps: true, and every dependency slug must
already be an existing live card. Prefer fkanban_dep_add and fkanban_dep_rm
for ordinary edge edits.
Register it with Claude Code (the -- separates the claude mcp add flags from
the command it runs). With the global kanban shim on PATH, use the short
form:
claude mcp add fkanban -- kanban mcpOtherwise point bun at this repo's entrypoint:
claude mcp add fkanban -- bun "$PWD/src/mcp/main.ts"kanban doctor prints whichever of these applies to your setup. It reads the
same ~/.kanban/config.json the CLI writes (override the path with
$KANBAN_CONFIG, or the compatibility $FKANBAN_CONFIG).
The read tools fkanban_list and fkanban_search are token-budgeted by
default, so a board with hundreds of cards doesn't blow an agent's context
window β card bodies are the bulk of a page's tokens, so both the result count
and each body are capped unless you opt out.
- Count cap. Results default-cap to 20 cards (
DEFAULT_SEARCH_LIMIT), and every response reportstotal(matches before the cap) andtruncated(whether the cap hid any). Raise the cap withlimit: N(0= uncapped) orall: true. - Body preview. Each returned card's
bodyis a ~200-char single-line PREVIEW with abodyTruncatedflag. Passfull_body: trueto inline complete bodies, or callfkanban_show <slug>β the full-body path for a single card.
(The CLI's --json output is unaffected β it intentionally returns full bodies.)
done_at is stamped once when a card first enters its board's final column
(usually done) and is preserved across later tag/body grooming updates. Legacy
or not-yet-complete cards expose it as an empty string.
The fkanban/Card and fkanban/Board schemas are private in visibility, but
every identity is registered with Schema Service. kanban init asks Mini to
resolve/register them and persists the returned catalog hashes in config after
write-probing them.
Shared-surface publication is only for contracts fkanban deliberately exposes to another app or an external surface. Ordinary board storage does not publish its schemas, but registration with Schema Service is still mandatory.
- NodeOwner writes. Mutations go in without a capability token β correct
for a local / ephemeral node with
APP_IDENTITY_ENFORCEoff. Under enforcement the app would need a consent handshake (seefbrain'scapability.ts); that's intentionally out of scope here. - Delete.
rmuses fold_db's native delete mutation, so tombstoned records are skipped by the node before scans. To preserve dependency resolution, card deletion refuses while live dependents still point at the card;board rm --forcehas the same guard for cards outside the board being removed. Read paths still hide the historical__fkanban_deleted__tag written by older kanban builds. - Append-with-gaps positions. New cards land at
maxPosition + 10so a card can later be inserted between two others. - Priority is a signal over
position. A card's priority (Priority:header orp0..p3tag) does nothing on its own;kanban rankis what turns it into thepositionfield pickup/list/sort already order by. Keeps priority republish-free (rides ontags) and keeps one ordering primitive (position).