fix: plan-design-review agent guardrails for feedback loop

Four fixes to prevent agents from reinventing the feedback loop badly:

1. Sequential generate rule: explicit instruction that $D generate calls
   must run one at a time (API rate-limits concurrent image generation).
2. No-AskUserQuestion-for-feedback rule: agent reads feedback.json instead
   of re-asking what the user picked.
3. Remove file:// references: $B goto file:// was always rejected by
   url-validation.ts. The --serve flag handles everything.
4. Remove $B eval polling reference: no longer needed with HTTP POST.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-03-27 10:27:43 -06:00
parent c0226bfcf6
commit 6c43199211
4 changed files with 22 additions and 4 deletions

View File

@@ -29,8 +29,10 @@ _PROACTIVE=$($GSTACK_BIN/gstack-config get proactive 2>/dev/null || echo "true")
_PROACTIVE_PROMPTED=$([ -f ~/.gstack/.proactive-prompted ] && echo "yes" || echo "no") _PROACTIVE_PROMPTED=$([ -f ~/.gstack/.proactive-prompted ] && echo "yes" || echo "no")
_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown") _BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
echo "BRANCH: $_BRANCH" echo "BRANCH: $_BRANCH"
_SKILL_PREFIX=$($GSTACK_BIN/gstack-config get skill_prefix 2>/dev/null || echo "false")
echo "PROACTIVE: $_PROACTIVE" echo "PROACTIVE: $_PROACTIVE"
echo "PROACTIVE_PROMPTED: $_PROACTIVE_PROMPTED" echo "PROACTIVE_PROMPTED: $_PROACTIVE_PROMPTED"
echo "SKILL_PREFIX: $_SKILL_PREFIX"
source <($GSTACK_BIN/gstack-repo-mode 2>/dev/null) || true source <($GSTACK_BIN/gstack-repo-mode 2>/dev/null) || true
REPO_MODE=${REPO_MODE:-unknown} REPO_MODE=${REPO_MODE:-unknown}
echo "REPO_MODE: $REPO_MODE" echo "REPO_MODE: $REPO_MODE"
@@ -54,6 +56,11 @@ types (e.g., /qa, /ship). If you would have auto-invoked a skill, instead briefl
"I think /skillname might help here — want me to run it?" and wait for confirmation. "I think /skillname might help here — want me to run it?" and wait for confirmation.
The user opted out of proactive behavior. The user opted out of proactive behavior.
If `SKILL_PREFIX` is `"true"`, the user has namespaced skill names. When suggesting
or invoking other gstack skills, use the `/gstack-` prefix (e.g., `/gstack-qa` instead
of `/qa`, `/gstack-ship` instead of `/ship`). Disk paths are unaffected — always use
`$GSTACK_ROOT/[skill-name]/SKILL.md` for reading skill files.
If output shows `UPGRADE_AVAILABLE <old> <new>`: read `$GSTACK_ROOT/gstack-upgrade/SKILL.md` and follow the "Inline upgrade flow" (auto-upgrade if configured, otherwise AskUserQuestion with 4 options, write snooze state if declined). If `JUST_UPGRADED <from> <to>`: tell user "Running gstack v{to} (just updated!)" and continue. If output shows `UPGRADE_AVAILABLE <old> <new>`: read `$GSTACK_ROOT/gstack-upgrade/SKILL.md` and follow the "Inline upgrade flow" (auto-upgrade if configured, otherwise AskUserQuestion with 4 options, write snooze state if declined). If `JUST_UPGRADED <from> <to>`: tell user "Running gstack v{to} (just updated!)" and continue.
If `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. If `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle.

View File

