---
name: console-visual
description: Use when the owner console's doorbell carries a `visual` request (the owner pressed "Request a visual" on an item) - draw it as a Mermaid diagram or a static, self-contained HTML mock with a short doc, store it with `agent.py visual`, and land it by PR from your own worktree with `agent.py visual-export`. Called by console-process for every waiting visual request.
---

# Draw a visual the owner asked for

The owner pressed **Request a visual** on an item and said what it should
show. You answer with **one picture and a short doc**. The console server
stores them in its own state directory (never in the project) and shows them
on the item: a Mermaid diagram as its source text, an HTML mock inside a
sandboxed frame. To put them in the repository, you export them into **your
own worktree** and open a pull request (step 5).

Set up `KIT`, `STATE` and `A` as in the console-process skill: from the
user's registry only, and stop if this project is not registered there.

## 1. Find the request

    A todo

`todo.visuals` lists every waiting request as its `id` and `item`. A visual
request is an owner message with `"intent": "visual"`; one is waiting when
nothing in `view.visuals[ITEM]` names it as its `request`. Read its item:

    A view --item ITEM

The request is the message with that id in `view.threads[ITEM]`, and its
`text` says what to draw. If a read exits 4, run the narrower command named on stderr; do not retry the same command and do not add --full.

## 2. Choose the form

- **Mermaid** (`--format mermaid`, a `.mmd` file) for structure: a flow, a
  state machine, a sequence, a dependency map. The console shows its
  **source as text**; no diagram library runs on the owner's page. So write it
  to read well as text too: short node labels, one edge per line.
- **HTML mock** (`--format html`, one `.html` file) for layout: what a screen
  looks like at a width. It must be **self-contained and static**:
  - inline `<style>` only; images as `data:` URIs; no external URL of any
    kind (fonts, scripts, images, stylesheets): the server's policy lets it
    load nothing else, so an external asset simply does not appear;
  - **no JavaScript**. The frame is sandboxed with no scripts, and so is the
    file when it is opened on its own. A mock that needs script to show its
    states should show them side by side instead;
  - no forms that go anywhere (they are blocked), and no text pretending to
    be a login or a real product page.
- Either way, at most **256 KiB**. A larger one is refused by name, never
  cut: split it into two visuals (a request takes up to three).

Write the drawing and the doc in a scratch folder, never inside the server's
checkout.

## 3. Write the doc

A few sentences to at most 4000 characters, plain text: what the visual
shows, what it leaves out, which spec lines or files it rests on
(`path:line`), and any decision it implies that the owner has not made. A
decision it implies goes to the console as a question (console-ask), never
decided in the doc.

## 4. Store it

    A visual REQUEST_ID --format html --file grid.html --doc grid.md --title "Grid at 375 px"

`REQUEST_ID` is the request message's record id. The server:

- checks the request is an owner visual request, and the store's rules,
  **before** writing anything;
- writes `<state>/visuals/<item>/<request[:8]>-<sha256[:12]>.html` (or `.mmd`)
  byte for byte, and a `.md` doc beside it that links to it and quotes the
  owner's request. **Nothing is written into the project**;
- appends one `visual` record holding the path, size and sha256. If the file
  is later edited or swapped for a symlink, the console refuses to show it
  and says why.

A refusal names what is wrong: fix it and run the command again. A retry of
the same content is stored once. The owner can see the visual now.

## 5. Land it from your own worktree, and reply

If `view.config.visuals_dir` is null, the project has nowhere to land
visuals: skip to the reply, and say it is in the console only.

Otherwise export into **your own worktree on a branch**. **Never run it
against the server's checkout** (the directory the console server runs
from): that checkout follows main with `git merge --ff-only`, and a file
written there blocks the next fast-forward. The command refuses it anyway,
naming why.

    # from the repository YOU work in (your clone), not the server's checkout
    WT=$(A worktree new --kind visual --item ITEM)
    A visual-export --project "$WT" --visual VISUAL_RECORD_ID

`A worktree new` (1.50.0) fetches origin, makes your own worktree under
`~/.overture/worktrees/<project>/` on the branch `overture/visual/<item>`
(cut from `origin/main`), marks the item worked on with that branch, and
prints its path. Run it again for the same item and it gives the same
worktree back (a fresh one once its PR merged or closed). It needs your agent
name, as `working` does. If it names another agent on the item (an overlap),
go on, and say so in your reply. If it prints a suggested setup step, Overture
has not run it: run it yourself, as its own Bash call, only if you need it.
Never make a worktree by hand.

`--project` must be the TOP of that worktree, never a folder inside it.
`--visual` may repeat; without it every stored visual is exported, and one
already in the worktree with the same bytes is skipped. It exits 0 when every
chosen visual was exported, **3 when files were written but a visual was
refused** (each refusal is named on stderr: land what was written and say in
the reply which one was not), and 1 when nothing was written. It writes
`<visuals_dir>/<item>/<name>.*` and regenerates `<visuals_dir>/INDEX.md` from
what is in that folder. It refuses, writing nothing, a different file already
at a target path, or an `INDEX.md` it did not generate: look, move the file
aside if it is stale, and run it again. Then, in `$WT`, commit those paths
only, push the branch (`git -C "$WT" push -u origin HEAD`) and open a pull
request from it; never commit to the main branch. Leave the worktree: the
steward removes it once the PR merges or closes. A decision-log or digest
line about the visual, if the project keeps one, is added at merge time.
Reply once on the item:

    A reply ITEM "Drew <title>: <one line>. PR <url>." --reply-to REQUEST_ID

and return to console-process.
