@lovek4d/kickflip 0.5.3 → 0.6.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 +82 -46
- package/SKILL.md +21 -15
- package/bin/doctor.mjs +5 -4
- package/bin/install.mjs +3 -3
- package/bin/kickflip.mjs +12 -12
- package/bin/wait-events.mjs +2 -2
- package/board/agents.mjs +2 -2
- package/board/arch-review.mjs +4 -4
- package/board/bin/board.mjs +179 -92
- package/board/build-script.mjs +2 -1
- package/board/domain.mjs +9 -7
- package/board/finish.mjs +4 -4
- package/board/headless.mjs +9 -5
- package/board/onboarding.mjs +11 -0
- package/board/prototype-base.mjs +1 -0
- package/board/prototype-page.mjs +1 -0
- package/board/public/app-arch.js +1 -1
- package/board/public/app-cards.js +40 -47
- package/board/public/app-header.js +6 -7
- package/board/public/app-lanes.js +19 -45
- package/board/public/app-needs.js +36 -31
- package/board/public/app-snapshot.js +43 -70
- package/board/public/app-threads.js +42 -46
- package/board/public/app.html +9 -4
- package/board/public/app.js +78 -32
- package/board/public/hub-kit.js +62 -2
- package/board/public/hub.css +2 -0
- package/board/public/new-task.js +8 -6
- package/board/public/progress-review.html +46 -0
- package/board/public/progress-review.js +158 -0
- package/board/public/prototype-kit.js +109 -4
- package/board/public/prototype-switcher.js +130 -31
- package/board/public/prototype.html +57 -3
- package/board/public/router.js +7 -6
- package/board/public/shell.js +65 -24
- package/board/public/sidebar.css +6 -0
- package/board/public/sidebar.js +19 -69
- package/board/public/style.css +116 -73
- package/board/public/ui-cards.js +78 -57
- package/board/public/ui-enums.js +2 -2
- package/board/public/ui-header.js +23 -16
- package/board/public/ui-hub.js +19 -5
- package/board/public/ui-links.js +7 -7
- package/board/public/ui-order.js +1 -1
- package/board/public/ui-page-header.js +19 -7
- package/board/public/ui-patch.js +7 -33
- package/board/public/ui-progress-bar.js +28 -0
- package/board/public/ui-questions.js +25 -17
- package/board/public/ui-sidebar.js +31 -23
- package/board/public/ui-snapshot.js +44 -53
- package/board/public/ui-threads.js +57 -28
- package/board/public/ui.js +94 -18
- package/board/public/view-hub-settings.js +12 -58
- package/board/public/view-hub.js +5 -2
- package/board/public/view-notes.js +27 -7
- package/board/public/view-questions.js +90 -68
- package/board/public/view-settings.js +133 -15
- package/board/render-check.mjs +10 -0
- package/board/review.mjs +1 -1
- package/board/server.mjs +20 -19
- package/board/stop.mjs +1 -0
- package/board/store.mjs +29 -18
- package/board/sync.mjs +2 -0
- package/board/tickets.mjs +3 -3
- package/board/transcript.mjs +2 -2
- package/board/worktree.mjs +22 -21
- package/hooks-plugin/hooks/board-data-gate.mjs +9 -6
- package/hooks-plugin/hooks/usage-gate.mjs +20 -3
- package/hub/board-repo.mjs +1 -1
- package/hub/boards.mjs +4 -4
- package/hub/front-door.mjs +2 -2
- package/hub/github.mjs +3 -3
- package/hub/hub.mjs +11 -11
- package/hub/incoming.mjs +2 -2
- package/hub/owner-checks.mjs +1 -1
- package/hub/pr-report.mjs +2 -2
- package/hub/review-send.mjs +1 -1
- package/hub/sessions.mjs +2 -2
- package/hub/share.mjs +1 -1
- package/hub/slack.mjs +2 -2
- package/hub/try.mjs +6 -6
- package/hub/upgrade.mjs +1 -1
- package/hub/usage.mjs +3 -3
- package/hub/views.mjs +1 -1
- package/package.json +1 -1
- package/shared/card-prs.mjs +1 -1
- package/shared/machine-gate.mjs +2 -0
- package/shared/prototype-frame.js +1 -0
- package/shared/tailscale.mjs +1 -1
- package/shared/usage-gate.mjs +1 -1
- package/board/public/ui-phase-bars.js +0 -17
package/CONTEXT.md
CHANGED
|
@@ -31,7 +31,7 @@ The machine the hub and its sessions run on, a Mac or a Linux machine. Its **hub
|
|
|
31
31
|
_Avoid_: the Mac, server (for the machine)
|
|
32
32
|
|
|
33
33
|
**Sidebar**:
|
|
34
|
-
The list of every site beside each board and hub page: New version with Reload when the hub’s code changed since the app loaded
|
|
34
|
+
The list of every site beside each board and hub page: New version with Reload, only when the hub’s code changed since the app loaded (the hub pulls and restarts itself, and a failed pull or restart shows nothing; [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)), then Hub, then Turn on notifications when needed, then Pages (sites that aren't boards), then Boards with their status words, lane chips, waiting counts and **context window** (its owner session's last reported percent, e.g. “62% ctx”, from `~/.claude/kickflip/context/<session>.json`, which the status line writes; dimmed with its age once ten minutes old; none on cards or for subagents; a board not listening at 95% or more reads **context full**, and the hub board's session gets `/compact` typed into its tmux pane once ([a board session compacts before its context fills](docs/adr/2026-11-03-1823-a-board-session-compacts-before-its-context-fills.md))). The last row of Boards is **New board**, a + tile opening a sheet that chooses a GitHub repo from the list or a pasted GitHub link or `owner/name`, then its branch, Name, optional What it’s for and Tickets (Internal · INT by default); a line under the repo field points a repo already on the host at `kickflip join` in its folder. Start is the confirm: the hub starts the board’s session itself once the request passes its checks; a muted, non-link row shows its name, its three start steps (**cloning**, **starting orchestrator**, **landing it**) on the board's phase bars, and the step with its seconds, cloning with git's percent, until its route joins and the row turns into the board's ([a new board shows its start steps and live clone progress](docs/adr/2026-11-04-1914-a-new-board-shows-its-start-steps-and-clone-progress.md)). When claude fails to start, or after 15 minutes without a join, it keeps the board's name in red with **failed to start** under it ([the hub starts a new board's session itself](docs/adr/2026-10-31-0137-the-hub-starts-a-new-boards-session.md)); tapping it opens a sheet with the clone or session error line, what the start used, Dismiss and **Retry**, which starts it again from the same record ([a failed start retries from its sheet](docs/adr/2026-11-02-2006-a-failed-start-retries-from-its-sheet.md)). Hub carries notification problems and the tools’ 5-hour usage bars under its sub line, and a moon after its name while pushes are held or snoozed, whose tooltip says until when; the whole row opens the hub page and stays selected on the hub page and its settings modals. Boards and Pages stay apart wherever sites are listed. The header's logo toggles it at every width; it carries no count, and shows a plain accent dot while a new version waits. From 900px it is a rail, which its own logo collapses out of sight until the header's logo brings it back; narrower, it is a drawer. Its header reads Kickflip. Below 900px every page header is a bottom bar, and the drawer header sits at its foot under New board; desktop headers stay at the top ([phone headers sit at the bottom, with boards nearest the thumb](docs/adr/2026-10-31-1532-phone-headers-sit-at-the-bottom.md)). In the **app shell** it is mounted once, beside every view and framed page, and a site's row swaps the view in place. `/` opens this device's **last board**, which the app shell stores as each board opens, never a page ([a sidebar of every board replaces the hub home](docs/adr/2026-10-29-1639-a-sidebar-of-every-board-replaces-the-hub-home.md), [one app for the whole hub](docs/adr/2026-10-29-2005-one-app-for-the-whole-hub.md)).
|
|
35
35
|
_Avoid_: hub home, switcher, nav
|
|
36
36
|
|
|
37
37
|
**Switch mode**:
|
|
@@ -47,11 +47,11 @@ The one page a browser's load of `/`, a hub page or any site's page gets, `board
|
|
|
47
47
|
_Avoid_: SPA, wrapper, frame
|
|
48
48
|
|
|
49
49
|
**View**:
|
|
50
|
-
One page's content in the app shell, mounted when its URL opens and unmounted, with every listener, timer and stream it added, when another takes its place. A board is a view, and so are its Waiting on you and Notes, and the **hub page**; hub settings open over Hub and Board Settings opens over its board as modals; a board left and opened again paints from its **last visit**, live
|
|
50
|
+
One page's content in the app shell, mounted when its URL opens and unmounted, with every listener, timer and stream it added, when another takes its place. A board is a view, and so are its Waiting on you and Notes, and the **hub page**; hub settings open over Hub and Board Settings opens over its board as modals; a board left and opened again paints from its **last visit**, live, and catches up from its **change number**. Opened again in the same page, unless its link names a card, it also returns to where the owner left it: the page's scroll, its open threads' windows and edit boxes, and, with a mouse or trackpad, the box being typed in with its caret or selection; a phone keeps the keyboard shut. A reload starts fresh. Any other page, another site's or a board's prototype, is a **frame view**: the page in a frame beside the board header, or its own when it draws that header, with Open alone ↗ to load it by itself.
|
|
51
51
|
_Avoid_: screen, tab, page (a page is its own document)
|
|
52
52
|
|
|
53
53
|
**Page tree**:
|
|
54
|
-
The levels back climbs in the app shell: a board, its Waiting on you, then a separately opened prototype page tied to one of its questions by `?q=`. On each, the back arrow, the browser's back and a swipe all go up one level: from a prototype to Waiting on you on its question, from there to the board, with the card still open when the owner left the board from that card's thread. However the owner arrives, by a push, a link or a reload, the levels above are written into history under the page first ([Back follows the page tree](docs/adr/2026-10-30-1125-back-follows-the-page-tree.md)).
|
|
54
|
+
The levels back climbs in the app shell: a board, its Waiting on you, then a separately opened prototype page tied to one of its questions by `?q=`. On each, the back arrow, the browser's back and a swipe all go up one level: from a prototype to Waiting on you on its question, from there to the board, with the card still open when the owner left the board from that card's thread. However the owner arrives, by a push, a link or a reload, the levels above are written into history under the page first ([Back follows the page tree](docs/adr/2026-10-30-1125-back-follows-the-page-tree.md)). From 900px Waiting on you is no page of its own: every URL of it shows the board at the board's URL with its topic open in the pane, so the tree is the board and a prototype ([Board and Open questions are two pages](docs/adr/2026-11-07-1300-board-and-open-questions-are-two-pages.md)).
|
|
55
55
|
_Avoid_: nav stack, breadcrumbs
|
|
56
56
|
|
|
57
57
|
**Hub page**:
|
|
@@ -71,9 +71,17 @@ The last reported Claude or Codex usage for its 5-hour and weekly windows, with
|
|
|
71
71
|
_Avoid_: quota, live usage
|
|
72
72
|
|
|
73
73
|
**Pause line**:
|
|
74
|
-
The Usage card's “Pause work at”, last in the group below Codex: `pauseAt` in `~/.claude/kickflip/settings.json`, 50–100 in steps of 5, default 90 (10% buffer); 100 reads Off. Either live Claude window at or over it pauses new work until that window resets. Running steps finish; builders and new agents wait, watchers hold the hub's work events, and owner messages get a brief “paused until <time>”. Keep going lifts that window's pause until its reset; Stop restores it. Codex hands work to Opus builders at the same line, without pausing. The Hub banner and sidebar and board header status slots show the pause, never the logo. `shared/usage-gate.mjs` owns it; `kickflip usage-gate` prints it ([work pauses at the pause line](docs/adr/2026-11-01-1710-work-pauses-at-the-pause-line.md)).
|
|
74
|
+
The Usage card's “Pause work at”, last in the group below Codex: `pauseAt` in `~/.claude/kickflip/settings.json`, 50–100 in steps of 5, default 90 (10% buffer); 100 reads Off. Either live Claude window at or over it pauses new work until that window resets. Running steps finish; builders and new agents wait, watchers hold the hub's work events, and owner messages get a brief “paused until <time>”. Keep going lifts that window's pause until its reset; Stop restores it. Codex hands work to Opus builders at the same line, without pausing. The Hub banner and sidebar and board header status slots show the pause, never the logo. Claude's reading joins the status line's with every headless run log's newest `rate_limit_event`. Within twice the buffer of the line the gate is **near**: the board server starts one agent at a time, each once the last has reported its usage, and the Hub banner reads "Approaching usage limit, reducing parallel agents" with its own Keep going. `shared/usage-gate.mjs` owns it; `kickflip usage-gate` prints it ([work pauses at the pause line](docs/adr/2026-11-01-1710-work-pauses-at-the-pause-line.md), [the pause line reads every headless agent's usage](docs/adr/2026-11-06-1249-the-pause-line-reads-every-headless-agents-usage.md)).
|
|
75
75
|
_Avoid_: buffer threshold, quota guard
|
|
76
76
|
|
|
77
|
+
**Pause hub** and **Pause board**:
|
|
78
|
+
The owner's manual pause, first in Hub settings and Board settings, with the snooze picker's chips, Forever included, and Custom: until its end (Forever's lasts until Resume) it pauses new work exactly as the **pause line** does, Codex builders included, on every board for Pause hub (settings.json's `paused_until`) and on that board alone for Pause board (board.json's `paused_until`, no board setting). It outranks the usage pause and Keep going, Pause hub first. Resume ends it, and the end wakes the boards with `usage-resumed {window: "manual"}`. It reads paused in gray wherever the usage pause shows: Pause hub on the Hub banner and row and every board, Pause board on its own sidebar row, header and cards ([Pause board and Pause hub pause new work by hand](docs/adr/2026-11-05-1849-pause-board-and-pause-hub-pause-new-work-by-hand.md)).
|
|
79
|
+
_Avoid_: snooze (pushes only), hold (one card)
|
|
80
|
+
|
|
81
|
+
**Busy Mac**:
|
|
82
|
+
This Mac at memory pressure critical or a 1-minute load of 4× its cores or more, until pressure is warn or lower and load is under 3× its cores. While busy every board holds all new work as the **pause line** does, Codex builders, landers and bumped cards included, and running work finishes. The hub's tick keeps the state in `~/.claude/kickflip/machine-state.json` (`shared/machine-gate.mjs`), which the one gate carries as `machine`. It reads busy, in words only, on the Hub row, every board row, the board header and Health's Machine row, and a card whose launch it holds gets a thread line ([a busy Mac holds new work](docs/adr/2026-11-06-0106-a-busy-mac-holds-new-work.md)).
|
|
83
|
+
_Avoid_: resources low, overload
|
|
84
|
+
|
|
77
85
|
**Claude model**:
|
|
78
86
|
The Usage card's Opus · Auto · Sonnet control, opening Claude's block: `claudeModel` in `~/.claude/kickflip/settings.json`, default Auto. It decides which model builds a card Claude builds: Opus or Sonnet always, or under Auto the card's own `--model`, else Sonnet for a card `--size small` and Opus for the rest. `builder pick` prints it with why, and a build's `builder start` refuses a `--model` it rules out. Codex builds, prototypes and grills don't read it ([usage picks Opus, Auto or Sonnet for Claude builders, and builder pick says which and why](docs/adr/2026-11-03-1526-usage-picks-opus-auto-or-sonnet-for-claude-builders.md)).
|
|
79
87
|
_Avoid_: Opus builders, allow Opus
|
|
@@ -145,15 +153,15 @@ A start and end time, 10:00pm to 8:00am by default. With its hold on, pushes que
|
|
|
145
153
|
_Avoid_: overnight window, wake times
|
|
146
154
|
|
|
147
155
|
**Hub settings**:
|
|
148
|
-
The
|
|
156
|
+
The summary rows below the **hub page**’s health and status: **Pause hub** first, then Notifications, Quiet hours, Keep awake, Linear, Slack, Rules for every board and Closed boards. Each opens its controls in a centred modal with its own scroll area. Snooze and Keep awake share one duration picker: 1h, 3h, 6h, 1d, Forever and Custom. Keep awake has the hub run `caffeinate -ims` until its end, and is disabled on hosts other than macOS ([snooze and Keep awake share one duration picker](docs/adr/2026-11-02-1402-snooze-and-keep-awake-share-one-duration-picker.md)). Old Hub Settings links open the matching modal over Hub ([hub settings open as modals](docs/adr/2026-11-01-1221-hub-settings-open-as-modals.md)).
|
|
149
157
|
_Avoid_: Hub Settings page, preferences, hub config
|
|
150
158
|
|
|
151
159
|
**Shared person**:
|
|
152
|
-
Someone else signed in to Tailscale whose login a board's Sharing lists: they see that board
|
|
160
|
+
Someone else signed in to Tailscale whose login a board's Sharing lists: they see that board in a shell whose sidebar lists only the boards shared with them, and open its Visit links; the rest of the hub refuses them ([a board is shared view only with a Tailscale login](docs/adr/2026-11-05-2215-a-board-is-shared-view-only-with-a-tailscale-login.md)). Each is **View**, looking only, or **Full**, also answering, writing in threads, attaching files, tapping card buttons and adding New tasks, named in the thread; Merge and Board settings stay the owner's at both ([a shared person is View or Full](docs/adr/2026-11-05-1912-a-shared-person-is-view-or-full.md)).
|
|
153
161
|
_Avoid_: guest, viewer, collaborator
|
|
154
162
|
|
|
155
163
|
**Board Settings**:
|
|
156
|
-
The centred modal opened from a board header’s gear, at every width, which scrolls inside on a phone. It contains only that board’s settings: repo and branch (Change uses the same list and GitHub link search as New board), ticket source, auto-merge, auto-build, auto-pull (Auto implement Todo cards) with Maximum parallel implementers and planners, auto-triage, reviewers, sharing, rules and Close board with typed-name confirmation. Closing returns to the same board and open card without another history entry ([hub settings expand in place and board settings open in a modal](docs/adr/2026-10-31-1721-hub-settings-expand-in-place-and-board-settings-open-in-a-modal.md)).
|
|
164
|
+
The centred modal opened from a board header’s gear, at every width, which scrolls inside on a phone. It contains only that board’s settings: **Pause board** first, then repo and branch (Change uses the same list and GitHub link search as New board), ticket source, auto-merge, auto-build, auto-pull (Auto implement Todo cards) with Maximum parallel implementers and planners, auto-triage, reviewers, sharing, rules and Close board with typed-name confirmation. Closing returns to the same board and open card without another history entry ([hub settings expand in place and board settings open in a modal](docs/adr/2026-10-31-1721-hub-settings-expand-in-place-and-board-settings-open-in-a-modal.md)).
|
|
157
165
|
_Avoid_: Settings page
|
|
158
166
|
|
|
159
167
|
**Codex setting**:
|
|
@@ -183,11 +191,11 @@ What the hub owes a board, each passing or broken: GitHub polling (not on a boar
|
|
|
183
191
|
_Avoid_: health, status, integrations
|
|
184
192
|
|
|
185
193
|
**Change signal**:
|
|
186
|
-
The board server's note on its `api/stream` that a file the board reads changed; the hub passes it on as `change {route}` on its one stream, and an open board reloads at once, naming the
|
|
194
|
+
The board server's note on its `api/stream` that a file the board reads changed; the hub passes it on as `change {route}` on its one stream, and an open board reloads at once, naming the **change number** it shows, so a changed board comes as a patch of the cards, questions and topics that changed after it ([the board sends per-card patches](docs/adr/2026-11-04-0332-the-board-sends-per-card-patches.md), [the board syncs by change number](docs/adr/2026-11-05-1819-the-board-syncs-by-change-number.md)). The header's time counts from the last one that brought something new, or the last ↻ tap ([the board reloads on a change signal](docs/adr/2026-10-29-1639-the-board-reloads-on-a-change-signal.md)).
|
|
187
195
|
_Avoid_: push (a push is a notification from the hub), live update
|
|
188
196
|
|
|
189
197
|
**Owner tap**:
|
|
190
|
-
A button the owner taps on the board, sent as an event. The board's rule for taps: one whose result follows from the tap alone (a bump, Hold, Done, Build, an edit) is applied by the board server inside the POST, which answers with the board, and the page draws it at once, a bump, unbump, edit or delete even before the POST, taken back off with a toast if the POST fails. The event is a record for the session, never what the owner waits on; only judgment or outside tools (Grill, prototypes,
|
|
198
|
+
A button the owner taps on the board, sent as an event. The board's rule for taps: one whose result follows from the tap alone (a bump, Hold, Done, Build, an edit) is applied by the board server inside the POST, which answers with the board, and the page draws it at once, a bump, unbump, edit or delete even before the POST, taken back off with a toast if the POST fails. The event is a record for the session, never what the owner waits on; only judgment or outside tools (Grill, prototypes, triage, a GitHub check) wait on the session. A tap reloads the board once, through the change signal ([every owner tap the server can apply draws at once](docs/adr/2026-11-03-0500-every-owner-tap-the-server-can-apply-draws-at-once.md)).
|
|
191
199
|
_Avoid_: action, click
|
|
192
200
|
|
|
193
201
|
**Wave**:
|
|
@@ -203,7 +211,7 @@ One step of a **lineup**: a set of its cards that build side by side, each block
|
|
|
203
211
|
_Avoid_: stage, batch; a builder's phase (reading, building, …) is its progress, not this
|
|
204
212
|
|
|
205
213
|
**Wave band**:
|
|
206
|
-
A wave shown inside Todo: one band per open **lineup**, then on a board over `~/.claude/waves` one per unfinished wave file, above Todo's cards in no wave ("No wave"; every other lane groups its cards by wave too, a header per wave with cards there and its x/y/k/z counts across lanes, [docs/adr/2026-11-05-0215-every-lane-groups-its-cards-by-wave.md](docs/adr/2026-11-05-0215-every-lane-groups-its-cards-by-wave.md)). Its head reads its name (the goal as its tooltip, or a long-press popover), its Todo count
|
|
214
|
+
A wave shown inside Todo: one band per open **lineup**, then on a board over `~/.claude/waves` one per unfinished wave file, above Todo's cards in no wave ("No wave"; every other lane groups its cards by wave too, a header per wave with cards there and its x/y/k/z counts across lanes, [docs/adr/2026-11-05-0215-every-lane-groups-its-cards-by-wave.md](docs/adr/2026-11-05-0215-every-lane-groups-its-cards-by-wave.md)). Its head reads its name (the goal as its tooltip, or a long-press popover), its Todo count and its started cards, then "Notes ↗" (a wave file has none), then Implement for a lineup's next card when it is ready, else "next: #N <why not>". Open, it lists its Todo cards in wave order with step numbers, one per phase, and a ⋯ menu that swaps a card with the Todo card above or below, each taking the other's phase, after one "N done" line. A lineup's next card is its first ready Todo card, so a phase's ready cards take Implement in turn. Only the first band with a ready next card starts open ([waves are bands in Todo, each with its next card's Implement](docs/adr/2026-11-03-1840-waves-are-bands-in-todo.md)).
|
|
207
215
|
_Avoid_: Waves section, wave bars, wave filter, pills
|
|
208
216
|
|
|
209
217
|
**Wave triage**:
|
|
@@ -211,15 +219,15 @@ Claude reading the code for a lineup's unstarted cards and proposing to split, m
|
|
|
211
219
|
_Avoid_: grooming, refinement
|
|
212
220
|
|
|
213
221
|
**Architecture review**:
|
|
214
|
-
Claude reviewing a board's repo, chosen by `hub/board-repo.mjs` `boardRepo`, with the mattpocock skills: the bulb
|
|
222
|
+
Claude reviewing a board's repo, chosen by `hub/board-repo.mjs` `boardRepo`, with the mattpocock skills: the bulb at the foot of the board, beside the gear, opens a sheet with the last review and Run, which confirms. The board server makes a **lineup** "Architecture <date>", or on a board over `~/.claude/waves` a wave file of its own, whose first card is its audit card, and wakes the session with `arch-review`. The bulb glows orange while the audit card is open with no question yet. The audit card's Notes are the report, and it asks one question per finding, with possible solutions and Skip; each finding not skipped becomes a card after it. One review is open at a time, so Run while one is open opens its audit card. A board on the running kickflip clone, as the hub board is, has its review cover kickflip's code, the board template and the model, reading the live data only for its shapes. It waits, saying why, while a skill it follows isn't installed ([the bulb runs an architecture review of the board's repo](docs/adr/2026-11-02-1813-the-bulb-runs-an-architecture-review-of-the-boards-repo.md)).
|
|
215
223
|
_Avoid_: improvements round, audit (for the whole review), bulb round
|
|
216
224
|
|
|
217
225
|
**Reviewers**:
|
|
218
|
-
The people who get a board's PR links once they are ready, and the weekday digest. Each board keeps its own in `board.json`, which its Settings modal lists, and a new wave copies them into its own `reviewers`. The board server writes both an add and a remove: an add picks a Slack member and a GitHub login from lists it fetches with the hub's Slack token and `gh`, and the server opens the DM ([the server adds reviewers from fetched lists](docs/adr/2026-11-05-2100-the-server-adds-reviewers-from-fetched-lists.md), extending [the board server removes reviewers itself](docs/adr/2026-11-04-0119-the-board-server-removes-reviewers-itself.md)). Kickflip owns the sent
|
|
226
|
+
The people who get a board's PR links once they are ready, and the weekday digest. Each board keeps its own in `board.json`, which its Settings modal lists, and a new wave copies them into its own `reviewers`. The board server writes both an add and a remove: an add picks a Slack member and a GitHub login from lists it fetches with the hub's Slack token and `gh`, and the server opens the DM ([the server adds reviewers from fetched lists](docs/adr/2026-11-05-2100-the-server-adds-reviewers-from-fetched-lists.md), extending [the board server removes reviewers itself](docs/adr/2026-11-04-0119-the-board-server-removes-reviewers-itself.md)). Kickflip owns the sent messages per PR, not per card, in each board's `data/pr-slack.json` `{<owner/repo#n>: {head, links: {<name>: {channel, ts, reactions}}, replies}}`: a card holds 1:m PRs, and each PR has 1:m reviewer DMs sharing one thread and one set of reactions. The card, Stale age, hub Slack link and digest read each reviewer's first link across the card's PRs, with an item's older `review_link_ts` and slack-bridge topic files only as a fallback ([Slack sends hang off PRs and go out from the hub tick](docs/adr/2026-11-07-0300-slack-sends-hang-off-prs-and-go-out-from-the-hub-tick.md)). The hub sends them as the owner, through the Slack user token pasted on Hub settings › Slack and kept in `~/.claude/kickflip/secrets.json` beside Linear's key, opening the owner's DM with each reviewer, and records each message as it posts, so a failed one goes again next poll and a posted one never twice ([the hub sends reviewer Slack messages with its own token](docs/adr/2026-11-05-0141-the-hub-sends-reviewer-slack-messages-with-its-own-token.md)). Hub Slack identity lives in `~/.claude/kickflip/slack.json`, read or set by `board.mjs slack`; its timezone sets the weekday 09:00 to 17:00 digest window ([kickflip owns the reviewer record](docs/adr/2026-11-01-2347-kickflip-owns-the-reviewer-record.md)).
|
|
219
227
|
_Avoid_: approvers, watchers
|
|
220
228
|
|
|
221
229
|
**Finished wave**:
|
|
222
|
-
A wave with work items that are all
|
|
230
|
+
A wave with work items that are all in Done. Done shows it as one row that opens to its cards, and its **wave band** leaves Todo ([lists never cut silently](docs/adr/2026-10-29-1639-lists-never-cut-silently.md)).
|
|
223
231
|
_Avoid_: closed wave, archived wave
|
|
224
232
|
|
|
225
233
|
**Work item**:
|
|
@@ -247,7 +255,7 @@ A chip on a card or page that shows a status, such as Install or a PR's state. I
|
|
|
247
255
|
_Avoid_: chip (in what the owner reads), tag, label
|
|
248
256
|
|
|
249
257
|
**Button**:
|
|
250
|
-
A control that acts: it sends something to the board, such as Merge, Hold or Grill, or opens a place to act, such as
|
|
258
|
+
A control that acts: it sends something to the board, such as Merge, Hold or Grill, or opens a place to act, such as Questions. The open card's workflow row holds Merge, Hold or Unhold, the **action button**, Serve or Build when the card has a build script and branch changes and Auto-build is off, and last **Implement** on a Todo card that can start (a held Todo card's Implement takes the place of its Unhold), below the details list whose final line holds Notes, Install and Review on GitHub links in that order ([a card's external links share the last details line](docs/adr/2026-10-30-2008-a-cards-external-links-share-the-last-details-line.md)). A card that can be bumped, every Todo card (held or waiting on the owner included) and a running In Progress one that isn't held, carries its bump as an icon at its top right instead, closed or open, as a New card does (the empty icon always shows on a touch screen and with a mouse only while the card is hovered or has focus; a bumped card's filled one always shows) ([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)). It sends with no confirm, and on a bumped card it is filled orange and unbumps (`card-unbump {key}`) ([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)). The control that clears the card's **Action needed** is orange.
|
|
251
259
|
_Avoid_: badge, pill (a pill is only a look)
|
|
252
260
|
|
|
253
261
|
**Badge tone**:
|
|
@@ -283,16 +291,20 @@ _Avoid_: backlog item, todo
|
|
|
283
291
|
_Avoid_: history, old cards
|
|
284
292
|
|
|
285
293
|
**Lane**:
|
|
286
|
-
Where a card sits (In Review,
|
|
294
|
+
Where a card sits (In Review, In Progress, Todo, Done, Asks), set by who acts next ([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)). In Progress means a card is building: a running build agent, a **checking** item, or a ready PR whose CI is red, or a red draft on a board that **skips the draft**. A work card stores its **lane** (todo, progress, review, done, with `lane_at`), which one writer moves with a "Moved to <lane>: <why>" thread line; a card has no status, and held, blocked, merged and dropped are facts beside the lane ([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)). A work card that has left Todo never drops back to it unless held or blocked ([a card moves to In Progress only once building starts](docs/adr/2026-11-03-0202-a-card-moves-to-in-progress-only-once-building-starts.md)). A running grill or prototype agent shows its status line but leaves the card where it is. In Review means finished work waits on a person: the reviewers, or the owner's review of a draft ("Review draft PR #n", whatever its CI), Merge, manual steps or the Done of an ask (see **Action needed**), or of a reopened card. An owner message or a new question on a Done card, merged or not, reopens it: In Progress until Claude answers, then In Review until the owner's Done, its next step "Tap Done once it is settled" ([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), [a card waiting only to be closed has no Action needed](docs/adr/2026-11-03-0137-a-card-waiting-only-to-be-closed-has-no-action-needed.md)). A card waiting only on those moves there from In Progress; one Claude still works on stays in In Progress. A card with several PRs, in any repos, sits where its least-ready PR puts it, shows a PR badge for each, and is Done once every PR has merged or closed with at least one merged ([a card holds several PRs across repos](docs/adr/2026-11-03-1904-a-card-holds-several-prs-across-repos.md)). Todo holds work that hasn't started building: the New cards, which wait on Claude ([the + makes a New card, which Claude files, folds or answers](docs/adr/2026-10-29-1639-the-plus-makes-a-new-card.md)), and every work card with no build yet, where its **Implement** shows. Discussion keeps a card there: open questions or a prototype pick, with Action needed, answered or resolved questions, grill and prototype agents, a working mark on a message in its thread and a prototype recorded for it ([a card moves to In Progress only once building starts](docs/adr/2026-11-03-0202-a-card-moves-to-in-progress-only-once-building-starts.md)). A started card that gets a question keeps its lane ([an unstarted card waits on its questions in Todo, and its one action button follows what it waits on](docs/adr/2026-10-30-1309-an-unstarted-card-waits-on-its-questions-in-todo.md)). Each lane has one fixed order, with no sort menu ([each lane has one fixed order](docs/adr/2026-11-03-0223-each-lane-has-one-fixed-order.md)): Todo lists its New cards first, oldest first, then its bumped cards, the latest bump on top ([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)), then the rest oldest made first, so a new card joins the bottom ([new Todo cards join the bottom, so old ones leave first](docs/adr/2026-11-05-2345-new-todo-cards-join-the-bottom.md)); In Progress, its bumped cards first, then by when each came into the lane, its reopening or its latest build agent's start, the newest arrival on top; In Review by when the PR was first sent to a reviewer, the newest on top; Done by when each card closed, the most recent on top; Asks, the answered asks in their own lane below Done, by when Claude answered, the newest on top. Done and Asks each show 10 cards, then a Show more, the thread's, that adds 10 and says how many are left; a card the owner has open stays shown ([answered asks have their own section below Done, and Done and Asks show 10 cards at a time](docs/adr/2026-11-03-0259-answered-asks-have-their-own-section-below-done.md)). Every card, a New card included, ends with one muted line holding the time its lane sorts by: the time only today, the day too before today ("10/31, 2:49 PM"), and the year too past 365 days. A card with no such time has no time on that line.
|
|
287
295
|
_Avoid_: column, status (status is the item's own field)
|
|
288
296
|
|
|
289
297
|
**Checking**:
|
|
290
|
-
The item status a builder's `builder done` sets when it hands back finished work with unverified judgment calls, including one naming why it couldn't finish. The card sits in In Progress reading "Orchestrator review" while the owning session verifies the calls; its `builder verified` **finishes** the card ([finishing a build is one step](docs/adr/2026-11-04-1611-finishing-a-build-is-one-step.md)). Only
|
|
298
|
+
The item status a builder's `builder done` sets when it hands back finished work with unverified judgment calls, including one naming why it couldn't finish. The card sits in In Progress reading "Orchestrator review" while the owning session verifies the calls; its `builder verified` **finishes** the card ([finishing a build is one step](docs/adr/2026-11-04-1611-finishing-a-build-is-one-step.md)). Only a card in Done unblocks dependents ([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)).
|
|
291
299
|
_Avoid_: verifying, in QA, review (review is the reviewers' part)
|
|
292
300
|
|
|
293
301
|
**Stale**:
|
|
294
|
-
A
|
|
295
|
-
_Avoid_: old, overdue
|
|
302
|
+
A card the board reads as having had no updates for a while, on the signals it already checks: a run still recorded as running with no progress line and no change to its Claude transcript for at least 10 minutes (counted from its start before its first progress), or whose headless process is gone; or a review waiting more than seven days since its first review link went out, which stays In Review ([a PR in review shows its age, and goes stale after seven days](docs/adr/2026-10-29-1639-a-pr-in-review-shows-its-age-and-goes-stale-after-seven-days.md)). Its **footer status** reads a grey "stale", a stale run's status line goes grey with no tap on it, and the card is a `stale` wait on the orchestrator, which restarts it or flags it **stalled** ([stale is automatic, stalled is the orchestrator's flag](docs/adr/2026-11-06-1252-stale-is-automatic-stalled-is-the-orchestrators-flag.md)). Silence calls for a check, without establishing that the process has failed.
|
|
303
|
+
_Avoid_: stalled (only the orchestrator's flag), old, overdue
|
|
304
|
+
|
|
305
|
+
**Footer status**:
|
|
306
|
+
The words after the time on a card's last line: held, blocked by, Action needed, an orange "staging", a green "ready", a red "stalled" or a grey "stale", then an In Progress card's phase bars and its unread count (owner, gh327-pause).
|
|
307
|
+
_Avoid_: time line, status line (the line under the title)
|
|
296
308
|
|
|
297
309
|
**Next step**:
|
|
298
310
|
Claude's next step on a card and what sets it off, such as "Next: merge when CI is green", kept in the item's `next` and cleared once done. A card waiting on its reviewers reads its next step from GitHub instead ([a card derives its lane and its review next step from GitHub, never from a kept status](docs/adr/2026-10-29-1639-a-card-derives-its-lane-from-github.md)), and one waiting on the owner reads its action. It is orange while it is someone's turn and grey on a Todo, Done or held card. It shares its place under the title with the builder line, which takes it while a builder record is open, and an In Progress card with neither reads "Next: none set yet": the CLI refuses a `builder done` or `item set` that would leave one so without `--next` ([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)). A Next set while the card has an open question clears once a build starts on it, or once Claude's acting leaves none of its questions unresolved ([an answer stops waiting once it's acted on, and a Next set during the card's questions clears](docs/adr/2026-11-03-1313-an-answer-stops-waiting-once-its-acted-on.md)).
|
|
@@ -303,20 +315,24 @@ Who the card is waiting for: the owning session's check, the owner's Ready, the
|
|
|
303
315
|
_Avoid_: blocked by, assignee
|
|
304
316
|
|
|
305
317
|
**Card state**:
|
|
306
|
-
What a card made from a **New task** does next,
|
|
318
|
+
What a card made from a **New task** does next: **grilling** (questions on the card), **prototyping** (takes on the card), **staging** (the owner has acted: a Send that left it nothing open, an Implement, or a Reply on a ready card, whose words the board wrote into its notes; the orchestrator judges it) or **ready** (its notes leave the owner nothing to decide, so it can be built; the plan lives only in the notes). Only the board sets staging; the session sets the others with `item set --state`, and ready only from staging, or on an Implement ask it files. A question added on a ready or staging card moves it to grilling. Moving a staging or ready card back to grilling or prototyping starts that round from code ([staging, then ready](docs/adr/2026-11-07-0700-staging-then-ready.md)). The board enforces the four: `--state` refuses any other, and ready while the card has an open question. Until it has one, the card reads New beside its ticket id and is never pulled. So does a card an agent added with `item add` and no `--state`, which a `card-added` event hands the session to link and file ([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)). A Ready card's time line reads a green "ready" in Action needed's place ("10:26 · held · ready · 2 new messages") while nothing blocks it and nothing waits on the owner, and the idle pull takes it like any settled card; a staging card reads an orange "staging" there and is never pulled ([a new card is ready, grilling or prototyping, and reads ready in green when it is](docs/adr/2026-11-03-0516-a-new-card-is-ready-grilling-or-prototyping.md)).
|
|
307
319
|
_Avoid_: triage state, status (the wave entry's `status` is a different field)
|
|
308
320
|
|
|
309
321
|
**Action needed**:
|
|
310
|
-
The orange words last among the orange ones on a card's time line ("10:26 · held · blocked by #53 · Action needed"), on a card waiting on the owner, in any lane ([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)): an open question or a prototype pick, a green draft's Ready, the Done of an ask, manual steps on an approved PR,
|
|
322
|
+
The orange words last among the orange ones on a card's time line ("10:26 · held · blocked by #53 · Action needed"), on a card waiting on the owner, in any lane ([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)): an open question or a prototype pick, a green draft's Ready, the Done of an ask, manual steps on an approved PR, with **auto-merge** off an approved PR's Merge, or a **stalled** card's "stalled: <why>", which a message in its thread clears, its Send or Reply orange. It links to the thing to act on. Reviewer waits and held cards get none ([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)), and so does a reopened card waiting only on the owner's Done, which is only waiting to be closed ([a card waiting only to be closed has no Action needed](docs/adr/2026-11-03-0137-a-card-waiting-only-to-be-closed-has-no-action-needed.md)). An unstarted card with open questions carries it in Todo ([an unstarted card waits on its questions in Todo, and its one action button follows what it waits on](docs/adr/2026-10-30-1309-an-unstarted-card-waits-on-its-questions-in-todo.md)).
|
|
311
323
|
_Avoid_: open items, needs you (Needs you is the box at the top of the board)
|
|
312
324
|
|
|
313
325
|
**Request**:
|
|
314
|
-
The owner's ask for a grill or a
|
|
326
|
+
The owner's ask for a grill, a prototype or a **visual** on a card: the thread composer's fire, eye or image, each sending at once, or /grill, /prototype or /visual typed in the box on Reply, sending `grill-more`, `prototype-request` or `visual-request` with whatever was typed; a question's own eye on Waiting on you asks for a prototype of that question. A request with nothing typed is one gray **status line** in the thread, "Grill requested", "Prototype requested" or "Visual requested", keyed `grill`, `prototype` or `visual` as every button without a text box keys its line ([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)); one with text is the owner's message carrying it, with that status in the message's footer, and "Waiting for Claude…" to its right until Claude picks it up. An answer submitted from Waiting on you is likewise a message whose footer reads "answers submitted". A question asked for a prototype reads "prototype requested", locked, until a question naming it in `round_of` resolves it, and `question resolve` refuses it; a prototype request still waiting 30 minutes on with no prototype agent running comes back to the session as `prototype-overdue` ([a button tap is a status line or a message footer](docs/adr/2026-11-04-2130-a-button-tap-is-a-status-line-or-a-message-footer.md), [a prototype request waits for its prototype](docs/adr/2026-11-04-2130-a-prototype-request-waits-for-its-prototype.md)).
|
|
315
327
|
_Avoid_: Grill button, Prototype button (on a card)
|
|
316
328
|
|
|
329
|
+
**Visual**:
|
|
330
|
+
A one-off HTML page that answers the owner in a card's thread visually, such as a diagram, a flow or a comparison. It is not a prototype or a grill: it asks no question, has no takes and leaves the card as it was. The thread's image or /visual (a **request**) has the board launch a headless visual agent on Sonnet. The agent runs beside any other agent on the card, as its own record `visual-<request id>`. Its page goes in with `visual add`, to `public/visuals/<card id>/<slug>.html`, a new page each time. The page shows in the thread as a link line, "<title> →", that opens it full page. A card's visual requests are drawn one after another ([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)).
|
|
331
|
+
_Avoid_: diagram (one kind of visual), prototype (takes for a decision)
|
|
332
|
+
|
|
317
333
|
**Action button**:
|
|
318
|
-
The open card's one workflow button, which `board/domain.mjs` picks as the card's `actionButton`: **
|
|
319
|
-
While the card carries **Action needed**, the button that clears it is orange, in the notice color: the card's `resolvedBy` from `board/domain.mjs`, by the action's kind. A question or a pick makes
|
|
334
|
+
The open card's one workflow button, which `board/domain.mjs` picks as the card's `actionButton`: **Needs you** (`openQuestions`) while it has open questions or a prototype pick, opening the first; otherwise none; an ask waiting on the owner's Done has it in its thread box, beside Reply. A grill or prototype is asked for from the thread's fire and eye (**request**), and the card reads a grey "preheating" while a grill or prototype request waits for its planner (not yet replied to, no questions posted on the card after it, and no planner of its kind started after it finished), then a planner line "grilling" or "prototyping" in its lane's colour once that planner runs ([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 new card is ready, grilling or prototyping, and reads ready in green when it is](docs/adr/2026-11-03-0516-a-new-card-is-ready-grilling-or-prototyping.md)). A Done card has none ([an unstarted card waits on its questions in Todo, and its one action button follows what it waits on](docs/adr/2026-10-30-1309-an-unstarted-card-waits-on-its-questions-in-todo.md)). It reaches the prototypes too, as each is a question on the card with a View prototypes link, Done cards included; there is no Prototypes button ([the Needs you button reaches the prototypes, and the Prototypes button is dropped](docs/adr/2026-11-09-1100-needs-you-button-reaches-the-prototypes.md)).
|
|
335
|
+
While the card carries **Action needed**, the button that clears it is orange, in the notice color: the card's `resolvedBy` from `board/domain.mjs`, by the action's kind. A question or a pick makes Questions orange (a pick makes Prototypes orange too), the Done of an ask makes the thread's Done orange (`BUTTON.done`), a green draft's Ready or manual steps make Review on GitHub orange, and an approved PR's Merge makes Merge orange. A held card's Questions stay plain. A reopened card waiting only on the owner's Done has its thread's Done primary, in the accent color ([a card waiting only to be closed has no Action needed](docs/adr/2026-11-03-0137-a-card-waiting-only-to-be-closed-has-no-action-needed.md)).
|
|
320
336
|
The button names (`BUTTON`: the action buttons, `github` and `merge`) and the action kinds (`ACTION_KIND`) are two frozen enums in `board/public/ui-enums.js`, which the page loads as a script and `board/domain.mjs` runs in a vm context; code compares against their members, never a bare string.
|
|
321
337
|
_Avoid_: Open items, Action needed (the badge)
|
|
322
338
|
|
|
@@ -333,8 +349,12 @@ A card with no PR lands the same way: with Auto-merge off its builder's `done` s
|
|
|
333
349
|
The headless run the board server starts on a card whose open PR, draft or ready, GitHub reads CONFLICTING, once per head and base: in the card's worktree, or one made from the PR's branch, it rebases onto the board's branch, reruns the suite and finishes with `builder done`, which force-pushes the PR's branch with a lease and leaves the PR as it is. The card stays In Review, its status line the run's; one it can't resolve hands the card back with a judgment call, to the orchestrator before the owner. A merge counts the run's push after an approval as trivial when it only replayed the PR's commits, and says so. The GitHub tick no longer rebases ([the board rebases a conflicting PR with a headless run](docs/adr/2026-11-06-0200-the-board-rebases-a-conflicting-pr-with-a-headless-run.md)).
|
|
334
350
|
_Avoid_: rebase lander, conflict fix
|
|
335
351
|
|
|
352
|
+
**Orchestrator stop**:
|
|
353
|
+
The orchestrator's stop of a run the board launched on a card, with every process under it: `board.mjs builder stop` for its headless builder, lander or rebase run, `board.mjs land stop` for its land, the suite included. A stopped build stays In Progress, waiting on the orchestrator, and nothing relaunches it; a stopped Merge land leaves the land queue and the card's Merge shows again. The card's status line and thread line read the stop in one pattern, "build stopped by orchestrator" or "land stopped by orchestrator". A bump, the owner's or the orchestrator's `item bump`, puts the card's land ahead in the land queue without stopping the one running ([the orchestrator stops the board's own runs](docs/adr/2026-11-05-1809-the-orchestrator-stops-the-boards-own-runs.md)).
|
|
354
|
+
_Avoid_: kill, cancel, Stopped (the status), land first
|
|
355
|
+
|
|
336
356
|
**Landing**:
|
|
337
|
-
A board's one choice of how a card lands, a section above Auto in Board settings, shown on a GitHub board that builds in its own clone
|
|
357
|
+
A board's one choice of how a card lands, a section above Auto in Board settings, shown on a GitHub board that builds in its own clone and on the hub board, which starts on Merge (no other local board shows it): **Draft PR** (each card opens a draft PR and waits for the owner to mark it ready), **Ready PR** (the hub's GitHub check marks the draft ready for review once its CI passes) or **Merge** (no PR opens; each card lands on the board's base branch, which is pushed, and turning it on needs Push main granted, except on the hub board). On a PR mode the hub board's builders branch from origin's base branch in its folder and each finish opens a PR; on Merge they branch from the folder's own base branch and land there, pushing it only with Push main granted. Reviewers show only while cards open PRs. The words never say "main", whatever the base branch. **Auto-merge** stays its own switch and covers both: merging an approved PR, and landing a build that waits to merge into the base branch ([Landing is one choice](docs/adr/2026-11-05-0200-landing-is-one-choice-draft-pr-ready-pr-or-merge.md), [the hub board shows Landing](docs/adr/2026-11-05-1100-the-hub-board-shows-landing-and-defaults-to-merge.md)).
|
|
338
358
|
It is stored as two `board.json` settings, read together: `prs`, on unless set (off is Merge), and `skip_draft`, off unless set (on is Ready PR); `board.mjs settings set prs|skip-draft` sets each. With no reviewers on the board a PR merges once it is green and clean, with no approval ([a land waits for your Merge](docs/adr/2026-11-04-2100-a-land-waits-for-your-merge.md), [a board can skip the draft](docs/adr/2026-11-04-1913-a-board-can-skip-the-draft.md)).
|
|
339
359
|
_Avoid_: PRs switch, Skip the draft, PR mode, no-PR mode, auto-ready
|
|
340
360
|
|
|
@@ -347,7 +367,7 @@ The app card's one badge that opens its build on the owner's phone, or the badge
|
|
|
347
367
|
_Avoid_: download, TestFlight (a different channel), older build
|
|
348
368
|
|
|
349
369
|
**Build script**:
|
|
350
|
-
The repo's reviewed, executable `.kickflip/build`, run by the hub from each card's worktree and main's hub-owned detached worktree. The hub passes the key (or `main`) and worktree, plus `KICKFLIP_BOARD`. Websites serve at their root on their own Tailscale HTTPS port, without a path prefix or `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)). Printing `port <n>` and staying alive serves a website; exiting 0 without a port finishes an app build that publishes an install through the board CLI. The last finished run decides the board's kind. The hub writes try state and logs; failed card runs append one thread line, and successful runs none. There is no script path setting ([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)).
|
|
370
|
+
The repo's reviewed, executable `.kickflip/build`, or `.kickflip/build-<target>` when Board Settings' Build target names one, run by the hub from each card's worktree and main's hub-owned detached worktree. One repo can hold several targets, such as `build-web` and `build-ios`; each board runs one, and main builds the same target as its cards. The hub passes the key (or `main`) and worktree, plus `KICKFLIP_BOARD`. Websites serve at their root on their own Tailscale HTTPS port, without a path prefix or `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)). Printing `port <n>` and staying alive serves a website; exiting 0 without a port finishes an app build that publishes an install through the board CLI. The last finished run decides the board's kind. The hub writes try state and logs; failed card runs append one thread line, and successful runs none. There is no script path setting: the board's `build_target` picks among the repo's `.kickflip/build-*` scripts, and with none the hub runs `.kickflip/build` ([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), [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)).
|
|
351
371
|
_Avoid_: install script, session install runner
|
|
352
372
|
|
|
353
373
|
**Serve**:
|
|
@@ -367,7 +387,7 @@ The thread line, of kind `build-refused`, the board server writes when it refuse
|
|
|
367
387
|
_Avoid_: Couldn't start the build, build error, failed start
|
|
368
388
|
|
|
369
389
|
**Auto-pull**:
|
|
370
|
-
The board's `auto_pull` setting, off by default, which reads "Auto implement Todo cards" in Board settings' Auto section and turns on or off with no confirmation. On, the board server starts and launches the build of the top **pullable** cards in board order, one per **implementer slot** free, on every board change and at start ([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)): a pullable card is a Ready, unstarted work card that nothing blocks or holds, with no question open or waiting on Claude, no grill under way and no message a session is working on, taken in Todo's order, bumped first and then oldest first ([the idle pull takes ready cards first, and plans the top card when none is ready](docs/adr/2026-11-03-1631-the-idle-pull-takes-ready-cards-first.md), [a card moves to In Progress only once building starts](docs/adr/2026-11-03-0202-a-card-moves-to-in-progress-only-once-building-starts.md)). The slots are the board's **Maximum parallel implementers** (`max_implementers`, 10 by default, the number beside the switch), less the
|
|
390
|
+
The board's `auto_pull` setting, off by default, which reads "Auto implement Todo cards" in Board settings' Auto section and turns on or off with no confirmation. On, the board server starts and launches the build of the top **pullable** cards in board order, one per **implementer slot** free, on every board change and at start ([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)): a pullable card is a Ready, unstarted work card that nothing blocks or holds, with no question open or waiting on Claude, no grill under way and no message a session is working on, taken in Todo's order, bumped first and then oldest first ([the idle pull takes ready cards first, and plans the top card when none is ready](docs/adr/2026-11-03-1631-the-idle-pull-takes-ready-cards-first.md), [a card moves to In Progress only once building starts](docs/adr/2026-11-03-0202-a-card-moves-to-in-progress-only-once-building-starts.md)). The slots are the board's **Maximum parallel implementers** (`max_implementers`, 10 by default, the number beside the switch), less the running implementer agents, one each (a build, a rebase run, a lander, a **helper** that writes), less the pulled cards whose build hasn't started; a running grill or prototype, a read-only helper, an agent blocked on its own helper, and a card waiting in Orchestrator review or on the owner take none ([planners and implementers are two kinds of agent](docs/adr/2026-11-03-1551-planners-and-implementers-are-two-kinds-of-agent.md), [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)). A helper that writes and is waiting for a slot takes it before the pull, the topmost card's first. New cards are never pulled, nor a card from an ask still New, grilling or prototyping; a Ready one is ([a new card is ready, grilling or prototyping, and reads ready in green when it is](docs/adr/2026-11-03-0516-a-new-card-is-ready-grilling-or-prototyping.md)). It writes "Pulled in: an implementer slot was free." in the card's thread ([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)). Busy board or idle, it also launches a grill on each card that **arrives in Todo**: an open work card in Todo not set Ready or held, with no planner record, no grill or prototype asked for and no questions yet, however it was filed. Up to **Maximum parallel planners** (`max_planners`, 3 by default, the number under the implementers) run at once, less the grills and prototypes running; the rest wait in board order. Each gets one grill, never a prototype straight away, and the card's thread reads "Landed in Todo, so the board started its grill." ([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), [the hub launches every agent from the card](docs/adr/2026-11-04-2130-the-hub-launches-every-agent-from-the-card.md)).
|
|
371
391
|
_Avoid_: auto-start, idle pickup
|
|
372
392
|
|
|
373
393
|
**Auto-triage**:
|
|
@@ -383,21 +403,29 @@ The board's `idle_notification` setting, off by default, which reads "Idle notif
|
|
|
383
403
|
_Avoid_: idle reminder, armed reminder
|
|
384
404
|
|
|
385
405
|
**Notes**:
|
|
386
|
-
The owning session's understanding of a work item so far: what was asked, what is settled, what is open.
|
|
406
|
+
The owning session's understanding of a work item so far: what was asked, what is settled, what is open. The card's own Markdown file in its wave's folder, named in `plan`: the board makes `<id>-notes.md` with the card and is its only writer, appending a section on each `item notes` and keeping it read-only, so no two cards share one ([the board owns a card's notes file](docs/adr/2026-11-09-1100-the-board-owns-a-cards-notes-file.md)); a card from before then keeps the name it had, or with no file shows its short `notes` text. "Notes ↗" opens them as a page sized for the phone, first on the open card's final details line before Install and Review on GitHub; the board keeps no summary of them and a card with no notes omits the link. The thread keeps the short news ([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), [a card's external links share the last details line](docs/adr/2026-10-30-2008-a-cards-external-links-share-the-last-details-line.md)).
|
|
387
407
|
_Avoid_: full plan, plan, spec
|
|
388
408
|
|
|
389
409
|
**Held**:
|
|
390
|
-
A work card the owner paused with its Hold button, which opens the shared duration picker: Forever, until the owner taps Unhold, or until a time, its **pick-up time**. Hold and Unhold apply on the board at once, and the board server writes them to the wave file with the owner's thread line ([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)). It doesn't start, and the session stops work on a running one, until it is resumed (a held Todo card's Build resumes and starts it, [a held Todo card shows Build in place of Unhold](docs/adr/2026-11-03-0234-a-held-todo-card-shows-build-in-place-of-unhold.md)) ([the board applies the owner's Hold, Resume and Done at once](docs/adr/2026-11-02-0009-the-board-applies-the-owners-hold-resume-and-done-at-once.md)). The card's last line reads "held" or "held until Wed 9:00 am" after its time. A card that leaves Todo is never still held: any write that takes it out (
|
|
410
|
+
A work card the owner paused with its Hold button, which opens the shared duration picker: Forever, until the owner taps Unhold, or until a time, its **pick-up time**. Hold and Unhold apply on the board at once, and the board server writes them to the wave file with the owner's thread line ([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)). It doesn't start, and the session stops work on a running one, until it is resumed (a held Todo card's Build resumes and starts it, [a held Todo card shows Build in place of Unhold](docs/adr/2026-11-03-0234-a-held-todo-card-shows-build-in-place-of-unhold.md)) ([the board applies the owner's Hold, Resume and Done at once](docs/adr/2026-11-02-0009-the-board-applies-the-owners-hold-resume-and-done-at-once.md)). The card's last line reads "held" or "held until Wed 9:00 am" after its time. A card that leaves Todo is never still held: any write that takes it out (a build's start, a hand-back, `--done`, `--pr`, `--pushed`) clears the hold and its pick-up time, and the board shows held only on a Todo card. Every other action-row button, Unhold included, asks to confirm first, through `B.confirm` (`dialogs.js`).
|
|
391
411
|
_Avoid_: paused, frozen, on hold (as a status name)
|
|
392
412
|
|
|
413
|
+
**Blocked**:
|
|
414
|
+
A work card that waits on something concrete before it can start: other cards (its deps, until each reaches Done), or a condition an agent can check, which the orchestrator clears with `item set --blocked-until ""` once it holds, either with a reason. Its time line reads "blocked by #53" or "blocked until <condition>", then ", <reason>". A time is a hold, never a block ([nothing waiting on the orchestrator is missed](docs/adr/2026-11-05-2358-nothing-waiting-on-the-orchestrator-is-missed.md)). Blocked In Progress, a card goes back to Todo with its builder stopped; blocked In Review, it stays but can't land, its Merge disabled ([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)).
|
|
415
|
+
_Avoid_: held (a pause, not a dependency), waits on (who the card waits for)
|
|
416
|
+
|
|
393
417
|
**Pick-up time**:
|
|
394
418
|
When a card held until a time resumes itself: `pick_up_at` in its wave file (`board.mjs item set --pick-up-at`), or the `until` of the owner's newer `card-hold`. Within a minute of it the board server resumes the card, writes a thread line, and sends `card-unblocked {key, until}` unless a dep is unfinished, so it starts on its own once nothing else blocks it ([a card can be held until a time](docs/adr/2026-11-02-1727-a-card-can-be-held-until-a-time.md)). A bump doesn't skip it; resume the card or change the time to start early. It is separate from a Linear due date.
|
|
395
419
|
_Avoid_: due date, reminder, snooze (for a card)
|
|
396
420
|
|
|
397
421
|
**Builder**:
|
|
398
|
-
An agent (Claude Opus, Claude Sonnet, Codex…) working on a work item, which owner-facing words call an implementer ([a Todo card's button reads Implement, and Build and Serve only mean the package](docs/adr/2026-11-03-1549-a-todo-cards-button-reads-implement.md)), with one builder record each (`board.mjs builder … --agent <name>`; the first is `main`). The record holds its label, kind (claude or codex; a record written as opus or sonnet reads as claude with that model), model (opus or sonnet for claude, set by `builder start --model`, which prints "model: Claude Sonnet"), start, ETA and finish, not its progress. Each progress line (`builder progress --phase <phase> "<detail>"`, which needs `--site`) goes only to the card's thread, as a **status line**: a phase, Reading, Building, Testing, Checking or Landing, and a detail of at most 80 characters, refused when longer ("Testing: fix for the scroll jump"; another agent's reads "Codex testing: …"), shown as one line with no bubble. Status lines written before phases stay as written ([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)). The card's status line under its title is the thread's newest status line since its earliest running agent started, its phase first ("Testing · fix for the scroll jump · 3m ago"), or "Starting" before the first, with its age, behind a pulsing dot as Orchestrator review and Working on it have, and, once a status line has a phase, five bars at the end of the card's time row, after its unread count, finished phases filled and the current one pulsing, only on an In Progress card while a builder runs ([a building card's phase bars end its time row](docs/adr/2026-11-03-1519-a-building-cards-phase-bars-end-its-time-row.md)), and an optional "ETA about 4:30 pm" line under that (owner ask on INT-76). In the thread every implementer's status line stays orange, dot included, whether its agent is working or done (owner, card INT-77). `builder done` marks the record done and keeps it;
|
|
422
|
+
An agent (Claude Opus, Claude Sonnet, Codex…) working on a work item, which owner-facing words call an implementer ([a Todo card's button reads Implement, and Build and Serve only mean the package](docs/adr/2026-11-03-1549-a-todo-cards-button-reads-implement.md)), with one builder record each (`board.mjs builder … --agent <name>`; the first is `main`). The record holds its label, kind (claude or codex; a record written as opus or sonnet reads as claude with that model), model (opus or sonnet for claude, set by `builder start --model`, which prints "model: Claude Sonnet"), start, ETA and finish, not its progress. Each progress line (`builder progress --phase <phase> "<detail>"`, which needs `--site`) goes only to the card's thread, as a **status line**: a phase, Reading, Building, Testing, Checking or Landing, and a detail of at most 80 characters, refused when longer ("Testing: fix for the scroll jump"; another agent's reads "Codex testing: …"), shown as one line with no bubble. Status lines written before phases stay as written ([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)). The card's status line under its title is the thread's newest status line since its earliest running agent started, its phase first ("Testing · fix for the scroll jump · 3m ago"), or "Starting" before the first, with its age, behind a pulsing dot as Orchestrator review and Working on it have, and, once a status line has a phase, five bars at the end of the card's time row, after its unread count, finished phases filled and the current one pulsing, only on an In Progress card while a builder runs ([a building card's phase bars end its time row](docs/adr/2026-11-03-1519-a-building-cards-phase-bars-end-its-time-row.md)), and an optional "ETA about 4:30 pm" line under that (owner ask on INT-76). In the thread every implementer's status line stays orange, dot included, whether its agent is working or done (owner, card INT-77). `builder done` marks the record done and keeps it; with judgment calls on it the record is marked `handed_back`, the fact that replaces the old checking status, until a handover or a close. The thread shows each record as **agent lines** among its messages, with no bubble: "Claude Opus implementer started" (or "Claude Sonnet implementer", "Codex implementer"; the model, not the label, names it, a label's builder reading implementer) at its start, always orange and with its ETA while the agent runs, and "Claude Opus implementer finished" at its finish, the only green one (owner, question `int42-agents-look`, option C; owner ask on INT-63). The session's own thread summary closes the work. A builder is a **planner** or an **implementer**: planners are the grill and prototype agents, which write no output code; every other kind is an implementer. A planner's model defaults to Sonnet for a prototype and Opus for a grill ("Claude Sonnet prototype started"); its status and started lines in the thread are the owner's blue (`--accent`, the one human blue, [one human blue](docs/adr/2026-11-03-1627-one-human-blue.md)), and on the card take the card's lane colour, Todo's grey with grey dashes ([every run takes its lane's colour](docs/adr/2026-11-06-0145-every-run-takes-its-lanes-colour.md)); while a build runs, the build's line wins on the card; and a running planner takes no implementer slot and leaves the board idle ([planners and implementers are two kinds of agent](docs/adr/2026-11-03-1551-planners-and-implementers-are-two-kinds-of-agent.md)). The kind words are for code and ADRs; the screen says what each agent does.
|
|
399
423
|
_Avoid_: worker, bot
|
|
400
424
|
|
|
425
|
+
**Helper**:
|
|
426
|
+
An agent that another agent on a card, or the orchestrator, asks the board for with `board.mjs agent launch <key> --name <n> --task "<t>" [--writes]`. It runs beside the card's build under its own name, and its status lines carry that name ("Tests building: …"). The board server launches it headless on Claude. A read-only one launches at once and takes no implementer slot. One that writes takes a slot, waits for one ahead of the pull, and works in its own worktree off the card's branch, which the card's builder brings in with `agent merge`. It hands back with `builder done --agent <n> --text`, which its spawner reads with `agent wait`; while the spawner waits, it takes no slot ([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)).
|
|
427
|
+
_Avoid_: subagent (for one the board runs), sub-builder
|
|
428
|
+
|
|
401
429
|
**Dispatched record**:
|
|
402
430
|
A builder record open before its agent runs, marked with who opened it: `dispatched: 'tap'` when the owner's Implement tap (or the start of a build ready released) opened it, `dispatched: 'hub'` when the board server opened it to launch a pulled build or a planner (a grill or a prototype) itself, `dispatched: 'session'` when the session ran `builder start --dispatch` right before it launches some other agent. Either way the card's builder line reads "starting" from then until the agent's first status line. The agent's own `builder start` takes it up: the kind, a Claude model and the worktree stay, the record starts again at now and is no longer dispatched. A `--dispatch` on a record the tap opened changes nothing and prints "already open"; a `builder start --agent <other name>` refuses while the tap's main record is open and not taken up. The session never posts "a builder is working" 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)).
|
|
403
431
|
|
|
@@ -410,8 +438,8 @@ A question a running builder puts to the board's session, the **orchestrator**,
|
|
|
410
438
|
_Avoid_: builder question, check-in
|
|
411
439
|
|
|
412
440
|
**Stalled**:
|
|
413
|
-
|
|
414
|
-
_Avoid_: stuck, hung, failed
|
|
441
|
+
The orchestrator's flag on a **stale** card it can't restart, `board.mjs item stall <key> --reason "<why>"`: its run stops, its record stays open and stopped, its worktree stays, and it frees its implementer slot. The card stays in its lane with a red "stalled" in its **footer status** and an Action needed "stalled: <why>" in Needs you, with one push, waiting on nobody but the owner, whose next message in its thread clears the flag and reaches the orchestrator ([stale is automatic, stalled is the orchestrator's flag](docs/adr/2026-11-06-1252-stale-is-automatic-stalled-is-the-orchestrators-flag.md)).
|
|
442
|
+
_Avoid_: stale (the board's automatic reading), stuck, hung, failed
|
|
415
443
|
|
|
416
444
|
**Worktree**:
|
|
417
445
|
The git worktree a builder works in, never the folder the session, a running app or the hub uses. A board's is `~/.claude/kickflip/worktrees/<card id>` on branch `<card id>` from its chosen repo branch, or from the local copy of its recorded default branch for a **local board** ([a local board builds and lands on its default branch](docs/adr/2026-11-03-1851-a-local-board-builds-and-lands-on-its-default-branch.md)), of the board's own folder, the hub board's included (`hub/board-repo.mjs` decides which), made by a build's `board.mjs builder start` (or `--worktree`, or the Implement tap) and kept on the builder record; the builder checks and commits there, and **finishing** the card (its `builder done --text`, the session's `builder verified`, or `board.mjs land`) **lands** it: rebased onto that branch, refused if it adds an ADR named with a number instead of a timestamp, tested, fast-forwarded into the live folder's copy of it, the hub or board servers restarted, the worktree and branch removed, and with the board's "Push main after a land" switch on, the branch pushed to origin. On a GitHub board finishing pushes the card's branch and opens a draft PR instead, and on a plain git remote pushes the branch. A repo card's comes from wave-build ([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)).
|
|
@@ -420,11 +448,11 @@ _Avoid_: copy, checkout, live folder (for the builder's)
|
|
|
420
448
|
### Talking with the owner
|
|
421
449
|
|
|
422
450
|
**New task**:
|
|
423
|
-
A free-form request or question the owner sends from the board's + button (or by pressing n twice). Code and events call it an **ask**: an `ask` event whose thread is `ask:<event id>`. It is a **New card** at the top of Todo, with no wave and no Action needed, until Claude sorts it one of three ways ([the + makes a New card, which Claude files, folds or answers](docs/adr/2026-10-29-1639-the-plus-makes-a-new-card.md)): files it under a wave as a work item, whose thread opens with it (`item set --from-ask`), and sets its **card state**; folds it into the card it's about, whose thread then holds the message marked Moved (`item relate-ask`, undone by `ask unfold`); or answers it, which puts it in the Asks lane below Done, named by when it was asked, whose thread takes the owner's later replies ([answered asks have their own section below Done, and Done and Asks show 10 cards at a time](docs/adr/2026-11-03-0259-answered-asks-have-their-own-section-below-done.md)). An answer that leaves a question open on it keeps it in Todo with Action needed, never in Asks, until the owner answers and Claude replies, or it is closed; it stays in Todo while Claude takes up the answer ([an unstarted card waits on its questions in Todo, and its one action button follows what it waits on](docs/adr/2026-10-30-1309-an-unstarted-card-waits-on-its-questions-in-todo.md)). When another board fits it better, the owner can have it **moved there** (`ask move`): it becomes a New card on that board reading "Moved from <this board>", and here a Done card whose thread links to it. Folding is within one board; a move is between boards. An answer that waits on the owner, such as a choice only the owner can settle, keeps it in In Review with Action needed until the owner taps
|
|
451
|
+
A free-form request or question the owner sends from the board's + button (or by pressing n twice). Code and events call it an **ask**: an `ask` event whose thread is `ask:<event id>`. It is a **New card** at the top of Todo, with no wave and no Action needed, until Claude sorts it one of three ways ([the + makes a New card, which Claude files, folds or answers](docs/adr/2026-10-29-1639-the-plus-makes-a-new-card.md)): files it under a wave as a work item, whose thread opens with it (`item set --from-ask`), and sets its **card state**; folds it into the card it's about, whose thread then holds the message marked Moved (`item relate-ask`, undone by `ask unfold`); or answers it, which puts it in the Asks lane below Done, named by when it was asked, whose thread takes the owner's later replies ([answered asks have their own section below Done, and Done and Asks show 10 cards at a time](docs/adr/2026-11-03-0259-answered-asks-have-their-own-section-below-done.md)). An answer that leaves a question open on it keeps it in Todo with Action needed, never in Asks, until the owner answers and Claude replies, or it is closed; it stays in Todo while Claude takes up the answer ([an unstarted card waits on its questions in Todo, and its one action button follows what it waits on](docs/adr/2026-10-30-1309-an-unstarted-card-waits-on-its-questions-in-todo.md)). When another board fits it better, the owner can have it **moved there** (`ask move`): it becomes a New card on that board reading "Moved from <this board>", and here a Done card whose thread links to it. Folding is within one board; a move is between boards. An answer that waits on the owner, such as a choice only the owner can settle, keeps it in In Review with Action needed until the owner taps the Done beside Reply in its thread ([an ask can wait on the owner before Done, and the owner closes any open card from its thread](docs/adr/2026-10-29-1639-an-ask-can-wait-in-progress-until-the-owner-marks-it-done.md)).
|
|
424
452
|
_Avoid_: ask (in what the owner reads), message, prompt, Waiting for Claude strip
|
|
425
453
|
|
|
426
454
|
**Thread**:
|
|
427
|
-
The conversation on one work item: Claude's reports, builders' status lines, the owner's messages, mirrored GitHub comments, and answers to the item's questions.
|
|
455
|
+
The conversation on one work item: Claude's reports, builders' status lines, the owner's messages, mirrored GitHub comments, and answers to the item's questions. An In Review card's reply form sends with Reply then Done, which closes the card; a Todo card closes from Close, right of Hold in its actions, and an In Progress card has neither, only Send ([Done shows only in In Review, beside Reply](docs/adr/2026-11-05-1918-done-shows-only-in-in-review-beside-reply.md)).
|
|
428
456
|
An open card shows its thread's newest 3 messages as it opens, or from its oldest **unread message** when more than 3 messages follow it, at most 10, unread as of when the card opened. Messages that arrive while it is open add below, hiding none. Messages are the owner's, Claude's (replies included) and other people's; builder, status and ask-link lines show among the messages they sit between and don't count. "Show more · N previous messages" at the top adds the next 3 older messages each tap and goes when nothing older is left. The expansion lasts while the card stays open, through repaints and new messages, and closing the card puts it back to 3. A message being edited always shows, with every line after it; one waiting on Claude shows only where the window reaches it.
|
|
429
457
|
An owner message Claude hasn't answered yet ends with **Waiting for Claude…**, or Working on it while Claude is on it. An answer to a question stops waiting once it's acted on: its question resolved after it, a later prototype round on it, or a build started on the card after it ([an answer stops waiting once it's acted on, and a Next set during the card's questions clears](docs/adr/2026-11-03-1313-an-answer-stops-waiting-once-its-acted-on.md)). A batch of the owner's answers in a row in the same state carries it once, under the last answer.
|
|
430
458
|
_Avoid_: comments, chat
|
|
@@ -438,9 +466,17 @@ How far the owner has read a card: the time of the newest message, question or a
|
|
|
438
466
|
_Avoid_: seen mark, last seen
|
|
439
467
|
|
|
440
468
|
**Last visit**:
|
|
441
|
-
The board and threads this device last showed, kept in its browser
|
|
469
|
+
The board and threads this device last showed, with the board's **change number**, kept in its browser's IndexedDB. The next visit paints it live at first paint, readable at any age, and asks the board only for what changed after its number; the lines that catch-up changes flash a fading blue border round each lane count, Needs you line or thread message ([the board opens on the last visit](docs/adr/2026-10-29-1639-the-board-opens-on-the-last-visit.md), [the board syncs by change number](docs/adr/2026-11-05-1819-the-board-syncs-by-change-number.md)); a card that changed shows its own sign ([an updated card takes a brief tint](docs/adr/2026-11-02-2354-an-updated-card-takes-a-brief-tint.md)). It paints only under the build that saved it, a hash of the shell's file versions (`hub/shell.mjs` `shellHtml`), so code that changed since never reads it, except while the board is out of reach, when the page paints another build's copy inside a guard; where there is none, or IndexedDB refuses, the page paints nothing until the whole board lands, and shows the **down landing** if the load fails. Out of reach, the copy stays undimmed and readable, with only the header time red and the buttons that send held, each labelled one saying "Waits for the board"; Waiting on you shows the same copy, and Notes and Settings keep their own, Settings read only ([a board out of reach keeps its copy or shows a landing](docs/adr/2026-11-06-0135-a-board-out-of-reach-keeps-its-copy-or-shows-a-landing.md)). In code it is the copy.
|
|
442
470
|
_Avoid_: cache, offline copy, stale board
|
|
443
471
|
|
|
472
|
+
**Down landing**:
|
|
473
|
+
What a board's view shows in place of the board when the board can't be reached and the device has no copy to show: the kickflip mark, one bold line and one muted hint, the look of the no-access page. The line and hint name one of six states, read from what the hub marks on its answer (`x-kickflip-down`, `x-kickflip-hub`): Board restarting (its code changed, it's starting, or it crashed and the hub is relaunching it), Board stopped, This board is gone, You no longer have access, Board restarting (it answers with errors) and Board offline (nothing answers). It retries every 5 s while the board can come back by itself ([a board out of reach keeps its copy or shows a landing](docs/adr/2026-11-06-0135-a-board-out-of-reach-keeps-its-copy-or-shows-a-landing.md)).
|
|
474
|
+
_Avoid_: offline page, error page, landing (alone: a card lands)
|
|
475
|
+
|
|
476
|
+
**Change number**:
|
|
477
|
+
The board server's one counter, which steps once for each built board that differs from the one before and is the board's version. Each card, question and topic carries the number of its last change, and a removal leaves a tombstone with its number, all kept in `data/sync.json` so a restart carries on counting. A page naming the number it holds gets only what changed after it, answered from the current board; one older than the oldest tombstone kept gets the whole board ([the board syncs by change number](docs/adr/2026-11-05-1819-the-board-syncs-by-change-number.md)).
|
|
478
|
+
_Avoid_: sync id, version hash
|
|
479
|
+
|
|
444
480
|
**Answer banner**:
|
|
445
481
|
The one line at the top of a board, above Needs you, naming new tasks Claude answered without making work whose answer came after the card's read mark: "1 answer · <ask>" or "2 answers · <newest> and 1 more". A tap opens the newest one's card; opening a card anywhere takes its answer off at once, and ✕ marks every answer shown read, on every device. No push goes for an answer ([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)).
|
|
446
482
|
_Avoid_: notification, toast
|
|
@@ -458,7 +494,7 @@ The group an owner question belongs to; an item's questions use the topic `item:
|
|
|
458
494
|
_Avoid_: category, section
|
|
459
495
|
|
|
460
496
|
**Needs you**:
|
|
461
|
-
What waits on the owner on a board, led by the board session's **pending prompts** ([Needs you gathers what waits on the owner, and a topic's questions are answered on one page](docs/adr/2026-10-29-1639-needs-you-gathers-what-waits-and-questions-answer-on-one-page.md)). On a phone it is the **deck** at the top of the board: one thing at a time, a tap on a question's option drafting its answer, which Send on Waiting on you sends with its notes, a prompt's buttons answering it on the tap, Skip, a dot per thing waiting, View prototypes on a question with prototypes, and All open questions at its foot. From 900px it is a pane beside the lanes, one orange line per work item over Waiting on you, which arrivals update in place ([Needs you is a deck on a phone and a pane on a desktop](docs/adr/2026-11-05-0408-needs-you-is-a-deck-on-a-phone-and-a-pane-on-a-desktop.md)).
|
|
497
|
+
What waits on the owner on a board, led by the board session's **pending prompts** ([Needs you gathers what waits on the owner, and a topic's questions are answered on one page](docs/adr/2026-10-29-1639-needs-you-gathers-what-waits-and-questions-answer-on-one-page.md)). On a phone it is the **deck** at the top of the board: one thing at a time, a tap on a question's option drafting its answer, which Send on Waiting on you sends with its notes, a prompt's buttons answering it on the tap, Skip, a dot per thing waiting, View prototypes on a question with prototypes, and All open questions at its foot. From 900px it is a pane beside the lanes, one orange line per work item over Waiting on you, which arrivals update in place ([Needs you is a deck on a phone and a pane on a desktop](docs/adr/2026-11-05-0408-needs-you-is-a-deck-on-a-phone-and-a-pane-on-a-desktop.md)). The board and Waiting on you are a board's two pages: side by side from 900px, and narrower one at a time, the board header's ? (with the open-question count as its badge) opening Waiting on you, whose check goes back to the board ([Board and Open questions are two pages](docs/adr/2026-11-07-1300-board-and-open-questions-are-two-pages.md)).
|
|
462
498
|
_Avoid_: inbox, digest
|
|
463
499
|
|
|
464
500
|
**Pending prompt**:
|
|
@@ -483,7 +519,7 @@ _Avoid_: unread, queued
|
|
|
483
519
|
|
|
484
520
|
|
|
485
521
|
**Prototype**:
|
|
486
|
-
A page that shows each option of one owner question as it would ship, built from the board's real components fed fake data. An agent records it with `board.mjs prototype add <topic>` in the site's `data/prototypes.json`, with its title, card and takes, and writes only the take files; the board serves `prototype-<topic>.html` from its one template, `board/public/prototype.html`. `question add` accepts a prototype url only for a recorded topic, with option ids a non-empty subset of its take keys in order, without repeats, and every take file written ([the board serves every prototype from one template](docs/adr/2026-11-01-1448-the-board-serves-every-prototype-from-one-template.md)).
|
|
522
|
+
A page that shows each option of one owner question as it would ship, built from the board's real components fed fake data. An agent records it with `board.mjs prototype add <topic>` in the site's `data/prototypes.json`, with its title, card and takes, and writes only the take files; the board serves `prototype-<topic>.html` from its one template, `board/public/prototype.html`. `question add` accepts a prototype url only for a recorded topic, with option ids a non-empty subset of its take keys in order, without repeats, and every take file written ([the board serves every prototype from one template](docs/adr/2026-11-01-1448-the-board-serves-every-prototype-from-one-template.md)). A **served round** is recorded with `--served <path>`: it has no take files, its page lives in the board's **base prototype worktree** (`~/.claude/kickflip/worktrees/<route>-prototypes`, on main), and its named **states** show as chips in the viewer's bar ([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)). The page is the **viewer**: full bleed with no header, a ✕ that goes back, one take at a time switched by the floating bar's ‹ › pager, ←/→ or a swipe, Choose this on the bar's second row, and on a card with earlier rounds a Round pill opening a sheet of them ([prototypes have their own button and a full-bleed viewer](docs/adr/2026-11-07-0300-prototypes-have-their-own-button-and-viewer.md)).
|
|
487
523
|
_Avoid_: mockup, demo page
|
|
488
524
|
|
|
489
525
|
**Prototype round**:
|
|
@@ -521,11 +557,11 @@ Refs in text that Claude or the owner wrote are linked by the renderer, never by
|
|
|
521
557
|
| `ui.js` | Shared helpers: escaping, times, reply bodies, attachments, icons and message buttons, badges by tone, `setHTML`, which patches a region in place and keeps the focused field's focus when it moves, and `fetchJSON`, through which the side pages read the API and wait out a board restart |
|
|
522
558
|
| `ui-links.js` | Linking refs, Linear ids, PRs and URLs in written text; load it right after `ui.js` |
|
|
523
559
|
| `ui-enums.js` | `BoardUI.BUTTON` and `BoardUI.ACTION_KIND`, the **action button**'s enums, shared with `board/domain.mjs`, which runs it in a vm context; load it before `ui-threads.js` and `ui-cards.js`. `view.test.mjs` checks that every action kind makes one button orange and every action button draws |
|
|
524
|
-
| `ui-patch.js` | `BoardUI.
|
|
560
|
+
| `ui-patch.js` | `BoardUI.applyPatch`, applying the board's patches on the page: cards by key, questions and topics by id, every other part whole when it changed, onHost beside the board ([the board sends per-card patches](docs/adr/2026-11-04-0332-the-board-sends-per-card-patches.md), [the board syncs by change number](docs/adr/2026-11-05-1819-the-board-syncs-by-change-number.md)) |
|
|
525
561
|
| `ui-order.js` | `BoardUI.laneOrder`, the board's order of its items ([each lane has one fixed order](docs/adr/2026-11-03-0223-each-lane-has-one-fixed-order.md)), shared with `board/domain.mjs`, which runs it in a vm context, so a tap the page draws at once lands where the server puts it |
|
|
526
|
-
| `ui-cards.js` | A card's lines, in order: title with its ticket badge, or New chip on an unsorted ask (none once sorted); status with its ETA,
|
|
527
|
-
| `ui-
|
|
528
|
-
| `ui-sidebar.js` | `BoardUI.sidebar`, the sidebar's markup from `/_hub/sidebar.json`, with the New version row from `updateRow`, Reload or the npm update's Upgrade, headed by `BoardUI.header` itself, with each row's key in **switch mode**; `switchKeys`, which row each key opens; `othersWaiting`, for the logo's label; `shortcuts`, the **shortcuts sheet**'s content from the one list of shortcuts; and `startCaption`, a starting board's step and seconds. Needs `ui-
|
|
562
|
+
| `ui-cards.js` | A card's lines, in order: title with its ticket badge, or New chip on an unsorted ask (none once sorted); status with its ETA, grey when the builder is stale; then PR, review and other chips, then the try badge (Visit or Install, with running, failed and stale states); its lineup's grey wave chip; last the time its lane sorts by and its footer status: its hold, blocked by, Action needed, staging, ready, stalled or stale, an In Progress card's phase bars and its unread count; the Hold sheet's picker; and at its top right a New card's bump, edit and delete icons, or another bumpable card's bump icon, filled orange once bumped; and the action row's Merge and Serve/Build buttons, main's bar and build wording |
|
|
563
|
+
| `ui-progress-bar.js` | `BoardUI.progressBar({count, done, now, percent, dim, tone, label})`, the one progress bar every bar draws from: an In Progress card's five build phases and a Todo card's planner dashes (`ui-cards.js`), and a starting board's three start steps (`ui-sidebar.js`); done steps filled, the one step at index `now` pulsing (none when dim), a `percent` filling the next. `BoardUI.onePulse`, listening for `animationstart`, puts every pulse on the page, bars and status dots, on one clock ([a progress bar pulses one step at a time](docs/adr/2026-11-06-0038-a-progress-bar-pulses-one-step-at-a-time.md)). Needs nothing else: `hub/hub.mjs` renders the app shell's first sidebar with it in a vm context; load it before `ui-cards.js` and `ui-sidebar.js` |
|
|
564
|
+
| `ui-sidebar.js` | `BoardUI.sidebar`, the sidebar's markup from `/_hub/sidebar.json`, with the New version row from `updateRow`, Reload or the npm update's Upgrade, headed by `BoardUI.header` itself, with each row's key in **switch mode**; `switchKeys`, which row each key opens; `othersWaiting`, for the logo's label; `shortcuts`, the **shortcuts sheet**'s content from the one list of shortcuts; and `startCaption`, a starting board's step and seconds. Needs `ui-progress-bar.js` and `ui-page-header.js` loaded before it: `hub/hub.mjs` renders the app shell's first sidebar with all three in a vm context |
|
|
529
565
|
| `sidebar.js` | Painting the sidebar from the copy written into the shell, else this device's last copy, then from each copy the hub's stream sends; this device's push subscription for its Turn on row; the logo's toggle, the drawer and its swipes, the rail's collapse, which this device keeps, and the logo's label; **switch mode**'s keys, from the document and a framed page, each row opened through the shell; the **shortcuts sheet**'s h h and Escape |
|
|
530
566
|
| `app.html` | The app shell: the sidebar, the view's slot, and its scripts and CSS from `/_hub/app/`, with a board's loads started in its `<head>`; the hub serves it for a browser's load of `/` or a site's page outside try URLs, and every load of a hub page, with the sidebar and its data written in (`hub/shell.mjs` `pageOf`), and the board server for a board's four view paths without them (`shellHtml`) |
|
|
531
567
|
| `router.js` | `AppRouter`: every hub URL as a view and each view as its URL (`ui.test.mjs` tests both), the views the shell mounts in place, framed pages included, and catching taps on links to them and back and forward, with `{idx}` in each history entry and `pushed` on one a push opened; a back arrow goes one step back by them. On the **page tree** each entry also carries `up`, how many of its parents sit under it, which the router writes on every way in, and the arrow goes up a level. It frames the paths `hub/shell.mjs` `pageOf` answers with the shell, which `hub/shell.test.mjs` checks |
|
|
@@ -541,12 +577,12 @@ Refs in text that Claude or the owner wrote are linked by the renderer, never by
|
|
|
541
577
|
| `view-frame.js` | Any other page as a frame view: the frame beside the board header with Open alone ↗, hiding that header for a page that draws its own, whose logo then toggles the sidebar; each load's URL and title to the shell, and taps on links to other views sent to it, a prototype's back arrow included, which the shell takes up the **page tree** before the page's own script can |
|
|
542
578
|
| `sidebar.css` | The sidebar's rail, its collapse, the drawer and switch mode, plus the shared New board dialog and the shortcuts sheet; linked after `colors.css` |
|
|
543
579
|
| `hub.css` | The hub views' CSS and the hub's down page's, every rule under `.hub-view`, the class on a hub view's root, on the down page's `<html>` and on the board's Hold sheet picker, which shares the duration picker's rules; the shell links it after `style.css`, whose header the hub views share, and the down page as `/_hub/hub.css` |
|
|
544
|
-
| `ui-page-header.js` | `BoardUI.header`, every page's header: the logo (which toggles the sidebar), a back arrow where needed (beside a phone-only logo), the title, then the time and ↻, a
|
|
580
|
+
| `ui-page-header.js` | `BoardUI.header`, every page's header: the logo (which toggles the sidebar), a back arrow where needed (beside a phone-only logo), the title, then the time and ↻, or a page's own trail, and on a board's two pages the switch between them below 900px (the board's ? with the open-question count, Waiting on you's check); `BoardUI.boardFoot`, the bulb and gear at the foot of the board. On a page of its own, the back arrow's own script goes one step back, or to its href after a push; in the app shell `router.js` does that. Needs nothing else: `server.mjs` renders each page's `<!--header {…}-->` with it, such as a prototype's, and `hub/hub.mjs` the shell's first sidebar, whose head is one too (`ui-sidebar.js`), each in a vm context |
|
|
545
581
|
| `ui-header.js` | The header's time, or paused until from the shell's pause state, and when it moves, the GitHub status line and its Hub links mark, the Hub links list, the setup checklist, when a refresh asks for a GitHub check, and which board header controls take taps |
|
|
546
582
|
| `ui-threads.js` | Thread messages, with link, status and agent lines, the open card's window over them with its Show more, and the reply form's Done |
|
|
547
583
|
| `ui-questions.js` | Owner question cards with their View prototypes button and drawn takes, answer history, prototype status, a confirm's line, the topic head's round chip and the Waiting on you topic row; `cardTopics`, which names a card's question topic from its card; `BoardUI.nextQuestion`, the pure move-on rule after a Send, and `sentNotice`, the Sent line the board reads on return |
|
|
548
584
|
| `ui-markdown.js` | The Markdown subset `view-notes.js` renders a card's notes with |
|
|
549
|
-
| `ui-snapshot.js` | The last visit's stored shape and
|
|
585
|
+
| `ui-snapshot.js` | The last visit's stored shape and what reads as one, which threads preload, which lines flash, and what counts as a card's update |
|
|
550
586
|
| `attach.js` | Picking and uploading attachments, each to the site of the board view around its composer |
|
|
551
587
|
| `prototype.html` | The one prototype page: the server fills in a recorded topic's title, header and takes; the stage that contains each take, and the pill's room below it |
|
|
552
588
|
| `prototype-kit.js` | The **kit** and the take loader: each switch ends the last take's cleanup, listeners and timers, renders the next into a fresh stage at the same scroll position, with each box scrolled inside the take scrolled back where the new take draws it, and turns links and forms in the stage into toasts; `prototype-kit.test.mjs` tests it |
|
|
@@ -554,7 +590,7 @@ Refs in text that Claude or the owner wrote are linked by the renderer, never by
|
|
|
554
590
|
| `app-core.js` | The view's shared helpers: drafts, read marks, hiding, and `steady`, which runs a repaint keeping the box being typed in, else the open card's title row, still on screen, and its focus and cursor; where the owner left the board, its scroll and box, kept through `B.keep` and restored after its next first render in the page; re-exports `dialogs.js` as `B.confirm` and `notice` |
|
|
555
591
|
| `dialogs.js` | `BoardDialogs.confirm` and `notice`, which every board page's dialogs go through, and `fitSheet`, the sheets’ shared phone keyboard handling, `repoSheet` for New board and Repo → Change, and `ticketsControl`, shared by New board and Board Settings, which opens `linear-key.js`’s modal for Linear without a working key; loaded on every page |
|
|
556
592
|
| `rules-editor.js` | `RulesEditor`, the rules list on Board Settings and the Hub page, with its own CSS; `ui.test.mjs` tests its pure parts |
|
|
557
|
-
| `app-threads.js` | Loading a thread, once at a time per card; an open card's thread, its reply box, quick replies and
|
|
593
|
+
| `app-threads.js` | Loading a thread, once at a time per card; an open card's thread, its reply box, quick replies and its send buttons |
|
|
558
594
|
| `app-cards.js` | Cards, their open detail with the details list ending in Notes ↗ · Visit/Install ↗ · Review on GitHub ↗ when present, and the workflow row: Merge, Hold, the **action button**, Serve/Build and rightmost **Implement**, each confirming but Hold, which opens its sheet with the duration picker; try requests, failure-thread links and main’s failed-build log and Retry sheet; the bump icon's bump and unbump, with no confirmation; an ask's detail shows only its action button; the thread's Done confirmation and send |
|
|
559
595
|
| `app-lanes.js` | Lanes, Done's and Asks' Show more, Done's finished-wave folds, Todo's **wave bands** with their Implement, Triage and ⋯ moves, and Plan waves |
|
|
560
596
|
| `new-task.js` | The + button, its new-task sheet and press-n-twice shortcut, on every page of a board |
|
|
@@ -562,9 +598,9 @@ Refs in text that Claude or the owner wrote are linked by the renderer, never by
|
|
|
562
598
|
| `app-needs.js` | The Needs you box, led by the board session's pending prompts |
|
|
563
599
|
| `ui-prompts.js` | A pending prompt's Needs you line: its details, Allow once, Always allow and Deny, or a question's options, Skip and Send |
|
|
564
600
|
| `prompts.js` | `PromptAnswers`, answering pending prompts from their lines on a board and the hub page: which taps send at once, Always allow's confirmation, and the picks a Send waits on |
|
|
565
|
-
| `app-arch.js` | The
|
|
601
|
+
| `app-arch.js` | The bulb at the foot of the board and its **architecture review** sheet: the last review, Run with its confirm, what a review waits on, and the bulb's glow while one runs |
|
|
566
602
|
| `app-reader.js` | The **reader sheet**: a builder's log (readable or raw, following it as it grows) and a card's or lineup's Notes, opened over the board from their links, closing on ✕, Escape, the dim area or Back |
|
|
567
603
|
| `app-banner.js` | The answer banner, its tap and its ✕ |
|
|
568
604
|
| `app-header.js` | The board's header controls and time, refresh, the offline state, the In Review header's GitHub line, the Hub links sheet and the setup checklist |
|
|
569
|
-
| `app-snapshot.js` | Reading and saving the last visit, also as the view unmounts,
|
|
570
|
-
| `app.js` | `BoardView`: each board's `B`, its state and per-board store, mount and unmount, what each part keeps through `B.keep` for the board's next mount in the page (`B.place`), and the view's markup for the app shell; rendering main's slim bar and the view from its parts, painting the last visit
|
|
605
|
+
| `app-snapshot.js` | Reading and saving the last visit in IndexedDB, also as the view unmounts, with its change number for `app.html`'s first board request, the flash when the catch-up lands, and each card's sign: the flash on a card that changed lanes or took a New task's place, and the tint on a card otherwise updated, unless the owner changed it from this page |
|
|
606
|
+
| `app.js` | `BoardView`: each board's `B`, its state and per-board store, mount and unmount, what each part keeps through `B.keep` for the board's next mount in the page (`B.place`), and the view's markup for the app shell; rendering main's slim bar and the view from its parts, painting the last visit live, loading the board with its open threads (taking over the loads `app.html` starts), `B.send`, which sends an **owner tap**, draws it at once and lands the board the POST answers with, and the bump icon's fade, preloading active cards' threads, the reload timers, and the change signal from the shell |
|