The tombstone model is retired wholesale: deletion is a move into the reserved <root>/.trash/, always entering at the top (rank minting — no deleted: key, no timestamp sort), with modified stamped for the future age-based purge. Lanes are never trashed — lane delete is physical, native undo in-session the net. Put Back is gone: restore is drag-out or cut+paste (⌘X now enabled in the trash as the keyboard restore path). Trash cards are ordinary cards — search, selection, clipboard, and rendering uniform — and one container boundary replaces the effective-liveness, ancestor-walk, and kind-homogeneity machinery across 02 and 04. Delete stages by place (board moves, trash deletes permanently under the recoverability confirm); legacy deleted: keys migrate without destroying (cards relocate, lanes return live, notices). Templates exclude .trash; Duplicate carries it; the agent guide teaches delete-as-move. Materialized reserved lanes are named as a pattern — .archive is WISHLIST #8, and the backed-out release-presentation question is marked open in 03. Ruling: Redesign board Resolved card e8f1a6c2; 19 mooted tombstone-era rulings moved to the board's new Mooted lane. Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
17 KiB
Card Window
The standalone per-card window. Opened by fast double-click, ⌘↩, or the context menu; at most one window per card (reopening a live card focuses the existing window); board and card windows share one live store, so edits reflect everywhere instantly (02-architecture.md).
Status: designed — composition, body column, and the attributes sidebar are all settled. The storage-facing rules the pathfinder settled painfully — Preview/Edit over WYSIWYG, the untouched-body byte-identical guarantee, validate-before-write on the raw outlet, dirty-buffer-wins — carry over unchanged.
Composition
Two full-height columns: a wide body column (leading) and a narrow attributes sidebar (trailing), each scrolling independently. Visual reference: assets/card-sidebar-reference.png — a GitLab-style issue pane; its pattern (stacked small-caps sections, quiet read-first rows, actions at the bottom) is what carries over, not its enhanced-schema content.
- Body column, top to bottom: the title field — large, borderless; edits write through to frontmatter on commit (Return or focus loss); clearing it removes the
titlekey (titles are optional — the untitled placeholder shows here as on the face); Return commits and moves focus into the body. Escape abandons (settled — the board inline rename's abandon, applied here): the field reverts to the on-disk title and focus moves into the body, never a commit. The Edit-mode collision resolves by focus, 06-history-undo.md's first-responder rule: while the title field is focused, Escape is the title abandon even with the body in Edit; with the body editor focused, Escape is the Edit→Preview flip as specified. Beneath it, a quiet created/modified line ("Created ⟨date⟩ · Modified ⟨date⟩ · by ⟨modified-by⟩", secondary styling, omitting whichever keys are absent — the "by" segment renders only when the self-reported provenance stamp is present, 01-storage-format.md; this is provenance made visible where git history may not exist) — the read-only readout the pathfinder dropped with its inspector, back where the mockup puts it. Then the body (Preview/Edit, below). - Attributes sidebar: everything about the card that isn't the body — sections below. Fixed narrow width derived from font metrics (full relative scaling, 10-accessibility.md); the window's resize flex goes to the body.
(The pathfinder's compositions are both gone: the metadata bar — labels, assignees, due — left with those fields' move to the enhanced schema, and the horizontal attachments strip dissolves into the sidebar.)
Body: Preview / Edit — not WYSIWYG
Settled the hard way in the pathfinder (WYSIWYG built, then reversed): the body is read/write raw Markdown with a fully rendered preview. TextEditor can't lay out tables, so rendered-reading + raw-editing is the honest, lossless pairing for a file-backed app.
Mode grammar
- Preview is the resting state: a card opens in Preview — unless its body is empty, which opens straight into Edit with the cursor ready (a new card has nothing to preview, so ⌘↩ during creation flows title → body without a mode stop).
- ⌘E toggles (View ▸ Edit Body, checkmark state — 11-command-nexus.md). Return in Preview also enters Edit — the board's edit key applied to the body; fixed grammar like the board's Return, not a menu item. Escape in Edit returns to Preview.
- Clicking never edits (the same pivot as the board's click grammar, 04-interactions.md): clicking the rendered body selects text — Preview is selectable and copyable — and nothing else. The one interactive exception is task-list checkboxes, below.
- Leaving Edit flushes the debounce (mode flip, raw-source entry, window close) — the preview never lags the text that produced it, and neither does disk.
Preview
- Renders headings, bold/italic/code, bullet/ordered/task lists, fenced + indented code, nested quotes, GFM tables (per-column alignment, columns sized to contents with the browser sizing rule), thematic breaks, HTML shown verbatim as literal code-styled text (never interpreted — no web view, per 00-vision.md's no-web-tech stance), and images resolved against the card's own folder (
). - Remote images are never fetched — Preview does no networking (sandbox-quiet, files-first). An
renders as a quiet placeholder chip carrying the alt text (or the URL); the file-relative form above is the supported image story. - Task-list checkboxes are live: clicking a
- [ ]/- [x]checkbox flips exactly that marker in the source — a single-character textual edit; every other byte of the body is untouched. This is the deliberate exception to "Preview only reads": checklists are kanban's working currency, and a mode flip to tick a box is ceremony. A toggle is an ordinary user edit — the standard atomic write, auto-committed and undoable on git boards. The pointer-free path is the system focus model (settled): checkboxes — like Preview's links — are real controls in the keyboard-focus and accessibility tree, so Full Keyboard Access Tab-reaches them and Space toggles, and VoiceOver toggles with VO-Space (10-accessibility.md's real-accessible-checkboxes promise, honored natively). Without FKA they are not in the key loop — standard macOS content behavior, so ordinary Tab users never wade through a long checklist. In-content controls are content, not commands: no menu item, no chord — 04's every-function-has-a-menu-item contract covers commands, and 11-command-nexus.md scopes them accordingly. Under the read-only lock (02-architecture.md) the controls disable in place — an in-content mutation menu validation can't reach (and not the only such path: the attachment row's ⌫/Remove shares the posture — 02's every-entry-point predicate). - Links: external URLs open in the browser; relative links open the target file with its default app (resolved against the card folder, like images).
- Edit ▸ Find (⌘F) is find-in-text here — the standard find bar over the focused body surface (Preview's selectable text, the Edit editor, raw source); board search is a board-window concern (04-interactions.md ▸ Search).
Edit
- A monospaced editor with lightweight Markdown syntax highlighting — headings emphasized, bold/italic rendered as such, code tinted, link targets and structural markers dimmed. Highlighting is presentation only: the text is the raw Markdown, character for character — no hidden transforms, no smart substitutions.
- Saved on a ~700 ms debounce; flushed on leaving Edit, entering source mode, and window close.
- ⌘Z here is the text view's own undo — session-scoped, ending when the editor loses focus or the mode flips; it works on every board, git or not. Board-level undo routing: 06-history-undo.md ▸ Undo routing; commit granularity (one commit per Edit session — the Edit→Preview flip is the effective Save button; never per save tick): 06 ▸ Rules ▸ Auto-commit.
Write rules (settled, storage-facing)
- An untouched body is never rewritten — plain string comparison, so it stays byte-identical on disk. Three-gate write: untouched → never re-serialized; reverted → not written; echo of an external edit → not written back.
- Concurrent external edits — dirty buffer wins. A dirty Edit buffer is never reloaded under the cursor: while the user has unsaved keystrokes, watcher reloads update everything else (board, Preview, other windows) but leave the buffer alone; the debounced save then writes it — deliberate last-writer-wins, the same no-merge-UI philosophy as sync (07-sync-collab.md). A clean buffer follows disk. On git boards, flush-before-overwrite (06-history-undo.md) guarantees the overwritten external version was committed first — one revert away; on no-git and repo-nested boards it is lost — the app manages no git there, so flush-before-overwrite never runs (07's accepted caveat).
Raw source outlet
A toggle (View ▸ Raw Source, ⌥⌘E — 11-command-nexus.md) swaps the entire content area — title, body, and sidebar — for the literal on-disk index.md (frontmatter and all) in a monospaced editor with Cancel/Apply: the same frontmatter is being edited as raw text, so interactive controls over it would fight the raw edit. Entering source mode flushes any pending title/body edits first, then reads the file fresh from disk. Apply validates through the same fail-fast parse the loader uses (detailed alert on error, stays in source mode) before writing byte-for-byte (including a modified-by stamp the user typed or kept — Apply is the one app write that doesn't clear it, 01-storage-format.md); the watcher reload then refreshes every window. Cancel (and window close) discards without ceremony. This is the escape hatch that keeps everything — unknown keys, exotic formatting — reachable in-app. A pull landing mid-session neither blocks on the open buffer nor invalidates it (07-sync-collab.md — same-card signpost, Apply stays last-writer-wins); branch switch and undo restore instead settle it explicitly via save-or-discard (06-history-undo.md ▸ Branch switching).
Key grammar in source mode, completing the window's key story: Escape is Cancel, ⌘↩ is Apply, and toggling off via ⌥⌘E (menu or toolbar) is Apply too — leaving-by-toggle commits, mirroring leaving-Edit-flushes; a failed validation keeps source mode open (toggle stays checked) with the alert. Return just types — it's an editor. View ▸ Edit Body (⌘E) disables while source mode is active, matching its toolbar item.
The attributes sidebar
Stacked sections under small-caps headers, in this order; quiet rows, read-optimized, edit affordances only where a section edits. The sidebar is the card's non-body inventory — future attributes (enhanced-schema fields, if they ever ship) slot in as new sections rather than growing new bars.
Attachments
- Shows every top-level file of
attachments/— including files also embedded in the body (settled: the section is the card's complete file inventory, no reference-tracking magic; an image appearing in both places is honest, not a bug). Subfolders are tolerated but not surfaced (01-storage-format.md's attachments rules). - Compact rows: small QuickLook thumbnail (Finder-icon fallback) + middle-truncated filename, one row per file. The section header carries a quiet add affordance; empty, the section stays with a one-line hint (drop files, or File ▸ Add Attachment…, ⇧⌘A) — the drop surface remains the whole window (name collisions auto-rename, Finder-style — 01-storage-format.md). Drop precedence is split by payload (settled): file drops import as attachments anywhere in the window — Edit mode included, the text editor never intercepts a file drop; dragged text lands in the Edit editor at the caret within its bounds as ordinary insertion, and is inert elsewhere in the window.
- Row interactions: double-click or Return opens; context menu Open / Reveal in Finder / Remove (moves to the system Trash, never hard-deletes — 03-board-ui.md's naming constraint keeps this distinct from board deletion); rows drag out their file URL.
- Keyboard-native, new in the rewrite (the pathfinder's strip was pointer-only): the section is focusable; arrows move between rows, Space QuickLooks the selected row, Return opens it, ⌫ removes it (same system-Trash semantics).
Style
The card-level styling home: the embedded style editor — background palette grid (with the leading None well) and curated symbol grid, per 03-board-ui.md ▸ Styling ▸ Controls. Card styling is discoverable here without a context menu; the same component appears in the board popover and behind Style….
Details — unknown frontmatter keys
- Read-only key/value rows for every unknown frontmatter key, shown only when any exist, in file order (01-storage-format.md preserves key order verbatim — the sidebar honors it). This is the files-first payoff surfaced: an agent overlay (
project:,sphere:— 08-agent-integration.md) or any hand-added key is visible to the human without opening raw source. - Values render as plain text, leniently — exotic YAML shapes display best-effort, never error. Reserved enhanced-schema keys (
labels,assignees,due,remote, …) are ordinary unknown keys in this version and appear here like any other — no special rendering. - Editing is deliberately not offered: the raw source outlet is the write path for frontmatter the app doesn't own.
History (git boards only)
- The card's commit trail, read-only (settled): every commit that touched this card's folder, newest first — semantic subject, relative date, author. The trail is where the commit-message and attribution machinery (06-history-undo.md) pays off for humans: "Move card 'X' to Doing — 2 days ago — Claude" reads as a story, agent and hand edits included (foreign authorship and
modified-byrefinement render as the author). - The listing follows the card across lane moves (path changes; the UUID folder is the identity to track). A cross-board arrival starts fresh — not because identity changes (a move keeps its UUID; the import boundary remints only on collision — 01-storage-format.md) but because the destination board's repo has no commits for the arriving folder; the old board keeps the old trail either way.
- The section is absent on boards without app-managed git (mode none, repo-nested) — same honesty rule as the popover's git section (06-history-undo.md). Rows are focusable (arrows), but carry no actions in v1 — restoring an old version stays a git-client task for now; a per-row forward-restore and lane history are wishlist items, deliberately.
- Menu path (contract): View ▸ History in the card window focuses the section — no default chord.
Actions (bottom)
- Delete — moves the card to the trash (destructive styling; the window then dismisses itself per Deletion & lifecycle below; recoverable from the board's trash lane — 03-board-ui.md).
- Reveal in Finder — the card's folder.
Window
- The subtitle shows the card's place: "⟨board⟩ › ⟨lane⟩" under the window title, live-updating as the card moves (the window follows its card).
- New windows open at the last-used card-window size, cascaded; frames restore per card across relaunch where state restoration allows.
- Toolbar (settled — 03-board-ui.md ▸ Toolbar): default set Edit Body (single toggle, on-state in Edit) · Raw Source (toggle; while active, Edit Body disables) · Add Attachment; user-customizable like the board window's.
Deletion & lifecycle
- The window follows its card across lanes (keyed by board URL + GUID) — within its board. A cross-board move dismisses the window like a delete: the card left this board — its UUID travels with the move (reminted only on an import-boundary collision, 01-storage-format.md's identity lifecycle), but the window's key is board URL + GUID, and the board half no longer names it.
- Window dismisses itself if the card is deleted — and entering the trash counts as deleted (resettled 2026-07-28, the materialized trash): ⌫ on the board closes the card's open window (the card left the working set; restore and reopen if it was a slip), an external move into
.trash/observed by reload does the same, and deleting the card's lane deletes the card with it — the window dismisses because the card is gone. Restoring reopens nothing — reopening is the user's act, like any open. Dismissal never eats typed work silently where a save can land (settled): a dirty Edit buffer flushes into the card's folder at its new.trash/location before the window dismisses — a surgical body write, so the keystrokes survive a later restore and enter history on git boards (the composer reads it as an edit to a trashed card — accurate). An open raw-source buffer discards instead: its Apply would write a whole staleindex.mdover the trashed card — a delete is never fought by a stale buffer. A card whose lane was deleted discards both — nowhere left to write. A card hard-deleted externally (folder gone) discards both — nowhere left to write, the inline-rename rule. Cards in the shown trash lane don't open at all — restore first (03-board-ui.md). Reopening a live card focuses the existing window.
Changes from Kanban
- Two-column composition replaces the pathfinder's vertical title/strip/body stack: body column (title atop it, created/modified line beneath) plus a full-height attributes sidebar.
- The sidebar revives the dropped readouts: created/modified return under the title; unknown frontmatter keys get the read-only Details section (the pathfinder's inspector casualties, rehomed).
- Empty body opens in Edit; Return in Preview enters Edit; Escape returns to Preview (the pathfinder always opened in Preview, toggle-only).
- Live task-list checkboxes in Preview — the pathfinder's preview was fully inert.
- Syntax-highlighted editor — the pathfinder used a plain monospaced
TextEditor. - Keyboard-navigable attachments with Space-QuickLook — the strip was pointer-only.
- The window gains a live board › lane subtitle.
Open questions
None currently — the embedded-attachment duplication question is closed (the sidebar shows every file), and the click-grammar pivot is recorded in 04-interactions.md.