Files
Marcos Paulo de3ec375ae
ci / ci (macos-latest) (push) Has been cancelled
ci / ci (ubuntu-latest) (push) Has been cancelled
ci / ci (windows-latest) (push) Has been cancelled
docs: specs and briefs for Tasks, Templater, Kanban and icons/banners
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-21 06:06:54 -03:00

10 KiB

Tasks: Kanban board note (roadmap item 13)

One task = one agent's work (OpenCode brief template, specs/agents/opencode-runbook.md). [ ] open. Spec: spec.md (D-numbers point into it). Rules for every task: AGENTS.md, docs/CODE-MAP.md.

First tool call rule: after at most three reads, your FIRST write is the first OWNS file: a compiling stub with the signatures from GOAL and ONE failing test. Then make it pass. Do not explore the repo.

Standing VERIFY: cargo test -p <pkg> ; cargo clippy -p <pkg> --all-targets -- -D warnings ; rustfmt --edition 2024 <owned files>. UI/i18n tasks add cargo xtask i18n; the last task of a phase adds cargo xtask layers and cargo xtask tree. Always export PATH="$HOME/.cargo/bin:$PATH". Standing DO NOT: edit Cargo.toml/Cargo.lock, files outside OWNS, git state, cargo fmt --all; add allow attributes; use unwrap/expect/panic/[i]/[a..b] on input-derived data; add a dependency.

Owner/lead step 0 (not an agent task)

  1. Create the empty crate crates/kanban (package notescraft-kanban, [lints] workspace = true, deps: notescraft-markdown, thiserror), register it in the root [workspace.dependencies] and in xtask/src/layers.rs at L1.
  2. Q1: save a board with the real Obsidian Kanban plugin (3 lanes, one Complete lane, archive one card, a card with a date, tag, link and a continuation line) and commit it as crates/kanban/tests/fixtures/real-board.md. Agents never invent this fixture.

Phase 1 - the pure crate notescraft-kanban (no I/O)

  • 1. Parse a board (brief briefs/11-kanban-parse.md). OWNS: crates/kanban/src/lib.rs, crates/kanban/src/error.rs, crates/kanban/src/model.rs, crates/kanban/src/parse.rs, crates/kanban/tests/parse.rs. FILES TO OPEN: spec.md D1 to D3, crates/kanban/tests/fixtures/real-board.md, crates/markdown/src/frontmatter/mod.rs (frontmatter end offset). GOAL: Board, Lane, Card, Error, pub fn parse(src: &str) -> Result<Board> with D2 limits; kanban-plugin frontmatter required (board or basic) else Error::NotABoard. TESTS: real-board fixture lanes/cards/complete/archive counts; extra paragraph between lanes lands in Lane.extra; multi-line card; block id; ## Title (5) max items; CRLF file; no kanban-plugin is NotABoard; 201 lanes refused. VERIFY: standing, -p notescraft-kanban. DO NOT: serialise (task 2).
  • 2. Serialise with byte fidelity. OWNS: crates/kanban/src/write.rs, crates/kanban/tests/roundtrip.rs, crates/kanban/src/lib.rs (one mod). FILES TO OPEN: spec.md D3, crates/kanban/src/parse.rs, crates/kanban/src/model.rs. GOAL: pub fn to_markdown(board: &Board) -> String. Needs Board to keep what is needed for fidelity (add private raw fields to Card/Lane such as the original list marker and original text; edit model.rs + parse.rs minimally for them). TESTS: real-board round trip byte-identical; generated boards (a seeded loop of 200 random boards built from a small grammar) satisfy parse(write(parse(x))) == parse(x); untouched card keeps its original marker (*) when another card changes; trailing text after the footer kept. VERIFY: standing. DO NOT: normalise anything that is not in the D3 list.
  • 3. Settings footer and card meta. OWNS: crates/kanban/src/settings.rs, crates/kanban/src/meta.rs, crates/kanban/tests/settings.rs, crates/kanban/tests/meta.rs, crates/kanban/src/lib.rs (two mod). FILES TO OPEN: spec.md D4 and D5, crates/markdown/src/scanning/scan.rs (all_tags) and the link scanner next to it. GOAL: Settings::from_board(&Board), Settings::set_list_collapse(&mut Board, &[bool]) (rewrites the footer only for known keys, unknown keys kept in order), card_meta(&Card, &Settings) -> Meta. TESTS: footer with unknown keys survives a list-collapse change in order; missing footer gets one created only on a settings write; @{2026-10-21} and @@{13:00}; custom trigger !; tags and [[links]] found; nested JSON values opaque. VERIFY: standing. DO NOT: add serde_json.
  • 4. Board operations. OWNS: crates/kanban/src/ops.rs, crates/kanban/tests/ops.rs, crates/kanban/src/lib.rs (mod, pub use). FILES TO OPEN: spec.md D6 table, crates/kanban/src/model.rs. GOAL: methods on Board: add_card(lane, text, Position), edit_card, move_card(from, to) (complete-lane check flips checked), toggle_card, archive_card (creates the archive on first use), delete_card, add_lane, rename_lane, move_lane, delete_lane, archive_lane_cards. All return Result<()> with Error::OutOfRange for bad indexes; no clamping. TESTS: each op; index just past the end is an error; move within a lane (down and up) gives the right order; move into a Complete lane sets [x]; archive creates *** + ## Archive; delete last lane leaves a valid board; byte diff of move_card by one touches exactly two list lines. VERIFY: standing + cargo xtask layers. DO NOT: do I/O.

