# Lanework A native macOS kanban app whose boards are plain folders and Markdown files. Every board, lane, and card is a folder with an `index.md` (YAML frontmatter + Markdown body); the filesystem is the source of truth and the app is a live view over it. The defining consequence: anything that can read and write files is a first-class user of a board — text editors, Finder, shell scripts, git, and above all AI agents. Lanework's job is to be the best *human* surface over that substrate. ## Key features Lanework is in early development. This list tracks what has actually shipped and grows milestone by milestone; the full design lives in [DESIGN/](DESIGN/). - **Storage contract, read side** — frontmatter engine with a byte-perfect round-trip guarantee (unknown keys, comments, and formatting survive every rewrite; duplicate keys read last-wins; wrong-type scalars coerce read-side), gapped fractional ordering (Ranks), and a fail-fast board loader with UUID-gated level detection, warning-collecting skips, and tombstone-aware snapshots — pinned by a golden fixture suite of 18 on-disk boards. - **Storage contract, write side** — BoardWriter turns every mutation into an atomic temp-file+rename over exactly the files it touches: creates mint lowercase-UUIDv4 identities and `.kanban` packages; moves keep the UUID (with per-folder collision repair at the cross-board import boundary); copies mint fresh identities at every level; deletes are in-place tombstones with position-perfect restore and physical purge; attachment imports never overwrite and never refuse (Finder-style renames). Every app write stamps `modified`, clears `modified-by`, and preserves everything it didn't change byte-for-byte; readable-but-uneditable frontmatter shapes refuse loudly instead of corrupting. - **Live store** — every open board is one shared, watched, in-memory snapshot: an FSEvents folder watcher (debounced, `.git`-filtered, origin-reconciling) drives whole-tree reloads with a generation guard and single-flight coalescing; write brackets suppress self-echo; a file-identity-keyed store registry refcounts stores and watchers across windows and absorbs root renames via bookmark re-resolution (a vanished root locks the board and watches for its return); plus the board registry (recents, bookmarks, cached counts), the banner center's single precedence order, the dirty-buffer guard, and transient UI state. - **Window architecture** — the three window types and their lifecycle: a welcome window (branding, failed-open reporting), one board window per root (per-board frame memory, repositioned onto a live screen), and at-most-one card window per card (last-used size, cascaded; follows its card across lanes; dismisses on delete, tombstone, or cross-board move). Closing a board window or quitting runs one strict close flush — card sessions end, pending work drains, the registry is stamped — before the store tears down; launch restores the boards whose open-now flags survived quit (or crash), a preference gating only whether the flags are consulted. - **The board** — every lane always on screen, the window's width dividing across the lanes' width units with no horizontal scroll: cards flow into as many interior masonry columns as a lane is wide, a right-edge drag resizes between whole units by growing the *window* (snapping at the gap with release hysteresis, hard-stopping at the screen with rubber-band feedback), and ⌥⌘→/⌥⌘← re-divide the existing width instead. Lane chrome is a per-lane SF Symbol (unknown names fall back leniently), title or untitled placeholder, a card-count badge that counts exactly what's rendered, and a new-card button — the whole title bar doubling as the reorder drag surface, a plain click selecting the lane and movement carrying it above its siblings while they show the would-be order. - **Card faces** — a card reads as a leading SF Symbol, its title (or a quiet untitled placeholder), and a quiet paperclip when it has attachments — title-only by design, no body excerpt. Colour is an edge accent rather than a fill: `background` paints a stripe down the card's left edge and `iconColor` tints the symbol, both written as a kebab-case palette name (12 icon tints, 12 backgrounds) or a `#RRGGBB[AA]` hex. Everything degrades rather than complains — an unreadable colour simply doesn't paint, and the value stays on disk exactly as written. Each card's snapshot carries its attachment names, listed flat and in Finder order (top-level files only; subfolders, hidden files, and symlinks are preserved but never surfaced). - **Creating and renaming** — New Card (⌘N) files into the selected card's lane immediately after it, a selected lane's bottom, or the last-active lane, opening a focused pseudo-card that exists nowhere on disk until its title commits (Return commits and re-selects the lane, ⌘↩ also opens the card window, Escape or clicking away discards, and a failed create discards rather than waiting for a card that can't arrive). Inline rename — Return on a card, Board ▸ Rename for either kind — tracks its target by UUID, so a foreign move mid-edit is invisible and a tombstone or deletion discards the edit silently; committing empty removes the `title` key rather than writing a blank one. New Lane is ⇧⌘N. Every mutating command disables while an editor holds the keyboard and under the read-only lock. - **Styling** — one style editor serves every anchor: a background grid of the twelve palette wells behind a leading None well that *removes* the key, and a curated grid of five dozen kanban-relevant SF Symbols behind a leading level-default well that does the same. It is selection-aware (the selected cards or lanes; the board with nothing selected) and states the current value per dimension across the whole target set — agreement selects a well, disagreement reads "—", and a hand-written hex or uncurated symbol states itself verbatim outside the grids, replaced by any well you choose. A batch applies as one bracketed commit that skips every target already carrying the value, and the open editor tracks its targets live: one deleted out from under it leaves the set, and the last one closes the editor rather than quietly retargeting the board. Reached from Board ▸ Style… (⌥⌘S) or a card's or lane's context menu, where a compact row of app-wide recent colours recolours in one click and a lane's menu also carries its width stepper. Colour renders at all three levels — a card's `background` as a left-edge stripe, a lane's as a full-width band along its top edge, the board's as the window's content background — each painting nothing at all when the value doesn't resolve, bytes on disk untouched. ## Development The Xcode project is generated — `project.yml` is the source of truth, not the `.xcodeproj`: ```sh xcodegen generate xcodebuild build -project Kanban.xcodeproj -scheme Kanban -destination 'platform=macOS' xcodebuild test -project Kanban.xcodeproj -scheme Kanban -destination 'platform=macOS,arch=arm64' ``` macOS 26+, Swift 6 (strict concurrency), SwiftUI, sandboxed. Internal codename `Kanban` (target, scheme, bundle id `dev.rzen.indie.Kanban`); the app ships under the display name **Lanework**.