# 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.md` carries 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`/`iconColor` frontmatter. 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 `.trash/`** (Save as Template already strips it, but hand-dropped user templates can carry one; 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): an instantiated board is never in *git* mode — its actual mode follows 06's nearest-`.git`-wins detection at the destination the save panel chose: mode `none` in a plain folder, repo-nested when saved inside an existing repository (no app-managed git, no add-git — the popover explains; native undo still serves, 06-history-undo.md). 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 `BoardModel` via 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. Under the read-only lock, Save as Template disables with one exception — the unwritable-location state, where it stays live unless an open Edit or raw-source session holds unsaved content the suspended saves can't flush (reads the board, writes the app-side store; 02-architecture.md ▸ Live-reload resilience has the settled scoping). 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), `.trash/` is 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`, `.trash/`) — `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, and `CLAUDE.user.md` carrying a board's custom agent instructions into boards born from it is a feature. The app-owned `CLAUDE.md` copies inertly and self-heals to the current guide version when the new board is opened (08-agent-integration.md).

**Storage (re-homed 2026-07-30 with the one-app collapse): the app's Application Support container** (`…/Application Support/<bundle id>/Templates/`, beside the registry per 02-architecture.md ▸ Per-board app state's app-wide-state rule) as the canonical store — friction-free sandbox writes, no location ceremony. Templates are plain board folders — no bookmark grant ceremony, the container is the app's own. 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). An unloadable user template sorts with the keyless tier, by folder name — the failed load can supply neither `template.order` nor `title`, so the folder name is the only identity it has (and the one its unloadable row already shows). 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 (the app's Application Support container as the canonical store, re-homed 2026-07-30 with the one-app collapse; 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).
