Files
pbakaus_impeccable/skill/reference/generate.md
T
d397140a77 Port /impeccable generate to the engine crates
The Node-era server, CLI, hook, and pin halves of the generate command move
into the Rust workspace, with the protocol unchanged:

- crates/live: POST /agent-target is held open on a channel plus a timer
  thread (the manual-apply deferred pattern), releasing its turnstile
  ticket before it parks like /poll; /agent-target-result resolves it;
  /agent-target-claim is the roll call with its renewable lease. SSE
  connections carry the overlay's clientId: a late overlay is replayed
  every pending target, and a disconnect retires that overlay's report,
  releases its lease, and re-judges each roll call. Shutdown drains held
  requests with server_stopping.
- crates/live/src/live_generate.rs: the live-generate verb (the router
  already forwards every live* verb), same flags, verdicts, and
  _instructions, spelled with the engine's self command.
- crates/hook: every entry stands down on live preview markers
  (skipped: live-preview), checking the proposed content and the file on
  disk for hook-before-edit.
- crates/context: pin accepts generate; the crate's command-metadata.json
  copy carries its entry.

Tests: crates/cli/tests/agent_target.rs (six HTTP cases with an SSE reader),
tests/live-agent-target.test.mjs rewritten to drive the binary (28 cases,
registered in the live suite), hook stand-down cases, oracle goldens for
live-generate plus the re-recorded pin list goldens, the e2e prompt
assertion waiting for the journaled event, and the contract documented in
docs/CLI-CONTRACT.md.

AI-assisted: implemented and tested with Claude Code under maintainer
direction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-15 05:45:49 +05:00

7.3 KiB

Additional context needed: only the target element, when the request does not name one that resolves uniquely on the page.

Generate is a programmatic entry into live mode: the user names an element, a direction, and a count in one sentence, and you boot the live session, point the browser at the element, and the overlay scrolls to it, selects it, and fires the same Go a user click fires. Everything downstream is the standard live session. Read live.md in full now if you have not this session; this file is the entry ramp into its contract, and from Step 4 on you are inside it, with one deliberate divergence: Step 5 closes the session on its own once the accept lands, instead of staying open the way live does.

Web only. Live mode's browser overlay has no native equivalent; on ios / android / adaptive projects, decline this command and offer bolder or quieter on the source instead.

Three prohibitions cover the known ways this command goes wrong. Each names the tempting move first:

  • The poll shows no generate event yet, and writing variants straight into source feels faster. Never hand-write a variants wrapper or invent a session id. Only the browser mints session ids (8 hex characters, at Go), and the server refuses events for any other id; a missing event is fixed in Step 2 or Step 3, never with a direct source edit.
  • Handing the user a link to click feels polite. Open the page yourself (Step 2); a pasted link usually means no page ever connects.
  • The design hook may flag the preview scaffolding you just published. Do not act on hook findings while live markers are in the file, and do not restyle variants to appease them; impeccable live-complete verifies the file once the accepted variant is permanent. Current hooks stand down on the markers themselves; older installed hooks may still nag.

Step 1: Parse the request

Three parts, all from the user's sentence:

  • A number in the request: that is the count. No number: 3. The protocol caps count at 8.
  • The direction wording maps onto the live action vocabulary; never invent a new action value:
    • bold, bolder, stronger, punchier: bolder
    • quiet, calmer, softer, toned down: quieter
    • simpler, minimal, stripped: distill
    • refined, tightened, polished: polish
    • font and type words: typeset
    • color words: colorize
    • arrangement and spacing words: layout
    • device and breakpoint words: adapt
    • motion words: animate
    • playful words: delight
    • rule-breaking words: overdrive
    • Nothing fits: impeccable, with the user's wording passed as the prompt.
    • An action fits AND extra intent rides along ("bolder, but keep it monochrome"): that action, with the rest as the prompt.
  • The element description ("the pricing cards", "the hero heading"): Step 3 resolves it to a selector.

Done when you hold an action from the vocabulary, a count from 1 to 8, and the element description.

Step 2: Boot live mode and open the page

Run the boot exactly as live.md's Start section describes:

{{scripts_path}}/impeccable live

config_missing / config_invalid: follow live-setup.md first.

Then open the app URL that serves a pageFiles entry (never serverPort; that is the helper, not the app):

  • Cursor: browser_navigate to the URL now; do not skip it.
  • Any other harness with a browser tool: open the URL with that tool.
  • No browser tool exists in this harness: tell the user the exact URL to open, and pass --wait-for-browser 120000 in Step 3 so the command fires the moment their page connects.

Done when the boot printed "ok": true and a page with the overlay is connected, which Step 3 proves by answering anything other than no_browser_connected.

Step 3: Target the element

Derive the selector from project source, not from guesswork: an id first, then a unique class, then a landmark tag plus class. The request names a repeated component in plural ("the pricing cards"): target the container that holds the set, so scoped CSS restyles every instance at once. Unsure the selector resolves uniquely: probe with --dry-run; it resolves and reports without starting anything, and it works even mid-session.

{{scripts_path}}/impeccable live-generate --selector "section.pricing" --action bolder --count 3

Flags: --selector (required), --action, --count, --prompt, --text (keep only matches whose visible text contains a snippet), --index (1-based pick among matches), --dry-run, --wait-for-browser <ms>.

Every verdict carries _instructions with the next move for that exact situation, with real values filled in; follow them over your recollection of this file. Two verdicts deserve naming because their fix sits outside the command:

  • no_browser_connected: Step 2's page is not actually open; open it yourself, then rerun.
  • ambiguous: the candidates are listed in the output; target their common container, or rerun with --text "<visible text>" or --index <n>.

Done when the verdict is ok: true with a sessionId: the browser has scrolled to the element, entered the picked state, and fired Go.

Step 4: Generate

Start the poll loop per your harness policy in live.md. The queued event for the returned sessionId is a standard generate event with the picked element's context and a preflighted scaffold; handle it exactly per live.md's Handle generate, which owns everything from planning to the done reply.

Then tell the user, in one line, where their variants are: "Three [bolder] variants are live on [the pricing cards]: cycle with the floating bar's arrows, adjust the Tune knobs, and Accept the keeper."

Publishing variants does not end the session. Keep servicing the poll; accept, discard, and carbonize cleanup follow live.md unchanged, and the helper server stays up through the accept. Done when live.md's contract marks the event you handled complete and the poll is running again.

Step 5: Close the session

Generate is a one-shot command; this is where it diverges from an open-ended live session. Once the accept (or discard) completes, wrap up without being asked: carbonize cleanup is done and impeccable live-complete printed phase: "completed" (a discard needs no cleanup), so kill your background poll and run live.md's Cleanup:

{{scripts_path}}/impeccable live-server stop

Stopping removes the injected live script, and that removal reloads the page one last time: the user's browser now shows the accepted design with no overlay chrome, still served by their dev server.

  • The user asks for more variants before you wrapped up: skip the wrap-up, target the next element through the same session (Step 3, with --dry-run first when the selector is uncertain), and wrap up after the last accept.
  • Restarting the dev server to freshen the page feels like tidying. Never kill or restart the user's dev server, including one you started in Step 2. It keeps serving the accepted source after wrap-up; a tab that still looks stale needs one hard refresh, not a new server. A relaunched server also hops to the next free port and strands every open tab on the dead one.

Done when the helper is stopped, the stop output reported the script tag removed, and the dev site still answers with the accepted design.