@boopkit/cap-web 0.5.6 → 0.5.7

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/README.md CHANGED
@@ -17,6 +17,7 @@ Copied into your project on install:
17
17
  - `src/controllers/pages.ts` — example page controllers (`home`, `about`)
18
18
  - `src/routes/pages.ts` — Express router mounting the example pages
19
19
  - `reference/web-ui.ref.md` — reference doc describing the UI conventions
20
+ - `scripts/ux-eval-capture.ts` — Playwright page capture the UX workflows use for screenshots, run as `npm run ux:capture`
20
21
 
21
22
  ### Scripts added to `package.json`
22
23
 
@@ -24,6 +25,7 @@ Copied into your project on install:
24
25
  |--------|---------|
25
26
  | `tailwind:build` | `npx @tailwindcss/cli -i styles/styles.css -o public/css/style.css --minify` |
26
27
  | `tailwind:watch` | `npx @tailwindcss/cli -i styles/styles.css -o public/css/style.css --watch` |
28
+ | `ux:capture` | `tsx scripts/ux-eval-capture.ts` — `npm run ux:capture -- <path> <label>` writes `tmp/ux-eval/<label>.png` |
27
29
 
28
30
  ### Server hooks
29
31
 
@@ -53,6 +55,8 @@ Order numbers are the `preRoutes` phase ordering; other capabilities slot themse
53
55
 
54
56
  Run `npm run tailwind:build` once after install to compile `styles/styles.css` into `public/css/style.css`. `boop status` reminds you of this.
55
57
 
58
+ Before the first UX capture, run `npx playwright install chromium` once to fetch the browser binary.
59
+
56
60
  ## Requirements
57
61
 
58
62
  **Other capabilities:** none — `cap-web` is self-contained.
@@ -62,6 +66,7 @@ Run `npm run tailwind:build` once after install to compile `styles/styles.css` i
62
66
  - `express-handlebars` — view engine binding
63
67
  - `tailwindcss` — utility-first CSS framework
64
68
  - `@tailwindcss/cli` (devDependency) — CSS compilation
69
+ - `playwright` and `tsx` (devDependencies) — the UX capture script
65
70
 
66
71
  **Peer dependencies** (already provided by the `web-app` kernel):
67
72
 
@@ -69,7 +74,7 @@ Run `npm run tailwind:build` once after install to compile `styles/styles.css` i
69
74
  - `express-handlebars >=7.0.0`
70
75
  - `handlebars >=4.0.0`
71
76
 
72
- **Environment variables:** none required. `NODE_ENV=production` enables a 1-day cache on static assets; otherwise caching is disabled.
77
+ **Environment variables:** none required. `NODE_ENV=production` enables a 1-day cache on static assets; otherwise caching is disabled. The UX capture script reads three optional settings: `BASE_URL` (the origin to capture, default `http://localhost:3000`), and `UX_EVAL_AUTH_COOKIE_NAME` with `UX_EVAL_AUTH_COOKIE_VALUE` (an auth cookie for authenticated pages).
73
78
 
74
79
  ## Usage
75
80
 
package/capability.json CHANGED
@@ -10,7 +10,9 @@
10
10
  ],
11
11
  "devDependencies": [
12
12
  "@tailwindcss/cli@^4",
13
- "@types/express-handlebars@^6"
13
+ "@types/express-handlebars@^6",
14
+ "playwright@^1.60.0",
15
+ "tsx@^4.0.0"
14
16
  ],
15
17
  "files": [
16
18
  "views/",
@@ -19,10 +21,14 @@
19
21
  "src/controllers/pages.ts",
20
22
  "src/routes/pages.ts",
21
23
  "tailwind.config.ts",
22
- "reference/web-ui.ref.md"
24
+ "reference/web-ui.ref.md",
25
+ "scripts/ux-eval-capture.ts"
23
26
  ],
24
27
  "skills": [
25
- "boop-web-web-ui-design"
28
+ "boop-web-web-ui-design",
29
+ "boop-web-testing",
30
+ "boop-web-website-dev-workflow",
31
+ "boop-web-design-handoff-workflow"
26
32
  ],
27
33
  "scripts": {
28
34
  "tailwind:build": {
@@ -32,12 +38,25 @@
32
38
  "tailwind:watch": {
33
39
  "cmd": "npx @tailwindcss/cli -i styles/styles.css -o public/css/style.css --watch",
34
40
  "description": "Watch for changes and rebuild Tailwind CSS"
41
+ },
42
+ "ux:capture": {
43
+ "cmd": "tsx scripts/ux-eval-capture.ts",
44
+ "description": "Screenshot a page for the UX workflows: npm run ux:capture -- <path> <label> writes tmp/ux-eval/<label>.png"
35
45
  }
36
46
  },
47
+ "env": [
48
+ { "name": "BASE_URL", "description": "Base origin the UX capture script renders against" },
49
+ { "name": "UX_EVAL_AUTH_COOKIE_NAME", "description": "Name of an auth cookie to inject for authenticated UX captures (cap-users uses 'auth_id')" },
50
+ { "name": "UX_EVAL_AUTH_COOKIE_VALUE", "description": "Value (session token) for the auth cookie used in UX captures" }
51
+ ],
37
52
  "postInstall": {
38
53
  "steps": [
39
- "Build CSS for the first time: npm run tailwind:build"
40
- ]
54
+ "Build CSS for the first time: npm run tailwind:build",
55
+ "Install the Playwright browser binary once, for the UX capture script: npx playwright install chromium",
56
+ "Capture a page: npm run ux:capture -- <path> <label> (writes tmp/ux-eval/<label>.png; needs the dev server running)",
57
+ "For authenticated pages, set UX_EVAL_AUTH_COOKIE_NAME + UX_EVAL_AUTH_COOKIE_VALUE, or wire the cap-users opt-in block documented in the script header"
58
+ ],
59
+ "verify": "npm run ux:capture -- / baseline"
41
60
  },
