From 8d534cd95c597f6fc00f59de6b4c8e26c9222920 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Mon, 25 May 2026 19:43:41 -0700 Subject: [PATCH] fix(design): skill resolvers learn the daemon's BOARD_URL output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The five skills that invoke $D compare --serve (design-shotgun, design-consultation, plan-design-review, office-hours, design-review) parsed `SERVE_STARTED: port=N` from stderr and then POSTed to `/api/reload` at that port during regenerate cycles. The new daemon hosts boards under `/boards//` so the reload endpoint moved to `api/reload` — without this update, the regenerate phase of every skill invocation would silently fail against daemon mode. Updated scripts/resolvers/design.ts to parse `BOARD_URL:` instead of the port, and to POST reloads against the per-board URL. Regenerated the four SKILL.md files via bun run gen:skill-docs. Legacy `--no-daemon` invocations continue to emit `SERVE_STARTED:` and serve at `/api/reload` — the resolver instructions note both. Surfaced by the maintainability specialist during /ship review (the "stale comment" finding was actually a behavior bug pointing at five downstream consumers). Codex's plan-review pass flagged the migration story as incomplete but I dismissed the concern — Codex was right. Co-Authored-By: Claude Opus 4.7 (1M context) --- design-consultation/SKILL.md | 22 +++++++++++++++++----- design-shotgun/SKILL.md | 22 +++++++++++++++++----- office-hours/SKILL.md | 7 +++++-- plan-design-review/SKILL.md | 22 +++++++++++++++++----- scripts/resolvers/design.ts | 29 ++++++++++++++++++++++------- 5 files changed, 78 insertions(+), 24 deletions(-) diff --git a/design-consultation/SKILL.md b/design-consultation/SKILL.md index bc52edc10..8cecaa3d6 100644 --- a/design-consultation/SKILL.md +++ b/design-consultation/SKILL.md @@ -1307,8 +1307,12 @@ This command generates the board HTML, starts an HTTP server on a random port, and opens it in the user's default browser. **Run it in the background** with `&` because the server needs to stay running while the user interacts with the board. -Parse the port from stderr output: `SERVE_STARTED: port=XXXXX`. You need this -for the board URL and for reloading during regeneration cycles. +Parse the board URL from stderr output. Default daemon path: +`BOARD_URL: http://127.0.0.1:N/boards//` (already includes the per-board +path; use this for the AskUserQuestion URL AND as the base for the reload +endpoint). Legacy `--no-daemon` path emits `SERVE_STARTED: port=XXXXX` and +serves a single board at `/`, with reload at `/api/reload` — only relevant +when an external caller explicitly passes `--no-daemon`. **PRIMARY WAIT: AskUserQuestion with board URL** @@ -1316,11 +1320,14 @@ After the board is serving, use AskUserQuestion to wait for the user. Include th board URL so they can click it if they lost the browser tab: "I've opened a comparison board with the design variants: -http://127.0.0.1:/ — Rate them, leave comments, remix + — Rate them, leave comments, remix elements you like, and click Submit when you're done. Let me know when you've submitted your feedback (or paste your preferences here). If you clicked Regenerate or Remix on the board, tell me and I'll generate new variants." +Substitute `` with the URL parsed from stderr (the daemon path +emits `BOARD_URL: http://127.0.0.1:N/boards//`). + **Do NOT use AskUserQuestion to ask which variant the user prefers.** The comparison board IS the chooser. AskUserQuestion is just the blocking wait mechanism. @@ -1364,8 +1371,13 @@ the approved variant. 2. If `regenerateAction` is `"remix"`, read `remixSpec` (e.g. `{"layout":"A","colors":"B"}`) 3. Generate new variants with `$D iterate` or `$D variants` using updated brief 4. Create new board: `$D compare --images "..." --output "$_DESIGN_DIR/design-board.html"` -5. Reload the board in the user's browser (same tab): - `curl -s -X POST http://127.0.0.1:PORT/api/reload -H 'Content-Type: application/json' -d '{"html":"$_DESIGN_DIR/design-board.html"}'` +5. Reload the board in the user's browser (same tab) — the URL is per-board + under daemon mode, so use `` (from the `BOARD_URL:` stderr + line) as the base: + `curl -s -X POST "${BOARD_URL}api/reload" -H 'Content-Type: application/json' -d '{"html":"$_DESIGN_DIR/design-board.html"}'` + Under `--no-daemon` the reload endpoint is `/api/reload` at the legacy + port; this path only matters if the caller explicitly opted out of the + daemon. 6. The board auto-refreshes. **AskUserQuestion again** with the same board URL to wait for the next round of feedback. Repeat until `feedback.json` appears. diff --git a/design-shotgun/SKILL.md b/design-shotgun/SKILL.md index 178416ba2..36cbcb498 100644 --- a/design-shotgun/SKILL.md +++ b/design-shotgun/SKILL.md @@ -1193,8 +1193,12 @@ This command generates the board HTML, starts an HTTP server on a random port, and opens it in the user's default browser. **Run it in the background** with `&` because the server needs to stay running while the user interacts with the board. -Parse the port from stderr output: `SERVE_STARTED: port=XXXXX`. You need this -for the board URL and for reloading during regeneration cycles. +Parse the board URL from stderr output. Default daemon path: +`BOARD_URL: http://127.0.0.1:N/boards//` (already includes the per-board +path; use this for the AskUserQuestion URL AND as the base for the reload +endpoint). Legacy `--no-daemon` path emits `SERVE_STARTED: port=XXXXX` and +serves a single board at `/`, with reload at `/api/reload` — only relevant +when an external caller explicitly passes `--no-daemon`. **PRIMARY WAIT: AskUserQuestion with board URL** @@ -1202,11 +1206,14 @@ After the board is serving, use AskUserQuestion to wait for the user. Include th board URL so they can click it if they lost the browser tab: "I've opened a comparison board with the design variants: -http://127.0.0.1:/ — Rate them, leave comments, remix + — Rate them, leave comments, remix elements you like, and click Submit when you're done. Let me know when you've submitted your feedback (or paste your preferences here). If you clicked Regenerate or Remix on the board, tell me and I'll generate new variants." +Substitute `` with the URL parsed from stderr (the daemon path +emits `BOARD_URL: http://127.0.0.1:N/boards//`). + **Do NOT use AskUserQuestion to ask which variant the user prefers.** The comparison board IS the chooser. AskUserQuestion is just the blocking wait mechanism. @@ -1250,8 +1257,13 @@ the approved variant. 2. If `regenerateAction` is `"remix"`, read `remixSpec` (e.g. `{"layout":"A","colors":"B"}`) 3. Generate new variants with `$D iterate` or `$D variants` using updated brief 4. Create new board: `$D compare --images "..." --output "$_DESIGN_DIR/design-board.html"` -5. Reload the board in the user's browser (same tab): - `curl -s -X POST http://127.0.0.1:PORT/api/reload -H 'Content-Type: application/json' -d '{"html":"$_DESIGN_DIR/design-board.html"}'` +5. Reload the board in the user's browser (same tab) — the URL is per-board + under daemon mode, so use `` (from the `BOARD_URL:` stderr + line) as the base: + `curl -s -X POST "${BOARD_URL}api/reload" -H 'Content-Type: application/json' -d '{"html":"$_DESIGN_DIR/design-board.html"}'` + Under `--no-daemon` the reload endpoint is `/api/reload` at the legacy + port; this path only matters if the caller explicitly opted out of the + daemon. 6. The board auto-refreshes. **AskUserQuestion again** with the same board URL to wait for the next round of feedback. Repeat until `feedback.json` appears. diff --git a/office-hours/SKILL.md b/office-hours/SKILL.md index c13b87766..b54c7c791 100644 --- a/office-hours/SKILL.md +++ b/office-hours/SKILL.md @@ -1414,8 +1414,11 @@ If the JSON contains `"regenerated": true`: 1. Read `regenerateAction` (or `remixSpec` for remix requests) 2. Generate new variants with `$D iterate` or `$D variants` using updated brief 3. Create new board with `$D compare` -4. POST the new HTML to the running server via `curl -X POST http://localhost:PORT/api/reload -H 'Content-Type: application/json' -d '{"html":"$_DESIGN_DIR/design-board.html"}'` - (parse the port from stderr: look for `SERVE_STARTED: port=XXXXX`) +4. POST the new HTML to the running board. Parse the board URL from stderr + (`BOARD_URL: http://127.0.0.1:N/boards//` — the daemon path) or fall + back to the legacy port (`SERVE_STARTED: port=N` — only emitted under + `--no-daemon`, hits `/api/reload` root). Daemon path: + `curl -X POST "${BOARD_URL}api/reload" -H 'Content-Type: application/json' -d '{"html":"$_DESIGN_DIR/design-board.html"}'` 5. Board auto-refreshes in the same tab If `"regenerated": false`: proceed with the approved variant. diff --git a/plan-design-review/SKILL.md b/plan-design-review/SKILL.md index 45b56bf4d..2c95c67e6 100644 --- a/plan-design-review/SKILL.md +++ b/plan-design-review/SKILL.md @@ -1131,8 +1131,12 @@ This command generates the board HTML, starts an HTTP server on a random port, and opens it in the user's default browser. **Run it in the background** with `&` because the server needs to stay running while the user interacts with the board. -Parse the port from stderr output: `SERVE_STARTED: port=XXXXX`. You need this -for the board URL and for reloading during regeneration cycles. +Parse the board URL from stderr output. Default daemon path: +`BOARD_URL: http://127.0.0.1:N/boards//` (already includes the per-board +path; use this for the AskUserQuestion URL AND as the base for the reload +endpoint). Legacy `--no-daemon` path emits `SERVE_STARTED: port=XXXXX` and +serves a single board at `/`, with reload at `/api/reload` — only relevant +when an external caller explicitly passes `--no-daemon`. **PRIMARY WAIT: AskUserQuestion with board URL** @@ -1140,11 +1144,14 @@ After the board is serving, use AskUserQuestion to wait for the user. Include th board URL so they can click it if they lost the browser tab: "I've opened a comparison board with the design variants: -http://127.0.0.1:/ — Rate them, leave comments, remix + — Rate them, leave comments, remix elements you like, and click Submit when you're done. Let me know when you've submitted your feedback (or paste your preferences here). If you clicked Regenerate or Remix on the board, tell me and I'll generate new variants." +Substitute `` with the URL parsed from stderr (the daemon path +emits `BOARD_URL: http://127.0.0.1:N/boards//`). + **Do NOT use AskUserQuestion to ask which variant the user prefers.** The comparison board IS the chooser. AskUserQuestion is just the blocking wait mechanism. @@ -1188,8 +1195,13 @@ the approved variant. 2. If `regenerateAction` is `"remix"`, read `remixSpec` (e.g. `{"layout":"A","colors":"B"}`) 3. Generate new variants with `$D iterate` or `$D variants` using updated brief 4. Create new board: `$D compare --images "..." --output "$_DESIGN_DIR/design-board.html"` -5. Reload the board in the user's browser (same tab): - `curl -s -X POST http://127.0.0.1:PORT/api/reload -H 'Content-Type: application/json' -d '{"html":"$_DESIGN_DIR/design-board.html"}'` +5. Reload the board in the user's browser (same tab) — the URL is per-board + under daemon mode, so use `` (from the `BOARD_URL:` stderr + line) as the base: + `curl -s -X POST "${BOARD_URL}api/reload" -H 'Content-Type: application/json' -d '{"html":"$_DESIGN_DIR/design-board.html"}'` + Under `--no-daemon` the reload endpoint is `/api/reload` at the legacy + port; this path only matters if the caller explicitly opted out of the + daemon. 6. The board auto-refreshes. **AskUserQuestion again** with the same board URL to wait for the next round of feedback. Repeat until `feedback.json` appears. diff --git a/scripts/resolvers/design.ts b/scripts/resolvers/design.ts index 33247aab5..9f31b3619 100644 --- a/scripts/resolvers/design.ts +++ b/scripts/resolvers/design.ts @@ -891,8 +891,11 @@ If the JSON contains \`"regenerated": true\`: 1. Read \`regenerateAction\` (or \`remixSpec\` for remix requests) 2. Generate new variants with \`$D iterate\` or \`$D variants\` using updated brief 3. Create new board with \`$D compare\` -4. POST the new HTML to the running server via \`curl -X POST http://localhost:PORT/api/reload -H 'Content-Type: application/json' -d '{"html":"$_DESIGN_DIR/design-board.html"}'\` - (parse the port from stderr: look for \`SERVE_STARTED: port=XXXXX\`) +4. POST the new HTML to the running board. Parse the board URL from stderr + (\`BOARD_URL: http://127.0.0.1:N/boards//\` — the daemon path) or fall + back to the legacy port (\`SERVE_STARTED: port=N\` — only emitted under + \`--no-daemon\`, hits \`/api/reload\` root). Daemon path: + \`curl -X POST "\${BOARD_URL}api/reload" -H 'Content-Type: application/json' -d '{"html":"$_DESIGN_DIR/design-board.html"}'\` 5. Board auto-refreshes in the same tab If \`"regenerated": false\`: proceed with the approved variant. @@ -919,8 +922,12 @@ This command generates the board HTML, starts an HTTP server on a random port, and opens it in the user's default browser. **Run it in the background** with \`&\` because the server needs to stay running while the user interacts with the board. -Parse the port from stderr output: \`SERVE_STARTED: port=XXXXX\`. You need this -for the board URL and for reloading during regeneration cycles. +Parse the board URL from stderr output. Default daemon path: +\`BOARD_URL: http://127.0.0.1:N/boards//\` (already includes the per-board +path; use this for the AskUserQuestion URL AND as the base for the reload +endpoint). Legacy \`--no-daemon\` path emits \`SERVE_STARTED: port=XXXXX\` and +serves a single board at \`/\`, with reload at \`/api/reload\` — only relevant +when an external caller explicitly passes \`--no-daemon\`. **PRIMARY WAIT: AskUserQuestion with board URL** @@ -928,11 +935,14 @@ After the board is serving, use AskUserQuestion to wait for the user. Include th board URL so they can click it if they lost the browser tab: "I've opened a comparison board with the design variants: -http://127.0.0.1:/ — Rate them, leave comments, remix + — Rate them, leave comments, remix elements you like, and click Submit when you're done. Let me know when you've submitted your feedback (or paste your preferences here). If you clicked Regenerate or Remix on the board, tell me and I'll generate new variants." +Substitute \`\` with the URL parsed from stderr (the daemon path +emits \`BOARD_URL: http://127.0.0.1:N/boards//\`). + **Do NOT use AskUserQuestion to ask which variant the user prefers.** The comparison board IS the chooser. AskUserQuestion is just the blocking wait mechanism. @@ -976,8 +986,13 @@ the approved variant. 2. If \`regenerateAction\` is \`"remix"\`, read \`remixSpec\` (e.g. \`{"layout":"A","colors":"B"}\`) 3. Generate new variants with \`$D iterate\` or \`$D variants\` using updated brief 4. Create new board: \`$D compare --images "..." --output "$_DESIGN_DIR/design-board.html"\` -5. Reload the board in the user's browser (same tab): - \`curl -s -X POST http://127.0.0.1:PORT/api/reload -H 'Content-Type: application/json' -d '{"html":"$_DESIGN_DIR/design-board.html"}'\` +5. Reload the board in the user's browser (same tab) — the URL is per-board + under daemon mode, so use \`\` (from the \`BOARD_URL:\` stderr + line) as the base: + \`curl -s -X POST "\${BOARD_URL}api/reload" -H 'Content-Type: application/json' -d '{"html":"$_DESIGN_DIR/design-board.html"}'\` + Under \`--no-daemon\` the reload endpoint is \`/api/reload\` at the legacy + port; this path only matters if the caller explicitly opted out of the + daemon. 6. The board auto-refreshes. **AskUserQuestion again** with the same board URL to wait for the next round of feedback. Repeat until \`feedback.json\` appears.