@@ -26,8 +26,10 @@ _PROACTIVE=$($GSTACK_BIN/gstack-config get proactive 2>/dev/null || echo "true")
_PROACTIVE_PROMPTED=$([ -f ~/.gstack/.proactive-prompted ] && echo "yes" || echo "no") _PROACTIVE_PROMPTED=$([ -f ~/.gstack/.proactive-prompted ] && echo "yes" || echo "no")
_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown") _BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
echo "BRANCH: $_BRANCH" echo "BRANCH: $_BRANCH"
_SKILL_PREFIX=$($GSTACK_BIN/gstack-config get skill_prefix 2>/dev/null || echo "false")
echo "PROACTIVE: $_PROACTIVE" echo "PROACTIVE: $_PROACTIVE"
echo "PROACTIVE_PROMPTED: $_PROACTIVE_PROMPTED" echo "PROACTIVE_PROMPTED: $_PROACTIVE_PROMPTED"
echo "SKILL_PREFIX: $_SKILL_PREFIX"
source <($GSTACK_BIN/gstack-repo-mode 2>/dev/null) || true source <($GSTACK_BIN/gstack-repo-mode 2>/dev/null) || true
REPO_MODE=${REPO_MODE:-unknown} REPO_MODE=${REPO_MODE:-unknown}
echo "REPO_MODE: $REPO_MODE" echo "REPO_MODE: $REPO_MODE"
@@ -51,6 +53,11 @@ types (e.g., /qa, /ship). If you would have auto-invoked a skill, instead briefl
"I think /skillname might help here — want me to run it?" and wait for confirmation. "I think /skillname might help here — want me to run it?" and wait for confirmation.
The user opted out of proactive behavior. The user opted out of proactive behavior.
If `SKILL_PREFIX` is `"true"`, the user has namespaced skill names. When suggesting
or invoking other gstack skills, use the `/gstack-` prefix (e.g., `/gstack-qa` instead
of `/qa`, `/gstack-ship` instead of `/ship`). Disk paths are unaffected — always use
`$GSTACK_ROOT/[skill-name]/SKILL.md` for reading skill files.
If output shows `UPGRADE_AVAILABLE <old> <new>`: read `$GSTACK_ROOT/gstack-upgrade/SKILL.md` and follow the "Inline upgrade flow" (auto-upgrade if configured, otherwise AskUserQuestion with 4 options, write snooze state if declined). If `JUST_UPGRADED <from> <to>`: tell user "Running gstack v{to} (just updated!)" and continue. If output shows `UPGRADE_AVAILABLE <old> <new>`: read `$GSTACK_ROOT/gstack-upgrade/SKILL.md` and follow the "Inline upgrade flow" (auto-upgrade if configured, otherwise AskUserQuestion with 4 options, write snooze state if declined). If `JUST_UPGRADED <from> <to>`: tell user "Running gstack v{to} (just updated!)" and continue.
If `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle. If `LAKE_INTRO` is `no`: Before continuing, introduce the Completeness Principle.

View File

@@ -564,8 +564,6 @@ planning phase. Generating mockups during planning is the whole point.
Allowed commands under this exception: Allowed commands under this exception:
- `mkdir -p ~/.gstack/projects/$SLUG/designs/...` - `mkdir -p ~/.gstack/projects/$SLUG/designs/...`
- `$D generate`, `$D variants`, `$D compare`, `$D iterate`, `$D evolve`, `$D check` - `$D generate`, `$D variants`, `$D compare`, `$D iterate`, `$D evolve`, `$D check`
- `$B goto file:///` (to view comparison board in browser)
- `$B eval document.getElementById(...)` (to read user feedback from comparison board)
- `open` (fallback for viewing boards when `$B` is not available) - `open` (fallback for viewing boards when `$B` is not available)
First, set up the output directory. Name it after the screen/feature being designed and today's date: First, set up the output directory. Name it after the screen/feature being designed and today's date:
@@ -579,6 +577,8 @@ echo "DESIGN_DIR: $_DESIGN_DIR"
Replace `<screen-name>` with a descriptive kebab-case name (e.g., `homepage-variants`, `settings-page`, `onboarding-flow`). Replace `<screen-name>` with a descriptive kebab-case name (e.g., `homepage-variants`, `settings-page`, `onboarding-flow`).
**Generate mockups ONE AT A TIME. Do not parallelize `$D generate` calls.** The underlying API rate-limits concurrent image generation. When 3 generates run in parallel, 1 succeeds and 2 get aborted.
For each UI screen/section in scope, construct a design brief from the plan's description (and DESIGN.md if present) and generate variants: For each UI screen/section in scope, construct a design brief from the plan's description (and DESIGN.md if present) and generate variants:
```bash ```bash
@@ -684,6 +684,8 @@ Use AskUserQuestion to verify before proceeding.
echo '{"approved_variant":"<V>","feedback":"<FB>","date":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","screen":"<SCREEN>","branch":"'$(git branch --show-current 2>/dev/null)'"}' > "$_DESIGN_DIR/approved.json" echo '{"approved_variant":"<V>","feedback":"<FB>","date":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","screen":"<SCREEN>","branch":"'$(git branch --show-current 2>/dev/null)'"}' > "$_DESIGN_DIR/approved.json"
``` ```
**Do NOT use AskUserQuestion to ask which variant the user picked.** Read `feedback.json` — it already contains their preferred variant, ratings, comments, and overall feedback. Only use AskUserQuestion to confirm you understood the feedback correctly, never to re-ask what they chose.
Note which direction was approved. This becomes the visual reference for all subsequent review passes. Note which direction was approved. This becomes the visual reference for all subsequent review passes.
**Multiple variants/screens:** If the user asked for multiple variants (e.g., "5 versions of the homepage"), generate ALL as separate variant sets with their own comparison boards. Each screen/variant set gets its own subdirectory under `designs/`. Complete all mockup generation and user selection before starting review passes. **Multiple variants/screens:** If the user asked for multiple variants (e.g., "5 versions of the homepage"), generate ALL as separate variant sets with their own comparison boards. Each screen/variant set gets its own subdirectory under `designs/`. Complete all mockup generation and user selection before starting review passes.

