Resolves the 09-vs-03 contradiction: the principle is never-init- unasked, scoped to template instantiation; File ▸ Duplicate carries .git deliberately as a history fork. Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
8.2 KiB
Board Templates
Status: settled. The template inventory is settled (inherit all ten from the pathfinder, more to come); the definition format and the storage story below are signed off.
Inventory (settled)
All ten pathfinder templates carry over: Basic, Classic Kanban, Software Project, Content Pipeline, Job Hunt, Sales Pipeline, Weekly Planner, Roadmap, Event Planning, Bug Tracker — each with its existing lane titles, icons, palette icon colors, board icon, and blurb. Basic stays first and remains the plain To Do / Done scaffold. The set is expected to grow.
Definition format (settled)
A template is itself a board. Each template is a schema-valid board folder bundled in the app's resources — the same fractal folder + index.md structure, loadable by the same BoardLoader, validated by the same rules:
<app bundle>/Templates/
├── basic.kanban/
│ ├── index.md ← title: Basic; template: {order: 100}; body = picker blurb
│ ├── 3f2a9c41-…/index.md ← lane "To Do" (order: 1024)
│ └── 8d3b1f22-…/index.md ← lane "Done" (order: 2048)
├── classic-kanban.kanban/
│ └── …
- The template board's
index.mdcarries the picker metadata in its ordinary frontmatter:title= display name,icon/iconColor= the board icon shown in the picker and inherited by the new board, and the body = the blurb (shown in the picker and becoming the new board's description, as in the pathfinder). - One picker key:
template:— a mapping holding picker concerns;order(display position in the chooser) is its only subkey (settled — future subkeys possible). Carried onto instantiated boards, where it is ignored and preserved like any unknown key; specified in the core schema's board table (01-storage-format.md). - The bundle folder name (
basic.kanban) is the template's stable slug (tests, a11y ids). - Lane folders are ordinary GUID folders with ordinary
order/icon/iconColorfrontmatter. Templates may contain starter cards — a capability the Swift-struct format never had (e.g. a "How this board works" card).
Instantiation
Creating a board from a template: copy the tree — skipping tombstoned items (Save as Template already strips them, but hand-dropped user templates can carry them; a new board isn't born with trash) — mint fresh GUIDs for every lane/card folder, stamp created/modified fresh (the stated exception to 01-storage-format.md's copies-keep-created rule — a new board is born today, not forked from the template), seed the save panel's suggested name from the template title, and set the new board's title to the user-chosen document name (per 01-storage-format.md's board-naming rule, so display name and folder name start out matching). The template: key is kept — inert on an ordinary board. .git is never copied — a template is content, not history, and a hand-dropped user template that carries one must not produce boards that are silently in git mode (06-history-undo.md's no-silent-auto-init — the principle is never give the user a repo they didn't ask for, and it scopes to instantiation: File ▸ Duplicate deliberately carries .git, because a duplicate of a git board is a fork of its history — 03-board-ui.md): every instantiated board starts at mode none. Beyond the template: residue, the result is indistinguishable from a hand-built board.
Why this format
- Dogfood: the template format is the board format — no second schema, no parallel Swift model to keep in sync. The picker's mini per-lane preview renders from a real
BoardModelvia the normal loader. One bad template never fails the chooser (the user store is hand-editable, so a malformed board there is one edit away): a user template the loader rejects is still listed — by folder name, marked unloadable, carrying the loader's fail-fast specifics — but can't be instantiated or previewed; fix the files and it comes back. The same honest-surfacing posture as 02-architecture.md's welcome recents, which don't pre-detect broken boards either. - Authorable: adding a template = adding a folder (a human, or an agent, can author one without touching Swift); a template diff in review shows real frontmatter, not struct literals.
- Testable for free: template validity is enforced by the loader's own fail-fast rules at test time (walk
Templates/, load each). - Opens the door to user-defined templates — see Save as Template below.
Save as Template
A "Save as Template" function copies the current board into the user templates store; the chooser lists user templates after the bundled ones. The copy is preceded by the close flush (02-architecture.md ▸ Windows: editor saves, then the pending auto-commit — with the pull-style mechanical exception committing an open Edit session's on-disk saves as-is, sessions staying open), so the template never misses the last keystrokes; the same rule covers File ▸ Duplicate (03-board-ui.md), where the flush also keeps the copied .git's history from lagging its tree. Because a template is a board, the copy is nearly literal: .git is not copied (a template is content, not history — copying it would embed the board's full repo, every attachment version included, in the template store; see 06-history-undo.md's repo-growth note), tombstoned items are dropped, a template: key is added — or, when the board already carries one (e.g. it was itself instantiated from a template), its stale order is overwritten — with an order appended after existing user templates; GUIDs are left as-is (instantiation mints fresh ones anyway), and timestamps are kept per 01-storage-format.md's copies-keep-created rule (equally inert — instantiation restamps them).
Two edges, settled:
- Store collisions auto-rename, Finder-style (
Board.kanban→Board 2.kanban) — the 01 import precedent: saving never overwrites an existing template and never refuses. - Strays copy through. The copy is literal apart from the stated exclusions (
.git, tombstoned items) —CLAUDE.user.md, a seeded.gitignore, and other non-schema files carry through Save as Template and instantiation alike. Deliberate: a template is the folder, andCLAUDE.user.mdcarrying a board's custom agent instructions into boards born from it is a feature. The app-ownedCLAUDE.mdcopies inertly and self-heals to the current guide version when the new board is opened (08-agent-integration.md).
Storage (settled): Application Support (…/Lanework/Templates/, inside the app container) as the canonical store — friction-free sandbox writes, no location ceremony — kept honest by a Reveal in Finder affordance in the template chooser: revealed, it's plain board folders, hand-editable and agent-writable, and a board folder dropped in becomes a template — no template: key required. Chooser order: bundled templates by template.order, then keyed user templates by template.order, then keyless user boards last, sorted by display name (title ?? folder name — 01-storage-format.md's board naming). The app never stamps a key into store files it didn't write itself — a hand-dropped board is never touched, and adding a key by hand is how its user picks a position; the one writer of keyed files is Save as Template, whose own copies arrive keyed (above). A user-visible or user-configurable location was considered and set aside as ceremony disproportionate to a secondary feature; revisit if template sharing becomes a real workflow.
Rejected alternative
Keeping the Swift-struct catalog (pathfinder approach). Simpler to ship, but it's a second definition of "a board" that must track schema changes by hand, can't hold starter cards naturally, and forecloses non-programmer template authoring.
Settled
- No dialect, one schema: bundled (and user) templates use GUID folder names like any board — no relaxed template-only format.
Open questions
None currently — the storage location is settled (Application Support as the canonical store, kept honest by Reveal in Finder; a user-visible or configurable location was set aside as ceremony, revisit if template sharing becomes a real workflow).