A kanban over dstask, built as a
kedi:app WASM plugin — a ratatui board that runs
inside kedi as a governed capability. It never touches
the filesystem: it reaches the task store only through a dstask capability the warden grants
and records, so every read and write is mediated.
Columns: TODAY (+now) · NEXT (the actionable pool, P3 hidden) ·
WAITING (+waiting) · DONE (resolved today). A detail pane shows the selected task
and doubles as an in-place, multi-line note editor.
deck installs into kedi's plugin dir as a .wasm component — cleanly, with no hand-editing of
the registry:
just install # build + copy deck.wasm + register it in plugins.toml (idempotent)Then launch deck from kedi's plugin launcher. just uninstall removes the wasm and its
registry entry.
Requires the wasm32-wasip2 Rust target (rustup target add wasm32-wasip2) and, on the host
running kedi, the dstask CLI plus a dstask repo (~/.dstask, or $DSTASK_GIT_REPO).
KEDI_PLUGIN_DIR overrides the install location (default
${XDG_CONFIG_HOME:-~/.config}/kedi/plugins).
| Key | Action |
|---|---|
h l j k |
move cursor · g/G top/bottom of a column |
H L |
drag the selected card across columns (retags / resolves) |
a |
capture a task (parses +tags, project:, Pn) |
N |
edit the card's note — an in-place, multi-line editor (Esc save · ^C discard) |
m |
modify the card — +tag -tag Pn project:x (dstask-style, in place) |
/ |
live filter by area / state / summary |
d n s |
resolve · toggle today (+now) · start↔stop |
: I |
ask the AI agent about the card · ingest AI-suggested tasks |
r q |
reload · quit |
The layout is responsive: narrow panes collapse to a single focused column (with a
◂ TODAY 1/4 ▸ strip; h/l switch columns); short panes drop the detail pane so the board
keeps its rows.
: and I reach an LLM through a governed ai capability — deck never shells out or hits the
network; the warden runs a configured command and records the call. Set the backend once, in kedi's
environment:
export KEDI_AI_CMD='ollama run llama3.2' # or a Claude wrapper, or any scriptThe command receives deck's prompt on stdin and returns the answer on stdout (backend-agnostic — point it at anything). Then in deck:
:on a card → type an instruction ("draft a reply", "what's the next step?"). deck frames the task + its notes + your instruction, fires the query, and shows⋯ thinking— the pane stays responsive (the call runs async; deck polls it on its tick). The answer appears in the detail pane:yappends it to the card's note, Esc dismisses.I→ asks the backend for tasks you might be missing; each line becomes adstask add.
deck declares caps = ["dstask", "ai"] in plugins.toml (set by just install). With KEDI_AI_CMD
unset, :/I report "not configured" rather than doing anything.
deck is a kedi:app WASM component (wit/app/app.wit, the plugin ABI, vendored from warden):
- UI — real ratatui (
Layout/Block/List/Paragraph) rendered into aTestBackendbuffer, serialized to ANSI, and pushed to the host viarender(one buffer flush = one frame). - Task store — reached only through
host.invoke("dstask", op, …), which crosses the warden chokepoint to a granteddstaskcapability. The plugin's WASI is empty; it has no other door. - Governance — every op is policy-gated, recorded, and killable by the host, exactly like a pty pane. Least privilege is structural: deck can reach dstask and nothing else.
just build # → target/wasm32-wasip2/release/kedi_app_deck.wasm
just check # fmt · clippy · testMIT.