@lovek4d/kickflip 0.10.0 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CONTEXT.md CHANGED
@@ -387,11 +387,11 @@ The repo's reviewed, executable `.kickflip/build`, or `.kickflip/build-<target>`
387
387
  _Avoid_: install script, session install runner
388
388
 
389
389
  **Serve**:
390
- The workflow button after the **action button** for a website work card with a build script, last but for **Implement**, while Auto serve is off and the card's branch has changes ([only the owner or Auto serve starts a card run](docs/adr/2026-11-02-1806-only-the-owner-or-auto-build-starts-a-card-run.md)). It confirms before the hub runs the script. Its one badge reads "Serving…", "Visit ↗", "Visit (stale) ↗" or "Serve failed ↗". A served card opens at `https://<host>:<port>/`, with a port from 8500–8599 kept through re-serves. A loopback relay tracks visits; 30 idle minutes stops the card and releases its port. Main has a fixed port recorded per board, keeps its link across merges and restarts and never idles out. Its red Serve failed button opens the same log and Retry sheet as an app’s, reading Serving… in orange while retrying the recorded failed tip, even if origin has moved. Both open the server itself, outside the app shell ([a try build serves on its own Tailscale port](docs/adr/2026-11-01-2254-a-try-build-serves-on-its-own-tailscale-port.md)).
390
+ The workflow button after the **action button** for a website work card with a build script, last but for **Implement**, while Auto serve is off and the card's branch has changes ([only the owner or Auto serve starts a card run](docs/adr/2026-11-02-1806-only-the-owner-or-auto-build-starts-a-card-run.md)). It confirms before the hub runs the script. Its one badge reads "Serving…", "Visit ↗", "Visit (stale) ↗" or "Serve failed ↗". A served card opens at `https://<host>:<port>/`, with a port from 8500–8599 kept through re-serves. A card's serve stays up while its card is open and its worktree is there: Done, merged, dropped or a removed worktree stops it, a hub restart serves it again, and one that exits on its own serves again up to 3 times in 10 minutes before it reads Serve failed. While it runs or is up, Serve reads Kill, Auto serve on or off; a killed serve stays down until its head moves or the owner taps Serve. A board keeps up to its **Maximum parallel serves** (`max_serves`, 10 by default) card serves at once; past it a Serve is refused with a dialog, and on a busy host Serve asks "The host is busy, start this serve anyway?" ([a card's serve stays up while its worktree does](docs/adr/2026-11-12-0112-a-card-serve-stays-up-while-its-worktree-does.md)). Main has a fixed port recorded per board and keeps its link across merges and restarts. Its red Serve failed button opens the same log and Retry sheet as an app’s, reading Serving… in orange while retrying the recorded failed tip, even if origin has moved. Both open the server itself, outside the app shell ([a try build serves on its own Tailscale port](docs/adr/2026-11-01-2254-a-try-build-serves-on-its-own-tailscale-port.md)).
391
391
  _Avoid_: preview site, separate page
392
392
 
393
393
  **Auto serve**:
394
- The board's `auto_build` setting (the key keeps its name), labelled "Auto serve" in Settings, off by default. On, each card with commits beyond main builds or serves after each new head, and cards show no Serve; off, cards wait for the owner's Serve. A session starts a card run only to carry out the owner's words, quoting them with `build <key> --asked` ([only the owner or Auto serve starts a card run](docs/adr/2026-11-02-1806-only-the-owner-or-auto-build-starts-a-card-run.md)). Main always builds after every merge. The hub runs a nonoverlapping tick every 15 seconds and fetches other boards' origin branches on each check. The Settings toggle saves immediately; `settings set auto-build on|off` sets it through the CLI.
394
+ The board's `auto_build` setting (the key keeps its name), labelled "Auto serve" in Settings, off by default. On, each card with commits beyond main builds or serves after each new head, while the board has room under Maximum parallel serves and the host isn't busy, and cards show no Serve; off, cards wait for the owner's Serve. A session starts a card run only to carry out the owner's words, quoting them with `build <key> --asked` ([only the owner or Auto serve starts a card run](docs/adr/2026-11-02-1806-only-the-owner-or-auto-build-starts-a-card-run.md)). Main always builds after every merge. The hub runs a nonoverlapping tick every 15 seconds and fetches other boards' origin branches on each check. The Settings toggle saves immediately; `settings set auto-build on|off` sets it through the CLI.
395
395
  _Avoid_: Auto-build, build rule
396
396
 
397
397
  **Implement**:
package/SKILL.md CHANGED
@@ -20,7 +20,7 @@ kickflip init
20
20
 
21
21
  `init` is the first-run name for `doctor --fix`; both run the same steps and finish with a doctor report. Init links `~/.claude/skills/kickflip` to the installed package's folder (with `npm link` from a clone, to the clone) and `~/.claude/skills/kickflip-hooks` through `kickflip/hooks-plugin/`. Correct skill links are checked and kept. A real folder is accepted only when it is the target itself. A skill link pointing elsewhere, including a broken link, is refused with a message; move an existing real folder or explicitly remove a wrong link before retrying. `--force` does not bypass these checks.
22
22
 
23
- `kickflip update` runs `npm i -g @lovek4d/kickflip@latest`, then restarts the hub (`--no-restart` leaves it running). It refuses a clone; update that with `git pull`. An npm install's hub checks npm for a newer version as it starts and hourly; it pulls a newer one itself with `kickflip update --no-restart`, whatever runs, and the hub then restarts itself, after which the sidebar reads New version · Reload. A failed pull is logged and retried at the next check, and shows nothing; `kickflip update` is the backup. A clone never pulls ([the hub offers a newer kickflip from npm](docs/adr/2026-11-03-1521-the-hub-offers-a-newer-kickflip-from-npm.md), [the update row shows only New version and Reload](docs/adr/2026-11-06-0800-the-update-row-shows-only-new-version-and-reload.md)).
23
+ `kickflip update` runs `npm i -g @lovek4d/kickflip@latest`, then restarts the hub (`--no-restart` leaves it running). It refuses a clone; update that with `git pull`. An npm install's hub checks npm for a newer version as it starts and every 15 wall-clock minutes, so a Mac's sleep can't stretch the wait; it pulls a newer one itself with `kickflip update --no-restart` once you have been away 15 minutes by the hub's away reading (the moon; about 18 minutes after your last key or tap), so an update never lands mid-use, and at once when you tap the hub page's version, and the hub then restarts itself, after which the sidebar reads New version · Reload. A failed pull is logged and retried at the next check, and shows nothing; a pull still running after 10 minutes is killed, logged and retried the same way; `kickflip update` is the backup. Each check logs `kickflip update check: npm <latest>, running <installed>` to hub.log when that changes and otherwise at most hourly, and every update line starts with `kickflip update`. A clone never pulls ([the hub offers a newer kickflip from npm](docs/adr/2026-11-03-1521-the-hub-offers-a-newer-kickflip-from-npm.md), [the update row shows only New version and Reload](docs/adr/2026-11-06-0800-the-update-row-shows-only-new-version-and-reload.md), [the npm check rides the hub's tick every 15 wall-clock minutes](docs/adr/2026-11-12-0110-the-npm-check-rides-the-hubs-tick-every-15-wall-clock-minutes.md), [an npm hub pulls only once the owner has been away 15 minutes](docs/adr/2026-11-12-0300-an-npm-hub-pulls-only-once-the-owner-has-been-away-15-minutes.md)).
24
24
 
25
25
  For development, clone the private repo, run `npm install`, `npm link`, then `kickflip init`. `npm run build` makes the minified package in `dist/`, which is what gets published. To release, when the owner asks: run `node scripts/release.mjs <x.y.z>` in the clone, which runs `npm version` with the message `chore(release): <x.y.z>` and the subjects landed since the last tag listed below it, then `git push origin main v<x.y.z>`. A commit you make by hand, outside any card's land, follows the same commit standard: a Conventional subject of at most 72 characters with no card ref in it, and a `Refs: <ref>` trailer when it is for a card ([commits are Conventional and name their card in a Refs trailer](docs/adr/2026-11-11-1700-commits-are-conventional-and-name-their-card-in-a-refs-trailer.md)). The tag runs `.github/workflows/release.yml`, which runs the suite, builds, checks the tag against `dist/package.json`'s version, smoke-installs the packed `dist/` and publishes it to npm by trusted publishing ([a v* tag publishes kickflip to npm](docs/adr/2026-11-03-1345-a-v-tag-publishes-kickflip-to-npm.md)).
26
26
 
@@ -86,7 +86,7 @@ These make a site Claude answers: a board, or a page joined with `--watch`.
86
86
 
87
87
  **Your role on a board.** A board has settled towards mostly being a mechanical task board: the board server and `board.mjs` move cards across lanes, launch planners and builders, and apply the owner's button taps themselves. You step in where judgment is needed. Make sure a card marked as staging is prepared to move to ready, judging it against the whole board, since that is when the task board is freshest before implementation begins; from ready it moves across lanes on its own. Answer questions across cards, and be available for being grilled by or grilling the implementing agents and the grilling agents that might have questions before those questions surface to the owner: a builder's reach you as `builder-ask`, a finished grill's as a `screen` wait, and you settle what the board already answers. And walk your `waits` lines on every wake. Everything else that wakes you is the owner's typed message or answer, a bump, or the hub's GitHub, review and triage work, each with its line in the watcher's output and its entry here; a wake that reads like a notice for the owner is still yours to act on ([every signal that wakes the orchestrator says what to do](docs/adr/2026-11-07-0043-every-signal-that-wakes-the-orchestrator-says-what-to-do.md)).
88
88
 
