create-workbench · git:20261012.77e988d · 2026-10-12 · sha256 f220799280866c71

create-workbench git:20261012.77e988dA

Immutable. This exact content never changes and is served at /api/v1/blob/f220799280866c71.

---
name: create-workbench
description: "Use when a page is wanted to work on something with the person during development, fed the project's real data (comparing model answers, walking an agent call by call, measuring an output against its template), or when such a workbench has to change or its feed broke. Produces the page in aiview, kind `workbench`, and the project's `workbench-<bench>` skill with its feed and operating steps. Not for designing a product screen (design-prototype) or verifying user stories (verification-skill-create)."
---

# Create a workbench

**A workbench is a dev tool for iterating on an idea, and it has two users**: the person, who
needs a clear UI that opens on what is being tried now, and the agent, who needs the bench
cheap to read, change and check. It is judged by the time from "what if…" to the result seen.

**Two things are produced, and a later agent works the bench from them alone**: the page,
in the data home like every document, and the project's `workbench-<bench>` skill, which
holds the feed that fills the page and the steps to operate it.

**The bench's skill makes the agent operating it the bench's owner**, by its role: that agent
keeps the page, the feed and the scripts true, fast and easy to drive, adapting them in place
when the project moves on. No other skill maintains them.

**The person is in the build.** Every change is shown in the watched browser before the
next question, as the `design-prototype` skill paces a mockup. A bench described in chat
was not seen.

## Before building

- **A `workbench-<bench>` skill's scope covers this question** in the project's local
  skill folder: read it and its page, and add the question to both as a view or a mode.
  Never a second bench for one scope: one bench per question and the project's local
  skills grow with every plan.
- **Read the sources before asking**: the files the project produces that the bench will
  show (recordings, requests as sent, fixtures, templates), where they live, their exact
  shape, and the code that writes them.
- **The watched browser**: a headed browser the person sees and the agent drives, a
  Playwright MCP over DevTools or a script over CDP. The project's own when it has one,
  named in its local skills. None: start Playwright's Chromium headed with
  `--remote-debugging-port=9222`, say so, and stop it at the end.

## Define, through the `interview` skill

Each answer is written into the bench skill's head as it lands.

1. **The bench's scope**: a kind of work on a part of the product (any model call, any
   agent walk, one family of screens), as wide as its sources allow, and the bench's
   label. The question at hand is its first view.
2. **The sources**, each file or call, as the project produces it.
3. **The feed's kind.** *Derived*: the block is rebuilt from the sources on every run.
   *Log*: entries are appended and never rewritten, for data the project cannot produce
   again (a request as sent during a walk). The page is then the only record.
4. **What the person does on it**: compare, judge, pick, measure. The controls follow.
5. **Whether operating it takes steps**: start the stack, hold a call, reset state,
   record an answer. Each becomes a script.

## Build, live

1. **The page**: `node scripts/page.mjs <path> --label "<label>"`, at the path the `aiview`
   skill gives for `YYYY-MM-DD-<bench>.workbench.html`. Register it through the `aiview`
   skill: kind `workbench`, tags the bench and `trace` for a walk, group the
   piece of work it serves. Open it in the watched browser. A bench that makes one page
   per run (a walk, a session) keeps the page's code as `page-template.html` in its skill instead:
   its feed's `init` makes each run's page from it, and its `refresh` puts a changed
   `page-template.html` onto every page while keeping each page's data block.
2. **The feed**: copy `scripts/data-block.mjs` into the bench skill's `scripts/` and write
   `feed.mjs` over it. A derived feed calls `writeData` and takes `--watch`. A log feed
   takes verbs that call `appendEntry` and `annotate`. Run it: aiview reloads the page.
3. **Then one change at a time**: write it, read the screenshot, show the person, ask the
   next question.

## The page

- **The bench bar opens on the label.** It is the one standard part. The rest of the bar
  and the page carry whatever the bench needs.
- **Controls are Basecoat**, shadcn's design system in plain HTML, inlined by `page.mjs`:
  `class="btn" data-variant="outline" data-size="sm"`, `card`, `tabs`, `badge`, `input`,
  `select`. Basecoat carries no Tailwind utilities, so layout is the page's own CSS. The
  product the bench shows (a document, a screen, a card) is drawn in the project's design
  language, from the `design-prototype` skill's reference when there is one.
- **JSON is always shown through `jsonTree`**, the reader `page.mjs` inlines, with its toolbar
  (Fold all, Unfold all, Unfold 2 levels, Copy): never a `<pre>` dump or a reader of the
  bench's own. When the bench shows any JSON, read `references/json-data.md`.
- **The page opens on the current question**, and each thing is shown once: a view that repeats
  another, or that nobody looks at any more, is removed with its code and its feed fields.
- **The data is the project's, as it is.** Copied byte for byte, never renamed, reshaped
  or summarised: the page adapts to the shape, so the bench stays as close to the real
  run as it can. A rendering that interprets the data is what the app already shows.
- **Only the feed writes the data block.** The agent edits the page's code, never its data.
- **Self-contained**: no CDN, no fetch, the page opens offline.

## Ergonomic for the agent

- **The scripts that drive the bench are built with it**, each with the view or control
  that needs it: open a view, set its controls, screenshot it, read back what it shows as
  text. An agent drives the bench through them, never with hand-written browser calls.
- **The loop is one command**, named in the bench skill's Iterating section: feed, reload,
  screenshot. An agent never rebuilds it.
- **The scripts are one CLI with verbs, terse by default.** Each verb prints a short plain
  summary (counts, what changed, what failed); the full output only with `--full`, machine
  output with `--json`. The agent reads summaries and diffs, never the raw files the bench
  shows (a prompt, a reply, a recording): a result is checked without filling the context.
- **Anything can go to the person's phone in one command, without passing through the
  agent's context.** A `shot` verb with `--mobile` takes a phone-width PNG of any view, with one item
  opened if asked, and prints only its path. `--md` on the reading verbs also writes the
  output as a short markdown file laid out for a phone: lists, not wide tables. The agent
  sends the file it names (the harness's send-file tool) and reads neither.
- **The bench's code is read by its marker**, never the whole page: Basecoat and the
  JSON reader are inlined above it and cost tokens for nothing.
- **The feed writes only what a view shows.**

## The bench's skill

**`workbench-<bench>/SKILL.md` in the folder the project already uses for local skills**,
`.claude/skills/` when it has none, with every deterministic step a script in its
`scripts/`. Written to the shape in `bench-skill.md`, read before its first line: the
sentences outside its brackets are carried as written.

## Prove it

Run the feed from a clean shell, see the page reload with real data in the watched
browser, and walk once, with the person, what they do on it. A bench whose feed has not
run is not handed over.

## Handoff

The page's URL, the skill's path, the sources and the feed's kind, what was walked.

## Red flags

| Thought | Reality |
|---|---|
| "I'll map the data to a cleaner shape for the page" | The page adapts to the project's shape. A translation hides what the app really produced, and drifts from it unseen. |
| "Quicker to paste the data into the page" | Only the feed writes the block. A pasted copy is stale on the next run and nothing says so. |
| "I'll keep the old view in case" | A dropped idea leaves with its view, its code and its feed fields, in the same change. A bench that only grows is slow for both users. |
| "This JSON is small, a `<pre>` will do" | Every JSON goes through `jsonTree`, with its toolbar. One reader, read the same way everywhere. |
| "The feed can sit next to the page in the data home" | It reads the project, so it lives in the project's skill. In the data home it breaks without anyone seeing. |