Root cause of the owner's repro (board window frontmost, File ▸ Print… enabled, chosen from the menu, alert appears anyway): Kanban.entitlements carried no com.apple.security.print key. The app is sandboxed, and a sandboxed NSPrintOperation is denied by the sandbox with exactly this wording — "This application does not support printing. Please contact the application's developer." — regardless of which code path invokes it. Fix: add the entitlement. Alongside it, hardening for a separate, narrower failure mode that happens to produce the identical alert text by a different mechanism: PrintCommand used to disable itself over a window that published neither a board nor a printable card (welcome, the template chooser, Settings, the restore-bootstrap window, a card window whose board hasn't joined). A disabled SwiftUI Button still owns its .keyboardShortcut, so the unclaimed ⌘P chord fell through to AppKit's own nil-target printDocument: action, whose stock failure is the same system alert. The row now claims ⌘P unconditionally in every window; scope resolves at the moment of the action instead (board, then card, then a polite "Nothing to Print" / "Open a board or a card to print it." refusal in the app's own voice). The boolean isEnabled(hasBoard: hasPrintableCard:) becomes a three-way PrintCommand.resolveScope(...) -> Scope pure function. Also implements AppDelegate's application(_:printFiles:withSettings: showPrintPanels:) — Finder's own File ▸ Print… / drag-to-printer / print-and-open path was previously unhandled, its own separate route to the same stock alert. PrintCoordinator.printFiles loads each path headless through BoardLoader (no store, no window) and either prints it or gives the same one-sentence refusal; the operation-building code shared with the in-app path is factored out of run(_:) into makeOperation(for:showsPrintPanel:) and runOperation(_:session:). Docs: 11-command-nexus.md's Print row, PrintCommand's and PrintCoordinator's doc comments, KanbanApp.swift's CommandGroup comment, and project.yml's entitlements comment all narrate the entitlement as the actual fix and the scope work as hardening beside it. Tests: PrintCommandValidationTests now exercises resolveScope's three arms in place of the old boolean. A new PrintFinderResolutionTests suite covers PrintCoordinator.resolveFinderPrint(atPath:) — the one piece of the Finder half a test can drive without handing AppKit a real print job — against a real board, an empty non-board folder, a plain file, and an unsupported schema. Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
Lanework — Design Documents
A ground-up rewrite of the Kanban app, to ship as Lanework on the Mac App Store. The old repo (../../Kanban, one level above this repository — not the rewrite's own Kanban/ source folder, which shares the codename) was a pathfinder — it never shipped, but it is the reference implementation and the source of hard-won decisions. This design starts from a clean slate and keeps only what earned its place. The rewrite keeps the internal codename Kanban (bundle id dev.rzen.indie.Kanban).
Each document covers one aspect of the design. Within each:
- Decisions — settled, either carried over from the old app or newly made.
- Changes from Kanban — where this rewrite deliberately diverges.
- Open questions — flagged for iteration; nothing here is implicitly settled.
Index
| Doc | Aspect |
|---|---|
| 00-vision.md | What Lanework is, who it's for, goals and non-goals |
| 01-storage-format.md | On-disk contract: folders, frontmatter, ordering, the materialized trash |
| 02-architecture.md | App structure: source of truth, stores, watchers, concurrency |
| 03-board-ui.md | Board window: layout, lanes, cards, styling, templates |
| 04-interactions.md | Selection, drag & drop, keyboard, clipboard, search |
| 05-card-window.md | The card window: Markdown preview/edit, attachments |
| 06-history-undo.md | Git-backed undo/redo and history — retired 2026-08-08 (git excised, strategy/01-git-excision.md; Undo routing migrated to 13) |
| 07-sync-collab.md | Board modes and git-rails sync — retired 2026-08-08 as written; successor: the ops-based sync service workstream |
| 08-agent-integration.md | AI agents as first-class users of the board |
| 09-templates.md | Board templates: inventory and definition format |
| 10-accessibility.md | VoiceOver, text scaling, visual accommodations |
| 11-command-nexus.md | The command Nexus — every command and action: bindings, contexts, customizability |
| 12-editions.md | The tiers — mooted 2026-08-08: one version, everything free, tier machinery excised; Pro returns with the iPhone/sync era as a fresh pass (the doc is record: entitlement mechanics, distribution, the git rows) |
| 13-native-undo.md | macOS-native undo/redo — the history substrate (sole since 2026-08-08); owns Undo routing |
| 14-git-operations.md | Extracted pathfinder git-operations conclusions — retired 2026-08-08 (superseded record) |
Deferred design iterations
The card window (05-card-window.md), toolbar (03-board-ui.md ▸ Toolbar), styling controls (03-board-ui.md ▸ Styling ▸ Controls), and comments (01 ▸ Enhanced schema + 05 ▸ The comments column — designed 2026-07-29, shipping post-2.0) each had their focused pass and are settled.
The authoritative list of open design passes is the findings board (Lanework Redesign.kanban ▸ Issues to Resolve) — this section stopped enumerating by hand after drifting twice. Standing examples as of 2026-07-29: the attachment-undo staging design and the EchoLedger foreign-undo bridge (both flagged in 13-native-undo.md), Teams' tracker integration (no design yet), the fail-fast decision surface (01 ▸ Refuse), and the drop-release settle presentation (03 ▸ Motion — deliberately last in line).
Wishlist
Ideas worth keeping but outside the committed design live in ../WISHLIST.md.
Terminology
The rewrite adopts lane as the canonical term for what the old app called a column (it's in the name: Lane-work). "Column" survives only when referring to the old app or to interior card-grid columns inside a wide lane.