View File

@@ -176,8 +176,6 @@ planning phase. Generating mockups during planning is the whole point.
Allowed commands under this exception: Allowed commands under this exception:
- `mkdir -p ~/.gstack/projects/$SLUG/designs/...` - `mkdir -p ~/.gstack/projects/$SLUG/designs/...`
- `$D generate`, `$D variants`, `$D compare`, `$D iterate`, `$D evolve`, `$D check` - `$D generate`, `$D variants`, `$D compare`, `$D iterate`, `$D evolve`, `$D check`
- `$B goto file:///` (to view comparison board in browser)
- `$B eval document.getElementById(...)` (to read user feedback from comparison board)
- `open` (fallback for viewing boards when `$B` is not available) - `open` (fallback for viewing boards when `$B` is not available)
First, set up the output directory. Name it after the screen/feature being designed and today's date: First, set up the output directory. Name it after the screen/feature being designed and today's date:
@@ -191,6 +189,8 @@ echo "DESIGN_DIR: $_DESIGN_DIR"
Replace `<screen-name>` with a descriptive kebab-case name (e.g., `homepage-variants`, `settings-page`, `onboarding-flow`). Replace `<screen-name>` with a descriptive kebab-case name (e.g., `homepage-variants`, `settings-page`, `onboarding-flow`).
**Generate mockups ONE AT A TIME. Do not parallelize `$D generate` calls.** The underlying API rate-limits concurrent image generation. When 3 generates run in parallel, 1 succeeds and 2 get aborted.
For each UI screen/section in scope, construct a design brief from the plan's description (and DESIGN.md if present) and generate variants: For each UI screen/section in scope, construct a design brief from the plan's description (and DESIGN.md if present) and generate variants:
```bash ```bash
@@ -213,6 +213,8 @@ rate the others, remix elements, and click Submit when you're done."
{{DESIGN_SHOTGUN_LOOP}} {{DESIGN_SHOTGUN_LOOP}}
**Do NOT use AskUserQuestion to ask which variant the user picked.** Read `feedback.json` — it already contains their preferred variant, ratings, comments, and overall feedback. Only use AskUserQuestion to confirm you understood the feedback correctly, never to re-ask what they chose.
Note which direction was approved. This becomes the visual reference for all subsequent review passes. Note which direction was approved. This becomes the visual reference for all subsequent review passes.
**Multiple variants/screens:** If the user asked for multiple variants (e.g., "5 versions of the homepage"), generate ALL as separate variant sets with their own comparison boards. Each screen/variant set gets its own subdirectory under `designs/`. Complete all mockup generation and user selection before starting review passes. **Multiple variants/screens:** If the user asked for multiple variants (e.g., "5 versions of the homepage"), generate ALL as separate variant sets with their own comparison boards. Each screen/variant set gets its own subdirectory under `designs/`. Complete all mockup generation and user selection before starting review passes.