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):

Esta página está em inglês; a tradução está a caminho.

6.1 User flow#

  1. 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.
  2. 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.
  3. 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.
  4. 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 (visible set 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.
  5. A follow-up (“make the button full width”) continues the same session on the same proposal.
  6. Accept applies the whole proposal as one undo step; Discard drops it. With ud.ai.applyDirectly: true there 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):

text
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
  • claude is ud.ai.claude.command (default claude); the working directory is the workspace folder that contains the design, so installed skills and CLAUDE.md apply. Because CLAUDE.md, the skills and .claude/settings.json come 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.json attaches only the ui-designer server, pointing at the extension’s own ud with 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"] } } }

    --allow is the registry allowlist of the run (§5.1): the design loop needs use_figma, ud_apply, the read tools and a handful of ud_run commands, and nothing else is offered. Each quick action and workflow has its own, shorter list (§8, §9). Independently of the list, --proposal makes ud mcp refuse every command flagged writesFiles or network (CMD-17), every URL input and create_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-config keeps the user’s other MCP servers out of the run.

  • <run-dir>/settings.json is a Claude Code settings override written per run. It carries Read deny rules for .env*, *.pem, id_* (and ud.ai.denyRead additions), 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.json cannot 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 runs claude --version and 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 --proposal restrictions. 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 --proposal refuses, 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 claude command is missing or not signed in, the panel says so and offers the vscode.lm backend (§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:

  1. When a turn starts, the editor forks the document at its current seq and 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.
  2. 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.
  3. At the end of the turn the panel asks the editor for the review data: ud diff between the fork point and the fork head (CMD-35) gives the change list and the before/after images per frame.
  4. 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”.
  5. Discard drops the fork. Nothing reaches the file.
  6. 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:

  1. The first mutating call of an MCP session (one ud mcp process) asks the editor to open a proposal for that session; the proposal id is the session’s and is reported by whoami and ud_run where.
  2. Every later write of the session lands in that proposal, as in the panel; reads see the proposal.
  3. 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.
  4. 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 conflict so it re-reads.
  5. Headless (no editor has the file open) there is no panel to accept in, so auto means live writes under the file lock, and whoami reports proposal: null with 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.