From bbf1c84fd267e2303f9a722fc6a25b7d63e7c3d9 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Wed, 10 Jun 2026 11:41:57 +0200 Subject: [PATCH] T-307: gate frame0-wireframe skill on per-screen approval The Core Workflow ran straight through and tended to fan out a whole set of screens unprompted. Reframe it as a design conversation: author one screen, show it, then STOP for explicit user approval before building the next (loop back to step 2 per screen). Multi-screen requests become a one-at-a-time queue. Closes T-307 (under UI epic T-276). Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/skills/frame0-wireframe/SKILL.md | 20 ++++++++++++++++++-- .pql/changelog/ticket_history/2026-06.sql | 1 + .pql/changelog/tickets/2026-06.sql | 5 +++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/.claude/skills/frame0-wireframe/SKILL.md b/.claude/skills/frame0-wireframe/SKILL.md index 05bb1255..dc80e021 100644 --- a/.claude/skills/frame0-wireframe/SKILL.md +++ b/.claude/skills/frame0-wireframe/SKILL.md @@ -32,8 +32,14 @@ Always check first: ## Core Workflow +Wireframing is a **design conversation, not a batch job.** Produce **one screen +at a time**, show it, and **stop for the user's reaction** before authoring the +next. Each shown screen is a checkpoint — never fan out a whole set of +wireframes unprompted, even if the user described several screens up front. + 1. **Health check** — verify Frame0 is running -2. **Write wireframe JSON** — to `docs/design/wireframes/{category}/{name}.json` +2. **Write wireframe JSON** — to `docs/design/wireframes/{category}/{name}.json`. + Author **one** screen. 3. **Push to Frame0** — `frame0-sync.py push ` 4. **Export PNG** — `frame0-sync.py export ` 5. **Show it inline** — surface the exported PNG in the conversation so the @@ -45,7 +51,17 @@ Always check first: way to put an image in the clide conversation — a bare `Read` only shows it in the transcript, not in the UI the user is looking at. - **Otherwise**: `Read` the PNG so it renders inline in the transcript. -6. **Clean up** — delete test/scratch pages from Frame0 when done +6. **STOP and wait for approval** — after showing a screen, pause and ask the + user for feedback. Do **not** author, push, or export the next screen until + they give an explicit go-ahead. Iterate on the current screen until they're + happy, then proceed to the next one — looping back to step 2 for each. +7. **Clean up** — delete test/scratch pages from Frame0 when done + +> **Multi-screen requests are still one-at-a-time.** If the user asks for +> several screens, treat it as a queue: build the first, show it, get approval, +> then move on. The only exception is an explicit, unambiguous instruction to +> generate a batch without stopping (and even then prefer the batch-export +> dry-run + approval flow below). ### Scripts diff --git a/.pql/changelog/ticket_history/2026-06.sql b/.pql/changelog/ticket_history/2026-06.sql index 772f0fca..f1123fb2 100644 --- a/.pql/changelog/ticket_history/2026-06.sql +++ b/.pql/changelog/ticket_history/2026-06.sql @@ -2445,3 +2445,4 @@ INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, chang INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM42VPM50VKAWXBCAM8', 'status', 'ready', 'done', NULL, '2026-06-10 08:57:51', '2026-06-10 08:57:51', '2026-06-10 08:57:51', NULL, 'fe6d00feb488f12fd0931852b2e66236', 2) ON CONFLICT(hash) DO NOTHING; INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB16FJ7KXGFHQXEG88MYRFTG', 'status', 'backlog', 'in_progress', NULL, '2026-06-10 09:13:08', '2026-06-10 09:13:08', '2026-06-10 09:13:08', NULL, '56fbf20da154b3465d3d2e7dcc87dfc9', 2) ON CONFLICT(hash) DO NOTHING; INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB16FJ7KXGFHQXEG88MYRFTG', 'status', 'in_progress', 'done', NULL, '2026-06-10 09:39:52', '2026-06-10 09:39:52', '2026-06-10 09:39:52', NULL, '5f059718e9cf548a13a9d141970ccd2e', 2) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB170DJA02EH2E8HMH7X7SS4', 'status', 'backlog', 'done', NULL, '2026-06-10 09:41:52', '2026-06-10 09:41:52', '2026-06-10 09:41:52', NULL, '67000e62833f645575e2b557a711d292', 2) ON CONFLICT(hash) DO NOTHING; diff --git a/.pql/changelog/tickets/2026-06.sql b/.pql/changelog/tickets/2026-06.sql index e0a3de05..1c83c23a 100644 --- a/.pql/changelog/tickets/2026-06.sql +++ b/.pql/changelog/tickets/2026-06.sql @@ -1344,3 +1344,8 @@ All card categories share a small set of spacing CONSTANTS (inter-card bottom ga - Wireframe: docs/design/wireframes/cards/collapser-card.{json,png}. - After landing: update the ui-design skill''s conversation-panel guidance to describe the three card categories + the collapser. ', 'done', 'medium', NULL, NULL, NULL, '2026-06-10 08:15:39', '2026-06-10 09:39:52', NULL, 'd173d4e6a58bb9dba5ad279d705f083b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB170DJA02EH2E8HMH7X7SS4', 'task', '06FB0TNQM5TWC00GW0P3X02HZW', 'frame0-wireframe skill: pause for user approval after showing each screen', 'The `frame0-wireframe` skill (.claude/skills/frame0-wireframe/SKILL.md) currently runs its Core Workflow straight through — write JSON → push → export → show — and tends to keep generating additional wireframes/screens on its own without stopping. The point of the skill is *dialogue*: each shown screen is a checkpoint for the user to react to, not busywork to batch through. + +Adjust the skill so that after step 5 (showing an exported screen inline), it STOPS and waits for explicit user approval/feedback before authoring or exporting the next screen. One screen at a time: show it, ask, then proceed only on a go-ahead. Do not fan out a whole set of wireframes unprompted. + +Acceptance: SKILL.md instructs the agent to surface one screen and pause for user approval before continuing; the loop is approval-gated, framing wireframing as a back-and-forth design conversation rather than a one-shot generation run.', 'done', 'medium', NULL, NULL, NULL, '2026-06-10 08:17:57', '2026-06-10 09:41:52', NULL, 'ed51880a7f0f3c9f29949d91d4c4ad32', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);