89
- **Board template** (`--template board`, `~/.claude/skills/kickflip/board/`): a work board over item files. A builder reads starting until its first progress line. A headless builder the board launched reads from its process: quiet, in grey, once 5 minutes pass with no progress line and no change to its Claude transcript, and stopped, in grey, once its process is gone without done and the board has stopped relaunching it (a first exit relaunches within a minute); any other running builder reads stale, its line grey, once 10 minutes pass with no progress line and no change to its Claude transcript (from its start before its first progress; a run with no readable transcript has progress lines alone) ([a card's status word comes from a signal the board checks](docs/adr/2026-11-05-0410-a-card-status-word-comes-from-a-signal-the-board-checks.md)). A silent or gone builder reads grey "stale" in its card's footer status and is a `stale` kind on the orchestrator's list, waking you once per spell like any wait; there is no nudge, since the owner reaches you by a message in the card's thread. Check the builder's process and log, restart or finish the run as needed, and write one thread line on the card saying what you found. When you can't restart it, flag it: `item stall <key> --reason "<why>"` stops its run, keeps its worktree, frees its slot and leaves it in its lane reading red "stalled", an Action needed "stalled: <why>" with one push, waiting on nobody but the owner; their next message on the card clears it and reaches you ([stale is automatic, stalled is the orchestrator's flag](docs/adr/2026-11-06-1252-stale-is-automatic-stalled-is-the-orchestrators-flag.md)). To stop a run the board launched, never use a raw kill: `builder stop <key>` stops a card's headless builder, lander or rebase run, and `land stop <key>` its land with the suite, each saying what it stopped. To put a card's land first, bump it (`item bump <key>`); `land queue` lists the order ([the orchestrator stops the board's own runs](docs/adr/2026-11-05-1809-the-orchestrator-stops-the-boards-own-runs.md)). For a parallel part of a card's work, ask the board for a helper rather than an in-process subagent it can't see or count: `agent launch <key> --name <n> --task "<t>" [--writes]`. The board launches it headless; one that writes takes an implementer slot and works in its own worktree off the card's branch. `agent wait <key> --name <n>` prints its hand-back, and `agent merge` brings in a writing helper's branch ([the implementer limit counts agents, and any agent on a card can ask the board for helpers](docs/adr/2026-11-06-0425-the-implementer-limit-counts-agents-and-a-card-spawns-helpers.md)). Every write an agent makes to a board site goes through `node ~/.claude/skills/kickflip/board/bin/board.mjs --site <route> <command>`: replies, thread lines, question topics and questions, item status and `next`, and builder records. Its usage text lists the commands. Hand-edited JSON skips the checks the pages rely on. PreToolUse hook (`hooks-plugin/hooks/board-data-gate.mjs`) denies Edit and Write on a board site's `board.json`, its `data/**/*.json`, its item file and its cards' notes `.md` files, naming the `board.mjs` command that makes the change ([a hook refuses hand edits to board data files](docs/adr/2026-11-05-2330-a-hook-refuses-hand-edits-to-board-data-files.md), [the board owns a card's notes file](docs/adr/2026-11-09-1100-the-board-owns-a-cards-notes-file.md)); Bash stays open, but a notes file is read-only. Write a question draft for `question add --file` in the site's `drafts/` folder, where Edit and Write still work. A new card is `board.mjs item add <file> --title …`, never a hand edit of an item file. Yours carries `--phase <s>` and its `--relate <keys>` so it is filed and linked in that one call, while an agent's has no `--phase` and comes back to you as `card-added`: it makes the card's ticket, names the card from it and prints `<label> added as <key>`; use that key, and pass `<file>/<id>` only to import a card with its own id ([a card is named by its board's ticket source](docs/adr/2026-11-02-2100-a-card-is-named-by-its-boards-ticket-source.md)). A card filed from another card's thread, grill or answer, a follow-up included, takes `--parent <that card's key>`; one from the + has none ([a follow-up is a work card with a Parent](docs/adr/2026-11-03-0526-a-follow-up-is-a-work-card-with-a-parent.md)). A board serves `GET /_claude/needs` itself, one item per Needs you line. The + sends an `ask` event, which arrives as a New `T-<n>` card at the top of Todo, titled from the ask's first line with the owner's message its first thread line, until you sort it ([the + makes a New card, which Claude files, folds or answers](docs/adr/2026-10-29-1639-the-plus-makes-a-new-card.md), [every ask is a task card from the moment it arrives](docs/adr/2026-11-09-1900-every-ask-is-a-task-card-from-the-moment-it-arrives.md)). **You sort New cards** ([the orchestrator sorts new tasks itself](docs/adr/2026-11-07-0115-the-orchestrator-sorts-new-tasks-itself.md)): each new task, each owner message in a New card's thread, and each `card-added` card wakes you, and waits on your list as an `intake` wait until it is sorted. Take them from the top: sort the card (`item notes`, then `item set <key> --phase …`), merge it into the card it's about (`item relate-ask`), or answer it (`reply <key>`), as below. A New card reads a grey "waiting" until the watcher marks it working, then "thinking". **The ask is the work item from the start** ([every ask is a task card from the moment it arrives](docs/adr/2026-11-09-1900-every-ask-is-a-task-card-from-the-moment-it-arrives.md)): its card wears a New mark where its ticket would be until you sort it with `item set <key> --phase …` (`--title` renames it). Answered with `reply <key> --text … [--title …]`, it waits in In Review for the owner's Done, and an owner reply there waits on you as any thread message. Merged with `item relate-ask`, it is gone: its thread shows in the other card's, and the owner's banner names that card. No ask draws as its own row: the board server files every ask with no card as its T-<n> card, an old one Claude had answered closed in Done at its answer time ([old asks migrate into cards and the ask-only records retire](docs/adr/2026-11-09-2000-old-asks-migrate-into-cards-and-the-ask-only-records-retire.md)). **Every new task is grilled or prototyped at once, unless the owner chose Implement** ([every new task is grilled or prototyped at once](docs/adr/2026-11-04-0131-every-new-task-is-grilled-or-prototyped-at-once.md)). **Linking is part of filing** ([the orchestrator links a new card when it files it](docs/adr/2026-11-05-0130-the-orchestrator-links-a-new-card-when-it-files-it.md)). Before you set a new card's state, check the cards still pending (Todo and In Progress) for ones it overlaps, depends on or would duplicate. Link them in the same call that sorts it: `item set <key> --relate <keys> --phase …` after its `item notes` (`item add <file> --title … --notes-from <draft.md> --relate <keys> --phase …` for a card of your own) (`--relate` adds links and keeps the rest, `--unrelate` takes them off on both cards, `--related` replaces the list; `--deps` for a card it truly waits on). Then add a short `Related` section to each linked card's notes and to the new card's with `item notes`, naming the other card and how they overlap. A card never reaches Todo unlinked: its planner launches from there, and the planner's and builder's briefs list the card's Related to, Parent and deps with their notes paths, so they gather the broader context from your links. On a board `item add` refuses a card with no `--phase`, naming grilling and prototyping, so every card an agent adds (a builder's or planner's follow-up, or one you file, held ones included: `--held` holds it as it is filed) is filed at once; a `card-added {key, title}` event is only an older card still unfiled, which you file: add to its notes with `item notes`, link it the same way, then set its `--phase`; that clears New, and the board grills it on arrival. `item add` and `item set` refuse `--phase ready`, bar a Quick build ask's card: an agent's follow-up reaches ready only through staging. A card filed grilling gets its questions from the board's planner, so write its notes and ask nothing on it yourself. The New task sheet sends with one of two buttons, Discuss (⌘↵) or Implement (⌥↵); an Implement ask comes as `ask {text, quick: true}`, and its thread reads "Implementation requested" under it. On a Discuss ask, file the card `--phase grilling` with notes that brief its grill, and dispatch nothing: with Auto implement on, the board launches a grill headless on every card that lands in Todo, however it was filed (an ask, `item add`, the +, an import), up to Maximum parallel planners at once (`setting max-planners <n>`, 3 by default, set with `settings set max-planners <n>` only on the owner's word), the rest waiting in board order. An arrival is a work card in Todo that isn't ready, staging or held, with no planner record and no questions yet; it gets one grill, never a prototype straight away, and the grill asks for a prototype round when the card changes a UI ([every card arriving in Todo is grilled by the board](docs/adr/2026-11-04-2359-every-card-arriving-in-todo-is-grilled-by-the-board.md)). A grill ends with its prototype gate, so the owner's Send settles every card; where the owner asked for prototypes, or a board rule wants a UI prototype first, it ends prototyping. A card has no status: it stores its lane (Todo, In Progress, In Review, Done), which a build's start, a handover (`--pr`, `--pushed`, a verified merge-ready build), a block and a close move at once, and the board server moves the rest as GitHub, messages and holds change, each move with a "Moved to <lane>: <why>" thread line; `item set --status` is refused ([a card stores its lane, and facts replace statuses](docs/adr/2026-11-07-1400-a-card-stores-its-lane-and-facts-replace-statuses.md)). Don't watch Todo or write grill prompts; a finished grill's questions wait on you first, as a `screen` wait, before they reach the owner, and you act on each `owner-answer`. An Implement ask goes straight to ready, since your filing is its judgment: check it against the whole board as you would a staging card (the checklist under Staging, below), then write its plan with `item notes <key>`, never on the card, and sort it `item set <key> --phase ready --size <small|large>`. Staging is only for the owner's replies on a card that exists. A Todo card's reply box sends with Reply (⌘↵) or Implement (⌥↵), the card's only Implement, and each message's thread footer names its button ([each text box sends its intent from a key](docs/adr/2026-11-04-2343-each-text-box-sends-its-intent-from-a-key.md), [Implement in the thread queues the card for the orchestrator](docs/adr/2026-11-05-0300-implement-in-the-thread-queues-the-card-for-the-orchestrator.md)). Reply comes as `item-message {key, text, intent: 'reply'}`; answer it as any message. Implement comes as `item-message {key, text, intent: 'build'}`: the board has already staged the card in Todo, unheld it, resolved its open questions "Skipped: you tapped Implement" and written the words into its notes verbatim (its footer reads "Implement", the watcher's line "Implement asked on <card>"). A Reply on a ready card stages it the same way. **Staging, then ready** ([staging, then ready](docs/adr/2026-11-07-0700-staging-then-ready.md)): staging is the state the board sets on the owner's Send that leaves an unstarted card with nothing open (a gate "no" included), on an Implement, and on a Reply to a ready card; only the board sets it. `item set --phase ready` takes a card only from staging, or one already ready. The orchestrator's wait on a staging card reads "Judge the staged card against the whole board": this is where the board is freshest before the build begins, so judge it against every open card, not only its own notes. Read its notes, where the owner's words already are, and its thread; then check that no open or merged card already covers it or overlaps its files, that the cards it depends on or that should land first are linked with `--deps`, that a related card's settled answers don't contradict it, that its size and model fit what the notes now ask, and that nothing it asks is left as a question for the owner. Then `item set <key> --phase ready --text "<what you checked>"` (with its `--size`), whose one line goes into its notes under Ready (orchestrator) for its builder, and which `item set` refuses to leave out on a staging card; or `--phase grilling` or `--phase prototyping` for another round, which the board starts itself ([every signal that wakes the orchestrator says what to do](docs/adr/2026-11-07-0043-every-signal-that-wakes-the-orchestrator-says-what-to-do.md)). Where its notes answer a split question "Split as proposed", file the split instead (**A grill can propose a split**, below). A staging card is never pulled; a ready card waits for the pull like any other, so never start that build yourself. A question added on a ready or staging card moves it to grilling, and so does the owner's Grill or Prototype tap. An empty Implement on a Todo card records no event: the board server writes its "Implementation requested" line, stages the card, with a gray "Marked as staging" line after it, and starts no build: the orchestrator reviews the card and sets it ready, which writes a green "Marked as ready" line. Every owner move into staging (answers, Implement, Reply) writes that same "Marked as staging" line. **Every button without a text box, and Implement with nothing typed, posts only a status line in the thread, keyed by `command`** in `/api/thread` (and in the thread file for the lines the board server writes); read a key only when the card has no clearly defined next step: `command: implement` "Implementation requested" (the owner wants it built as it is; the board has already started it), `command: prototype` "Prototype requested", `command: grill` "Grill requested", `command: visual` "Visual requested" (each comes with its event, and the board server launches that planner or agent), `command: reask` "Re-ask requested" (ask that resolved question again), `command: hold` "Held" or "Held until <time>" (leave the card alone until it resumes), `command: resume` "Resumed" (it can move again) and `command: done` "Marked done" (the owner closed it). The board writes four more as your lines when a link changes, each naming the other card in its `card` field: `command: related` "Related to", `command: unrelated` "Unrelated from", `command: followup` "Follow-up" (in a Parent's thread) and `command: followup-of` "Follow-up of" (in the child's); they ask nothing of you. Each has its icon in `board/public/ui.js` MARK_ICONS ([a button without a text box posts a keyed status line](docs/adr/2026-11-06-0021-a-button-without-a-text-box-posts-a-keyed-status-line.md)). On a New card (`key` `ask:<eventId>`) file an Implement the same way. An ask whose work still has an outcome pending after you act on it (a release run, a deploy, a CI run, a push someone else must see) is a card, not a thread answer: file it with `item add`, link the ask, and keep it blocked with `--blocked-until "<the outcome it waits on>"` until that outcome is known, then close it with `--done --text` or say what failed. A `visual-request {key, text?, files?}` (the thread's image, or /visual) asks for a visual, a one-off HTML page answering in the thread: the board server launches a headless visual agent on Claude Sonnet beside any other agent on the card (one visual at a time per card), which places its page with `visual add <key> --file <page.html> --title <t>` and a link line in the thread; it wakes nobody ([a visual is a page an agent draws for a thread](docs/adr/2026-11-05-1921-a-visual-is-a-page-an-agent-draws-for-a-thread.md)). A `grill-more {key, text?, files?}` (the thread's fire, or /grill) or a `prototype-request {key, text?, files?}` (the thread's eye, or /prototype, or the owner's eye on one question) is the owner's request: the card already reads a grey "preheating" until the planner picks it up, then "grilling" or "prototyping" in the lane's colour, and the thread a muted "Grill requested" or "Prototype requested", or, with text, the owner's message with that status in its footer, and the board server has already launched that planner itself, headless in the board's repo folder with a brief built from the card and the owner's text and files (Claude Opus for a grill, Claude Sonnet for a prototype), and written "Planner launched on <model> in <folder>." in the thread; neither event wakes you ([the hub launches every agent from the card](docs/adr/2026-11-04-2130-the-hub-launches-every-agent-from-the-card.md)). A prototype request is answered only by a prototype: never answer it in the thread instead. One still waiting 30 minutes on, with no prototype agent running on the card, comes back as `prototype-overdue {key, request, question?, since}`, once per request: dispatch its prototype agent now ([a prototype request waits for its prototype](docs/adr/2026-11-04-2130-a-prototype-request-waits-for-its-prototype.md)). First check it against the other boards: each one's title and description in `~/.claude/kickflip/manifest.json`, its folder (`node $KF sessions`) and its cards. Only when another board clearly fits better, add an open question on the New card (`question add`, topic `item:<file>/<id>`, the card's): "Move to <board>" recommended, then "Keep here", each with `diagram` and `practice`. On Move, run `board.mjs --site <route> ask move <eventId> --to <other route>`, which makes it a New card there and wakes that board's session, then `question resolve`; on Keep, sort it here. Hand a long build or investigation to a builder, which reports in the card's thread. The owning session only triages events, writes board lines and dispatches: a full test suite, a scratch hub, screenshots, `board.mjs land` and anything else that takes more than a few seconds run in a background agent or background task. A session sitting in foreground work leaves events waiting, and its cards read stale. The watcher marks each ask, thread message and wave triage it prints as Working, so the page reads "Working on it" until you reply, write a later thread line on its card, reply to its ask, turn or fold its ask into a card, or the card closes. Answer a New card with `board.mjs reply <key> --text "…"` (or `--file`), in markdown. An answer never pushes: the board's answer banner and the thread's unread mark carry it ([a push goes out only when something waits on the owner, on the hub's schedule](docs/adr/2026-10-29-1639-pushes-only-when-something-waits-on-the-owner.md)). The answered card waits in In Review for the owner's Done. A card's **Notes** is your understanding of the task so far: what was asked, what's settled, what's still open. A card filed from an ask opens its notes with the owner's words verbatim under "## Asked (owner, <date>)", then a short "## What it is" in plain words. The board owns the file ([the board owns a card's notes file](docs/adr/2026-11-09-1100-the-board-owns-a-cards-notes-file.md)): `item add` makes the card's own `<id>-notes.md` beside its item file, seeded with `--notes-from <draft.md>` or `--notes <text>`, and every later write is `board.mjs item notes <file>/<id> --heading "<heading>" --file <draft.md>`, which appends a `## <heading>` section, or `--from <other key>` to fold another card's notes in. Write each draft outside the board's data folder; a draft that is any card's notes file, live, done or archived, is refused, naming that card, and the notes file itself is read-only. Two cards never share notes: link them with `--relate`. Append a dated section as the grill settles things (later sections override earlier ones) rather than freezing it as a plan; the thread keeps the short news. `item notes` resolves the card's answered questions still waiting on Claude, noting "Recorded in the card's notes", and prints `resolved: <id>` for each. The open card's details list ends with a "Notes ↗" link, which opens `notes.html`, a view that renders the file for the phone, or the item's short `notes` text when it has no file ([notes replace the full plan, and a card starts on its own](docs/adr/2026-10-29-1816-notes-replace-the-full-plan-and-cards-start-on-their-own.md), [notes is a link in the details list, with no stored summary](docs/adr/2026-10-30-1626-notes-is-a-link-in-the-details-list.md)). `item set --title` renames a card. When an ask is about an existing item, fold it in with `board.mjs item relate-ask <eventId> <file>/<id> --summary "<one concise line>" --title "<the ask in plain words>"`: the New card goes, and the owner's message moves into the item's thread marked Moved, with the summary after it. When the owner says it went to the wrong card, relate-ask it to the right one, or run `board.mjs ask unfold <eventId>` to give it a New card again. An `item-message` whose `key` is `ask:<eventId>` is the owner replying in a Done ask's thread: answer it with `board.mjs reply <its eventId>` or `board.mjs thread ask:<eventId> --text …`, as in a work item's thread. A thread message (`thread --text`, a close's `--text`) holds at most 2000 characters, and a longer one is refused: rewrite it shorter, or put the detail in a page (`visual add`) and link it. Your thread messages and replies draw as compact markdown (lists, `**bold**`, `code`, short headings), so write a multi-part one as a list; the owner's own messages stay as typed, and a visual stays an HTML page. The board writes its own holds, launches, blocks and faults as status lines, so never repeat one as a message. An `ask-withdrawn {id}` event (with `key` from a thread) deletes a pending message ([a pending ask or thread message can be deleted or edited, and a pending ask bumped](docs/adr/2026-10-29-1639-a-pending-ask-can-be-deleted-or-bumped.md)). An `ask-edited {id, text}` event (with `key` from a thread) replaces a pending message's text: use the new text, and if you had started, adjust the work to it and say what changed. Only what the owner types in a thread is a message to you; a button tap changes the card or starts an agent in the board server, and wakes you only where noted ([only typed thread messages wake the orchestrator](docs/adr/2026-11-06-1100-only-typed-thread-messages-wake-the-orchestrator.md)). A `card-bump {key}` event bumps a work card, and is the one tap that still wakes you, since the owner wants it done urgently ([a card that hasn't started, or is running, can be bumped](docs/adr/2026-10-29-1639-a-card-that-hasnt-started-can-be-bumped.md)): the board already takes a bumped card first in the pull, planners, landers, rebase runs and the land queue, starting it past the cap and bumping out the newest unbumped build, which pauses In Progress, when every slot is full, so a card that hasn't started needs nothing from you; a bumped card's next steps (its builder's questions, review fixes, CI), and its `waits` lines, which come first and read `bumped`, come ahead of your other work until it is unbumped or closes ([a bump marks the priority through every lane](docs/adr/2026-11-06-1700-a-bump-marks-the-priority-through-every-lane.md)). On the `card-bump` wake, handle each of that card's `waits` lines before anything else; when it has none, write nothing and leave it to the board ([every signal that wakes the orchestrator says what to do](docs/adr/2026-11-07-0043-every-signal-that-wakes-the-orchestrator-says-what-to-do.md)). A `card-hold {key, hold, until?}` event is the owner's Hold (`hold: true`, with `until` when they picked a time) or Resume (`false`) on a work card, and wakes nobody. A held card never starts on its own; the board server has already stopped the held card's planner and given its build a card pause, so stop nothing yourself, and start no new builder, review fixes or CI reruns while it is held. On Resume the board server resumes the paused build's own session, or relaunches the grill or prototype the hold stopped, and the pull takes a card whose hold stopped nothing; a card a relaunch leaves with nothing running reaches you as an orchestrator wait. When the owner's words give a time to pick a card up, hold it with `item set <key> --pick-up-at <ISO time>` (no offset is the Mac's local time). Within a minute of that time the board server resumes the card itself and appends `card-unblocked {key, until}` unless a dep is unfinished ([a card can be held until a time](docs/adr/2026-11-02-1727-a-card-can-be-held-until-a-time.md)); the board relaunches what the hold stopped, as on Resume. A `card-done {key}` event is the owner closing a card from an In Review thread's Done or a Todo card's Close: the board server has already stopped the card's headless builder and closed its records (a land in progress finishes), so it wakes nobody. Closing a card yourself (`item set <key> --done`) takes `--text "<what was done, or why it closes without landing>"`, which becomes its last thread line and says whether it merged, was given up (a duplicate, not feasible) or was superseded; it moves the card's ticket to Done whatever the reason. Never leave a card open because part of it can't be done: close it and file a follow-up card for what stays open. Closing resolves each of its questions that has an answer, noting "Closed with the card"; one still open, with no answer yet, stops it, and the refusal names that question. `--force` closes the card anyway and resolves that one too. Never touch GitHub for it: an open PR stays as it is. The owner's Merge on a card whose PR is approved, green and CLEAN merges it in the board server and records no event, so it never wakes you; a refusal is a thread line, which ends the button's "Merging…" ([the Merge tap and auto-merge run in code](docs/adr/2026-11-04-2045-the-merge-tap-and-auto-merge-run-in-code.md)). A card whose open questions are all answered goes to staging, and from ready the pull starts it without waiting for a go; `unblocked: <key>` or a `card-unblocked {key}` record means a dep or hold no longer stops it, and the pull takes it ([notes replace the full plan, and a card starts on its own](docs/adr/2026-10-29-1816-notes-replace-the-full-plan-and-cards-start-on-their-own.md)). The Implement tap on a ready card and Auto implement's pull both start the build in the board server: it makes the refusals a build's `builder start` makes, picks the builder (claude with a model, or codex), makes the worktree, marks the card building and clears its Next, then launches the builder itself, headless in the worktree (`claude -p`, or `codex exec` under workspace-write for a codex pick) with a standard brief built from the card's notes and the rules, and writes "Builder launched on <model> in <worktree>, session <id>." in the thread; no event reaches you. The builder's own first step is `builder start <key> --kind build`, which takes up the record the board opened; its first status line then replaces "starting". A refused tap, or a launch that fails, puts the card back in Todo with the reason in its thread ([a Build tap starts the build in the board server](docs/adr/2026-11-03-0219-a-build-tap-starts-the-build-in-the-board-server.md), [the hub launches every agent from the card](docs/adr/2026-11-04-2130-the-hub-launches-every-agent-from-the-card.md)). `item set --phase ready` refuses a card without `--size`, without a notes file, or whose notes don't name the id of each question the owner answered on it, and marking it ready resolves those questions, so record every answer in the notes before marking it ready. The builder asks you as any builder does, and finishes its own work with `builder done --text`, rebasing and resolving conflicts itself; finishing never comes to you. A build with calls hands back as before: verify them (`builder verified`, with `--title "<type>(<scope>): <summary>"` to title the draft PR it opens on a GitHub board from what the whole diff does), which finishes the card in the same step; when a question on the card was still open, or that finish refused, the server launches a headless lander once no question is open, which acts on the owner's answers and finishes it, so don't land it yourself ([builders launch headless, check their notes and land on their own](docs/adr/2026-11-04-0306-builders-launch-headless-check-their-notes-and-land-on-their-own.md)). With Auto implement Todo cards on (`setting auto-pull on|off`, set with `settings set auto-pull on|off` only on the owner's word), the board pulls ready Todo cards into free implementer slots and launches their builds, one per free slot, up to Maximum parallel implementers (`setting max-implementers <n>`, 10 by default, set with `settings set max-implementers <n>` only on the owner's word), counting cards building or in Orchestrator review ([an idle board pulls in its top Todo card](docs/adr/2026-11-02-1754-an-idle-board-pulls-in-its-top-todo-card.md), [auto implement fills In Progress up to Maximum parallel implementers, on every board change](docs/adr/2026-11-04-0057-auto-implement-fills-in-progress-up-to-a-cap.md)). Only ready cards are pulled ([the idle pull takes ready cards first](docs/adr/2026-11-03-1631-the-idle-pull-takes-ready-cards-first.md)); every other card that lands in Todo gets its grill on arrival ([every card arriving in Todo is grilled by the board](docs/adr/2026-11-04-2359-every-card-arriving-in-todo-is-grilled-by-the-board.md)). A `pr-review {pr, head, repo, title, author, url, touches, asked}` event, with auto review on, asks you to review a teammate's PR that touches the listed cards or asks the owner: read its diff and the reviews already on it, then `review post <pr> --file <review.md> --read-at <when you read it>` with only points no other review made (it adds the header and marker, posts one Comment review and records it posted, and refuses if another review landed since you read), or post nothing and `review record <pr> --state posted --file <note.md>`. When it finds a blocker, disagrees with a decision on a card or clashes with a card in progress, hold it with `review record <pr> --state needs --file <draft.md>` instead; the owner's Post it or Skip comes back as `review-answer {pr, answer}`, after which you `review post` it (or don't, and record it posted) ([each board reviews incoming PRs that touch its work, in an Auto Review lane](docs/adr/2026-11-03-1731-each-board-reviews-incoming-prs-that-touch-its-work.md)). An `overnight-triage {date, topic, cards}` event is the board asking for its overnight triage, with auto-triage on (`setting auto-triage on|off`, set only on the owner's word): it goes out once a night from the middle of quiet hours, when two or more cards, `cards`, wait on the owner's open questions and nothing builds. First read those cards' open questions against each other. Questions that ask the same thing become one, on a single card ([a question for several cards moves to the card built first](docs/adr/2026-11-05-1000-a-question-for-several-cards-moves-to-the-card-built-first.md)): pick the card the pull would build first, and run `question move <id>,<id>,… --to <that card> --block <the other cards, in build order>`. The first id moves onto that card, the others resolve "Duplicate of <ref>'s question <id>", and each blocked card is blocked by the one before it and related to the first. The owner's answer lands on that one card and starts it as any answer does; a blocked card's builder reads the related card's thread and notes once it is done. Cards whose grills show they are the same work merge as a clear duplicate does below. Then check each open question left against the owner's earlier answers on other cards and their long-running context, such as what they said in other cards' threads and notes, not against ADRs or CONTEXT.md, which the grill already read. When one of those answers settles a question and you are confident it carries over, `question add` it again on the same topic with a new id, its options unchanged and `suggested: {option, card, answer, reason}`: the option, the earlier card's ref, the owner's answer in their words and your own words for why it carries over (the question reads "Orchestrator choice: <reason>" in blue under the option's label). Then `question resolve` the old one with `--note "Replaced by <new id>"`. Never act on a suggestion yourself: the page pre-checks it, and it waits for the owner's Send ([overnight triage suggests your earlier answers](docs/adr/2026-11-04-2200-overnight-triage-suggests-your-earlier-answers.md)). Leave the other questions you could answer yourself as they are. Then read the Todo cards and stale reviews against each other and against merged work, leaving Done alone (old Done cards leave by the archive rule, [the board keeps the newest 100 Done cards](docs/adr/2026-11-04-0307-the-board-keeps-the-newest-100-done-cards.md)), and find duplicates, cards a newer card covers, cards merged work already did, and deps that no longer hold. Link related cards (`item set --relate`) and merge a clear duplicate into the newer card yourself, dropping the older with a thread line naming the one it went into. A close, or anything you aren't sure of, is one question per finding on `topic`, all in one `question add` array; quiet hours hold their push until morning. Then reply to the event, even when you changed nothing ([triage runs once overnight on cards waiting on your answers](docs/adr/2026-11-04-1900-triage-runs-once-overnight-on-cards-waiting-on-your-answers.md)). Set `deps` for work that waits on other cards. When a close finishes the last dep, it prints `unblocked: <key>` and appends a `card-unblocked {key}` event; leave a held card held until the owner unholds it ([cards wait on explicit blocked-by links](docs/adr/2026-10-29-1639-cards-wait-on-explicit-blocked-by-links.md), [Build on a blocked card queues it, and blocked, bumped and Action needed leave the badges](docs/adr/2026-11-03-0301-build-on-a-blocked-card-queues-it.md)). Every builder you start for a card works in its own git worktree, never in the folder you, a running app or the hub use ([every builder works in a worktree, and the hub's own fault shows once](docs/adr/2026-10-30-1654-every-builder-works-in-a-worktree.md)). A repo card's builder uses the board's manifest `github` and `branch` when following wave-build; it never switches the shared clone's checkout. A build's `builder start` on a board makes the card's worktree when its record keeps none, `~/.claude/kickflip/worktrees/<card id>` on branch `<card id>`, and prints `worktree: <path>`; the builder's prompt names that path as the only place it edits, tests and runs scratch hubs. Right before it launches any builder agent, the session runs `board.mjs --site <route> builder start <key> --dispatch --kind <kind> [--model …]`, which opens the record (`dispatched: 'session'`) so the card reads "starting" at launch, and changes nothing on a record the Implement tap already opened (`dispatched: 'tap'`), printing "already open"; it never posts a "builder is working" line itself ([the session opens the builder record when it dispatches an agent](docs/adr/2026-11-03-0513-the-session-opens-the-builder-record-when-it-dispatches-an-agent.md), [a card reads starting from its tap, with one dispatched mark](docs/adr/2026-11-03-1718-a-card-reads-starting-from-its-tap-with-one-dispatched-mark.md)). Every builder, prototype and grill agents included (`--kind prototype` or `--kind grill`), runs, as required steps in its prompt, `board.mjs --site <route> builder start <key> --kind <kind> --label "<label>"` first, which takes up the dispatched record (the label carries no model word) (a build agent passes `--kind build`, which records the kind and model `builder pick <key>` prints), `builder progress <key> --phase <reading|building|testing|checking|landing> "<detail>"` (or `--text "<detail>"`; the board adds the phase word, so don't start the detail with it) at each milestone (a planner, kind grill or prototype, passes no `--phase`: its line reads "Preheating: <detail>" or "Prototyping: <detail>" in the lane's colour, never a builder phase word, and a `--phase` it passes is dropped) and `builder done <key>` before it hands back, so the card sits in In Progress with a live status line. Closing a card's last open record when it stays In Progress with no Next is refused: pass `builder done <key> --next "<what happens next>"`, or record a judgment call with `builder call <key>` (so `builder done` hands the card back) or `land`, which closes the record itself. A card with a step only the owner can do once its code lands (a publisher to add, a release to tag) takes `--owner-step "<the step>"` on whichever of `builder done` and `land` finishes it: it then waits in In Review with that step as its Next and its ticket open, and only the owner's Done closes it ([a card whose code landed stays in review while an owner step remains](docs/adr/2026-11-04-0158-a-card-whose-code-landed-stays-in-review-while-an-owner-step-remains.md)). When code can prove the step done, add one `--check "<name> <args>"` on the final evidence beside `--owner-step`: `tag <owner/repo> <pattern>`, `npm <package> <version-or-range>`, `run <owner/repo> <workflow>`, `gh <owner/repo> <api-path> <field>=<value>` or `url <address> [<status> | <text>]`, never a shell command. The hub's poll runs it once the code lands and closes the card when it passes; on `owner-check-broken {key, check, error}`, fix it with `item set <key> --check "<check>"`, or remove it with `--check ""`, and write one thread line saying which ([an owner step can carry a code check](docs/adr/2026-11-04-2308-an-owner-step-can-carry-a-code-check; `item set` likewise refuses a write that would leave a built card with neither ([an In Progress card always has a builder line or a Next](docs/adr/2026-11-03-0237-an-in-progress-card-always-has-a-builder-line-or-a-next.md)). The detail is plain words: what the builder is doing and why it matters to the owner, such as `--phase testing "fix for the scroll jump into Done"`. A wait on a lock or a Codex limit goes in the detail. Commits, test counts, ADR numbers, file names and screenshots go in the hand-back and the session's thread message, not the line ([a builder status line is a phase and a short detail](docs/adr/2026-11-03-0128-a-builder-status-line-is-a-phase-and-a-short-detail.md)). A build's `builder start` is the one write that marks the card building: it moves the ticket to In Progress and prints `ref: <label>`, the card's name for its commits' `Refs: <label>` trailer. `building` and `fixing` count as working only while a builder record on that card is open; with none open, its PR and other state place it as if the status were absent. `builder done` clears either status when it closes the card’s last open builder record; `item set --pr` clears either status too and closes ordinary builders while install builders keep running. When a subagent stops, a SubagentStop hook, `board/bin/builder-stop-hook.mjs`, closes the records it started and left open, but not one another agent restarted later, and not while background work the subagent started still runs (the input's `background_tasks`), since it resumes when that work ends. A skill's own hooks don't fire for SubagentStop, so the hook ships as the plugin `hooks-plugin/`, which Claude Code loads as `kickflip-hooks@skills-dir` through the link `~/.claude/skills/kickflip-hooks` (`claude plugin list` shows it); a new host needs that link. A site card's builder lands its own card: it runs the tests and checks the board at phone width in its worktree, commits there as the repo's configured user (`git -c core.commentChar=';' commit -F <file>`, or `--cleanup=verbatim`, so git keeps any line starting with "#") with a Conventional subject of at most 72 characters, no ref in it, and a `Refs: <label>` trailer, the only shape land takes, then runs `board.mjs --site <route> builder done <key> --text "<what it checked>"`. With no unverified calls that finishes the card, the one step `land` also runs, as `builder done`'s usage lists: it lands the worktree, closes the card as done with that text as its last thread line, and with the board's "Push main after a land" switch on pushes main to origin itself, so no session pushes after a land; on a GitHub board it pushes the branch and opens a draft PR instead, titled by `--title "<type>(<scope>): <summary>"` (else the first commit subject), and on a plain git remote pushes the branch ([finishing a build is one step](docs/adr/2026-11-04-1611-finishing-a-build-is-one-step.md)). A finish that fails refuses with the reason and the builder stays on: it fixes what the refusal names and runs `builder done` again. Only a builder that can't finish hands back, with a `builder call` naming why, then `builder done`: the card sits in In Progress reading "Orchestrator review" and unblocks nothing, and the owning session checks it, and its `builder verified` finishes it ([site cards build in parallel when their files don't overlap](docs/adr/2026-10-29-1639-site-cards-build-in-parallel-when-their-files-dont-overlap.md), [the board records what it knows, and commands make the rule calls](docs/adr/2026-11-03-0003-the-board-records-what-it-knows-and-commands-make-the-rule-calls.md)). On a refusal, fix what its line names in the worktree and finish again. **Judgment calls** ([a builder records its judgment calls and the session verifies them before land](docs/adr/2026-11-03-0514-a-builder-records-its-judgment-calls-and-the-session-verifies-them.md)): every builder's brief includes these steps. Right after `builder start`, it records each gap or ambiguity in its brief as `builder call <key> "Question: …"`; with any, it runs `builder done <key>`, which hands the card back for them, and stops, its report the questions. Answer them from the card's notes and thread, asking the owner on the card only what those don't settle, and resume it with SendMessage; its `builder start` then resumes the record, calls kept. While building, it records each judgment call as it makes it, `builder call <key> "<call>"`, one plain line each. A builder with calls doesn't finish: `builder done <key>` hands the card back for them to be verified, and its report lists them. Check each (`builder calls <key>`) against the owner's words and the other cards: one that conflicts with what the owner said goes to the owner as a question on the card, any other wrong one back to the builder by SendMessage. Then run `builder verified <key> [--note "<what you checked>"]`, which finishes the card in the same step, the note its closing line; while a question on the card is open it says so and the card waits, and a finish that fails keeps the mark and says why. `land` refuses while a record on the card has unverified calls. **Builder asks** ([a builder asks the orchestrator mid-build, and only what it defers reaches the owner](docs/adr/2026-11-04-0247-a-builder-asks-the-orchestrator-mid-build.md)): a builder's brief says it decides, records the call and carries on, and asks you only when blocked (every way forward would likely be thrown away: a spec that contradicts itself or the code, a rule that needs the owner's go before code is written, or a fact only you have; [the blocked-only rule](docs/adr/2026-11-07-1300-a-builder-asks-the-orchestrator-only-when-blocked.md)): then it runs `builder ask <key> "<question>"`, waits with `builder asks <key> --wait`, and hands the question back as a "Question:" call after 30 minutes without a reply. A problem it finds outside its card is a "Found: …" call for you to file at review; it asks at once only when that stalls other cards' builds or lands. The ask shows in the card's thread as "Claude Opus builder" (by its model) and wakes you as a `builder-ask {key, ask, agent, text}` event; the card itself stays quiet. Answer from the card's notes, thread and the owner's words with `builder answer <key> <ask> --text "<answer>"`, or, when you aren't confident or the owner's opinion is wanted, `builder defer <key> <ask> --text "<what to carry on with>"`: never ask the owner mid-build. Both show in the thread as Orchestrator. A deferral is a "Question:" call on the builder's record, so its build hands back to you; after you've reviewed everything else, and before a draft PR or In Review, put it to the owner as a card question naming the ask (`"ask": "<ask>"` in the question file), which `builder verified` requires. The card then shows Questions and "1 new question", with no Action needed. **A repo card's built work always goes straight to a draft PR** once it is checked (owner, 2026-10-23): on a GitHub board the finish (`builder done --text`, or your `builder verified` on a handed-back build) pushes the card's branch, opens the draft with `gh pr create --draft` and records it as `item set --pr` does, closing the builder records. A PR opened by hand on the card's branch, a same-repo head named by the card id, is linked by the hub's poll as `item set --pr` does, with the thread line "Found PR #12 on branch GH-230." and a `linked` change ([the poll links a PR opened by hand](docs/adr/2026-11-05-1000-the-poll-links-a-pr-opened-by-hand-on-a-cards-branch.md)); run `item set <key> --pr <n>` yourself only for a PR on another branch. Either way the card sits in In Review with the PR, with Action needed linking to it once it waits on the owner, also while the owner tries it on a test deploy; a ready PR whose CI fails reads Next "Fix the failing CI" there until you start a builder to fix it, which moves it to In Progress ([In Progress means a builder runs](docs/adr/2026-11-09-1804-in-progress-means-a-builder-runs.md)). A card whose work spans repos holds a PR in each: run `item set <key> --pr <owner/repo#n>` once per PR (it adds, never replaces; a bare number is the board's repo). Each PR gets its own badge and polling, the least-ready one decides the lane and Next, `merge` merges them all in order, and `pr` prints a line per PR ([a card holds several PRs across repos](docs/adr/2026-11-03-1904-a-card-holds-several-prs-across-repos.md)). A board whose repo is a plain git remote (manifest `remote`, no `github`) has no PRs: the finish pushes the card's branch to origin and records it as `item set <key> --pushed <branch>` does (by hand: `git push origin <branch>` in its worktree, then that command), so the card waits In Review on the owner's merge; the hub's poll moves it to Done once the branch is merged into the board's branch or gone from the remote, with a thread line ([a board can work on any git remote](docs/adr/2026-11-02-1850-a-board-can-work-on-any-git-remote.md)). A card's lane follows who acts next: one waiting only on the owner's Ready, Merge, manual steps or an ask's Done sits in In Review with Action needed, and goes back to In Progress once Claude works on it again ([the lane follows who acts next, and a card waiting on the owner says Action needed](docs/adr/2026-10-29-1639-the-lane-follows-who-acts-next.md)). One that hasn't started and waits only on its open questions or a prototype pick, ask or work card, stays in Todo with Action needed. An owner `item-message` on a Done card, or a question you add on one, reopens it on the board with no step from you: it waits in In Review, reading "Your reply waits on the orchestrator" and on your `waits` lines until you answer the message, then until the owner's Done (an open question puts Action needed on it at once). Answer and leave it, or start a builder on it, the only thing that moves it to In Progress ([In Progress means a builder runs](docs/adr/2026-11-09-1804-in-progress-means-a-builder-runs.md), [a message or question on a Done card reopens it until the owner's Done](docs/adr/2026-11-02-1952-a-message-or-question-on-a-done-card-reopens-it.md), [a merged card reopens on a message, and its PR badge shows the PR's state](docs/adr/2026-11-03-1843-a-merged-card-reopens-and-its-pr-badge-shows-the-prs-state.md)). `item set <key> --deps <list>` sets a card's blockers after it exists; `--blocked-until "<condition>"` blocks it on something concrete that isn't a card, which you check on your morning walk over the lanes and clear with `--blocked-until ""` once it holds, and `--block-reason "<why>"` says why for either; a time is a hold, not a block ([nothing waiting on the orchestrator is missed](docs/adr/2026-11-05-2358-nothing-waiting-on-the-orchestrator-is-missed.md)). A card that waits on another card's work (a release waiting on a fix, a step queued after a land) is blocked by it with `--deps`, not by a Next that names it: `item set --next` refuses a Next naming an unfinished card by its id or `#number` unless it is in `--deps`, so the wait shows on the card and the unblock reaches you as an `unblocked` wait. Blocking, holding or usage-pausing a card In Progress gives its build a card pause: the card stays In Progress, the builder's next progress report, call or ask (or the `builder asks --wait` it sits in) answers it to commit and stop, the board stops a headless one after 15 minutes, and once the cause clears the board resumes the builder's own session in its worktree, before the pull starts new cards. A builder in your session gets the same reply and ends its turn; the clear wakes you with `builder-resume`: tell it to carry on where it stopped, its record still open ([a card pause stops its builder at its next stopping point](docs/adr/2026-11-09-1300-a-card-pause-stops-its-builder-at-its-next-stopping-point.md)). A card In Progress with no build running (handed back, or a reopened card's build ended) stays In Progress when blocked. A blocked card In Review stays there but never lands: `land`, `merge`, auto-merge and the lander refuse or skip it, and its Merge shows disabled. A block never silences a wake ([a block past Todo bumps a build and holds a land](docs/adr/2026-11-06-0102-a-block-past-todo-bumps-a-build-and-holds-a-land.md)). A PR that changes what a page looks like carries screenshots in its description, as wave-build's build step says. **Each card and main has a version to try** ([a board's build script serves or builds each card and main](docs/adr/2026-11-01-1846-a-boards-build-script-serves-or-builds-each-card-and-main.md)). When setting up a board whose repo lacks `.kickflip/build`, write that executable repo file for the project. A repo with several build targets, such as a web front end and an iOS app, gets one executable `.kickflip/build-<target>` each, and each board picks its target in Board Settings' Build target (`settings set build-target <target>|default`); with none set the hub runs `.kickflip/build`, and main builds the same target as the board's cards ([Board Settings picks which build script a board runs](docs/adr/2026-11-05-1823-board-settings-picks-which-build-script-a-board-runs.md)). The hub runs each branch's copy with `<key> <worktree>` (key `main` for main), cwd the worktree, `KICKFLIP_BOARD=<route>`. Keep it owned by the current user and writable by neither group nor others. A website script starts its server, prints exactly `port <n>` on stdout and stays running as its server process. It listens on `HOST` (127.0.0.1), so only the hub's gated relay reaches it. Serve browser paths at `/`; each served card and main gets its own Tailscale HTTPS port, with no `KICKFLIP_BASE` ([a try build serves on its own Tailscale port](docs/adr/2026-11-01-2254-a-try-build-serves-on-its-own-tailscale-port.md)). An app script exits 0 after publishing its install: `board.mjs --site "$KICKFLIP_BOARD" item set <key> --install <url> --install-sha <head sha>`, or `main set --install <url> [--install-sha <sha>]` for main. iOS uses `itms-services://?action=download-manifest&url=https://…/manifest.plist`; Android uses an https `.apk`. Keep install files under the site's `public/installs/`. Signing still needs the login keychain unlocked on macOS. The hub owns runs and their logs in `data/try/<id>.log`, reports only failed card runs in the thread and leaves each card in its lane. Try builds wait on Tailscale; the hub refuses a run with the readiness reason until it is ready. Only the owner's Serve or Build and Auto-build start a card run; a session never starts one on its own, not even for a device app after a push, and a board rule asking for that is the owner's cue to turn Auto-build on. When the owner asks for a run in words, run `board.mjs --site <route> build <key> --asked "<the owner's words>"` (`install` is an alias), quoting their ask, card message or answer note; it refuses words the owner didn't write on the board, prints `started` and exits ([only the owner or Auto-build starts a card run](docs/adr/2026-11-02-1806-only-the-owner-or-auto-build-starts-a-card-run.md)). Auto-build cards, off by default, runs each new head when on, and the card then has no Serve or Build; otherwise the card waits for Serve or Build, shown once its branch has changes. Set `settings set auto-build on|off` only on the owner's word. Main always builds after each merge, independent of the toggle, in the hub's detached worktree, and shows its version above the lanes. A served card stops after 30 minutes without a visit; main stays up. The card badge reads Visit/Install, Visit (stale)/Install (stale), an inert Serving…/Building… spinner or Serve failed/Build failed opening its thread. Main’s red Serve failed/Build failed button opens a bottom sheet with the last 40 log lines and Retry at the recorded failed tip, even if origin has moved. Retry waits on Tailscale readiness and shows refusals in the sheet; while running it reads Serving…/Building… in orange, then closes with a toast when main is ready or refreshes the log after another failure. Maintain a broken script through a card. **Marking a PR ready for a reviewer includes the Slack link** (owner, 2026-10-24): add them to the board's reviewers if they're missing (Board reviewers, below); the hub then DMs them the bare PR link and records its ts, as Reviewers below describes. Every hub feature finds boards through one registry, `hub/boards.mjs`, so each serves both kinds alike ([one board registry for every hub feature](docs/adr/2026-10-29-1639-one-board-registry-for-every-hub-feature.md)): the hub polls every open PR on any board's card, whatever `monitor.json` watches (a card's PR is in the board's `github` repo, else its wave's `repo`; with neither, the card has no PR link and nothing polls it), and a PR's `github-change` goes to each board with an eligible changed card. Boards over their own file (`--items`) use the same GitHub tick as wave boards. The hub checks GitHub every minute while Love is here and every 5 when away, and boards draw their PR badges from that check, running no gh per PR, and wakes you only on a change, or at the daily wake when quiet hours end ([the hub checks every minute while you’re here and every 5 when away](docs/adr/2026-11-04-0226-the-hub-checks-every-minute-while-youre-here-and-every-5-when-away.md)): a `github-change {prs: [{file, id, pr, changes}]}` event, where `changes` lists `ci`, `review`, `comments`, `merged`, `mergeable`, `draft`, or `linked` (the poll just linked a PR opened by hand, so handle its CI and comments from the start), means run one GitHub tick for those PRs. A `check-github {}` event is the owner's refresh asking for a check, and `check-github {reason: "morning"}` is the hub's daily wake (8:00am by default), for either, run one GitHub tick; the morning one also has you walk every lane (Watch, above). The hub sends reviewer links and digests itself (Reviewers, below). The hub writes `checked.json` after each of its checks and sends the pushes a tick queued at its next check. When the header reads "not listening" in your own session, relaunch the watcher ([the board shows GitHub checks and Claude's activity, with one refresh](docs/adr/2026-10-29-1639-the-board-shows-github-checks-and-watcher-health.md)); it also reads so while the board's session isn't running and the hub can't wake it. When an event has waited 15 minutes while the board reads so, the hub pushes the owner "<title> isn't listening" once. A `hello` event is the hub testing a new board's links (`join --template board` runs `node $KF handshake <route>`, then asks the hub for one poll so the GitHub link passes at once): the watcher answers it itself and prints `hello <eventId> from the hub answered`. The board shows a Connecting checklist until that and the hub's GitHub check reach it; cards can start meanwhile. The In Review header's GitHub mark opens the Hub links sheet (GitHub polling, the repo fetch on a board with a repo, events, daily wakes, pushes, reviewer links). The watcher prints each broken one at once, after the rules, as `link <name> <detail>`; the mark gets a red dot only for a link still broken past its grace period, and the sheet shows it settling until then ([hub links turn red only after a grace period](docs/adr/2026-10-29-1639-hub-links-turn-red-only-after-a-grace-period.md)). Fix what is yours straight away, such as a missing reviewer link or a stopped watcher. `link hub` means the hub runs older code than its files, which the sidebar's Hub row and the hub page show in amber, never a board. The hub restarts itself once its new code is whole on disk ([the hub restarts itself on a done signal](docs/adr/2026-11-06-0010-the-hub-restarts-itself-on-a-done-signal-from-whatever-brought-the-code.md)), so a link that stays up means that restart failed (see the hub log): restart it with the command the link names: `launchctl kickstart -k gui/$(id -u)/local.claude.kickflip-hub` on macOS, `systemctl --user restart kickflip-hub.service` on Linux. Tell the owner the rest. A card that changes the hub's or a board's UI starts with an in-situ prototype before any builder touches the skill: one prototype per question, one take per option, and an open question on the card whose `url` opens it; build only after the owner picks. The prototype planner the board launches for a `prototype-request {key}` posts its page as a card question ([prototypes come only when obviously helpful or on request](docs/adr/2026-10-29-1639-prototypes-come-on-request.md)); for a `prototype-request {key?, question, note, choice}`, the owner's eye on one question asked in place of an answer, it builds takes of that whole question, following the note and the option `choice` names when it isn't null, and posts them as the round's question with `question add`, adding `round_of: "<that question id>"` beside the prototype url. The asked question reads "prototype requested", locked, and `question resolve` refuses it, until that round's `question add` with `round_of` resolves it, numbering the round and noting "Followed by prototype round N" on it; the card reads prototyping until a take is picked ([a prototype round ends with a one-take confirm](docs/adr/2026-11-02-1332-a-prototype-round-ends-with-a-one-take-confirm.md), [a question asked for a prototype is resolved, and the page moves on](docs/adr/2026-11-03-1803-a-question-asked-for-a-prototype-is-resolved.md), [a prototype request waits for its prototype](docs/adr/2026-11-04-2130-a-prototype-request-waits-for-its-prototype.md)). A question on Waiting on you with an answer sent, or resolved, is read-only and green with a Resolved badge; tapping the badge and confirming sends the record-only `question-reopen {key?, question}`, which opens the question again and writes "Question N was reopened" in the card's thread, so act only on the new answer that follows ([a sent answer is resolved in place until the page reloads](docs/adr/2026-11-05-2331-a-sent-answer-is-resolved-in-place-until-the-page-reloads.md)). No page sends `reask-request {key?, question}` now; one that arrives has the card's thread already reading a muted "re-ask requested", so write no thread message. Re-read the card's notes and thread, and ask that question again as they stand today with `question add`, adding `reask_of: "<that question id>"`; on a card with a planner running, have the planner ask it. `question add` notes "Asked again as <new id>" on the old question, which ends the request ([a resolved question is read-only and can be asked again](docs/adr/2026-11-04-2001-a-resolved-question-is-read-only-and-can-be-asked-again.md)). **The board owns the page; you write only the takes** ([the board serves every prototype from one template](docs/adr/2026-11-01-1448-the-board-serves-every-prototype-from-one-template.md)). Record the prototype with `board.mjs --site <route> prototype add <topic> --title "…" --card <file>/<id> --take A:"Label" --take B:"Label"` (topic `a-z0-9-`, each key one capital letter, labels never starting with "A. ", since the take pill shows the label alone), which prints the take files to write, `public/prototypes/<topic>/<KEY>.js`. The board then serves `prototype-<topic>.html` from its one template: the header with back to the card, the shared take pill, `?take=` and `?q=`, and a stage for the take. `prototype list` shows what is recorded, and `prototype rm <topic>` drops a record once no open question uses it. A round is take files by default, built from the repo's existing components ([take files unless a board rule asks for in situ](docs/adr/2026-11-09-1300-a-prototype-round-is-take-files-unless-a-board-rule-asks-for-in-situ.md)); a board whose rules ask for it runs the round in situ instead ([a prototype round is a page in the board's base prototype worktree](docs/adr/2026-11-06-1500-a-prototype-round-is-a-page-in-the-boards-base-worktree.md)): `prototype base` makes or moves the board's base prototype worktree on main and prints its path and the listener, `shared/prototype-frame.js`; the round is one page there built from the repo's real components fed mock data, recorded with `prototype add <topic> --served <path> --take K:"Label" … --state key:"Label" …`, and the viewer frames it at `?variant=&state=`, then sends each switch as a message the page takes with `KickflipPrototype.on((take, state) => …)`. The hub serves the base worktree while an open question links a served round. Each take file is a module, `export function render(stage, kit) { stage.innerHTML = …; return cleanup }`, rerun with a fresh stage on every switch. `kit` draws the real components fed fake data: `kit.sidebar()`, `kit.hub({usage, afterUsage, usageCard, settings…})`, `kit.cards()` and `kit.sheet(html, {title})`, with `kit.toast`, `kit.on`, `kit.fake` and `kit.esc`; `BoardUI` and `HubUI` are globals too, and `board/public/prototype-kit.js` documents each. Build each take from these, changing only what the take is about; a look-alike copy drifts from what ships (owner, on back-to-card). The stage contains its take, `position: fixed` included, so nothing covers the header or pill; links and forms in it only toast, and the listeners and timers a take adds end on the next switch. Every interaction must work on a tap. Include this prototype paragraph in the brief of any builder or agent asked to make a prototype. With each prototype, add an open question on its card: one option per take, the option ids the take keys in take order (a later round may list only some takes, still in take order), and the recommended option tagged with `recommended: true`, with `url` set to `prototype-<topic>.html?q=<question id>`, relative to the site root and stored as given. A question added on a card's topic resolves each question there that is answered and still waiting on Claude, noting "Followed by <new id>", and prints `resolved: <old id>`; a question re-asked on the same topic and prototype resolves any other unresolved one it replaces, noting "Replaced by <new id>", and prints `replaced: <old id>` ([an answered question stops waiting once Claude acts on its card](docs/adr/2026-11-01-1813-an-answered-question-stops-waiting-once-claude-acts-on-its-card.md)). Acting on a card's answers resolves them the same way, noting what acted: a build's start ("Acted on: build started"), `builder start` ("Acted on: builder started"), and a `reply` to an ask or a wave triage for the answered questions on its topic ("Acted on: replied") ([the CLI and board server do the board's housekeeping](docs/adr/2026-11-02-2044-the-cli-and-board-server-do-the-boards-housekeeping.md)). A pick, with a note or none, settles its round: the note is the build's guidance, and the build starts as any card's does ([a prototype pick is the build's go, and more of the skill moves into code](docs/adr/2026-11-03-0504-a-prototype-pick-is-the-builds-go.md)). An answer with a note and no take, the owner having cleared the pick, resolves its question and leaves the card prototyping with Next "Prototype again" until a take is picked; its owner-answer event carries `prototype_again: true`: draw the next round from the note as for a `prototype-request`, or grill when the note asks a question ([a prototype answer with no pick prototypes again, so a card is never stuck](docs/adr/2026-11-03-1646-a-prototype-answer-with-no-pick-prototypes-again.md)). A prototype question on Waiting on you shows plain options and a View prototypes button, which opens the prototype page, the full-page viewer: one take at a time, ‹ › and ←/→ switch takes keeping the scroll position, and Pick drafts the take with its note and goes back to the question, whose Send sends it ([a question's prototypes open in a full-page viewer](docs/adr/2026-11-05-1302-a-questions-prototypes-open-in-a-full-page-viewer.md)). In the app, back from the page goes to Waiting on you on that question and then to the board, however the owner arrived; the header's `backHref` applies only when the page is opened alone ([Back follows the page tree](docs/adr/2026-10-30-1125-back-follows-the-page-tree.md)). A page that links the board's `style.css` links `colors.css` before it, since every color lives there ([one colour constants file shared by the hub and every board](docs/adr/2026-10-29-1639-one-colour-constants-file-shared-by-the-hub-and-every-board.md)). The board pushes it (Push notifications, below). Add prototypes to a card's question unasked only when they obviously help. A choice with nothing to see, such as a code structure, a data flow or a policy, gets `diagram` and `practice` on each option instead (`question add` usage): boxes and arrows the questions page draws, and a line or two of what it means in practice (what a new feature must do, what changes, what it costs), so the pick is between concrete options, not labels (owner, 2026-10-24, on hb-model; [a question's takes show inline, and back goes one step](docs/adr/2026-10-29-1639-a-questions-takes-show-inline.md)). **Grill a card through open questions on the card**, never a separate page or a link ([a card is grilled through its own open questions](docs/adr/2026-10-29-1639-a-card-is-grilled-through-its-own-open-questions.md)): `board.mjs question add` each question with topic `item:<file>/<id>`, options in take order with the recommended option tagged, and a prototype page in `url` when one helps. They land in Needs you and on the open card. When the ask is to grill new work, its card is already there: sort it, then the questions. Questions that span several cards go under a declared topic (`topic add`). **Messages stand alone.** Every reply, thread line and question reads on its own in the card's thread, where the owner reads it: name cards by their label (e.g. #96), and a pointer such as "above", "below" or "here" must make sense in the card's own thread, never point into this session. The owner reads only the board, not this session.
89
+ **Board template** (`--template board`, `~/.claude/skills/kickflip/board/`): a work board over item files. A builder reads starting until its first progress line. A headless builder the board launched reads from its process: quiet, in grey, once 5 minutes pass with no progress line and no change to its Claude transcript, and stopped, in grey, once its process is gone without done and the board has stopped relaunching it (a first exit relaunches within a minute); any other running builder reads stale, its line grey, once 10 minutes pass with no progress line and no change to its Claude transcript (from its start before its first progress; a run with no readable transcript has progress lines alone) ([a card's status word comes from a signal the board checks](docs/adr/2026-11-05-0410-a-card-status-word-comes-from-a-signal-the-board-checks.md)). A silent or gone builder reads grey "stale" in its card's footer status and is a `stale` kind on the orchestrator's list, waking you once per spell like any wait; there is no nudge, since the owner reaches you by a message in the card's thread. Check the builder's process and log, restart or finish the run as needed, and write one thread line on the card saying what you found. When you can't restart it, flag it: `item stall <key> --reason "<why>"` stops its run, keeps its worktree, frees its slot and leaves it in its lane reading red "stalled", an Action needed "stalled: <why>" with one push, waiting on nobody but the owner; their next message on the card clears it and reaches you ([stale is automatic, stalled is the orchestrator's flag](docs/adr/2026-11-06-1252-stale-is-automatic-stalled-is-the-orchestrators-flag.md)). To stop a run the board launched, never use a raw kill: `builder stop <key>` stops a card's headless builder, lander or rebase run, and `land stop <key>` its land with the suite, each saying what it stopped. To put a card's land first, bump it (`item bump <key>`); `land queue` lists the order ([the orchestrator stops the board's own runs](docs/adr/2026-11-05-1809-the-orchestrator-stops-the-boards-own-runs.md)). For a parallel part of a card's work, ask the board for a helper rather than an in-process subagent it can't see or count: `agent launch <key> --name <n> --task "<t>" [--writes]`. The board launches it headless; one that writes takes an implementer slot and works in its own worktree off the card's branch. `agent wait <key> --name <n>` prints its hand-back, and `agent merge` brings in a writing helper's branch ([the implementer limit counts agents, and any agent on a card can ask the board for helpers](docs/adr/2026-11-06-0425-the-implementer-limit-counts-agents-and-a-card-spawns-helpers.md)). Every write an agent makes to a board site goes through `node ~/.claude/skills/kickflip/board/bin/board.mjs --site <route> <command>`: replies, thread lines, question topics and questions, item status and `next`, and builder records. Its usage text lists the commands. Hand-edited JSON skips the checks the pages rely on. PreToolUse hook (`hooks-plugin/hooks/board-data-gate.mjs`) denies Edit and Write on a board site's `board.json`, its `data/**/*.json`, its item file and its cards' notes `.md` files, naming the `board.mjs` command that makes the change ([a hook refuses hand edits to board data files](docs/adr/2026-11-05-2330-a-hook-refuses-hand-edits-to-board-data-files.md), [the board owns a card's notes file](docs/adr/2026-11-09-1100-the-board-owns-a-cards-notes-file.md)); Bash stays open, but a notes file is read-only. Write a question draft for `question add --file` in the site's `drafts/` folder, where Edit and Write still work. A new card is `board.mjs item add <file> --title …`, never a hand edit of an item file. Yours carries `--phase <s>` and its `--relate <keys>` so it is filed and linked in that one call, while an agent's has no `--phase` and comes back to you as `card-added`: it makes the card's ticket, names the card from it and prints `<label> added as <key>`; use that key, and pass `<file>/<id>` only to import a card with its own id ([a card is named by its board's ticket source](docs/adr/2026-11-02-2100-a-card-is-named-by-its-boards-ticket-source.md)). A card filed from another card's thread, grill or answer, a follow-up included, takes `--parent <that card's key>`; one from the + has none ([a follow-up is a work card with a Parent](docs/adr/2026-11-03-0526-a-follow-up-is-a-work-card-with-a-parent.md)). A board serves `GET /_claude/needs` itself, one item per Needs you line. The + sends an `ask` event, which arrives as a New `T-<n>` card at the top of Todo, titled from the ask's first line with the owner's message its first thread line, until you sort it ([the + makes a New card, which Claude files, folds or answers](docs/adr/2026-10-29-1639-the-plus-makes-a-new-card.md), [every ask is a task card from the moment it arrives](docs/adr/2026-11-09-1900-every-ask-is-a-task-card-from-the-moment-it-arrives.md)). **You sort New cards** ([the orchestrator sorts new tasks itself](docs/adr/2026-11-07-0115-the-orchestrator-sorts-new-tasks-itself.md)): each new task, each owner message in a New card's thread, and each `card-added` card wakes you, and waits on your list as an `intake` wait until it is sorted. Take them from the top: sort the card (`item notes`, then `item set <key> --phase …`), merge it into the card it's about (`item relate-ask`), or answer it (`reply <key>`), as below. A New card reads a grey "waiting" until the watcher marks it working, then "thinking". **The ask is the work item from the start** ([every ask is a task card from the moment it arrives](docs/adr/2026-11-09-1900-every-ask-is-a-task-card-from-the-moment-it-arrives.md)): its card wears a New mark where its ticket would be until you sort it with `item set <key> --phase …` (`--title` renames it). Answered with `reply <key> --text … [--title …]`, it waits in In Review for the owner's Done, and an owner reply there waits on you as any thread message. Merged with `item relate-ask`, it is gone: its thread shows in the other card's, and the owner's banner names that card. No ask draws as its own row: the board server files every ask with no card as its T-<n> card, an old one Claude had answered closed in Done at its answer time ([old asks migrate into cards and the ask-only records retire](docs/adr/2026-11-09-2000-old-asks-migrate-into-cards-and-the-ask-only-records-retire.md)). **Every new task is grilled or prototyped at once, unless the owner chose Implement** ([every new task is grilled or prototyped at once](docs/adr/2026-11-04-0131-every-new-task-is-grilled-or-prototyped-at-once.md)). **Linking is part of filing** ([the orchestrator links a new card when it files it](docs/adr/2026-11-05-0130-the-orchestrator-links-a-new-card-when-it-files-it.md)). Before you set a new card's state, check the cards still pending (Todo and In Progress) for ones it overlaps, depends on or would duplicate. Link them in the same call that sorts it: `item set <key> --relate <keys> --phase …` after its `item notes` (`item add <file> --title … --notes-from <draft.md> --relate <keys> --phase …` for a card of your own) (`--relate` adds links and keeps the rest, `--unrelate` takes them off on both cards, `--related` replaces the list; `--deps` for a card it truly waits on). Then add a short `Related` section to each linked card's notes and to the new card's with `item notes`, naming the other card and how they overlap. A card never reaches Todo unlinked: its planner launches from there, and the planner's and builder's briefs list the card's Related to, Parent and deps with their notes paths, so they gather the broader context from your links. On a board `item add` refuses a card with no `--phase`, naming grilling and prototyping, so every card an agent adds (a builder's or planner's follow-up, or one you file, held ones included: `--held` holds it as it is filed) is filed at once; a `card-added {key, title}` event is only an older card still unfiled, which you file: add to its notes with `item notes`, link it the same way, then set its `--phase`; that clears New, and the board grills it on arrival. `item add` and `item set` refuse `--phase ready`, bar a Quick build ask's card: an agent's follow-up reaches ready only through staging. A card filed grilling gets its questions from the board's planner, so write its notes and ask nothing on it yourself. The New task sheet sends with one of two buttons, Discuss (⌘↵) or Implement (⌥↵); an Implement ask comes as `ask {text, quick: true}`, and its thread reads "Implementation requested" under it. On a Discuss ask, file the card `--phase grilling` with notes that brief its grill, and dispatch nothing: with Auto implement on, the board launches a grill headless on every card that lands in Todo, however it was filed (an ask, `item add`, the +, an import), up to Maximum parallel planners at once (`setting max-planners <n>`, 3 by default, set with `settings set max-planners <n>` only on the owner's word), the rest waiting in board order. An arrival is a work card in Todo that isn't ready, staging or held, with no planner record and no questions yet; it gets one grill, never a prototype straight away, and the grill asks for a prototype round when the card changes a UI ([every card arriving in Todo is grilled by the board](docs/adr/2026-11-04-2359-every-card-arriving-in-todo-is-grilled-by-the-board.md)). A grill ends with its prototype gate, so the owner's Send settles every card; where the owner asked for prototypes, or a board rule wants a UI prototype first, it ends prototyping. A card has no status: it stores its lane (Todo, In Progress, In Review, Done), which a build's start, a handover (`--pr`, `--pushed`, a verified merge-ready build), a block and a close move at once, and the board server moves the rest as GitHub, messages and holds change, each move with a "Moved to <lane>: <why>" thread line; `item set --status` is refused ([a card stores its lane, and facts replace statuses](docs/adr/2026-11-07-1400-a-card-stores-its-lane-and-facts-replace-statuses.md)). Don't watch Todo or write grill prompts; a finished grill's questions wait on you first, as a `screen` wait, before they reach the owner, and you act on each `owner-answer`. An Implement ask goes straight to ready, since your filing is its judgment: check it against the whole board as you would a staging card (the checklist under Staging, below), then write its plan with `item notes <key>`, never on the card, and sort it `item set <key> --phase ready --size <small|large>`. Staging is only for the owner's replies on a card that exists. A Todo card's reply box sends with Reply (⌘↵) or Implement (⌥↵), the card's only Implement, and each message's thread footer names its button ([each text box sends its intent from a key](docs/adr/2026-11-04-2343-each-text-box-sends-its-intent-from-a-key.md), [Implement in the thread queues the card for the orchestrator](docs/adr/2026-11-05-0300-implement-in-the-thread-queues-the-card-for-the-orchestrator.md)). Reply comes as `item-message {key, text, intent: 'reply'}`; answer it as any message. Implement comes as `item-message {key, text, intent: 'build'}`: the board has already staged the card in Todo, unheld it, resolved its open questions "Skipped: you tapped Implement" and written the words into its notes verbatim (its footer reads "Implement", the watcher's line "Implement asked on <card>"). A Reply on a ready card stages it the same way. **Staging, then ready** ([staging, then ready](docs/adr/2026-11-07-0700-staging-then-ready.md)): staging is the state the board sets on the owner's Send that leaves an unstarted card with nothing open (a gate "no" included), on an Implement, and on a Reply to a ready card; only the board sets it. `item set --phase ready` takes a card only from staging, or one already ready. The orchestrator's wait on a staging card reads "Judge the staged card against the whole board": this is where the board is freshest before the build begins, so judge it against every open card, not only its own notes. Read its notes, where the owner's words already are, and its thread; then check that no open or merged card already covers it or overlaps its files, that the cards it depends on or that should land first are linked with `--deps`, that a related card's settled answers don't contradict it, that its size and model fit what the notes now ask, and that nothing it asks is left as a question for the owner. Then `item set <key> --phase ready --text "<what you checked>"` (with its `--size`), whose one line goes into its notes under Ready (orchestrator) for its builder, and which `item set` refuses to leave out on a staging card; or `--phase grilling` or `--phase prototyping` for another round, which the board starts itself ([every signal that wakes the orchestrator says what to do](docs/adr/2026-11-07-0043-every-signal-that-wakes-the-orchestrator-says-what-to-do.md)). Where its notes answer a split question "Split as proposed", file the split instead (**A grill can propose a split**, below). A staging card is never pulled; a ready card waits for the pull like any other, so never start that build yourself. A question added on a ready or staging card moves it to grilling, and so does the owner's Grill or Prototype tap. An empty Implement on a Todo card records no event: the board server writes its "Implementation requested" line, stages the card, with a gray "Marked as staging" line after it, and starts no build: the orchestrator reviews the card and sets it ready, which writes a green "Marked as ready" line. Every owner move into staging (answers, Implement, Reply) writes that same "Marked as staging" line. **Every button without a text box, and Implement with nothing typed, posts only a status line in the thread, keyed by `command`** in `/api/thread` (and in the thread file for the lines the board server writes); read a key only when the card has no clearly defined next step: `command: implement` "Implementation requested" (the owner wants it built as it is; the board has already started it), `command: prototype` "Prototype requested", `command: grill` "Grill requested", `command: visual` "Visual requested" (each comes with its event, and the board server launches that planner or agent), `command: reask` "Re-ask requested" (ask that resolved question again), `command: hold` "Held" or "Held until <time>" (leave the card alone until it resumes), `command: resume` "Resumed" (it can move again) and `command: done` "Marked done" (the owner closed it). The board writes four more as your lines when a link changes, each naming the other card in its `card` field: `command: related` "Related to", `command: unrelated` "Unrelated from", `command: followup` "Follow-up" (in a Parent's thread) and `command: followup-of` "Follow-up of" (in the child's); they ask nothing of you. Each has its icon in `board/public/ui.js` MARK_ICONS ([a button without a text box posts a keyed status line](docs/adr/2026-11-06-0021-a-button-without-a-text-box-posts-a-keyed-status-line.md)). On a New card (`key` `ask:<eventId>`) file an Implement the same way. An ask whose work still has an outcome pending after you act on it (a release run, a deploy, a CI run, a push someone else must see) is a card, not a thread answer: file it with `item add`, link the ask, and keep it blocked with `--blocked-until "<the outcome it waits on>"` until that outcome is known, then close it with `--done --text` or say what failed. A `visual-request {key, text?, files?}` (the thread's image, or /visual) asks for a visual, a one-off HTML page answering in the thread: the board server launches a headless visual agent on Claude Sonnet beside any other agent on the card (one visual at a time per card), which places its page with `visual add <key> --file <page.html> --title <t>` and a link line in the thread; it wakes nobody ([a visual is a page an agent draws for a thread](docs/adr/2026-11-05-1921-a-visual-is-a-page-an-agent-draws-for-a-thread.md)). A `grill-more {key, text?, files?}` (the thread's fire, or /grill) or a `prototype-request {key, text?, files?}` (the thread's eye, or /prototype, or the owner's eye on one question) is the owner's request: the card already reads a grey "preheating" until the planner picks it up, then "grilling" or "prototyping" in the lane's colour, and the thread a muted "Grill requested" or "Prototype requested", or, with text, the owner's message with that status in its footer, and the board server has already launched that planner itself, headless in the board's repo folder with a brief built from the card and the owner's text and files (Claude Opus for a grill, Claude Sonnet for a prototype), and written "Planner launched on <model> in <folder>." in the thread; neither event wakes you ([the hub launches every agent from the card](docs/adr/2026-11-04-2130-the-hub-launches-every-agent-from-the-card.md)). A prototype request is answered only by a prototype: never answer it in the thread instead. One still waiting 30 minutes on, with no prototype agent running on the card, comes back as `prototype-overdue {key, request, question?, since}`, once per request: dispatch its prototype agent now ([a prototype request waits for its prototype](docs/adr/2026-11-04-2130-a-prototype-request-waits-for-its-prototype.md)). First check it against the other boards: each one's title and description in `~/.claude/kickflip/manifest.json`, its folder (`node $KF sessions`) and its cards. Only when another board clearly fits better, add an open question on the New card (`question add`, topic `item:<file>/<id>`, the card's): "Move to <board>" recommended, then "Keep here", each with `diagram` and `practice`. On Move, run `board.mjs --site <route> ask move <eventId> --to <other route>`, which makes it a New card there and wakes that board's session, then `question resolve`; on Keep, sort it here. Hand a long build or investigation to a builder, which reports in the card's thread. The owning session only triages events, writes board lines and dispatches: a full test suite, a scratch hub, screenshots, `board.mjs land` and anything else that takes more than a few seconds run in a background agent or background task. A session sitting in foreground work leaves events waiting, and its cards read stale. The watcher marks each ask, thread message and wave triage it prints as Working, so the page reads "Working on it" until you reply, write a later thread line on its card, reply to its ask, turn or fold its ask into a card, or the card closes. Answer a New card with `board.mjs reply <key> --text "…"` (or `--file`), in markdown. An answer never pushes: the board's answer banner and the thread's unread mark carry it ([a push goes out only when something waits on the owner, on the hub's schedule](docs/adr/2026-10-29-1639-pushes-only-when-something-waits-on-the-owner.md)). The answered card waits in In Review for the owner's Done. A card's **Notes** is your understanding of the task so far: what was asked, what's settled, what's still open. A card filed from an ask opens its notes with the owner's words verbatim under "## Asked (owner, <date>)", then a short "## What it is" in plain words. The board owns the file ([the board owns a card's notes file](docs/adr/2026-11-09-1100-the-board-owns-a-cards-notes-file.md)): `item add` makes the card's own `<id>-notes.md` beside its item file, seeded with `--notes-from <draft.md>` or `--notes <text>`, and every later write is `board.mjs item notes <file>/<id> --heading "<heading>" --file <draft.md>`, which appends a `## <heading>` section, or `--from <other key>` to fold another card's notes in. Write each draft outside the board's data folder; a draft that is any card's notes file, live, done or archived, is refused, naming that card, and the notes file itself is read-only. Two cards never share notes: link them with `--relate`. Append a dated section as the grill settles things (later sections override earlier ones) rather than freezing it as a plan; the thread keeps the short news. `item notes` resolves the card's answered questions still waiting on Claude, noting "Recorded in the card's notes", and prints `resolved: <id>` for each. The open card's details list ends with a "Notes ↗" link, which opens `notes.html`, a view that renders the file for the phone, or the item's short `notes` text when it has no file ([notes replace the full plan, and a card starts on its own](docs/adr/2026-10-29-1816-notes-replace-the-full-plan-and-cards-start-on-their-own.md), [notes is a link in the details list, with no stored summary](docs/adr/2026-10-30-1626-notes-is-a-link-in-the-details-list.md)). `item set --title` renames a card. When an ask is about an existing item, fold it in with `board.mjs item relate-ask <eventId> <file>/<id> --summary "<one concise line>" --title "<the ask in plain words>"`: the New card goes, and the owner's message moves into the item's thread marked Moved, with the summary after it. When the owner says it went to the wrong card, relate-ask it to the right one, or run `board.mjs ask unfold <eventId>` to give it a New card again. An `item-message` whose `key` is `ask:<eventId>` is the owner replying in a Done ask's thread: answer it with `board.mjs reply <its eventId>` or `board.mjs thread ask:<eventId> --text …`, as in a work item's thread. A thread message (`thread --text`, a close's `--text`) holds at most 2000 characters, and a longer one is refused: rewrite it shorter, or put the detail in a page (`visual add`) and link it. Your thread messages and replies draw as compact markdown (lists, `**bold**`, `code`, short headings), so write a multi-part one as a list; the owner's own messages stay as typed, and a visual stays an HTML page. The board writes its own holds, launches, blocks and faults as status lines, so never repeat one as a message. An `ask-withdrawn {id}` event (with `key` from a thread) deletes a pending message ([a pending ask or thread message can be deleted or edited, and a pending ask bumped](docs/adr/2026-10-29-1639-a-pending-ask-can-be-deleted-or-bumped.md)). An `ask-edited {id, text}` event (with `key` from a thread) replaces a pending message's text: use the new text, and if you had started, adjust the work to it and say what changed. Only what the owner types in a thread is a message to you; a button tap changes the card or starts an agent in the board server, and wakes you only where noted ([only typed thread messages wake the orchestrator](docs/adr/2026-11-06-1100-only-typed-thread-messages-wake-the-orchestrator.md)). A `card-bump {key}` event bumps a work card, and is the one tap that still wakes you, since the owner wants it done urgently ([a card that hasn't started, or is running, can be bumped](docs/adr/2026-10-29-1639-a-card-that-hasnt-started-can-be-bumped.md)): the board already takes a bumped card first in the pull, planners, landers, rebase runs and the land queue, starting it past the cap and bumping out the newest unbumped build, which pauses In Progress, when every slot is full, so a card that hasn't started needs nothing from you; a bumped card's next steps (its builder's questions, review fixes, CI), and its `waits` lines, which come first and read `bumped`, come ahead of your other work until it is unbumped or closes ([a bump marks the priority through every lane](docs/adr/2026-11-06-1700-a-bump-marks-the-priority-through-every-lane.md)). On the `card-bump` wake, handle each of that card's `waits` lines before anything else; when it has none, write nothing and leave it to the board ([every signal that wakes the orchestrator says what to do](docs/adr/2026-11-07-0043-every-signal-that-wakes-the-orchestrator-says-what-to-do.md)). A `card-hold {key, hold, until?}` event is the owner's Hold (`hold: true`, with `until` when they picked a time) or Resume (`false`) on a work card, and wakes nobody. A held card never starts on its own; the board server has already stopped the held card's planner and given its build a card pause, so stop nothing yourself, and start no new builder, review fixes or CI reruns while it is held. On Resume the board server resumes the paused build's own session, or relaunches the grill or prototype the hold stopped, and the pull takes a card whose hold stopped nothing; a card a relaunch leaves with nothing running reaches you as an orchestrator wait. When the owner's words give a time to pick a card up, hold it with `item set <key> --pick-up-at <ISO time>` (no offset is the Mac's local time). Within a minute of that time the board server resumes the card itself and appends `card-unblocked {key, until}` unless a dep is unfinished ([a card can be held until a time](docs/adr/2026-11-02-1727-a-card-can-be-held-until-a-time.md)); the board relaunches what the hold stopped, as on Resume. A `card-done {key}` event is the owner closing a card from an In Review thread's Done or a Todo card's Close: the board server has already stopped the card's headless builder and closed its records (a land in progress finishes), so it wakes nobody. Closing a card yourself (`item set <key> --done`) takes `--text "<what was done, or why it closes without landing>"`, which becomes its last thread line and says whether it merged, was given up (a duplicate, not feasible) or was superseded; it moves the card's ticket to Done whatever the reason. Never leave a card open because part of it can't be done: close it and file a follow-up card for what stays open. Closing resolves each of its questions that has an answer, noting "Closed with the card"; one still open, with no answer yet, stops it, and the refusal names that question. `--force` closes the card anyway and resolves that one too. Never touch GitHub for it: an open PR stays as it is. The owner's Merge on a card whose PR is approved, green and CLEAN merges it in the board server and records no event, so it never wakes you; a refusal is a thread line, which ends the button's "Merging…" ([the Merge tap and auto-merge run in code](docs/adr/2026-11-04-2045-the-merge-tap-and-auto-merge-run-in-code.md)). A card whose open questions are all answered goes to staging, and from ready the pull starts it without waiting for a go; `unblocked: <key>` or a `card-unblocked {key}` record means a dep or hold no longer stops it, and the pull takes it ([notes replace the full plan, and a card starts on its own](docs/adr/2026-10-29-1816-notes-replace-the-full-plan-and-cards-start-on-their-own.md)). The Implement tap on a ready card and Auto implement's pull both start the build in the board server: it makes the refusals a build's `builder start` makes, picks the builder (claude with a model, or codex), makes the worktree, marks the card building and clears its Next, then launches the builder itself, headless in the worktree (`claude -p`, or `codex exec` under workspace-write for a codex pick) with a standard brief built from the card's notes and the rules, and writes "Builder launched on <model> in <worktree>, session <id>." in the thread; no event reaches you. The builder's own first step is `builder start <key> --kind build`, which takes up the record the board opened; its first status line then replaces "starting". A refused tap, or a launch that fails, puts the card back in Todo with the reason in its thread ([a Build tap starts the build in the board server](docs/adr/2026-11-03-0219-a-build-tap-starts-the-build-in-the-board-server.md), [the hub launches every agent from the card](docs/adr/2026-11-04-2130-the-hub-launches-every-agent-from-the-card.md)). `item set --phase ready` refuses a card without `--size`, without a notes file, or whose notes don't name the id of each question the owner answered on it, and marking it ready resolves those questions, so record every answer in the notes before marking it ready. The builder asks you as any builder does, and finishes its own work with `builder done --text`, rebasing and resolving conflicts itself; finishing never comes to you. A build with calls hands back as before: verify them (`builder verified`, with `--title "<type>(<scope>): <summary>"` to title the draft PR it opens on a GitHub board from what the whole diff does), which finishes the card in the same step; when a question on the card was still open, or that finish refused, the server launches a headless lander once no question is open, which acts on the owner's answers and finishes it, so don't land it yourself ([builders launch headless, check their notes and land on their own](docs/adr/2026-11-04-0306-builders-launch-headless-check-their-notes-and-land-on-their-own.md)). With Auto implement Todo cards on (`setting auto-pull on|off`, set with `settings set auto-pull on|off` only on the owner's word), the board pulls ready Todo cards into free implementer slots and launches their builds, one per free slot, up to Maximum parallel implementers (`setting max-implementers <n>`, 10 by default, set with `settings set max-implementers <n>` only on the owner's word), counting cards building or in Orchestrator review ([an idle board pulls in its top Todo card](docs/adr/2026-11-02-1754-an-idle-board-pulls-in-its-top-todo-card.md), [auto implement fills In Progress up to Maximum parallel implementers, on every board change](docs/adr/2026-11-04-0057-auto-implement-fills-in-progress-up-to-a-cap.md)). Only ready cards are pulled ([the idle pull takes ready cards first](docs/adr/2026-11-03-1631-the-idle-pull-takes-ready-cards-first.md)); every other card that lands in Todo gets its grill on arrival ([every card arriving in Todo is grilled by the board](docs/adr/2026-11-04-2359-every-card-arriving-in-todo-is-grilled-by-the-board.md)). A `pr-review {pr, head, repo, title, author, url, touches, asked}` event, with auto review on, asks you to review a teammate's PR that touches the listed cards or asks the owner: read its diff and the reviews already on it, then `review post <pr> --file <review.md> --read-at <when you read it>` with only points no other review made (it adds the header and marker, posts one Comment review and records it posted, and refuses if another review landed since you read), or post nothing and `review record <pr> --state posted --file <note.md>`. When it finds a blocker, disagrees with a decision on a card or clashes with a card in progress, hold it with `review record <pr> --state needs --file <draft.md>` instead; the owner's Post it or Skip comes back as `review-answer {pr, answer}`, after which you `review post` it (or don't, and record it posted) ([each board reviews incoming PRs that touch its work, in an Auto Review lane](docs/adr/2026-11-03-1731-each-board-reviews-incoming-prs-that-touch-its-work.md)). An `overnight-triage {date, topic, cards}` event is the board asking for its overnight triage, with auto-triage on (`setting auto-triage on|off`, set only on the owner's word): it goes out once a night from the middle of quiet hours, when two or more cards, `cards`, wait on the owner's open questions and nothing builds. First read those cards' open questions against each other. Questions that ask the same thing become one, on a single card ([a question for several cards moves to the card built first](docs/adr/2026-11-05-1000-a-question-for-several-cards-moves-to-the-card-built-first.md)): pick the card the pull would build first, and run `question move <id>,<id>,… --to <that card> --block <the other cards, in build order>`. The first id moves onto that card, the others resolve "Duplicate of <ref>'s question <id>", and each blocked card is blocked by the one before it and related to the first. The owner's answer lands on that one card and starts it as any answer does; a blocked card's builder reads the related card's thread and notes once it is done. Cards whose grills show they are the same work merge as a clear duplicate does below. Then check each open question left against the owner's earlier answers on other cards and their long-running context, such as what they said in other cards' threads and notes, not against ADRs or CONTEXT.md, which the grill already read. When one of those answers settles a question and you are confident it carries over, `question add` it again on the same topic with a new id, its options unchanged and `suggested: {option, card, answer, reason}`: the option, the earlier card's ref, the owner's answer in their words and your own words for why it carries over (the question reads "Orchestrator choice: <reason>" in blue under the option's label). Then `question resolve` the old one with `--note "Replaced by <new id>"`. Never act on a suggestion yourself: the page pre-checks it, and it waits for the owner's Send ([overnight triage suggests your earlier answers](docs/adr/2026-11-04-2200-overnight-triage-suggests-your-earlier-answers.md)). Leave the other questions you could answer yourself as they are. Then read the Todo cards and stale reviews against each other and against merged work, leaving Done alone (old Done cards leave by the archive rule, [the board keeps the newest 100 Done cards](docs/adr/2026-11-04-0307-the-board-keeps-the-newest-100-done-cards.md)), and find duplicates, cards a newer card covers, cards merged work already did, and deps that no longer hold. Link related cards (`item set --relate`) and merge a clear duplicate into the newer card yourself, dropping the older with a thread line naming the one it went into. A close, or anything you aren't sure of, is one question per finding on `topic`, all in one `question add` array; quiet hours hold their push until morning. Then reply to the event, even when you changed nothing ([triage runs once overnight on cards waiting on your answers](docs/adr/2026-11-04-1900-triage-runs-once-overnight-on-cards-waiting-on-your-answers.md)). Set `deps` for work that waits on other cards. When a close finishes the last dep, it prints `unblocked: <key>` and appends a `card-unblocked {key}` event; leave a held card held until the owner unholds it ([cards wait on explicit blocked-by links](docs/adr/2026-10-29-1639-cards-wait-on-explicit-blocked-by-links.md), [Build on a blocked card queues it, and blocked, bumped and Action needed leave the badges](docs/adr/2026-11-03-0301-build-on-a-blocked-card-queues-it.md)). Every builder you start for a card works in its own git worktree, never in the folder you, a running app or the hub use ([every builder works in a worktree, and the hub's own fault shows once](docs/adr/2026-10-30-1654-every-builder-works-in-a-worktree.md)). A repo card's builder uses the board's manifest `github` and `branch` when following wave-build; it never switches the shared clone's checkout. A build's `builder start` on a board makes the card's worktree when its record keeps none, `~/.claude/kickflip/worktrees/<card id>` on branch `<card id>`, and prints `worktree: <path>`; the builder's prompt names that path as the only place it edits, tests and runs scratch hubs. Right before it launches any builder agent, the session runs `board.mjs --site <route> builder start <key> --dispatch --kind <kind> [--model …]`, which opens the record (`dispatched: 'session'`) so the card reads "starting" at launch, and changes nothing on a record the Implement tap already opened (`dispatched: 'tap'`), printing "already open"; it never posts a "builder is working" line itself ([the session opens the builder record when it dispatches an agent](docs/adr/2026-11-03-0513-the-session-opens-the-builder-record-when-it-dispatches-an-agent.md), [a card reads starting from its tap, with one dispatched mark](docs/adr/2026-11-03-1718-a-card-reads-starting-from-its-tap-with-one-dispatched-mark.md)). Every builder, prototype and grill agents included (`--kind prototype` or `--kind grill`), runs, as required steps in its prompt, `board.mjs --site <route> builder start <key> --kind <kind> --label "<label>"` first, which takes up the dispatched record (the label carries no model word) (a build agent passes `--kind build`, which records the kind and model `builder pick <key>` prints), `builder progress <key> --phase <reading|building|testing|checking|landing> "<detail>"` (or `--text "<detail>"`; the board adds the phase word, so don't start the detail with it) at each milestone (a planner, kind grill or prototype, passes no `--phase`: its line reads "Preheating: <detail>" or "Prototyping: <detail>" in the lane's colour, never a builder phase word, and a `--phase` it passes is dropped) and `builder done <key>` before it hands back, so the card sits in In Progress with a live status line. Closing a card's last open record when it stays In Progress with no Next is refused: pass `builder done <key> --next "<what happens next>"`, or record a judgment call with `builder call <key>` (so `builder done` hands the card back) or `land`, which closes the record itself. A card with a step only the owner can do once its code lands (a publisher to add, a release to tag) takes `--owner-step "<the step>"` on whichever of `builder done` and `land` finishes it: it then waits in In Review with that step as its Next and its ticket open, and only the owner's Done closes it ([a card whose code landed stays in review while an owner step remains](docs/adr/2026-11-04-0158-a-card-whose-code-landed-stays-in-review-while-an-owner-step-remains.md)). When code can prove the step done, add one `--check "<name> <args>"` on the final evidence beside `--owner-step`: `tag <owner/repo> <pattern>`, `npm <package> <version-or-range>`, `run <owner/repo> <workflow>`, `gh <owner/repo> <api-path> <field>=<value>` or `url <address> [<status> | <text>]`, never a shell command. The hub's poll runs it once the code lands and closes the card when it passes; on `owner-check-broken {key, check, error}`, fix it with `item set <key> --check "<check>"`, or remove it with `--check ""`, and write one thread line saying which ([an owner step can carry a code check](docs/adr/2026-11-04-2308-an-owner-step-can-carry-a-code-check; `item set` likewise refuses a write that would leave a built card with neither ([an In Progress card always has a builder line or a Next](docs/adr/2026-11-03-0237-an-in-progress-card-always-has-a-builder-line-or-a-next.md)). The detail is plain words: what the builder is doing and why it matters to the owner, such as `--phase testing "fix for the scroll jump into Done"`. A wait on a lock or a Codex limit goes in the detail. Commits, test counts, ADR numbers, file names and screenshots go in the hand-back and the session's thread message, not the line ([a builder status line is a phase and a short detail](docs/adr/2026-11-03-0128-a-builder-status-line-is-a-phase-and-a-short-detail.md)). A build's `builder start` is the one write that marks the card building: it moves the ticket to In Progress and prints `ref: <label>`, the card's name for its commits' `Refs: <label>` trailer. `building` and `fixing` count as working only while a builder record on that card is open; with none open, its PR and other state place it as if the status were absent. `builder done` clears either status when it closes the card’s last open builder record; `item set --pr` clears either status too and closes ordinary builders while install builders keep running. When a subagent stops, a SubagentStop hook, `board/bin/builder-stop-hook.mjs`, closes the records it started and left open, but not one another agent restarted later, and not while background work the subagent started still runs (the input's `background_tasks`), since it resumes when that work ends. A skill's own hooks don't fire for SubagentStop, so the hook ships as the plugin `hooks-plugin/`, which Claude Code loads as `kickflip-hooks@skills-dir` through the link `~/.claude/skills/kickflip-hooks` (`claude plugin list` shows it); a new host needs that link. A site card's builder lands its own card: it runs the tests and checks the board at phone width in its worktree, commits there as the repo's configured user (`git -c core.commentChar=';' commit -F <file>`, or `--cleanup=verbatim`, so git keeps any line starting with "#") with a Conventional subject of at most 72 characters, no ref in it, and a `Refs: <label>` trailer, the only shape land takes, then runs `board.mjs --site <route> builder done <key> --text "<what it checked>"`. With no unverified calls that finishes the card, the one step `land` also runs, as `builder done`'s usage lists: it lands the worktree, closes the card as done with that text as its last thread line, and with the board's "Push main after a land" switch on pushes main to origin itself, so no session pushes after a land; on a GitHub board it pushes the branch and opens a draft PR instead, titled by `--title "<type>(<scope>): <summary>"` (else the first commit subject), and on a plain git remote pushes the branch ([finishing a build is one step](docs/adr/2026-11-04-1611-finishing-a-build-is-one-step.md)). A finish that fails refuses with the reason and the builder stays on: it fixes what the refusal names and runs `builder done` again. Only a builder that can't finish hands back, with a `builder call` naming why, then `builder done`: the card sits in In Progress reading "Orchestrator review" and unblocks nothing, and the owning session checks it, and its `builder verified` finishes it ([site cards build in parallel when their files don't overlap](docs/adr/2026-10-29-1639-site-cards-build-in-parallel-when-their-files-dont-overlap.md), [the board records what it knows, and commands make the rule calls](docs/adr/2026-11-03-0003-the-board-records-what-it-knows-and-commands-make-the-rule-calls.md)). On a refusal, fix what its line names in the worktree and finish again. **Judgment calls** ([a builder records its judgment calls and the session verifies them before land](docs/adr/2026-11-03-0514-a-builder-records-its-judgment-calls-and-the-session-verifies-them.md)): every builder's brief includes these steps. Right after `builder start`, it records each gap or ambiguity in its brief as `builder call <key> "Question: …"`; with any, it runs `builder done <key>`, which hands the card back for them, and stops, its report the questions. Answer them from the card's notes and thread, asking the owner on the card only what those don't settle, and resume it with SendMessage; its `builder start` then resumes the record, calls kept. While building, it records each judgment call as it makes it, `builder call <key> "<call>"`, one plain line each. A builder with calls doesn't finish: `builder done <key>` hands the card back for them to be verified, and its report lists them. Check each (`builder calls <key>`) against the owner's words and the other cards: one that conflicts with what the owner said goes to the owner as a question on the card, any other wrong one back to the builder by SendMessage. Then run `builder verified <key> [--note "<what you checked>"]`, which finishes the card in the same step, the note its closing line; while a question on the card is open it says so and the card waits, and a finish that fails keeps the mark and says why. `land` refuses while a record on the card has unverified calls. **Builder asks** ([a builder asks the orchestrator mid-build, and only what it defers reaches the owner](docs/adr/2026-11-04-0247-a-builder-asks-the-orchestrator-mid-build.md)): a builder's brief says it decides, records the call and carries on, and asks you only when blocked (every way forward would likely be thrown away: a spec that contradicts itself or the code, a rule that needs the owner's go before code is written, or a fact only you have; [the blocked-only rule](docs/adr/2026-11-07-1300-a-builder-asks-the-orchestrator-only-when-blocked.md)): then it runs `builder ask <key> "<question>"`, waits with `builder asks <key> --wait`, and hands the question back as a "Question:" call after 30 minutes without a reply. A problem it finds outside its card is a "Found: …" call for you to file at review; it asks at once only when that stalls other cards' builds or lands. The ask shows in the card's thread as "Claude Opus builder" (by its model) and wakes you as a `builder-ask {key, ask, agent, text}` event; the card itself stays quiet. Answer from the card's notes, thread and the owner's words with `builder answer <key> <ask> --text "<answer>"`, or, when you aren't confident or the owner's opinion is wanted, `builder defer <key> <ask> --text "<what to carry on with>"`: never ask the owner mid-build. Both show in the thread as Orchestrator. A deferral is a "Question:" call on the builder's record, so its build hands back to you; after you've reviewed everything else, and before a draft PR or In Review, put it to the owner as a card question naming the ask (`"ask": "<ask>"` in the question file), which `builder verified` requires. The card then shows Questions and "1 new question", with no Action needed. **A repo card's built work always goes straight to a draft PR** once it is checked (owner, 2026-10-23): on a GitHub board the finish (`builder done --text`, or your `builder verified` on a handed-back build) pushes the card's branch, opens the draft with `gh pr create --draft` and records it as `item set --pr` does, closing the builder records. A PR opened by hand on the card's branch, a same-repo head named by the card id, is linked by the hub's poll as `item set --pr` does, with the thread line "Found PR #12 on branch GH-230." and a `linked` change ([the poll links a PR opened by hand](docs/adr/2026-11-05-1000-the-poll-links-a-pr-opened-by-hand-on-a-cards-branch.md)); run `item set <key> --pr <n>` yourself only for a PR on another branch. Either way the card sits in In Review with the PR, with Action needed linking to it once it waits on the owner, also while the owner tries it on a test deploy; a ready PR whose CI fails reads Next "Fix the failing CI" there until you start a builder to fix it, which moves it to In Progress ([In Progress means a builder runs](docs/adr/2026-11-09-1804-in-progress-means-a-builder-runs.md)). A card whose work spans repos holds a PR in each: run `item set <key> --pr <owner/repo#n>` once per PR (it adds, never replaces; a bare number is the board's repo). Each PR gets its own badge and polling, the least-ready one decides the lane and Next, `merge` merges them all in order, and `pr` prints a line per PR ([a card holds several PRs across repos](docs/adr/2026-11-03-1904-a-card-holds-several-prs-across-repos.md)). A board whose repo is a plain git remote (manifest `remote`, no `github`) has no PRs: the finish pushes the card's branch to origin and records it as `item set <key> --pushed <branch>` does (by hand: `git push origin <branch>` in its worktree, then that command), so the card waits In Review on the owner's merge; the hub's poll moves it to Done once the branch is merged into the board's branch or gone from the remote, with a thread line ([a board can work on any git remote](docs/adr/2026-11-02-1850-a-board-can-work-on-any-git-remote.md)). A card's lane follows who acts next: one waiting only on the owner's Ready, Merge, manual steps or an ask's Done sits in In Review with Action needed, and goes back to In Progress once Claude works on it again ([the lane follows who acts next, and a card waiting on the owner says Action needed](docs/adr/2026-10-29-1639-the-lane-follows-who-acts-next.md)). One that hasn't started and waits only on its open questions or a prototype pick, ask or work card, stays in Todo with Action needed. An owner `item-message` on a Done card, or a question you add on one, reopens it on the board with no step from you: it waits in In Review, reading "Your reply waits on the orchestrator" and on your `waits` lines until you answer the message, then until the owner's Done (an open question puts Action needed on it at once). Answer and leave it, or start a builder on it, the only thing that moves it to In Progress ([In Progress means a builder runs](docs/adr/2026-11-09-1804-in-progress-means-a-builder-runs.md), [a message or question on a Done card reopens it until the owner's Done](docs/adr/2026-11-02-1952-a-message-or-question-on-a-done-card-reopens-it.md), [a merged card reopens on a message, and its PR badge shows the PR's state](docs/adr/2026-11-03-1843-a-merged-card-reopens-and-its-pr-badge-shows-the-prs-state.md)). `item set <key> --deps <list>` sets a card's blockers after it exists; `--blocked-until "<condition>"` blocks it on something concrete that isn't a card, which you check on your morning walk over the lanes and clear with `--blocked-until ""` once it holds, and `--block-reason "<why>"` says why for either; a time is a hold, not a block ([nothing waiting on the orchestrator is missed](docs/adr/2026-11-05-2358-nothing-waiting-on-the-orchestrator-is-missed.md)). A card that waits on another card's work (a release waiting on a fix, a step queued after a land) is blocked by it with `--deps`, not by a Next that names it: `item set --next` refuses a Next naming an unfinished card by its id or `#number` unless it is in `--deps`, so the wait shows on the card and the unblock reaches you as an `unblocked` wait. Blocking, holding or usage-pausing a card In Progress gives its build a card pause: the card stays In Progress, the builder's next progress report, call or ask (or the `builder asks --wait` it sits in) answers it to commit and stop, the board stops a headless one after 15 minutes, and once the cause clears the board resumes the builder's own session in its worktree, before the pull starts new cards. A builder in your session gets the same reply and ends its turn; the clear wakes you with `builder-resume`: tell it to carry on where it stopped, its record still open ([a card pause stops its builder at its next stopping point](docs/adr/2026-11-09-1300-a-card-pause-stops-its-builder-at-its-next-stopping-point.md)). A card In Progress with no build running (handed back, or a reopened card's build ended) stays In Progress when blocked. A blocked card In Review stays there but never lands: `land`, `merge`, auto-merge and the lander refuse or skip it, and its Merge shows disabled. A block never silences a wake ([a block past Todo bumps a build and holds a land](docs/adr/2026-11-06-0102-a-block-past-todo-bumps-a-build-and-holds-a-land.md)). A PR that changes what a page looks like carries screenshots in its description, as wave-build's build step says. **Each card and main has a version to try** ([a board's build script serves or builds each card and main](docs/adr/2026-11-01-1846-a-boards-build-script-serves-or-builds-each-card-and-main.md)). When setting up a board whose repo lacks `.kickflip/build`, write that executable repo file for the project. A repo with several build targets, such as a web front end and an iOS app, gets one executable `.kickflip/build-<target>` each, and each board picks its target in Board Settings' Build target (`settings set build-target <target>|default`); with none set the hub runs `.kickflip/build`, and main builds the same target as the board's cards ([Board Settings picks which build script a board runs](docs/adr/2026-11-05-1823-board-settings-picks-which-build-script-a-board-runs.md)). The hub runs each branch's copy with `<key> <worktree>` (key `main` for main), cwd the worktree, `KICKFLIP_BOARD=<route>`. Keep it owned by the current user and writable by neither group nor others. A website script starts its server, prints exactly `port <n>` on stdout and stays running as its server process. It listens on `HOST` (127.0.0.1), so only the hub's gated relay reaches it. Serve browser paths at `/`; each served card and main gets its own Tailscale HTTPS port, with no `KICKFLIP_BASE` ([a try build serves on its own Tailscale port](docs/adr/2026-11-01-2254-a-try-build-serves-on-its-own-tailscale-port.md)). An app script exits 0 after publishing its install: `board.mjs --site "$KICKFLIP_BOARD" item set <key> --install <url> --install-sha <head sha>`, or `main set --install <url> [--install-sha <sha>]` for main. iOS uses `itms-services://?action=download-manifest&url=https://…/manifest.plist`; Android uses an https `.apk`. Keep install files under the site's `public/installs/`. Signing still needs the login keychain unlocked on macOS. The hub owns runs and their logs in `data/try/<id>.log`, reports only failed card runs in the thread and leaves each card in its lane. Try builds wait on Tailscale; the hub refuses a run with the readiness reason until it is ready. Only the owner's Serve or Build and Auto-build start a card run; a session never starts one on its own, not even for a device app after a push, and a board rule asking for that is the owner's cue to turn Auto-build on. When the owner asks for a run in words, run `board.mjs --site <route> build <key> --asked "<the owner's words>"` (`install` is an alias), quoting their ask, card message or answer note; it refuses words the owner didn't write on the board, prints `started` and exits ([only the owner or Auto-build starts a card run](docs/adr/2026-11-02-1806-only-the-owner-or-auto-build-starts-a-card-run.md)). Auto-build cards, off by default, runs each new head when on, and the card then has no Serve or Build; otherwise the card waits for Serve or Build, shown once its branch has changes. Set `settings set auto-build on|off` only on the owner's word. Main always builds after each merge, independent of the toggle, in the hub's detached worktree, and shows its version above the lanes. A served card stops after 30 minutes without a visit; main stays up. The card badge reads Visit/Install, Visit (stale)/Install (stale), an inert Serving…/Building… spinner or Serve failed/Build failed opening its thread. Main’s red Serve failed/Build failed button opens a bottom sheet with the last 40 log lines and Retry at the recorded failed tip, even if origin has moved. Retry waits on Tailscale readiness and shows refusals in the sheet; while running it reads Serving…/Building… in orange, then closes with a toast when main is ready or refreshes the log after another failure. Maintain a broken script through a card. **Marking a PR ready for a reviewer includes the Slack link** (owner, 2026-10-24): add them to the board's reviewers if they're missing (Board reviewers, below); the hub then DMs them the bare PR link and records its ts, as Reviewers below describes. Every hub feature finds boards through one registry, `hub/boards.mjs`, so each serves both kinds alike ([one board registry for every hub feature](docs/adr/2026-10-29-1639-one-board-registry-for-every-hub-feature.md)): the hub polls every open PR on any board's card, whatever `monitor.json` watches (a card's PR is in the board's `github` repo, else its wave's `repo`; with neither, the card has no PR link and nothing polls it), and a PR's `github-change` goes to each board with an eligible changed card. Boards over their own file (`--items`) use the same GitHub tick as wave boards. The hub checks GitHub every minute while Love is here and every 5 when away, and boards draw their PR badges from that check, running no gh per PR, and wakes you only on a change, or at the daily wake when quiet hours end ([the hub checks every minute while you’re here and every 5 when away](docs/adr/2026-11-04-0226-the-hub-checks-every-minute-while-youre-here-and-every-5-when-away.md)): a `github-change {prs: [{file, id, pr, changes}]}` event, where `changes` lists `ci`, `review`, `comments`, `merged`, `mergeable`, `draft`, or `linked` (the poll just linked a PR opened by hand, so handle its CI and comments from the start), means run one GitHub tick for those PRs. A `check-github {}` event is the owner's refresh asking for a check, and `check-github {reason: "morning"}` is the hub's daily wake (8:00am by default), for either, run one GitHub tick; the morning one also has you walk every lane (Watch, above). The hub sends reviewer links and digests itself (Reviewers, below). The hub writes `checked.json` after each of its checks and sends the pushes a tick queued at its next check. When the header reads "not listening" in your own session, relaunch the watcher ([the board shows GitHub checks and Claude's activity, with one refresh](docs/adr/2026-10-29-1639-the-board-shows-github-checks-and-watcher-health.md)); it also reads so while the board's session isn't running and the hub can't wake it. When an event has waited 15 minutes while the board reads so, the hub pushes the owner "<title> isn't listening" once. A `hello` event is the hub testing a new board's links (`join --template board` runs `node $KF handshake <route>`, then asks the hub for one poll so the GitHub link passes at once): the watcher answers it itself and prints `hello <eventId> from the hub answered`. The board shows a Connecting checklist until that and the hub's GitHub check reach it; cards can start meanwhile. The In Review header's GitHub mark opens the Hub links sheet (GitHub polling, the repo fetch on a board with a repo, events, daily wakes, pushes, reviewer links). The watcher prints each broken one at once, after the rules, as `link <name> <detail>`; the mark gets a red dot only for a link still broken past its grace period, and the sheet shows it settling until then ([hub links turn red only after a grace period](docs/adr/2026-10-29-1639-hub-links-turn-red-only-after-a-grace-period.md)). Fix what is yours straight away, such as a missing reviewer link or a stopped watcher. `link hub` means the hub runs older code than its files, which the sidebar's Hub row and the hub page show in amber, never a board. The hub restarts itself once its new code is whole on disk ([the hub restarts itself on a done signal](docs/adr/2026-11-06-0010-the-hub-restarts-itself-on-a-done-signal-from-whatever-brought-the-code.md)), so a link that stays up means that restart failed (see the hub log): restart it with the command the link names: `launchctl kickstart -k gui/$(id -u)/local.claude.kickflip-hub` on macOS, `systemctl --user restart kickflip-hub.service` on Linux. Tell the owner the rest. A card that changes the hub's or a board's UI starts with an in-situ prototype before any builder touches the skill: one prototype per question, one take per option, and an open question on the card whose `url` opens it; build only after the owner picks. The prototype planner the board launches for a `prototype-request {key}` posts its page as a card question ([prototypes come only when obviously helpful or on request](docs/adr/2026-10-29-1639-prototypes-come-on-request.md)); for a `prototype-request {key?, question, note, choice}`, the owner's eye on one question asked in place of an answer, it builds takes of that whole question, following the note and the option `choice` names when it isn't null, and posts them as the round's question with `question add`, adding `round_of: "<that question id>"` beside the prototype url. The asked question reads "prototype requested", locked, and `question resolve` refuses it, until that round's `question add` with `round_of` resolves it, numbering the round and noting "Followed by prototype round N" on it; the card reads prototyping until a take is picked ([a prototype round ends with a one-take confirm](docs/adr/2026-11-02-1332-a-prototype-round-ends-with-a-one-take-confirm.md), [a question asked for a prototype is resolved, and the page moves on](docs/adr/2026-11-03-1803-a-question-asked-for-a-prototype-is-resolved.md), [a prototype request waits for its prototype](docs/adr/2026-11-04-2130-a-prototype-request-waits-for-its-prototype.md)). A question on Waiting on you with an answer sent, or resolved, is read-only and green with a Resolved badge; tapping the badge and confirming sends the record-only `question-reopen {key?, question}`, which opens the question again and writes "Question N was reopened" in the card's thread, so act only on the new answer that follows ([a sent answer is resolved in place until the page reloads](docs/adr/2026-11-05-2331-a-sent-answer-is-resolved-in-place-until-the-page-reloads.md)). No page sends `reask-request {key?, question}` now; one that arrives has the card's thread already reading a muted "re-ask requested", so write no thread message. Re-read the card's notes and thread, and ask that question again as they stand today with `question add`, adding `reask_of: "<that question id>"`; on a card with a planner running, have the planner ask it. `question add` notes "Asked again as <new id>" on the old question, which ends the request ([a resolved question is read-only and can be asked again](docs/adr/2026-11-04-2001-a-resolved-question-is-read-only-and-can-be-asked-again.md)). **The board owns the page; you write only the takes** ([the board serves every prototype from one template](docs/adr/2026-11-01-1448-the-board-serves-every-prototype-from-one-template.md)). Record the prototype with `board.mjs --site <route> prototype add <topic> --title "…" --card <file>/<id> --take A:"Label" --take B:"Label"` (topic `a-z0-9-`, each key one capital letter, labels never starting with "A. ", since the take pill shows the label alone), which prints the take files to write, `public/prototypes/<topic>/<KEY>.js`. The board then serves `prototype-<topic>.html` from its one template: the header with back to the card, the shared take pill, `?take=` and `?q=`, and a stage for the take. `prototype list` shows what is recorded, and `prototype rm <topic>` drops a record once no open question uses it. A round is take files by default, built from the repo's existing components ([take files unless a board rule asks for in situ](docs/adr/2026-11-09-1300-a-prototype-round-is-take-files-unless-a-board-rule-asks-for-in-situ.md)); a board whose rules ask for it runs the round in situ instead ([a prototype round is a page in the board's base prototype worktree](docs/adr/2026-11-06-1500-a-prototype-round-is-a-page-in-the-boards-base-worktree.md)): `prototype base` makes or moves the board's base prototype worktree on main and prints its path and the listener, `shared/prototype-frame.js`; the round is one page there built from the repo's real components fed mock data, recorded with `prototype add <topic> --served <path> --take K:"Label" … --state key:"Label" …`, and the viewer frames it at `?variant=&state=`, then sends each switch as a message the page takes with `KickflipPrototype.on((take, state) => …)`. The hub serves the base worktree while an open question links a served round. Each take file is a module, `export function render(stage, kit) { stage.innerHTML = …; return cleanup }`, rerun with a fresh stage on every switch. `kit` draws the real components fed fake data: `kit.sidebar()`, `kit.hub({usage, afterUsage, usageCard, settings…})`, `kit.cards()` and `kit.sheet(html, {title})`, with `kit.toast`, `kit.on`, `kit.fake` and `kit.esc`; `BoardUI` and `HubUI` are globals too, and `board/public/prototype-kit.js` documents each. Build each take from these, changing only what the take is about; a look-alike copy drifts from what ships (owner, on back-to-card). The stage contains its take, `position: fixed` included, so nothing covers the header or pill; links and forms in it only toast, and the listeners and timers a take adds end on the next switch. Every interaction must work on a tap. Include this prototype paragraph in the brief of any builder or agent asked to make a prototype. With each prototype, add an open question on its card: one option per take, the option ids the take keys in take order (a later round may list only some takes, still in take order), and the recommended option tagged with `recommended: true`, with `url` set to `prototype-<topic>.html?q=<question id>`, relative to the site root and stored as given. A question added on a card's topic resolves each question there that is answered and still waiting on Claude, noting "Followed by <new id>", and prints `resolved: <old id>`; a question re-asked on the same topic and prototype resolves any other unresolved one it replaces, noting "Replaced by <new id>", and prints `replaced: <old id>` ([an answered question stops waiting once Claude acts on its card](docs/adr/2026-11-01-1813-an-answered-question-stops-waiting-once-claude-acts-on-its-card.md)). Acting on a card's answers resolves them the same way, noting what acted: a build's start ("Acted on: build started"), `builder start` ("Acted on: builder started"), and a `reply` to an ask or a wave triage for the answered questions on its topic ("Acted on: replied") ([the CLI and board server do the board's housekeeping](docs/adr/2026-11-02-2044-the-cli-and-board-server-do-the-boards-housekeeping.md)). A pick, with a note or none, settles its round: the note is the build's guidance, and the build starts as any card's does ([a prototype pick is the build's go, and more of the skill moves into code](docs/adr/2026-11-03-0504-a-prototype-pick-is-the-builds-go.md)). An answer with a note and no take, the owner having cleared the pick, resolves its question and leaves the card prototyping with Next "Prototype again" until a take is picked; its owner-answer event carries `prototype_again: true`, and the board launches the next round's prototype planner itself with the note as its guidance, whatever the note reads as, so there is nothing to do ([a prototype answer with no pick prototypes again, so a card is never stuck](docs/adr/2026-11-03-1646-a-prototype-answer-with-no-pick-prototypes-again.md), [a no-pick prototype answer starts the next round itself](docs/adr/2026-11-12-0100-a-no-pick-prototype-answer-starts-the-next-round-itself.md)). A prototype question on Waiting on you shows plain options and a View prototypes button, which opens the prototype page, the full-page viewer: one take at a time, ‹ › and ←/→ switch takes keeping the scroll position, and Pick drafts the take with its note and goes back to the question, whose Send sends it ([a question's prototypes open in a full-page viewer](docs/adr/2026-11-05-1302-a-questions-prototypes-open-in-a-full-page-viewer.md)). In the app, back from the page goes to Waiting on you on that question and then to the board, however the owner arrived; the header's `backHref` applies only when the page is opened alone ([Back follows the page tree](docs/adr/2026-10-30-1125-back-follows-the-page-tree.md)). A page that links the board's `style.css` links `colors.css` before it, since every color lives there ([one colour constants file shared by the hub and every board](docs/adr/2026-10-29-1639-one-colour-constants-file-shared-by-the-hub-and-every-board.md)). The board pushes it (Push notifications, below). Add prototypes to a card's question unasked only when they obviously help. A choice with nothing to see, such as a code structure, a data flow or a policy, gets `diagram` and `practice` on each option instead (`question add` usage): boxes and arrows the questions page draws, and a line or two of what it means in practice (what a new feature must do, what changes, what it costs), so the pick is between concrete options, not labels (owner, 2026-10-24, on hb-model; [a question's takes show inline, and back goes one step](docs/adr/2026-10-29-1639-a-questions-takes-show-inline.md)). **Grill a card through open questions on the card**, never a separate page or a link ([a card is grilled through its own open questions](docs/adr/2026-10-29-1639-a-card-is-grilled-through-its-own-open-questions.md)): `board.mjs question add` each question with topic `item:<file>/<id>`, options in take order with the recommended option tagged, and a prototype page in `url` when one helps. They land in Needs you and on the open card. When the ask is to grill new work, its card is already there: sort it, then the questions. Questions that span several cards go under a declared topic (`topic add`). **Messages stand alone.** Every reply, thread line and question reads on its own in the card's thread, where the owner reads it: name cards by their label (e.g. #96), and a pointer such as "above", "below" or "here" must make sense in the card's own thread, never point into this session. The owner reads only the board, not this session.
90
90
 
91
91
  **Waves** ([a wave the owner asks for is a lineup of cards](docs/adr/2026-11-02-1202-a-wave-the-owner-asks-for-is-a-lineup-of-cards.md)). A wave is a named set of cards from one item file, in build order, shown as a band in Todo with Implement for its next ready card ([waves are bands in Todo, each with its next card's Implement](docs/adr/2026-11-03-1840-waves-are-bands-in-todo.md)). Make one only when the owner asks with the +, or when you spot a grouping in Todo: then propose it as an open board question on a declared topic, with the cards in order, each one's conflicts and the goal, and make it only on a yes. A card waits only on the earlier cards it would conflict with ([a wave's cards wait only on the earlier cards they'd conflict with](docs/adr/2026-11-09-1321-a-waves-cards-wait-only-on-the-earlier-cards-they-conflict-with.md)): slice the work as vertical slices ([splits and waves follow vertical slices with stated conflicts](docs/adr/2026-11-09-2200-splits-and-waves-follow-vertical-slices-with-stated-conflicts.md)), each card one thin end-to-end behaviour a single builder lands and tests on its own, the first the thinnest end-to-end path. Read each card's notes and the code it will change, order the cards so a card comes after what it builds on, and name as a card's conflicts the earlier cards it builds on or shares a seam with (the same function, component, CLI command or doc paragraph); cards with no conflict between them build side by side. Two free cards that only share a file need nothing special: the later one rebases at land. Planning produces three things, through `board.mjs --site <route> wave create <slug> --title "<name>" --goal "<one line>" --card <file>/<id> --card <file>/<id>:<file>/<id>,… --note "<why this order and these conflicts, in a few lines>"`, one `--card` per card in build order, its conflicts after the colon: the wave's band in Todo, each card blocked by its conflicts alone (its links outside the wave stay), and the wave note that Notes opens. Each card stays one PR, and starts on its own as it unblocks, with no approval step. `wave add <slug> <file>/<id> [--after <file>/<id>,…]` puts a card last with its conflicts, `wave remove` takes one out, keeping its own links as ordinary blocked-by, and is refused while an open wave card waits on it: the refusal names each and the `wave set --after` to run, so relink each to its real conflicts (`""` for none), then remove ([a card leaves a wave only once no open card waits on it](docs/adr/2026-11-09-2345-a-card-leaves-a-wave-only-once-no-open-card-waits-on-it.md)); a removal that lifts a card's `wave:<slug>` block sends its Unblocked line, `wave set <slug> <file>/<id> --after <file>/<id>,…` rewrites only that card's conflicts (`""` clears them), `wave set` also renames it, sets its goal or rewrites its note, and `wave finish` takes its band out of Todo, refused while a card in it is open. To block a card on a whole wave, `item set <key> --deps wave:<slug>` waits on every card the wave holds as it grows, until each is Done ([a card can wait on a whole wave](docs/adr/2026-11-09-2330-a-card-can-wait-on-a-whole-wave.md)). A wave made in steps reads its steps in order and keeps its links. A wave whose cards are all Done leaves on its own. A `plan-waves {keys}` event is Plan waves at the foot of Todo, with the keys of its free cards ([Plan waves plans from any Todo cards](docs/adr/2026-11-03-0509-plan-waves-plans-from-any-todo-cards.md)). Triage those cards into one or more waves, each within one item file, each card naming the earlier cards it would conflict with, as above: ask each as one open question on a declared topic, with its order, conflicts and goal, and `wave create` only on a yes. Then `reply <eventId>` with one line, such as "2 waves proposed". A card you give up on, a duplicate or one not feasible as it stands, closes as done with `item set <key> --done --text "<why>"`, never left open; file a follow-up card with `item add --parent <key>` for whatever stays open.
92
92
 
@@ -1 +1 @@
1
- var h=Object.defineProperty;var t=(e,a)=>h(e,"name",{value:a,configurable:!0});import l from"node:path";import{waitsAgainLine as c}from"../board/domain.mjs";import{cardName as u}from"../board/store.mjs";import{routeRecord as d}from"../hub/routes.mjs";const f=["item-message","ask","ask-edited"],b=t((e,a)=>l.join(e,"data",`.shown-${a}.json`),"shownFile"),k=["main-pulled","settings","reviewers-removed","reviewers-added","question-reopen","repo-changed","ping","hello","card-hold","card-done","card-unbump","card-unblocked","grill-more","prototype-request","visual-request","usage-resumed"],p=t(e=>{try{return JSON.parse(e).kind}catch{return null}},"kindOf"),v=t(e=>k.includes(p(e)),"recordOnly"),o={"owner-answer":t(e=>`answer received to question ${e.data?.id}: act on it on its card`,"owner-answer"),ping:t(e=>`ping ${e.id} from the hub answered`,"ping"),hello:t(e=>`ping ${e.id} from the hub answered`,"hello"),"overnight-triage":t(e=>`Overnight triage ${e.data?.date} asks Claude to reply: ${e.data?.cards?.length} cards wait on open questions; run the triage, then board.mjs reply ${e.id}`,"overnight-triage"),"pr-review":t(e=>`review asked on PR #${e.data?.pr}: the board was idle; read its diff and review post it`,"pr-review"),"orchestrator-waits":t(e=>[e.data?.added?.length&&`waiting on you now: ${e.data.added.join(", ")}`,e.data?.again?.length&&c(e.data.again,Date.parse(e.ts))].filter(Boolean).join(" \xB7 "),"orchestrator-waits"),"check-github":t(e=>e.data?.reason==="morning"?"the daily wake: run one GitHub tick, then walk every lane top-down once: clear each blocked-until condition that holds, and act on any card stuck with no wait; a thread line on each card you act on, nothing else":"GitHub check asked: run one GitHub tick","check-github"),"github-change":t(e=>`${e.data?.prs?.length??0} PRs changed on GitHub: run one GitHub tick`,"github-change"),"review-answer":t(e=>e.data?.answer==="skip"?`skip answered on the review of PR #${e.data?.pr}: record it posted, post nothing`:`post answered on the review of PR #${e.data?.pr}: review post it`,"review-answer"),"plan-waves":t(e=>`Plan waves asked on ${e.data?.keys?.length??0} Todo cards: triage them into waves and ask the owner about them`,"plan-waves"),"arch-review":t(e=>`architecture review asked on ${e.data?.key}: review ${e.data?.repo} on ${e.data?.branch} and file the findings`,"arch-review"),rules:t(e=>`${e.data?.scope==="hub"?"hub":"board"} rules changed: the rule lines below are the new ones; follow them from now`,"rules"),"prototype-overdue":t(e=>`prototype overdue on ${e.data?.key}: dispatch its prototype agent now`,"prototype-overdue"),"slack-question":t(e=>e.data?.answer?`${e.data.from==="owner"?"the owner":e.data?.reviewer} wrote to the board in ${e.data?.reviewer}'s Slack review thread: slack thread ${e.id}, then, only if it asks something, answer about this board alone with slack answer ${e.id} --text (250 characters at most), or file a request for work with slack task ${e.id} <file>; a thanks gets no reply`:`the owner wrote in ${e.data?.reviewer}'s Slack review thread without @kickflip: slack thread ${e.id} for context; no reply`,"slack-question")},s={"item-message":t((e,a)=>String(a.data?.key).startsWith("ask:")&&a.data?.intent==="build"?`Implement asked on ${e}: file it with item add --from-ask --phase ready, with its --size and notes`:a.data?.intent==="build"?`Implement asked on ${e}: it is staging, the message in its notes; judge it against the whole board, then item set --phase ready --text "<what you checked>", or --phase grilling or prototyping`:`message received from ${e}'s thread: reply in its thread`,"item-message"),"card-bump":t(e=>`${e} bumped: handle its waits lines first; with none, leave it`,"card-bump"),"ask-edited":t(e=>`${e} edited: use the new text, and say what changed if you had started`,"ask-edited"),"ask-withdrawn":t(e=>`${e} deleted: drop it`,"ask-withdrawn"),"card-done":t(e=>`${e} marked done`,"card-done"),"card-hold":t((e,a)=>`${e} ${a.data?.hold?"held":"resumed"}`,"card-hold"),"card-unblocked":t(e=>`${e} unblocked`,"card-unblocked"),"prototype-request":t(e=>`prototype asked on ${e}`,"prototype-request"),"visual-request":t(e=>`visual asked on ${e}: the board launches its visual agent`,"visual-request"),"reask-request":t(e=>`question asked again on ${e}: ask it again with question add reask_of`,"reask-request"),"builder-resume":t((e,a)=>`${e}'s pause cleared (${a.data?.cleared}): tell its builder in your session to carry on where it stopped`,"builder-resume"),"builder-ask":t((e,a)=>`${a.data?.ask} from ${e}'s builder: ${a.data?.text} (builder answer it, or builder defer it)`,"builder-ask"),"owner-check-broken":t((e,a)=>`${e}'s owner-step check can't run: ${a.data?.error}; fix it with item set --check, or drop it`,"owner-check-broken"),"card-added":t(e=>`${e} added by an agent: link it and file it: item notes, then item set --relate and --phase`,"card-added"),ask:t((e,a)=>`new task ${a.id} received as ${e}: sort that New card: item notes, then item set <its key> --phase grilling or prototyping (ready, with --size, for a Quick build); merge it into a card with item relate-ask ${a.id} <card> --summary; or answer it with reply <its key>`,"ask")};async function x(e,a){let r;try{r=JSON.parse(a)}catch{return null}if(typeof r?.kind!="string")return null;const n=typeof r.data?.key=="string"?r.data.key:r.kind.startsWith("ask-")&&typeof r.data?.id=="string"?`ask:${r.data.id}`:r.kind==="ask"?`ask:${r.id}`:null,i=n&&await u(e,n).catch(()=>n);return d(o,r.kind)?o[r.kind](r):i&&d(s,r.kind)?s[r.kind](i,r):i?`${r.kind} on ${i}`:`${r.kind} received`}t(x,"plainLine");export{s as ON_CARD,f as OWNER_WORDS,o as PLAIN,k as RECORD_ONLY,x as plainLine,v as recordOnly,b as shownFile};
1
+ var h=Object.defineProperty;var t=(e,a)=>h(e,"name",{value:a,configurable:!0});import l from"node:path";import{waitsAgainLine as c}from"../board/domain.mjs";import{cardName as u}from"../board/store.mjs";import{routeRecord as o}from"../hub/routes.mjs";const f=["item-message","ask","ask-edited"],b=t((e,a)=>l.join(e,"data",`.shown-${a}.json`),"shownFile"),p=["main-pulled","settings","reviewers-removed","reviewers-added","question-reopen","repo-changed","ping","hello","card-hold","card-done","card-unbump","card-unblocked","grill-more","prototype-request","visual-request","usage-resumed"],k=t(e=>{try{return JSON.parse(e).kind}catch{return null}},"kindOf"),v=t(e=>p.includes(k(e)),"recordOnly"),d={"owner-answer":t(e=>`answer received to question ${e.data?.id}: ${e.data?.prototype_again?"it picks no take, so the board starts the next prototype round itself; nothing to do":"act on it on its card"}`,"owner-answer"),ping:t(e=>`ping ${e.id} from the hub answered`,"ping"),hello:t(e=>`ping ${e.id} from the hub answered`,"hello"),"overnight-triage":t(e=>`Overnight triage ${e.data?.date} asks Claude to reply: ${e.data?.cards?.length} cards wait on open questions; run the triage, then board.mjs reply ${e.id}`,"overnight-triage"),"pr-review":t(e=>`review asked on PR #${e.data?.pr}: the board was idle; read its diff and review post it`,"pr-review"),"orchestrator-waits":t(e=>[e.data?.added?.length&&`waiting on you now: ${e.data.added.join(", ")}`,e.data?.again?.length&&c(e.data.again,Date.parse(e.ts))].filter(Boolean).join(" \xB7 "),"orchestrator-waits"),"check-github":t(e=>e.data?.reason==="morning"?"the daily wake: run one GitHub tick, then walk every lane top-down once: clear each blocked-until condition that holds, and act on any card stuck with no wait; a thread line on each card you act on, nothing else":"GitHub check asked: run one GitHub tick","check-github"),"github-change":t(e=>`${e.data?.prs?.length??0} PRs changed on GitHub: run one GitHub tick`,"github-change"),"review-answer":t(e=>e.data?.answer==="skip"?`skip answered on the review of PR #${e.data?.pr}: record it posted, post nothing`:`post answered on the review of PR #${e.data?.pr}: review post it`,"review-answer"),"plan-waves":t(e=>`Plan waves asked on ${e.data?.keys?.length??0} Todo cards: triage them into waves and ask the owner about them`,"plan-waves"),"arch-review":t(e=>`architecture review asked on ${e.data?.key}: review ${e.data?.repo} on ${e.data?.branch} and file the findings`,"arch-review"),rules:t(e=>`${e.data?.scope==="hub"?"hub":"board"} rules changed: the rule lines below are the new ones; follow them from now`,"rules"),"prototype-overdue":t(e=>`prototype overdue on ${e.data?.key}: dispatch its prototype agent now`,"prototype-overdue"),"slack-question":t(e=>e.data?.answer?`${e.data.from==="owner"?"the owner":e.data?.reviewer} wrote to the board in ${e.data?.reviewer}'s Slack review thread: slack thread ${e.id}, then, only if it asks something, answer about this board alone with slack answer ${e.id} --text (250 characters at most), or file a request for work with slack task ${e.id} <file>; a thanks gets no reply`:`the owner wrote in ${e.data?.reviewer}'s Slack review thread without @kickflip: slack thread ${e.id} for context; no reply`,"slack-question")},s={"item-message":t((e,a)=>String(a.data?.key).startsWith("ask:")&&a.data?.intent==="build"?`Implement asked on ${e}: file it with item add --from-ask --phase ready, with its --size and notes`:a.data?.intent==="build"?`Implement asked on ${e}: it is staging, the message in its notes; judge it against the whole board, then item set --phase ready --text "<what you checked>", or --phase grilling or prototyping`:`message received from ${e}'s thread: reply in its thread`,"item-message"),"card-bump":t(e=>`${e} bumped: handle its waits lines first; with none, leave it`,"card-bump"),"ask-edited":t(e=>`${e} edited: use the new text, and say what changed if you had started`,"ask-edited"),"ask-withdrawn":t(e=>`${e} deleted: drop it`,"ask-withdrawn"),"card-done":t(e=>`${e} marked done`,"card-done"),"card-hold":t((e,a)=>`${e} ${a.data?.hold?"held":"resumed"}`,"card-hold"),"card-unblocked":t(e=>`${e} unblocked`,"card-unblocked"),"prototype-request":t(e=>`prototype asked on ${e}`,"prototype-request"),"visual-request":t(e=>`visual asked on ${e}: the board launches its visual agent`,"visual-request"),"reask-request":t(e=>`question asked again on ${e}: ask it again with question add reask_of`,"reask-request"),"builder-resume":t((e,a)=>`${e}'s pause cleared (${a.data?.cleared}): tell its builder in your session to carry on where it stopped`,"builder-resume"),"builder-ask":t((e,a)=>`${a.data?.ask} from ${e}'s builder: ${a.data?.text} (builder answer it, or builder defer it)`,"builder-ask"),"owner-check-broken":t((e,a)=>`${e}'s owner-step check can't run: ${a.data?.error}; fix it with item set --check, or drop it`,"owner-check-broken"),"card-added":t(e=>`${e} added by an agent: link it and file it: item notes, then item set --relate and --phase`,"card-added"),ask:t((e,a)=>`new task ${a.id} received as ${e}: sort that New card: item notes, then item set <its key> --phase grilling or prototyping (ready, with --size, for a Quick build); merge it into a card with item relate-ask ${a.id} <card> --summary; or answer it with reply <its key>`,"ask")};async function x(e,a){let r;try{r=JSON.parse(a)}catch{return null}if(typeof r?.kind!="string")return null;const n=typeof r.data?.key=="string"?r.data.key:r.kind.startsWith("ask-")&&typeof r.data?.id=="string"?`ask:${r.data.id}`:r.kind==="ask"?`ask:${r.id}`:null,i=n&&await u(e,n).catch(()=>n);return o(d,r.kind)?d[r.kind](r):i&&o(s,r.kind)?s[r.kind](i,r):i?`${r.kind} on ${i}`:`${r.kind} received`}t(x,"plainLine");export{s as ON_CARD,f as OWNER_WORDS,d as PLAIN,p as RECORD_ONLY,x as plainLine,v as recordOnly,b as shownFile};
@@ -380,9 +380,10 @@ moves every Linear board to no ticket source. If the source can't make a ticket,
380
380
  settings appear when set: {"auto_merge": false,
381
381
  "auto_build": false, "auto_pull": false,
382
382
  "max_implementers": 10, "max_planners": 3,
383
- "auto_triage": false, "auto_review": false,
384
- "idle_notification": false, "skip_draft": false,
385
- "prs": true, "github_login": "owner"}
383
+ "max_serves": 10, "auto_triage": false,
384
+ "auto_review": false, "idle_notification": false,
385
+ "skip_draft": false, "prs": true,
386
+ "github_login": "owner"}
386
387
  settings set auto-merge on|off on: the hub's tick merges an approved PR once CI is green and
387
388
  the merge state is CLEAN. off (the default): the card
388
389
  shows the owner a Merge button, and the board server merges