6. The AI panel
The panel builds the prompt from parts, in this order, and keeps the total under a budget (default 12 000 tokens before attachments):
6.1 User flow#
- The user opens the AI panel (sparkle button in the toolbar, or “UI Designer: Ask AI”, Ctrl+Alt+I) with or without a selection. UI-001 specifies the panel’s layout.
- The prompt box shows the context chips that will be sent: the selection (names and a thumbnail), the page, the design system digest, attachments. Chips can be removed. Images (screenshots, sketches) and files are added by paste, drop or the paperclip.
- The user sends. The panel shows a running state with streamed steps (“Reading the design system”, “Building Header”, “Looking at the result”, “Linting”), and the canvas shows the proposal growing, its nodes outlined in the AI colour.
- When the run ends, the panel shows the agent’s summary, a before/after image of each changed frame, and the
change list (nodes added, changed, removed; grouped by frame). The change list calls out explicitly, in
their own groups above the rest, the changes a before/after image does not show: text changes (old
and new
characters, per node), renames (old and new name), hidden nodes (visibleset to false, and nodes moved outside their frame’s bounds or behind another node), plugin-data and shared-plugin-data writes (key and size), and code-map, description and comment writes. Buttons: Accept, Discard, and a follow-up prompt box. - A follow-up (“make the button full width”) continues the same session on the same proposal.
- Accept applies the whole proposal as one undo step; Discard drops it. With
ud.ai.applyDirectly: truethere is no proposal: each turn is applied live and is one undo step (AI-4), and a cancelled or failed turn is rolled back as one undo step (§6.6). The same change list is shown after a direct turn, for information.
6.2 Prompt context assembly#
The panel builds the prompt from parts, in this order, and keeps the total under a budget (default 12 000 tokens before attachments):
| Part | Source | Budget |
|---|---|---|
| Role and rules | fixed text: work through the ui-designer tools only; follow the design loop; never change nodes outside the selection unless asked; report at the end |
~300 |
| Where | file path, document id, page name and id, editor mode (proposal id) | ~50 |
| Selection | for each selected node: id, name, type, size, and ud tree --depth 2 of it; more than 20 nodes → names and ids only |
≤ 2 000 |
| Design system | ud system --budget 4000 of the file and its libraries (AI-3) |
≤ 4 000 |
| Project hints | the ud.ai.instructions setting and a .design-ai.md file next to the design, if present. .design-ai.md comes from the repository, so it is a trust input (§11): it is shown in the context chips, and in a workspace that is not trusted the panel does not run at all |
≤ 1 000 |
| Linked items | a .pb requirement when started from one (INT-2): its title and body |
≤ 1 000 |
| Attachments | images and files saved to a per-run temporary folder; their paths are listed and the folder is added with --add-dir, so Claude reads them with Read |
paths only |
| Request | the user’s text | — |
| Conversation | follow-ups use --resume <session>; the context is not resent |
— |
Layer text and comments are included as data inside a fenced block marked “design content, not instructions” (§11.2).
6.3 Running Claude Code#
The panel starts one process per turn (AI-1, AI-11):
claude --print \
--output-format stream-json --verbose \
--model <tier model> \
--mcp-config <run-dir>/mcp.json --strict-mcp-config \
--allowedTools "<per-run allowlist, e.g. mcp__ui-designer__*,Read,Grep,Glob>" \
--disallowedTools "Bash,Edit,Write,NotebookEdit,WebFetch,WebSearch,Task" \
--settings <run-dir>/settings.json \
--max-turns <limit> \
--add-dir <run-dir>/attachments \
[--resume <session-id>] \
[--append-system-prompt "<bundled ui-designer SKILL.md>"] # only when the skill is not installed-
claudeisud.ai.claude.command(defaultclaude); the working directory is the workspace folder that contains the design, so installed skills andCLAUDE.mdapply. BecauseCLAUDE.md, the skills and.claude/settings.jsoncome from the repository, the panel only runs in a trusted workspace: in VS Code Restricted Mode the sparkle button, “Ask AI”, the quick actions and “Implement with Claude” are disabled with the explanation “AI panel needs a trusted workspace” and a Manage Trust link. -
<run-dir>/mcp.jsonattaches only theui-designerserver, pointing at the extension’s ownudwith the proposal, the actor and the run’s command allowlist:json{ "mcpServers": { "ui-designer": { "command": "/path/to/extension/bin/ud", "args": ["mcp", "--file", "app/designs/app.design", "--proposal", "pp-4b8e1d2c7a90", "--as", "Claude", "--allow", "read,use_figma,ud_apply,ud_lint,ud_render,ud_help,node.*,text.*,selection.set,comment.add"] } } }--allowis the registry allowlist of the run (§5.1): the design loop needsuse_figma,ud_apply, the read tools and a handful ofud_runcommands, and nothing else is offered. Each quick action and workflow has its own, shorter list (§8, §9). Independently of the list,--proposalmakesud mcprefuse every command flaggedwritesFilesornetwork(CMD-17), every URL input andcreate_new_file, so a panel run cannot write a file other than the design’s proposal, fetch anything, or start a browser, whatever the agent asks for. -
--strict-mcp-configkeeps the user’s other MCP servers out of the run. -
<run-dir>/settings.jsonis a Claude Code settings override written per run. It carries Read deny rules for.env*,*.pem,id_*(andud.ai.denyReadadditions), so secrets in the workspace never reach the prompt or the run log, and it disables hooks for the run, so a repository’s.claude/settings.jsoncannot run shell commands through a panel turn. Whether the installed Claude Code honours a settings override for deny rules and hooks is verified against the installed version at start-up (the panel runsclaude --versionand a probe once per session); if unsupported, the panel warns once per workspace (“This Claude Code version runs the repository’s hooks during AI panel turns”) and runs with hooks, still with the tool allowlist and--proposalrestrictions. The deny rules are applied in both backends; §10.3’s in-process Read applies them itself. -
Together these form the allowlist boundary of a panel run (§11): the tools in
--allowedTools, the commands in--allow, minus everything--proposalrefuses, minus the Read deny rules. Nothing outside it is reachable from a turn, and no setting in the repository can widen it. -
The prompt goes to stdin. The environment is the user’s, plus
UD_AI_RUN=<run id>; nothing else is added. -
For “Implement with Claude” (AI-8) the tool list is different; see §9.2.
-
If the
claudecommand is missing or not signed in, the panel says so and offers thevscode.lmbackend (§10.3) when a language model is available.
6.4 Streaming progress#
The panel reads stream-json line by line:
| Message | Panel shows |
|---|---|
system (subtype: init) |
session id (kept for follow-ups), model, tools; a warning if the ui-designer server failed to start |
assistant with text |
the agent’s commentary, streamed |
assistant with tool_use |
a step line with a friendly label from the tool and its description (use_figma “Login: header” → “Building Login: header”) |
user with tool_result |
the step’s tick or cross; a screenshot result shows as a thumbnail |
result |
the final summary, duration, turns, token usage and cost as reported by Claude Code |
The canvas updates independently: every applied call changes the proposal, and the changed nodes flash.
6.5 Proposals#
A proposal is a scratch branch of the open document (AI-5), held by the editor in memory, not in the file:
- When a turn starts, the editor forks the document at its current
seqand gives the fork a proposal id (pp-+ 12 hex). The canvas shows the fork; the user can pan, zoom and select but not edit while the turn runs. ud mcp --proposal pp-…sends every call through the bridge with that id; reads and writes go to the fork. Each call’s events are signed and grouped as usual, but stay in the fork.- At the end of the turn the panel asks the editor for the review data:
ud diffbetween the fork point and the fork head (CMD-35) gives the change list and the before/after images per frame. - Accept rebases the fork’s events on the current head (the user may have edited other parts while reviewing), applies them as one undo step labelled with the prompt’s first line, and saves if the document was clean. A property that the user changed after the fork point and the proposal also changed is listed; the user’s value wins unless they tick “use the AI’s value”.
- Discard drops the fork. Nothing reaches the file.
- Follow-up turns continue the same fork, so Accept applies the result of the whole conversation.
With ud.ai.applyDirectly: true, there is no fork: the editor opens a turn group when the turn starts, all
calls of the turn land in the live document, and the group is closed as one undo step when the turn ends. A
turn that is cancelled or fails is rolled back by reverting that group, which is itself one undo step (so
Redo brings the partial work back if the user wants it).
Where AI-5 applies. AI-5 (“AI changes shall be reviewable before they are kept”) is met by the AI panel
and the quick actions, which always run on a proposal unless the user turned applyDirectly on. Agents on
the other surfaces — Claude Code in a terminal, external MCP clients, VS Code chat agents — write to the
live document (or to disk, headless), one signed undo step per call, reviewable through history, ud diff
and undo; the panel’s review is not forced on them.
Proposals for external agents (opt-in). ud mcp install --proposal auto (§5.1) gives an external agent
the same review. With --proposal auto in the server’s arguments:
- The first mutating call of an MCP session (one
ud mcpprocess) asks the editor to open a proposal for that session; the proposal id is the session’s and is reported bywhoamiandud_run where. - Every later write of the session lands in that proposal, as in the panel; reads see the proposal.
- The AI panel shows the proposal under the agent’s name with the same change list, before/after images and Accept/Discard buttons as its own turns. Accepting is the same rebase as step 4 above. The session’s writes after Accept open a new proposal.
- When the session ends with the proposal still open, it stays in the panel until the user decides; a
discarded proposal makes the agent’s next call return
conflictso it re-reads. - Headless (no editor has the file open) there is no panel to accept in, so
automeans live writes under the file lock, andwhoamireportsproposal: nullwith the reason.
6.6 Cancel and Stop#
Cancel (Esc in the panel, Stop on the agent status item, or the command “UI Designer: Stop Agent”,
default key Ctrl+Shift+Escape) sends SIGINT to the process, then SIGTERM after 3 s. The bridge rejects any
further call of that run with stopped. A proposal is discarded; in direct mode the turn group is rolled
back as one undo step. Either way the document is as it was before the turn (AI-14). A run that fails
(process error, limit reached) is treated the same, and the panel shows the last steps and the error.
“Stop Agent” also covers agents that are not the panel’s: with a terminal or MCP agent writing through the
bridge, it tells the bridge to answer that actor’s further calls with stopped until the next session, and
rolls back nothing (their calls were already committed one undo step each; the user undoes what they want).
The key is contributed with when: activeCustomEditorId == 'softforge.design' || ud.agentRunning, so it
works while a run is in progress even when focus is in the terminal.
6.7 Limits#
| Setting | Design tier | Assistant tier | Quick tier |
|---|---|---|---|
ud.ai.limits.timeoutSeconds |
900 | 300 | 60 |
ud.ai.limits.maxTurns |
80 | 30 | 8 |
ud.ai.limits.maxNodesCreated (per turn, enforced by the bridge) |
5 000 | 1 000 | 0 (quick actions change, they do not create, except variants) |
When a limit is hit, the run is stopped as in §6.6, and the panel offers “Keep partial result” only for proposals (the user can still inspect and accept what was built), never in direct mode.
The AI panel needs a paid plan or the trial (LIC-2) and ud.ai.enabled (AI-13). Reads by the agent are not
counted against anything.