Phase 2 - engine

  • 5. kanban.read / kanban.is_board / kanban.create and the write commands. OWNS: crates/engine/src/kanban/mod.rs, .../commands.rs, .../apply.rs, one mod kanban; in crates/engine/src/lib.rs, one register_kanban(reg) in crates/engine/src/commands.rs::register_core, crates/engine/src/ai/assistant_gate.rs, crates/engine/tests/core_commands.rs (CORE_IDS), crates/engine/tests/kanban.rs. FILES TO OPEN: spec.md D6, crates/engine/src/bases/commands.rs + write.rs (group to copy), crates/engine/src/vault/properties.rs (undoable buffer edit), crates/engine/src/vault/notes.rs (write_note), crates/index/src/props.rs (note_props for is_board). GOAL: D6 table; expect_hash guard (conflict); open buffer gets one undoable edit; is_board from the index property, read re-parses the text; board JSON uses card_meta. TESTS: kanban.rs on a TempVault: read the real fixture to golden JSON; move writes only two lines (byte compare); conflict on stale hash; open buffer one undo step; create writes a valid board that read accepts; read-only session refuses writes; a non-board note gives invalid_params. VERIFY: standing for notescraft-engine + --test kanban --test core_commands. DO NOT: touch the UI; write outside the vault.

Phase 3 - UI (lead wires the dispatch lines)

  • 6. Board view shell: lanes, cards, read-only rendering. OWNS: crates/ui-egui/src/views/kanban_view/mod.rs, .../state.rs, .../lane.rs, .../card.rs, crates/ui-egui/src/text/views/kanban/mod.rs, new [ui.kanban] table at the END of crates/i18n/locales/en.toml, crates/ui-egui/assets/icons/kanban.svg, crates/ui-egui/src/design/icons.rs (one icon!("kanban")), crates/ui-egui/tests/kanban_view.rs. FILES TO OPEN: crates/ui-egui/src/views/base_view/state.rs, crates/ui-egui/src/views/base_view/table/grid.rs, .claude/skills/notescraft-egui-screen/, crates/ui-egui/src/views/note_view/blocks/inlines.rs (inline Markdown painting to reuse for card text). GOAL: D7 layout and visuals: lanes as floating cards, 280 px width, horizontal scroll, inline Markdown card text, tag/date chips, collapsed lanes, "Open as Markdown" header button. TESTS: kittest on the fixture vault: lanes and cards visible, a collapsed lane hides cards, a complete card shows the check, header button toggles. VERIFY: standing + cargo xtask i18n + cargo xtask tree; snapshot PNG at 1440x900 read and compared to the plugin screenshot description. DO NOT: hardcode strings; use raw egui buttons where a widget exists.
  • 7. Editing: add, edit, toggle, archive, delete cards; lane menu. OWNS: crates/ui-egui/src/views/kanban_view/add.rs, .../edit.rs, .../lane_menu.rs, crates/ui-egui/tests/kanban_edit.rs, crates/ui-egui/src/text/views/kanban/mod.rs (append keys). FILES TO OPEN: crates/ui-egui/src/widgets/context_menu.rs, crates/ui-egui/src/views/base_view/menus/ (menu pattern), ConfirmModal usage in crates/ui-egui/src/views/trash_view/. GOAL: inline Textarea add/edit, Cmd+Enter save, Esc cancel, checkbox toggle, lane menu (rename, move, archive cards, delete with confirm, collapse writes list-collapse). Each action = one engine call with expect_hash; on conflict reload and show a toast. TESTS: add a card then undo in the editor restores; edit commits on Cmd+Enter; delete asks first; collapse persists to the footer. VERIFY: standing + i18n. DO NOT: mutate the board locally before the engine answers (render from the engine's answer).
  • 8. Drag and drop between and within lanes, keyboard moves. OWNS: crates/ui-egui/src/views/kanban_view/drag.rs, .../keys.rs, crates/ui-egui/tests/kanban_drag.rs. FILES TO OPEN: crates/ui-egui/src/panels/tree/ (existing drag source/target code), crates/ui-egui/src/views/base_view/table/selection.rs. GOAL: CardRef { lane, index } payload via egui::DragAndDrop, drop line indicator, drop on lane header appends, Alt+arrows move, arrow focus; a drop sends one kanban.card.move. TESTS: kittest drags a card to another lane (one engine call counted), within the same lane to index 0, Alt+Down moves one place, dropping on itself is a no-op (no call). VERIFY: standing + cargo xtask tree. DO NOT: send a move while still dragging.
  • 9. Note tab integration: open boards as boards, New board command, Explorer icon. OWNS: crates/ui-egui/src/shell/app/window/views.rs (the TabKind::Note arm only), crates/ui-egui/src/shell/app/window/commands.rs (palette command "Kanban: New board"), crates/ui-egui/src/panels/tree/rows.rs (board icon on rows, only if Q3 is yes), crates/ui-egui/tests/kanban_open.rs. FILES TO OPEN: crates/ui-egui/src/shell/app/window/views.rs:229 (dispatch), crates/ui-egui/src/widgets/tabs/kind.rs, docs/CODE-MAP.md. GOAL: a note with kanban.is_board true renders kanban_view unless the tab has "open as markdown"; palette "Kanban: New board" runs kanban.create and opens it; cache is_board per path and index generation. TESTS: opening a board note shows lanes; "Open as Markdown" shows the editor; a normal note is untouched; creating a board opens it. VERIFY: standing + i18n. DO NOT: parse the file in the UI.
  • 10. Docs and status. OWNS: ROADMAP.md, docs/ARCHITECTURE.md, docs/CODE-MAP.md (kanban rows), specs/plugins-parity/roadmap.md (mark 13). GOAL: crate row, command list, status numbers. VERIFY: cargo xtask ci. DO NOT: edit code.