42
61
  "hooks": [
43
62
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boopkit/cap-web",
3
- "version": "0.5.6",
3
+ "version": "0.5.7",
4
4
  "description": "Express view engine configuration, Handlebars helpers, and static asset middleware",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -0,0 +1,103 @@
1
+ /**
2
+ * UX evaluation capture — single-page screenshot for the UX workflows.
3
+ *
4
+ * Renders one URL in headless Chromium and writes a labeled full-page PNG to
5
+ * the capture-output directory. Used by the boop-ux-eval-and-refine-workflow
6
+ * and boop-ux-app-ui-dev-workflow skills to produce before/after screenshots.
7
+ *
8
+ * Usage (cap-web supplies it as the `ux:capture` npm script):
9
+ * npm run ux:capture -- <path> <label>
10
+ * Examples:
11
+ * npm run ux:capture -- /items baseline
12
+ * npm run ux:capture -- /items after-change
13
+ *
14
+ * Environment:
15
+ * BASE_URL base origin to capture against (default http://localhost:3000)
16
+ * UX_EVAL_OUTPUT_DIR output directory (default tmp/ux-eval)
17
+ * UX_EVAL_AUTH_COOKIE_NAME optional — name of an auth cookie to inject
18
+ * UX_EVAL_AUTH_COOKIE_VALUE optional — value of that cookie (a valid session token)
19
+ *
20
+ * Public pages need no auth. For authenticated pages, supply a session cookie
21
+ * via the two UX_EVAL_AUTH_COOKIE_* env vars, or wire the cap-users opt-in
22
+ * block below to mint one automatically.
23
+ *
24
+ * One-time setup: `npx playwright install chromium` (downloads the browser).
25
+ */
26
+
27
+ import 'dotenv/config';
28
+ import { chromium } from 'playwright';
29
+ import * as fs from 'node:fs';
30
+ import * as path from 'node:path';
31
+
32
+ const BASE_URL = process.env.BASE_URL || 'http://localhost:3000';
33
+ const OUTPUT_DIR = path.resolve(
34
+ process.cwd(),
35
+ process.env.UX_EVAL_OUTPUT_DIR || path.join('tmp', 'ux-eval'),
36
+ );
37
+
38
+ const targetPath = process.argv[2] || '/';
39
+ const label = process.argv[3] || 'capture';
40
+
41
+ /**
42
+ * Resolve the auth cookie to inject, if any.
43
+ *
44
+ * Default: read a cookie name/value from the environment (works for any auth
45
+ * scheme — paste a valid session token into UX_EVAL_AUTH_COOKIE_VALUE).
46
+ *
47
+ * --- cap-users opt-in -------------------------------------------------------
48
+ * If this project uses @boopkit/cap-users, you can mint a session token here
49
+ * instead of pasting one, by replacing the body of this function with:
50
+ *
51
+ * import UserService from '../src/services/users.service';
52
+ * import { connectDatabase } from '@boopkit/cap-database';
53
+ * import db from '../src/db';
54
+ * await connectDatabase(db);
55
+ * const { identityService, authService } = UserService;
56
+ * const email = process.env.DEMO_EMAIL;
57
+ * const identity = await identityService.findByDomainAndKey('email', email);
58
+ * if (!identity) throw new Error(`No user for ${email}`);
59
+ * const token = await authService.generateSessionToken(identity.userId);
60
+ * await authService.setAuthorization(identity.userId, token, 'session', 'authenticated');
61
+ * return { name: 'auth_id', value: token }; // 'auth_id' is cap-users' cookie name
62
+ *
63
+ * (remember to `await db.$disconnect()` in main() if you open a DB connection).
64
+ * ---------------------------------------------------------------------------
65
+ */
66
+ async function resolveAuthCookie(): Promise<{ name: string; value: string } | null> {
67
+ const name = process.env.UX_EVAL_AUTH_COOKIE_NAME;
68
+ const value = process.env.UX_EVAL_AUTH_COOKIE_VALUE;
69
+ if (name && value) return { name, value };
70
+ return null;
71
+ }
72
+
73
+ async function main() {
74
+ fs.mkdirSync(OUTPUT_DIR, { recursive: true });
75
+
76
+ const browser = await chromium.launch({ headless: true });
77
+ const context = await browser.newContext({ viewport: { width: 1280, height: 900 } });
78
+
79
+ const cookie = await resolveAuthCookie();
80
+ if (cookie) {
81
+ await context.addCookies([
82
+ { name: cookie.name, value: cookie.value, domain: new URL(BASE_URL).hostname, path: '/' },
83
+ ]);
84
+ }
85
+
86
+ const page = await context.newPage();
87
+ const url = `${BASE_URL}${targetPath}`;
88
+ const response = await page.goto(url, { waitUntil: 'networkidle', timeout: 15_000 });
89
+ if (!response || response.status() >= 400) {
90
+ throw new Error(`HTTP ${response?.status() ?? 'no response'} for ${url}`);
91
+ }
92
+
93
+ const outFile = path.join(OUTPUT_DIR, `${label}.png`);
94
+ await page.screenshot({ path: outFile, fullPage: true });
95
+ console.log(`[ux-eval] Saved ${outFile}`);
96
+
97
+ await browser.close();
98
+ }
99
+
100
+ main().catch((e) => {
101
+ console.error(e);
102
+ process.exit(1);
103
+ });
@@ -0,0 +1,97 @@
1
+ ---
2
+ name: boop-web-design-handoff-workflow
3
+ description: "When the operator hands off a design package (a README plus a drop-in view template and CSS) for a redesigned surface, follow this process: read the README, VERIFY its claims against the real code, surface any buried decision to the operator, file an issue, run it as a sub-agent (branch for UAT or merge-on-clean-visual-check), then close out with knowledge integration and archival. The README is confident; confidence is not correctness — verify before you run."
4
+ metadata:
5
+ category: workflow
6
+ ---
7
+ > **Read `PROJECT.md`, beside this file, first.**
8
+ > It records how this project applies the guidance below, and where it deliberately differs.
9
+ > Where the two conflict, `PROJECT.md` wins.
10
+ > Record project-specific rules there, never in this file.
11
+
12
+ # Design-handoff workflow — turn a design package into shipped, reviewed code.
13
+
14
+ A design handoff package is a high-leverage input: someone has already done the design work and grounded it against the real view-model, so the implementation is mostly mechanical. The leverage is real, but so is the risk, and the risk lives in one place — **the README's claims about the existing code.** A handoff that says "the service already computes X, just re-expose it" is trivial if true and a hidden architectural decision if false. The whole process turns on verifying those claims before any code is written.
15
+
16
+ ## What a handoff package looks like
17
+
18
+ Three files, typically grouped under a per-handoff directory in the project's design/eval reference area:
19
+
20
+ - **`README.md`** — the authoritative spec. Names what is being built, which files it replaces, a "Data to surface" list (the view-model fields the redesign needs that the controller does not pass yet), what was deliberately dropped, and any follow-ons that are explicitly out of scope.
21
+ - **A drop-in view template** — replaces an existing view. Every new field is guarded (rendered only when the field is present) with a live fallback, so the template renders *today* against the current view-model and "lights up" as each data field lands. Ship the template first, work the data list independently.
22
+ - **A CSS file** — appended into an existing style block; its header comment names the rules it supersedes.
23
+
24
+ ## The process
25
+
26
+ ### 1. Read the README in full
27
+
28
+ It is the spec — read it before touching anything. Note the "Data to surface" items (the view-model gaps), what it claims already exists, what it dropped and why, and the named follow-ons.
29
+
30
+ ### 2. Verify the README's claims against the real code (the load-bearing step)
31
+
32
+ The README makes assertions about the current code: "X already exists," "Y was retired," "field Z is right there on the type," "this renders today with zero controller changes." **Every one of those is a feasibility claim, and each must be checked against the actual code before you judge the package.** This is the step that separates a clean run from a buried decision.
33
+
34
+ - Confirm each "already exists" / "is right there" claim by reading the named symbol. (In a real run: a handoff claimed a field was "right there" — it was, on the underlying type, just dropped on the way to the view-model; trivial. Another claimed an upstream surface "already computed" a value — it deliberately did *not*, behind a documented boundary; that was a hidden architectural decision, not a re-expose.)
35
+ - Confirm the template's "renders today" claim: the fields it depends on now exist on the view-model (or are provided by the controller), and the genuinely-new fields are guarded with a fallback.
36
+ - Confirm any "retired" / "dropped" claim — a value the README says is gone may still be live and reusable.
37
+
38
+ When every claim checks out, it is a clean single sub-agent run. When a claim is wrong — especially when "re-expose this" turns out to mean "reverse a deliberate architectural boundary" — there is a design decision hiding inside the package.
39
+
40
+ ### 3. Judge feasibility for a single sub-agent run
41
+
42
+ Ask: is the work bounded with a clear path, or is there a judgment call hiding — an architectural decision, a premise error in the README, a spec ambiguity, a value that has to be derived rather than re-exposed? If the path is clear, it is one sub-agent run. If a decision is hiding, **do not let a sub-agent silently resolve it** (it will take the easy path — e.g. calling the function that reverses the boundary — because that is what "makes it work").
43
+
44
+ ### 4. Surface the verdict and any decision to the operator
45
+
46
+ Report: feasible or not, the scope, and the one question that is genuinely theirs — the buried architectural decision, framed at their altitude with a recommendation. Use `boop-product-design-thought-partnership` here. Get the call, then bake the decision into the issue so the sub-agent inherits it rather than re-deriving it. (Example: "derive the value from the shared source, not by duplicating — the README's 're-expose' framing assumed an upstream surface already had it, which it didn't.")
47
+
48
+ ### 5. File a bd issue (goal/approach/context shape)
49
+
50
+ Per `boop-project-mgmt-beads-planning`. Breadcrumb the handoff README as the authoritative spec, and **if the operator settled a decision in step 4, state it in the issue and say it supersedes the README where they differ** — otherwise the sub-agent will follow the README's wrong premise. Note the template's graceful-degradation (template + CSS can drop first; view-model edits light it up). Name the visual-check as the done-gate.
51
+
52
+ ### 6. Run it as a sub-agent
53
+
54
+ - **Isolated worktree on a non-default port.** The operator's dev server on the main checkout (e.g. `:3000`) is theirs — never touch it. Create a worktree branch off main (e.g. `work/<id>`), run the worktree's dev server on a different port (`:3001`/`:3002`/etc.), copy `.env` in if tests/capture need it (gitignored, don't commit).
55
+ - **Apply template + CSS**, removing the rules the CSS header names as superseded.
56
+ - **Make the view-model edits** per the (corrected) data list.
57
+ - **Trim brittle tests rather than lovingly rework them.** A redesigned surface is in flux; the operator's visual UAT is the safety net. Keep the full suite green; do not invest in expanding coverage on a surface that is still moving.
58
+ - **The visual-check is the gate.** Build the CSS bundle, capture the affected states at desktop (1280) and mobile (390), and *read* the captures — the render is the proof, not the diff. (Auth caveat: the default capture tool may log in as a demo account and not reach the populated data you need; use a capture path that authenticates as the fully-populated account so the render shows real content.)
59
+ - **Never `pkill` or pattern-kill a process** — an over-broad `pkill -f "<server command>"` can kill the operator's main-checkout server. Stop only your own server, by precise PID via `lsof -i:<port>`.
60
+ - **Disposition:**
61
+ - **Branch for UAT** when the change is a substantial visual redesign the operator will want to see — leave the branch, the worktree, and the captures; do not merge, do not close.
62
+ - **Merge on a clean visual-check** when the change is quick, clear, and additive — merge to main only if the capture clearly confirms the result and tests are green; if verification is blocked or ambiguous, fall back to branch-for-UAT rather than merging blind.
63
+
64
+ ### 7. Close out (after the operator's UAT, or on a clean merge)
65
+
66
+ Often itself a sub-agent. Per `boop-product-design-knowledge-backfill`:
67
+
68
+ - **Merge** the branch to main; run the full suite green first.
69
+ - **Integrate the knowledge** — update the relevant reference page (e.g. the web-UI reference for a redesigned surface) to describe the new shape, and fix any reference line the redesign made stale. Commit docs direct to main.
70
+ - **Archive the handoff package** (unedited) to `specs/history/<name>-handoff/`.
71
+ - **Clean up** — close the issue, remove the worktree, delete the branch, stop the server by precise PID. Do not push to origin unless asked.
72
+
73
+ ## When to use this vs the other workflows
74
+
75
+ | Situation | Workflow |
76
+ |---|---|
77
+ | A design handoff package (README + drop-in template + CSS) for a surface | **this** |
78
+ | A goal-framed improvement to an existing surface, no package | `boop-light-dev-workflow` |
79
+ | A backlog cleanup sweep of lingering P1/P2 items | `boop-project-mgmt-issue-sweep-workflow` |
80
+ | A feature with backend work driven by a spec | `boop-feature-dev-workflow` |
81
+
82
+ ## Anti-patterns
83
+
84
+ - **Running the package without verifying its claims.** The README reads as authoritative; authority is not accuracy. The verify-against-code step (2) is the whole game — skip it and you ship a hidden decision or hit a wall mid-run.
85
+ - **Letting a sub-agent resolve a buried architectural decision.** When "re-expose X" actually means "reverse a documented boundary," a sub-agent will reverse it because that is the path of least resistance. Surface it to the operator instead.
86
+ - **Auto-merging a substantial visual redesign without the operator's eye.** Branch for UAT. Reserve merge-on-clean-visual-check for quick, clear, additive fixes.
87
+ - **Lovingly reworking brittle tests on a surface in flux.** Trim them; the visual UAT is the safety net. Reworking assertions that the redesign is about to invalidate again is wasted effort.
88
+ - **`pkill`.** It can kill the operator's main-checkout server. Precise PID only, and never the main checkout's server.
89
+ - **Following the README's premise after the operator corrected it.** If step 4 settled a decision, the issue must say it supersedes the README, or the sub-agent inherits the wrong framing.
90
+ - **Taking a package's scope at face value against the full mockup.** A handoff package may be a *subset* of the designer's full vision: a package redesigned only the primary list and scoped the header and empty-state out as "unchanged," but the full mockup redesigned them too — the gap only surfaced at the operator's UAT. In step 2/4, confirm the package's scope against the full design mockup; a package that says parts are "unchanged / out of scope" may still leave the surface divergent from what the operator expects. Surface that at UAT.
91
+
92
+ ## Related
93
+
94
+ - `boop-product-design-knowledge-backfill` — the archive + reference-integration discipline for the closeout.
95
+ - [`boop-web-web-ui-design`](../boop-web-web-ui-design/SKILL.md) — the visual-check-before-done rule the run leans on.
96
+ - `boop-light-dev-workflow` — the per-issue beats that run inside the sub-agent.
97
+ - `boop-product-design-thought-partnership` — surfacing the buried decision at the operator's altitude.
@@ -0,0 +1,94 @@
1
+ ---
2
+ name: boop-web-testing
3
+ description: "When you need to write or run tests for the Express server — services, controllers, middleware, and HTTP routes."
4
+ metadata:
5
+ category: test
6
+ ---
7
+ > **Read `PROJECT.md`, beside this file, first.**
8
+ > It records how this project applies the guidance below, and where it deliberately differs.
9
+ > Where the two conflict, `PROJECT.md` wins.
10
+ > Record project-specific rules there, never in this file.
11
+
12
+ # Testing: Express App (Web & APIs)
13
+
14
+
15
+ Parent skill: `boop-testing-testing` (philosophy, generic approach)
16
+
17
+ ---
18
+
19
+ ## Running Tests
20
+
21
+ ```bash
22
+ npm test # Full suite
23
+ npx jest tests/services/foo.test.ts --no-coverage # Single file
24
+ npx jest tests/services/foo --no-coverage # Pattern match
25
+ npx jest tests/services/foo.test.ts -t "handles replay" # By test name
26
+ ```
27
+
28
+ The focused forms are safe to reach for: the concurrency and per-worker memory settings live in `jest.config.js`, not in the `test` script, so `npx jest <path>` runs under the same settings the full suite does. Which of these you should be running on a given piece of work is a separate question — see "Which tests to run, and when" in the parent skill.
29
+
30
+ **Prerequisites**: integration tests run against the project's real backing services rather than mocks, so whatever the app talks to at runtime — the database first of all — has to be reachable from the machine running the tests. Which services those are depends on the capabilities the project has installed; its README and environment template are the authority.
31
+
32
+ ## Test File Layout
33
+
34
+ ```
35
+ tests/
36
+ helpers/ # shared setup, factories, harnesses (see below)
37
+ services/
38
+ foo.test.ts # Unit tests (mocked deps)
39
+ foo.integration.test.ts # Integration tests (real services)
40
+ controllers/
41
+ itemsAPI.test.ts # HTTP route tests
42
+ middleware/
43
+ utils/
44
+ ```
45
+
46
+ - `.test.ts` for Jest auto-discovery. Keep the mocked tests and the real-service tests for the same subject in **separate files**: `jest.mock` is hoisted above the imports and applies to every test in the module, so one file cannot both stub a dependency and exercise the real one. `.integration.test.ts` is the conventional name for the half that uses the real services.
47
+ - Group by domain: `services/`, `controllers/`, `middleware/`
48
+
49
+ ## Test Helpers
50
+
51
+ Shared test setup belongs in one place under `tests/`, not re-derived in each spec file: booting the app, creating the entities a test needs and tearing them down again, and harnesses that make an awkward dependency — a broker, a queue, a rendered template — drivable from a test.
52
+
53
+ **Read what the project already has before you write one.** These helpers are not scaffolded and cannot be, because they follow whichever capabilities and domain the project has. Every project grows its own set, and the shape varies from one shared module to a directory of purpose-built ones. Reuse what fits and extend it, rather than starting a private copy inside your test file. A helper used by exactly one test is not a helper — leave it in the test.
54
+
55
+ When you do add one, keep two properties. A factory returns a real, persisted entity rather than a hand-built object literal, so the test exercises the same shape production does. And whatever creates data owns its teardown, so one failed run does not poison the next.
56
+
57
+ ## Integration Test Data Isolation
58
+
59
+ Integration tests share their backing services with every other integration test, and with whatever the last run left behind. Three habits keep them from interfering with each other:
60
+
61
+ - **Namespace whatever you create.** A per-run prefix (`_test/${Date.now()}`, a UUID) keeps parallel runs and repeat runs from colliding on unique constraints.
62
+ - **Track created records and remove them in `afterAll`**, each cleanup wrapped in its own `try/catch` so one failure doesn't strand the rest.
63
+ - **Scope instead of deleting where deletes are expensive.** Some stores — append-only logs, analytics columnstores, anything with asynchronous merge semantics — make row deletion slow or eventually-consistent. Isolate those by writing under a test-specific tenant or key and leave the rows in place.
64
+
65
+ ## HTTP Route Tests
66
+ Test Express routes via **real HTTP requests** (`fetch()`) against a running local server. This exercises the full middleware chain (auth → controller → service → DB → response).
67
+
68
+ Why real HTTP over supertest: supertest skips TCP/listen and can mask middleware ordering or config bugs. Auth middleware is a critical path worth testing through, not around.
69
+
70
+ **Setup:**
71
+ ```typescript
72
+ const BASE_URL = process.env.TEST_BASE_URL || 'http://localhost:3000';
73
+ const TEST_API_KEY = process.env.TEST_API_KEY; // however this project issues API keys
74
+ const authHeaders = { 'Authorization': `Bearer ${TEST_API_KEY}`, 'Content-Type': 'application/json' };
75
+ ```
76
+
77
+ **What to cover:** auth rejection (401/403), request validation (400), the happy-path response shape, and the authorization boundary — that one account cannot reach another's data. If the project gates routes on anything further (feature flags, roles, plan tiers), cover the closed gate too, and assert the status code it actually returns rather than the one that seems right.
78
+
79
+ **Prereqs:** a local server running against a reachable database, a durable test account, and whatever credential the auth middleware expects (`TEST_API_KEY` by convention).
80
+
81
+ ## Ad-Hoc Testing Tools
82
+
83
+ Jest is what runs in CI and before a commit. Alongside it, projects grow small CLIs for the things a test suite is the wrong shape for: generating fixture data, poking a live local server, checking what actually landed in the database.
84
+
85
+ Boop scaffolds one — `npm run db:query` (database capability) — for reading the local database without opening Prisma Studio. Anything beyond that is project-grown; `package.json` scripts and `src/scripts/` are where to look for what yours has, and `--help` on each is faster than reading its source.
86
+
87
+ These are exploratory aids. They are not part of the automated suite, and none of them substitutes for a Jest test that can go red on its own.
88
+
89
+ ## References
90
+
91
+ - `boop-testing-testing` — testing philosophy and the generic approach
92
+ - `boop-testing-tdd-light` — the red/green loop for a single change
93
+ - The project's own shared test setup under `tests/` — read it before adding another helper
94
+ - `jest.config.js` at the project root — test discovery, transform, and match config
@@ -208,7 +208,7 @@ The flow:
208
208
 
209
209
  1. **Build the CSS bundle.** `npm run tailwind:build` (or the project's equivalent). Semantic classes compiled via `@apply` do not exist in the served bundle until it is rebuilt.
210
210
  2. **Restart the dev server if it caches the bundle at boot.** Many dev servers read the compiled CSS once at startup and a file watcher that ignores CSS will not pick up the rebuild.
211
- 3. **Capture the affected page** at desktop (1280px) and mobile (390px) widths via a headless capture tool — for example the `scripts/ux-eval-capture.ts` script `cap-ux` ships, or the project's equivalent.
211
+ 3. **Capture the affected page** at desktop (1280px) and mobile (390px) widths with `npm run ux:capture -- <path> <label>`, the Playwright capture script `cap-web` ships, or the project's equivalent.
212
212
  4. **Read the captures.** Confirm the new fields appear, the layout reads coherently, and nothing collapsed or stacked in a way the structural tests cannot see.
213
213
 
214
214
  If the capture surfaces a layout issue, fix it before closing the issue, even if all unit tests pass. A green test suite is not evidence that the surface looks right; only the capture is.
@@ -0,0 +1,206 @@
1
+ ---
2
+ name: boop-web-website-dev-workflow
3
+ description: "When you are tasked with implementing website changes end-to-end (new pages, page rewrites, IA changes, content/CTA updates), follow this guidance."
4
+ metadata:
5
+ category: workflow
6
+ ---
7
+ > **Read `PROJECT.md`, beside this file, first.**
8
+ > It records how this project applies the guidance below, and where it deliberately differs.
9
+ > Where the two conflict, `PROJECT.md` wins.
10
+ > Record project-specific rules there, never in this file.
11
+
12
+ # Workflow for building website changes.
13
+
14
+ This is the **website sibling** of `boop-feature-dev-workflow` — same step-by-step flow, same beads-issue structure, customized for marketing-site work (new pages, page rewrites, IA changes, content/CTA updates).
15
+
16
+ This workflow is **project-agnostic**. It names patterns of project artifacts (the driving spec, the brand reference docs, the audience-type marketing skill) rather than specific file paths. The Understand step (#1 below) is where you discover the specific artifacts that apply to *this* project and record them as breadcrumbs so the rest of the loop can pick them up.
17
+
18
+ ## Relevant skills
19
+
20
+ ### Project Management
21
+ - `boop-project-mgmt-beads-planning` — when you need to plan work with beads.
22
+ - `boop-project-mgmt-engineering-planning` — when you need to plan engineering work.
23
+
24
+ ### Design
25
+ - `boop-product-design-engineering-design` — when you need to design a feature or system.
26
+ - `boop-web-web-ui-design` — when you need to design web UIs; **the primary design skill for this workflow**.
27
+ - `boop-services-controllers` — when you need to design controllers, the route handlers that render views.
28
+
29
+ ### Coding
30
+ - `boop-coding-beads-flow` — when you need to start working on a claimed issue.
31
+ - `boop-coding-development` — when you need to develop or modify code.
32
+ - `boop-coding-commit-changes` — when you need to commit code changes.
33
+ - `boop-coding-review-changes` — when you need to review uncommitted code changes.
34
+
35
+ ### Testing
36
+ - `boop-testing-testing` — when you need to write or run tests.
37
+ - `boop-web-testing` — when you need to test Express web endpoints.
38
+
39
+ ### Documentation
40
+ - `boop-product-design-reference-integration` — when you need to integrate knowledge into reference docs.
41
+
42
+ ### Subject-matter marketing skills (discovered per project)
43
+ The project may ship an **audience-type marketing skill** carrying the universal copy patterns for whom it sells to — frameworks, default moves, forbidden patterns (e.g. a `b2b-marketing` skill when the project sells to businesses; consumer / marketplace / etc. variants exist for other audiences). boop does not bundle one; if the project provides it, the Understand step records its exact path. Use whichever matches the project's audience.
44
+
45
+ ## Project structure
46
+ Most projects this workflow runs on organize documents into:
47
+ - `reference/` — *current state.* The project's brand reference doc, brand realization (site) doc, product / positioning refs, and any tenets live here. These are the **guardrails**.
48
+ - `specs/` — *future state.* The driving spec for the work, plus any companion plans (`{feature-name}-plan-findings.md`, `{feature-name}-plan.md`) generated by this workflow.
49
+ - `skills/` — instructions for specific tasks. Additional skills reside in `packages/cap-*/skills/`.
50
+ - `tools/` — command-line tools used to automate the workflow. Do not run these until instructed to do so.
51
+
52
+ The Understand step (#1) records the exact files in *this* project's `reference/` and `specs/` that ground the work.
53
+
54
+ ### Where website content comes from
55
+
56
+ A website implementation task usually carries two layers of input:
57
+
58
+ - A **driving spec** in `specs/` — *future-state* intent. Defines which pages exist, what each page is *for* (its goal), the IA changes, and sometimes specific copy that has already been decided (a chosen hero line, an exact CTA label). The spec is the primary source of content **intent**.
59
+ - One or more **reference docs** in `reference/` — *current-state* guardrails. They do not usually carry page-level copy for new pages; they constrain how copy gets written: brand voice, audience model, tone modes, exclusions, settled positioning. Refs ground the spec and constrain slots the spec leaves underspecified — they are guardrails, not the canonical copy of new pages.
60
+
61
+ When a spec leaves a content slot underspecified (e.g. it states a goal but doesn't prescribe exact words), the implementer fills the gap using, in order:
62
+
63
+ 1. The spec's stated goal for that slot.
64
+ 2. The project's brand-voice and language constraints — read whichever ref doc carries them in this project (typically named in the Understand step's findings).
65
+ 3. The tone mode the project's brand realization doc assigns to that page or surface.
66
+ 4. The persona's buying motion and pain points named in the project's brand ref / audience model.
67
+ 5. The **audience-type marketing skill** for this project, if it ships one (discovered in the Understand step). This skill carries the universal copy patterns for that audience type — frameworks, default moves, forbidden patterns. The project's brand ref carries project-specific patterns on top.
68
+
69
+ If a content situation cannot be resolved by 1–5 (the refs don't cover it; the marketing skill is silent or absent; the spec doesn't speak to it), **flag it as a ref-doc gap or a spec gap** rather than guessing silently. Either:
70
+
71
+ - Update the relevant ref doc in the same branch and proceed (small additions, e.g. a new *Do/Don't* row), or
72
+ - File a follow-up issue and pick a placeholder for the current page (larger additions, e.g. a new persona).
73
+
74
+ This protects the ref docs as durable guardrails and keeps the next page's implementer from re-deriving the same decision.
75
+
76
+ ## Workflow
77
+ Prime directive: **Use beads issues for everything**. Beads has hierarchical issues (epics, features, tasks, sub-tasks, bugs). All steps of this website development workflow should be an issue, with appropriate dependencies and reference material (breadcrumbs, etc). We will use feature → task → sub-task for most work. If you find yourself doing work that is not in an issue, stop and create an issue for it.
78
+
79
+ **Flow overview.** The website work ships as a chain of issues, each one a separate task whose output is written somewhere the next task can find it:
80
+
81
+ > feature (parent) → understand → plan → decompose → implement → review → punch-list → closeout
82
+
83
+ The first issue is the feature parent; working it produces the next issue(s), and so on. `bd-loop` picks up each newly-ready issue and runs it until the chain is complete.
84
+
85
+ **The loop ends with the feature branch pushed for human review.** Merging, main-branch coordination, and branch deletion are out of scope for the loop. See step 6 (Closeout).
86
+
87
+ ### First step:
88
+ 1. **Create the feature issue**: Create a new feature issue in beads for the requested website work. This is the parent issue for all work tasks. Write a clear title and description that names the page(s) or IA change and links the driving spec (these are the 'breadcrumbs'). Ref-doc and marketing-skill identification happens in the Understand task (step 1 below); the feature issue does not need to enumerate them up front.
89
+
90
+ ### Task construction:
91
+ Create tasks as child issues of the feature issue. The descriptions below are the content of the created issue — so don't *do* the work described in the issue description, this is just the content of the issue.
92
+
93
+ 1. **Understand the work**: First task issue goal (don't *do* this work, this is the content of the task issue): Read the driving spec. Then **discover and record this project's guardrails**. For example:
94
+ - **Brand reference doc(s)** — read `reference/` and identify which file(s) define brand voice, language constraints, audience / personas, exclusions, and (if separate) the site-realization / tone-mode doc. Typical names include `brand.ref.md`, `branding-site.ref.md`, a tenets doc, and a product / positioning doc. Record the exact file paths.
95
+ - **Audience-type marketing skill** — based on whom the project sells to, identify the appropriate marketing skill if the project ships one. Record the exact skill path (or note that none exists).
96
+ - **Web design skill** — record the web UI / design skill the project uses (e.g. `boop-web-web-ui-design`).
97
+
98
+ Then, against the driving spec and those guardrails, identify:
99
+ - Which routes / controllers / views already exist for each affected page, and which need to be created. **For surfaces that may be scaffold-provided (auth, settings, account), check `node_modules/@boopkit/*/scaffold/` for existing views / controllers / routes before treating them as new work** — e.g. `cap-users` scaffolds login/signup views, an auth controller, and auth routes. Reuse or extend the scaffold surface rather than re-deriving it.
100
+ - For each affected page, **which content slots the spec already specifies** (hero line, CTA copy, page goal, IA placement) and **which slots the spec leaves underspecified** (sub-messaging, body copy, section headers, secondary calls-to-action). Underspecified slots will be filled at implementation time per *Where website content comes from* above.
101
+ - Which **tone mode** applies to each affected page (per whichever ref doc defines tone modes for this project).
102
+ - Which **personas / audience-model entries** the page is targeting (per the project's brand ref).
103
+ - Any pages explicitly marked **untouched** by the driving spec — do not touch these.
104
+ - Any retired pages that need their route + controller + view deleted (and what the spec prescribes for their replacement behavior — 404, redirect, or other).
105
+ - Any **ref-doc gaps** — content situations the page needs to address that the project's refs don't currently cover. Note them for resolution in the plan step.
106
+
107
+ If anything is unclear, ask for clarification rather than guessing.
108
+
109
+ **Findings handoff (critical):** The next task runs in a fresh session with zero context — anything not written to a discoverable file is lost. Write findings to `specs/{feature-name}-plan-findings.md` covering:
110
+ - **Guardrail registry** — the exact paths of the project's brand ref doc(s), realization / tone-mode doc, audience-type marketing skill (or "none"), and web design skill. These are the breadcrumbs the rest of the loop will carry forward.
111
+ - Spec understanding (what the driving spec says).
112
+ - List of affected routes / controllers / views and list of retired routes (with prescribed replacement behavior), noting which surfaces are scaffold-provided.
113
+ - Per-page content sourcing (what the spec specifies vs what's left to implementation judgment).
114
+ - Tone selection per page.
115
+ - Persona / audience targeting per page.
116
+ - Identified ref-doc gaps.
117
+ - Open questions and decisions / recommendations.
118
+
119
+ Reference this file as a breadcrumb in the "plan" task's issue description. The guardrail registry inside the findings file is what propagates the project's specific artifacts into all subsequent work tasks. A `bd close --reason` one-liner or short `--append-notes` summary is fine as a supplement, but the findings file is the primary handoff artifact — issue fields have length limits and aren't diff-friendly.
120
+
121
+ 2. **Plan the work**: Next task (don't *do* this work, this is the content of the task issue): **Start by reading the findings** at `specs/{feature-name}-plan-findings.md` from the "understand" task (path is in this task's breadcrumbs; also check `bd show <predecessor-id>` notes). The findings include the guardrail registry (brand ref, realization doc, audience-type marketing skill, web design skill) — these are the breadcrumbs you will propagate into the implementation, review, and punch-list tasks below.
122
+
123
+ Then find or create the website implementation plan at `specs/{feature-name}-plan.md`. Follow the `boop-project-mgmt-engineering-planning` skill. The plan should enumerate, for each in-scope page:
124
+ - Route + controller + view file paths (existing or new; flag scaffold-provided surfaces).
125
+ - **Per-block content sourcing** — for each major content block, whether the copy comes verbatim from the spec, is paraphrased from the spec, or will be written at implementation time per the project's brand-voice ref grounded by the audience-type marketing skill.
126
+ - The **tone mode** that applies (per the project's realization doc).
127
+ - The **persona(s)** the page is speaking to (per the project's brand ref).
128
+ - Any partials or semantic CSS classes that already exist and can be reused (per the project's web design skill).
129
+ - Any new semantic CSS classes that will be introduced.
130
+ - Metadata (page title, OG image strategy, description sourced from the hero lede).
131
+ - **Ref-doc gap resolution** — for each gap identified in step 1, either (a) a small in-branch ref-doc edit to close the gap, or (b) a placeholder for the page with a follow-up issue.
132
+ - **Acceptance** — what "done" looks like for this page (rendered in the browser per the project's golden path, brand-voice-aligned, semantic HTML, working CTAs, no broken links).
133
+
134
+ When you decompose the plan into implementation sub-tasks (step 3), **include the guardrail registry as breadcrumbs in each sub-task**: the brand ref doc(s), the realization / tone-mode doc, the audience-type marketing skill, the web design skill, and the per-page tone / persona selections from the plan. Review the plan to ensure it fully covers the spec; create follow-up tasks for any gaps it can't resolve.
135
+
136
+ 3. **Decompose the plan**: Next task (don't *do* this work, this is the content of the task issue): **Start by reading the website implementation plan** at `specs/{feature-name}-plan.md` (confirm path from this task's breadcrumbs). Break it down into a "do the work" task issue plus smaller sub-tasks following the `boop-project-mgmt-beads-planning` skill.
137
+
138
+ Sub-task granularity for website work is typically **page-level or surface-level**: one sub-task per new page, one per page rewrite, one per retired-route deletion, one for global-nav structure, etc. Shared concerns like semantic CSS extensions or new partials get their own sub-tasks and become blockers for the pages that depend on them.
139
+
140
+ **Propagate the guardrail registry into every sub-task as breadcrumbs** — brand ref doc(s), realization / tone-mode doc, audience-type marketing skill, web design skill — so the implementation agent does not have to re-discover them.
141
+
142
+ Create the feature branch `work/<feature-issue-id>` (e.g. `work/boop-arc.14`) — branch names MUST use the `work/` prefix + issue ID, never feature names like `home-page-refresh`. All sub-tasks work within this branch.
143
+
144
+ **Re-wire the Review dependency (critical):** Decompose only plans the work, it does not perform it. So Review (step 4) must depend on the "do the work" task, not on this Decompose task. If Review already exists with a Review→Decompose dep, fix it:
145
+ ```
146
+ bd dep remove <review-task-id> <this-decompose-task-id>
147
+ bd dep add <review-task-id> <do-the-work-task-id>
148
+ ```
149
+ If Review doesn't exist yet, create it now with the correct dep on the do-the-work task.
150
+
151
+ 4. **Review the work done**: Next task (don't *do* this work, this is the content of the task issue). Depends on the "do the work" task from step 3 (step 3 is responsible for rewiring this if pre-created with the wrong dep). Review all changes **in the feature branch** `work/<feature-issue-id>` (confirm with `git branch` or breadcrumbs). Run `bd children <feature-issue-id>` to see what sub-tasks were created and closed for context. Pull the **guardrail registry** from the findings file (`specs/{feature-name}-plan-findings.md`) before reviewing — every review below is anchored against those project-specific guardrails. This task will:
152
+ - Perform a **code review and content review** of all changes in the feature branch. The content review checks that each affected page (1) implements the driving spec's stated intent for every page-level goal, (2) where the spec specifies exact copy, uses that copy verbatim, and (3) where the spec leaves a content slot to implementation judgment, the copy aligns with the project's brand-voice ref and the audience-type marketing skill (no audience-register drift, no forbidden patterns, no superlatives without evidence, no invented positioning that contradicts settled ref-doc content).
153
+ - Perform a **brand-voice review** against the project's brand ref doc — its voice / language constraints / do-don't / exclusions sections. Flag any drift from the project-specific rules.
154
+ - Perform a **marketing-copy review** against the audience-type marketing skill (if the project ships one) — its universal forbidden patterns (hype cadence, vague universals, unearned superlatives, wrong-audience register) and its quick self-check.
155
+ - Perform a **tone-mode review** — each page uses the tone mode named in the plan (per the project's realization doc's tone-mode assignments).
156
+ - Perform a **machine-readability / semantic-HTML review** — headings describe sections; meaningful prose is in the HTML rather than JS-injected; code samples are `<pre><code>`, not background images; copy-paste-safe snippets; plain URLs for the things that matter; OG / meta descriptions truthful (and ideally lifted from the hero lede).
157
+ - Perform a **browser validation** — start the dev server on a port confirmed free (`lsof -ti tcp:<port>` prints nothing when free), load each affected page, and confirm the golden path (page renders, primary CTA is wired correctly, internal links work, no console errors, no broken images, the project's theme is intact, no contrast regressions). Test the page narrow (mobile-ish) as well as wide. **If browser validation isn't possible in this environment, say so explicitly — do not claim success.** (Per project `CLAUDE.md` / `AGENTS.md` conventions where present — *for UI or frontend changes, start the dev server and use the feature in a browser before reporting the task as complete.*)
158
+ - **Stop the dev server this task started** before it closes (`lsof -ti tcp:<port> | xargs kill`), by port only. Never pattern-kill (`pkill -f <runner>` reaches every other worktree's server and the operator's own — this project runs several worktrees and loops at once). Never stop a server you did not start: if the port you wanted is already held, identify the holder's cwd via `lsof -a -d cwd -p <pid> -Fn` and reuse it only when the directory is this feature's worktree, else take the next free port.
159
+ - Perform an **IA review** — the top-nav structure matches the driving spec; retired routes return the spec's prescribed behavior (404, redirect, or other); any home-page cross-links the spec prescribes are present; the primary CTA destination exists and is reachable from every surface that the spec routes traffic from.
160
+ - Write the review to `labs/claude-runs/{feature-issue-id}-review-summary.md`, structured as: code findings, content findings, brand-voice findings, marketing-copy findings, tone-mode findings, semantic-HTML findings, browser findings, IA findings, and an overall punch-list.
161
+ - Append a **punch-list** of issues that must be addressed before merge. Punch-list items typically span categories: code (refactor, naming, controller cleanliness), content (drift from spec intent or from brand-grounded copy judgment), brand-voice (project-specific forbidden phrasing, wrong register), marketing-copy (universal forbidden patterns — hype cadence, vague universals, unearned proof), tone (wrong mode applied), semantic HTML (heading order, missing alt text, JS-injected content), browser (visual bugs, broken links, console errors, mobile breaks, contrast issues), and IA (wrong nav, missing cross-links, retired routes still live).
162
+
163
+ 5. **Add a punch-list work task**: Create a 'punch list' task issue as a child of the feature issue. Its goal: turn each item in the punch-list from the review document into a sub-task issue under this punch-list task. **Propagate the guardrail registry into the punch-list task and its children** so the fixers operate against the same brand ref / marketing skill the implementation did.
164
+
165
+ **Hierarchy rule:** Create punch-list items with `--parent <punch-list-task-id>` so they are true hierarchical children: `bd create "..." --parent <punch-list-task-id> ...`. `bd dep add` creates sequencing only — it is not a substitute for `--parent`. Sequencing deps between siblings are fine to add after creation.
166
+
167
+ **Verify before closing the punch-list task:** Run `bd children <punch-list-task-id>` and confirm every item appears in the tree. Fix any missing item with `bd update <id> --parent <punch-list-task-id>` (remove conflicting deps first if needed). Only close once the tree is correct.
168
+
169
+ Punch-list sub-tasks of category "browser" or "content" should re-validate in the dev server after the fix, and each such sub-task stops the server it started before it closes, on the same terms as the browser validation in step 4. There is one sub-task per punch-list item, so deferring the stop to closeout leaves one stray watcher process per item. Sub-tasks of category "brand-voice" or "tone" should re-check against the project's brand ref doc. Sub-tasks of category "marketing-copy" should re-check against the audience-type marketing skill.
170
+
171
+ 6. **Close out the website work**: After the punch-list is resolved and the website work is complete, create a closeout task as a child of the feature issue. The closeout task performs two activities:
172
+
173
+ **a. Archive the spec:**
174
+ - Move the completed driving spec from `specs/` to `specs/history/` (create the directory if it doesn't exist).
175
+ - If any aspects of the spec were NOT implemented (deferred, descoped, or punted), extract those into a new revised spec in `specs/` that captures just the remaining work. Reference the archived spec for full context.
176
+ - The archived spec should be the full original — do not edit or trim it.
177
+ - If the work was driven by a *content* spec layered on top of a still-open *IA* spec, archive only the content spec and leave the IA spec in place.
178
+
179
+ **b. Integrate into reference:**
180
+ - Follow the `boop-product-design-reference-integration` skill to blend the new website knowledge into existing `reference/` pages.
181
+ - This is NOT "create a new page for the feature" — it's merging knowledge into the existing concept pages. The integration targets are the **guardrail registry** captured in the findings file:
182
+ - The project's brand realization / site doc — IA, page roster, retired-surfaces list, tone-mode assignments, any messaging tables (if rows changed).
183
+ - The project's brand ref doc — any voice / language drift discovered during implementation that warrants a new *Do/Don't* row, a new entry in *Language we avoid*, a new persona, etc.
184
+ - Any other project ref docs that surfaced gaps during the work.
185
+ - Update cross-links between affected reference pages.
186
+ - Remove or update any reference content that is now outdated (e.g. stale URLs, retired surfaces that the ref doc still names as live).
187
+
188
+ **c. Hand off — the loop ends at the feature branch:**
189
+
190
+ Terminal state: closeout commits pushed on `work/<feature-issue-id>`, beads synced, feature issue closed. A human reviews and (if approved) merges.
191
+
192
+ **Scope boundary:** Authority ends at the feature branch. The branch (local and remote) stays intact after closeout so the reviewer can inspect it — including a browser pass — and so it remains a revert anchor. Merging, pushing to `main`, and branch deletion belong to the human reviewer — partly because concurrent worktrees may have other `work/<id>` branches in flight that need out-of-band coordination.
193
+
194
+ **Final actions of the closeout task (in order):**
195
+ 1. Commit the closeout edits (spec archive + reference updates) on the feature branch.
196
+ 2. `git push` the feature branch to its own remote ref.
197
+ 3. `bd dolt push` so beads state is synced.
198
+ 4. `bd close <closeout-task-id>`.
199
+ 5. `bd close <feature-issue-id>` (all child work is now done).
200
+ 6. Stop. The loop will go idle on "No ready issues for prefix"; the next action belongs to the human reviewer.
201
+
202
+ ## Related
203
+
204
+ - [`boop-web-web-ui-design`](../boop-web-web-ui-design/SKILL.md) — the primary design skill for this workflow; read it at the design step, before deciding what a page is made of.
205
+ - `boop-ux-purpose-judgement` — when reviewing the rendered page, to ask whether each thing on it belongs there at all, which the visual pass does not ask.
206
+ - `boop-writing-technical-prose` — when writing the driving spec and the child issues; each is picked up cold by an agent who was not in this session.