visual-edit

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Visual Edit

可视化编辑

Use
/visual-edit
when the user wants to inspect or edit a real local app visually instead of generating standalone Alpine HTML. The source of truth is the running localhost app plus its route URLs. Design shows those routes as iframe-backed screens on the infinite canvas.
当用户希望以可视化方式检查或编辑真实本地应用,而非生成独立的Alpine HTML时,使用
/visual-edit
。数据源是运行中的localhost应用及其路由URL。Design会在无限画布上以基于iframe的屏幕形式展示这些路由。

Installing this skill for an external MCP host

为外部MCP主机安装此技能

The hosted install path (
npx @agent-native/core@latest skills add visual-edit
, or
design
for the full Design bundle) installs the exported instructions and registers the hosted Design MCP connector together. The open Skills CLI path (
npx skills@latest add BuilderIO/agent-native --skill visual-edit
) installs exported instructions only, with no MCP connector registration.
托管安装路径(
npx @agent-native/core@latest skills add visual-edit
,或使用
design
安装完整的Design包)会同时安装导出的指令并注册托管的Design MCP连接器。开放式Skills CLI路径(
npx skills@latest add BuilderIO/agent-native --skill visual-edit
)仅安装导出的指令,不注册MCP连接器。

Put Design Beside The Chat

将Design置于聊天窗口旁

Prefer the interactive MCP App returned by
open-visual-edit
when the coding host renders it. The user gets the Design canvas beside the conversation, and Apply design updates can submit the bounded source-edit handoff back to the current host conversation through the standard MCP Apps message bridge. The host may ask the user to confirm the current conversation or choose a new one.
Otherwise,
openUrl
is a credential-free, read-only fallback that is safe to show in model text or retain in logs. Do not claim that fallback is editable: the edit capability is intentionally available only to the host-managed MCP App launcher, where it is hidden from the model and redeemed once.
  • In Codex Desktop, prefer the rendered MCP App. Use the in-app Browser for the credential-free
    openUrl
    only when a read-only fallback is acceptable.
  • In Claude Code Desktop's Code tab, prefer the rendered MCP App. Preview
    openUrl
    in the Browser pane only as the read-only fallback.
  • In VS Code, use the Agent Native Design webview/deep link described below.
  • Inline browser availability is host-dependent. CLI, remote, or restricted sessions may not expose one. If the inline surface is unavailable or disabled, return the normal Open design link instead of claiming it opened.
Prefer the MCP App surface for a connected Design plugin, then the host's browser/preview tool as the universal fallback. Keep the canvas beside chat when the host supports rearrangeable panes.
Inside Design, use Show/Hide UI from the
Cmd K
menu or press Figma's
Shift \
shortcut to toggle all editing chrome so only the canvas remains. The same action is available from Design's empty-canvas context menu.
当编码主机渲染时,优先选择
open-visual-edit
返回的交互式MCP App。用户可在对话旁看到Design画布,且应用设计更新可通过标准MCP Apps消息桥将受限的源码编辑交接回当前主机对话。主机可能会要求用户确认当前对话或选择新对话。
否则,
openUrl
是无需凭证的只读回退方案,可安全地在模型文本中展示或保留在日志中。不要声称回退方案支持编辑:编辑功能仅对主机管理的MCP App启动器开放,该功能对模型隐藏且仅可使用一次。
  • 在Codex Desktop中,优先选择渲染后的MCP App。仅当只读回退方案可接受时,才使用应用内浏览器打开无需凭证的
    openUrl
  • 在Claude Code Desktop的代码标签页中,优先选择渲染后的MCP App。仅将
    openUrl
    作为只读回退方案在浏览器窗格中预览。
  • 在VS Code中,使用下文所述的Agent Native Design webview/深度链接。
  • 内嵌浏览器的可用性取决于主机。CLI、远程或受限会话可能不会提供内嵌浏览器。如果内嵌界面不可用或已禁用,请返回常规的打开设计链接,而非声称已打开。
优先选择连接的Design插件的MCP App界面,然后将主机的浏览器/预览工具作为通用回退方案。当主机支持可重排窗格时,将画布置于聊天窗口旁。
在Design内,从
Cmd K
菜单中选择显示/隐藏UI,或按下Figma的
Shift \
快捷键,可切换所有编辑控件,仅保留画布。同样的操作也可从Design的空白画布上下文菜单中执行。

Core Model

核心模型

  • Each screen is a URL-backed iframe, not copied HTML.
  • Each screen keeps URL metadata:
    connectionId
    ,
    routeId
    ,
    path
    ,
    url
    ,
    bridgeUrl
    , title, and viewport size.
  • Localhost Edit mode renders the running app through the local bridge as a live iframe with the same editor bridge used by HTML designs. It is never a frozen static DOM snapshot. Editing is direct DOM manipulation against that live document; the parallel
    /snapshot
    fetch feeds the editable source model only and must never be rendered in the frame.
  • The
    /visual-edit
    skill needs no Design account sign-in.
    open-visual-edit
    mints a five-minute, single-use capability for the exact
    /visual-edit/:designId
    local-editor route. The MCP host redeems it outside model-visible text, then opens the existing editor with localhost edit access. This capability is not an account session:
    /_agent-native/session
    remains signed out, and account-backed save/share/generate actions remain denied.
  • The skill enters through local
    pnpm action open-visual-edit
    . When that CLI has no account session, the action uses a stable, workspace-scoped local principal to register the bridge, create/reuse the local design, and place screens. That principal exists only inside the in-process CLI call; it is not a browser login and cannot be selected by an HTTP, MCP, or tunneled caller.
  • Public links are always read-only, including on loopback. Loopback peer identity is not an authentication boundary because a tunnel or reverse proxy can make a remote request appear local. A bare
    /visual-edit/:designId
    or
    /design/:designId
    URL carries no capability and must never release the connection's
    previewToken
    .
  • The live editor is same-origin through the local bridge proxy. This boots CSR apps and root-relative assets, but it is still a localhost editing proxy: app-origin cookies, WebSockets/HMR, SSE, and non-GET app API calls may need a future dev-server/plugin integration for perfect parity with the app's own origin.
  • There are exactly two views. The infinite canvas is where all editing happens, and the responsive interactive view (Interact) is where the app runs for real. There is no third "full view"/focused-edit state — clicking a screen in the Screens list, or the view toggle, opens the responsive view, and closing it returns to the canvas.
  • Interact keeps the left and right rails and adds a device bar above the canvas (device preset, editable width/height, zoom, close). It renders the app's normal URL so navigation, scrolling, links, and form controls behave as they would in the browser, and the wheel scrolls the app rather than panning the canvas. The canvas view is the opposite: the wheel pans and zooms it, and native interaction inside the frame is suppressed.
  • While a localhost screen has pending live visual edits, do not switch back to Interact until the user either applies the edits to source or explicitly aborts/discards the preview.
  • Alt-drag duplicates a screen. For localhost screens, duplication copies the iframe frame and URL metadata; change the copy's path/query for a new state.
  • Flow visualization is multiple URL states:
    /checkout?step=shipping
    ,
    /checkout?step=payment
    ,
    /checkout?step=done
    , etc.
  • When the user gives a named flow or numbered screen list, preserve that order and create one screen per URL/path. Shorthand like
    localhost:1234/onboarding/1
    means
    http://localhost:1234/onboarding/1
    .
  • 每个屏幕都是基于URL的iframe,而非复制的HTML。
  • 每个屏幕都保留URL元数据:
    connectionId
    routeId
    path
    url
    bridgeUrl
    、标题和视口大小。
  • Localhost编辑模式通过本地桥接器将运行中的应用渲染为实时iframe,使用与HTML设计相同的编辑器桥接器。它永远不会是冻结的静态DOM快照。编辑是对该实时文档的直接DOM操作;并行的
    /snapshot
    获取仅用于可编辑的源模型,绝不能在框架中渲染。
  • /visual-edit
    技能无需Design账户登录。
    open-visual-edit
    会为精确的
    /visual-edit/:designId
    本地编辑器路由生成一个5分钟有效期的一次性权限。MCP主机会在模型可见文本之外兑换该权限,然后打开具有localhost编辑访问权限的现有编辑器。此权限并非账户会话:
    /_agent-native/session
    保持未登录状态,且基于账户的保存/分享/生成操作仍被拒绝。
  • 该技能通过本地
    pnpm action open-visual-edit
    启动。当该CLI没有账户会话时,操作会使用一个稳定的、工作区范围的本地主体来注册桥接器、创建/复用本地设计并放置屏幕。该主体仅存在于进程内CLI调用中;它不是浏览器登录,无法被HTTP、MCP或隧道调用者选择。
  • 公共链接始终是只读的,包括环回链接。环回对等身份不是身份验证边界,因为隧道或反向代理可使远程请求看起来像是本地请求。无权限的
    /visual-edit/:designId
    /design/:designId
    URL永远不会释放连接的
    previewToken
  • 实时编辑器通过本地桥接代理实现同源。这支持CSR应用和根相对资产,但它仍然是localhost编辑代理:应用源Cookie、WebSockets/HMR、SSE和非GET应用API调用可能需要未来的开发服务器/插件集成,才能与应用自身的源完全一致。
  • 仅有两种视图。 无限画布是所有编辑操作的场所,响应式交互式视图(Interact)是应用实际运行的地方。不存在第三种“完整视图”/聚焦编辑状态——点击屏幕列表中的屏幕或视图切换按钮会打开响应式视图,关闭后返回画布。
  • Interact视图保留左右侧边栏,并在画布上方添加设备栏(设备预设、可编辑宽/高、缩放、关闭)。它渲染应用的常规URL,因此导航、滚动、链接和表单控件的行为与在浏览器中一致,滚轮会滚动应用而非平移画布。画布视图则相反:滚轮会平移和缩放画布,框架内的原生交互会被抑制。
  • 当localhost屏幕存在待处理的实时可视化编辑时,在用户将编辑应用到源码或明确中止/放弃预览之前,不要切换回Interact视图。
  • 按住Alt键拖动可复制屏幕。对于localhost屏幕,复制操作会复制iframe框架和URL元数据;更改副本的路径/查询可获取新状态。
  • 流程可视化包含多个URL状态:
    /checkout?step=shipping
    /checkout?step=payment
    /checkout?step=done
    等。
  • 当用户提供命名流程或编号屏幕列表时,保留其顺序并为每个URL/路径创建一个屏幕。类似
    localhost:1234/onboarding/1
    的简写表示
    http://localhost:1234/onboarding/1

Useful Canvas Sets

实用画布集合

Translate the user's requested review into the smallest useful set of frames:
  • Multi-step flow: one ordered frame per route or query state, such as cart, shipping, payment, and confirmation.
  • Multiple pages: one frame per meaningful route, such as home, pricing, docs, and account settings.
  • Responsive comparison: repeat the same route at the requested desktop, tablet, and mobile viewports so they align in one row.
  • State review: repeat a route for meaningful URL-addressable states such as empty, loading, error, modal-open, or selected-item views.
Do not expand every discovered route or every viewport unless the user asks for an exhaustive audit. Preserve the user's labels and sequence so the canvas reads like the workflow they described.
将用户要求的评审转换为最小的实用框架集合:
  • 多步骤流程: 每个路由或查询状态对应一个有序框架,例如购物车、配送、支付和确认页面。
  • 多个页面: 每个有意义的路由对应一个框架,例如首页、定价、文档和账户设置页面。
  • 响应式对比: 在用户要求的桌面、平板和移动视口下重复同一路由,使其在一行中对齐。
  • 状态评审: 针对有意义的URL可寻址状态重复同一路由,例如空状态、加载状态、错误状态、模态框打开状态或选中项视图。
除非用户要求全面审核,否则不要展开每个已发现的路由或每个视口。保留用户的标签和顺序,使画布符合用户描述的工作流程。

Select And Reprompt

选择与重新提示

When a chat message begins with
[Reprompt selection]
, the selected subtree is a hard write boundary. The only mutation path is
propose-node-rewrite
with the exact
repromptId
, target, and
baseVersionHash
captured in
design-reprompt-pending:<designId>:<fileId>
. Never use
apply-visual-edit
,
apply-source-edit
,
write-source
,
write-local-file
,
edit-design
, or any other content-writing action for that request. Clarifying questions are allowed, but a requested change must remain a proposal.
Produce one variant by default. Produce two or three only when the instruction asks for options. A retry includes
priorProposalId
; keep the same target and base version, incorporate the feedback, and call
propose-node-rewrite
again. The UI previews the returned subtree without persisting it.
Use
resolve-node-rewrite
for the accept/reject lifecycle. Accept applies the chosen variant as one version-checked inline/Yjs content transaction so one undo restores the prior structure; reject clears the proposal without changing content. For conversational resolution such as "apply the second one," call
view-screen
, read the active
design.reprompt.proposal
, and pass its
proposalId
plus the zero-based
variantIndex
to
resolve-node-rewrite
.
当聊天消息以
[Reprompt selection]
开头时,所选子树是硬写入边界。唯一的修改路径是使用
propose-node-rewrite
,并带上
design-reprompt-pending:<designId>:<fileId>
中捕获的精确
repromptId
、目标和
baseVersionHash
。绝不要使用
apply-visual-edit
apply-source-edit
write-source
write-local-file
edit-design
或任何其他内容写入操作来处理该请求。允许提出澄清问题,但请求的修改必须保持为提案形式。
默认生成一个变体。仅当指令要求提供选项时,才生成两个或三个变体。重试时需包含
priorProposalId
;保持相同的目标和基础版本,纳入反馈后再次调用
propose-node-rewrite
。UI会预览返回的子树,但不会持久化。
使用
resolve-node-rewrite
处理接受/拒绝生命周期。接受操作会将所选变体作为一次版本检查的内联/Yjs内容事务应用,因此一次撤销即可恢复之前的结构;拒绝操作会清除提案而不更改内容。对于诸如“应用第二个变体”的对话式决议,调用
view-screen
,读取活动的
design.reprompt.proposal
,并将其
proposalId
加上从零开始的
variantIndex
传递给
resolve-node-rewrite

Review Quality

评审质量

  • Treat the running app as the truth. Preserve its component language, tokens, route state, and real content unless the user explicitly asks for a new visual direction.
  • Use multiple URL states to reveal meaningful UX moments: empty/loading/error states, focused panels, modals, responsive breakpoints, and completed flow steps when those matter to the review.
  • For visual edits, compare before/after at the relevant viewport sizes and check key hover/focus/scroll states when the app exposes them.
  • 将运行中的应用视为事实来源。保留其组件语言、令牌、路由状态和真实内容,除非用户明确要求新的视觉方向。
  • 使用多个URL状态展示有意义的UX时刻:空/加载/错误状态、聚焦面板、模态框、响应式断点和完成的流程步骤(当这些对评审重要时)。
  • 对于可视化编辑,在相关视口大小下对比修改前后,并在应用暴露相关状态时检查关键的悬停/聚焦/滚动状态。

Account And Sharing Model

账户与分享模型

  • /visual-edit/:id
    is the dedicated local-editor surface. The one-time handoff returned by
    open-visual-edit
    opens it with edit access without a Design login. A copied or bare
    /visual-edit/:id
    URL is read-only because it does not carry the capability.
  • The capability permits live iframe inspection and session-local edits, undo/redo, Apply design updates through the connected host/local agent, and Copy prompt. Those flows hand bounded source instructions back to the coding agent; they do not silently persist account-owned Design data.
  • Public
    /design/:id
    links stay read-only without a signed-in owner/editor session. Never use the local capability to upgrade that ordinary sharing surface.
  • Prefer links returned by Design actions or
    /_agent-native/open
    deep links. Do not surface URLs with
    _session=
    tokens or hand-build capability URLs.
  • Do not attempt account-backed write actions with the browser capability. The trusted local
    open-visual-edit
    CLI call may register its bridge, create or reuse its workspace-owned local design, and place screens without an account. Direct source-file action writes, generation, saving into an account, and sharing still require an authenticated action caller. If a signed-out visitor wants those durable account operations, send them through the framework sign-in return flow first.
  • /visual-edit/:id
    是专用的本地编辑器界面。
    open-visual-edit
    返回的一次性交接链接无需Design登录即可打开并具有编辑权限。复制或无权限的
    /visual-edit/:id
    URL是只读的,因为它不携带权限。
  • 该权限允许实时iframe检查和会话本地编辑、撤销/重做、通过连接的主机/本地代理应用设计更新,以及复制提示。这些流程将受限的源指令交回编码代理;它们不会静默地持久化账户所有的Design数据。
  • 公共
    /design/:id
    链接在没有登录的所有者/编辑器会话时保持只读。绝不要使用本地权限升级该普通分享界面。
  • 优先使用Design操作或
    /_agent-native/open
    深度链接返回的链接。不要显示带有
    _session=
    令牌的URL或手动构建权限URL。
  • 不要尝试使用浏览器权限执行基于账户的写入操作。受信任的本地
    open-visual-edit
    CLI调用可在无需账户的情况下注册其桥接器、创建或复用其工作区所有的本地设计并放置屏幕。直接的源文件操作写入、生成、保存到账户以及分享仍需要经过身份验证的操作调用者。如果未登录的访问者需要这些持久化账户操作,请先将其引导至框架登录返回流程。

Required Local Bridge

必需的本地桥接器

The live-edit bridge is unlocked by a shared secret (the "bridge token") that must match on two sides: the local bridge process, and the user's connection row in Design (which the browser reads to authorize
/live-edit-bridge
,
/read-file
,
/write-file
). Get them to match by letting the
open-visual-edit
action mint the token, then starting the bridge with it. This is the only ordering that works for the remote-MCP flow — the bridge cannot push its own token to the server without a CLI auth token, so the server mints instead and the bridge adopts.
From the target app repo, make sure its dev server is running, then:
1. Discover routes without starting a durable bridge (one-shot, exits):
bash
npx @agent-native/core@latest design connect --url http://localhost:5173 --root . --json
This prints the manifest (routes + capabilities). Parse it to build
routeManifest
for the next step. (Skip this if the user already gave explicit paths/URLs to place.)
Inside the agent-native monorepo itself, use the workspace CLI instead of
npx
npx
installs the last published
@agent-native/core
, which will not contain local changes and costs a slow install on every call:
bash
pnpm dev:cli design connect --url http://localhost:5173 --root templates/<app> --json
2. Call
open-visual-edit
(see Action Flow below) with NO
bridgeToken
. The server mints one, stores it on the user's connection row, copies it into the placed screens' metadata, and returns it to you as
bridgeToken
. Capture it.
3. Start the persistent bridge adopting that token (single line; prefer the env var so the secret does not appear in
ps
):
bash
AGENT_NATIVE_BRIDGE_TOKEN="<bridgeToken from step 2>" npx @agent-native/core@latest design connect --url http://localhost:5173 --root . --daemon
(Equivalently, pass
--bridge-token <token>
.) This starts a detached bridge on
http://127.0.0.1:7331
, adopts the server-minted token — so bridge and row agree and live-edit authorizes with no self-registration — and stays alive after the command exits.
For a manual health/manifest check on the running bridge:
bash
curl http://127.0.0.1:7331/health
/health
needs no token. The full manifest at
/manifest.json
is preview-token protected, so an unauthenticated
curl
of it returns
{"ok":false,"error":"invalid or missing preview token"}
— that response means the bridge is up, not that it is broken.
Only use
--json
for the step-1 route probe. Never use
--json
,
--once
, or
--dry-run
for the durable step-3 bridge: they print the manifest and exit, so Design falls back to a non-editable live iframe.
The bridge listens on a single fixed port (7331) and refuses to start for a second, different app. It is detached with no log file, so if
--daemon
reports a timeout, check for a stale process (
lsof -ti:7331
) before retrying.
实时编辑桥接器由共享密钥(“桥接令牌”)解锁,该密钥必须在两端匹配:本地桥接器进程和Design中用户的连接行(浏览器读取该行以授权
/live-edit-bridge
/read-file
/write-file
)。通过让
open-visual-edit
操作生成令牌,然后使用该令牌启动桥接器,使两者匹配。这是远程MCP流程唯一可行的顺序——桥接器无法在没有CLI auth令牌的情况下将自己的令牌推送到服务器,因此由服务器生成令牌,桥接器采用该令牌。
从目标应用仓库中,确保其开发服务器正在运行,然后:
1. 发现路由而不启动持久桥接器(一次性操作,执行后退出):
bash
npx @agent-native/core@latest design connect --url http://localhost:5173 --root . --json
此命令会打印清单(路由 + 功能)。解析该清单以构建下一步的
routeManifest
。(如果用户已提供明确的路径/URL来放置屏幕,可跳过此步骤。)
在agent-native单体仓库内部,使用工作区CLI而非
npx
——
npx
会安装最后发布的
@agent-native/core
,其中不包含本地更改,且每次调用都会缓慢安装:
bash
pnpm dev:cli design connect --url http://localhost:5173 --root templates/<app> --json
2. 调用
open-visual-edit
(见下文的操作流程),且不传入
bridgeToken
。服务器会生成一个令牌,将其存储在用户的连接行中,复制到已放置屏幕的元数据中,并将其作为
bridgeToken
返回给您。请捕获该令牌。
3. 使用该令牌启动持久桥接器(单行命令;优先使用环境变量,以免秘密出现在
ps
中):
bash
AGENT_NATIVE_BRIDGE_TOKEN="<bridgeToken from step 2>" npx @agent-native/core@latest design connect --url http://localhost:5173 --root . --daemon
(等效于传入
--bridge-token <token>
。)此命令会在
http://127.0.0.1:7331
启动一个独立的桥接器,采用服务器生成的令牌——因此桥接器和连接行匹配,实时编辑无需自注册即可授权——并在命令退出后保持运行。
要对运行中的桥接器进行手动健康/清单检查:
bash
curl http://127.0.0.1:7331/health
/health
无需令牌。
/manifest.json
的完整清单受预览令牌保护,因此未认证的
curl
请求会返回
{"ok":false,"error":"invalid or missing preview token"}
——此响应表示桥接器已启动,而非故障。
仅在步骤1的路由探测中使用
--json
。绝不要在步骤3的持久桥接器中使用
--json
--once
--dry-run
:这些参数会打印清单并退出,导致Design回退到不可编辑的实时iframe。
桥接器监听单个固定端口(7331),并拒绝为第二个不同的应用启动。它是独立运行的,没有日志文件,因此如果
--daemon
报告超时,请在重试前检查是否有 stale 进程(
lsof -ti:7331
)。

Action Flow

操作流程

Prefer the single
open-visual-edit
action. It registers or refreshes the localhost bridge connection, mints and stores the bridge token, creates or reuses a Design project, places URL-backed screens, stores the active visual-edit context, and navigates to overview mode in one call. This avoids creating a private design under a synthetic CLI user and then handing the browser a tokenized URL that may be shadowed by an existing session.
Call it BEFORE starting the durable bridge (step 3 above): it does not contact the bridge, so the bridge need not be running yet, and you need its returned
bridgeToken
to start the bridge with a matching secret. Omit
bridgeToken
on the call so the server mints one.
bash
pnpm action open-visual-edit '{
  "title": "Docs homepage visual edit",
  "devServerUrl": "http://localhost:5173",
  "bridgeUrl": "http://127.0.0.1:7331",
  "rootPath": "/absolute/path/to/app",
  "routeManifest": { "...": "from /manifest.json" },
  "paths": ["/", "/pricing", "/checkout?step=payment"]
}'
The action returns
designId
,
connectionId
,
bridgeToken
,
screens
,
urlPath
, and a credential-free
openUrl
. Its MCP App metadata separately carries the one-time editor launcher so the host can redeem it without showing the capability to the model or retaining it in the action link. Keep
designId
/
connectionId
in the chat context for follow-ups, and pass
bridgeToken
to
design connect
(step 3) to start the bridge. On follow-up calls reusing an existing
connectionId
, the same token is returned (it is minted once and reused), so the running bridge stays valid.
优先选择单个
open-visual-edit
操作。它会注册或刷新localhost桥接器连接,生成并存储桥接令牌,创建或复用Design项目,放置基于URL的屏幕,存储活动的可视化编辑上下文,并在一次调用中导航到概览模式。这避免了在合成CLI用户下创建私有设计,然后向浏览器传递可能被现有会话覆盖的令牌化URL。
在启动持久桥接器(上述步骤3)之前调用它:它不会联系桥接器,因此桥接器无需已运行,且您需要其返回的
bridgeToken
来使用匹配的密钥启动桥接器。调用时省略
bridgeToken
,以便服务器生成一个。
bash
pnpm action open-visual-edit '{
  "title": "Docs homepage visual edit",
  "devServerUrl": "http://localhost:5173",
  "bridgeUrl": "http://127.0.0.1:7331",
  "rootPath": "/absolute/path/to/app",
  "routeManifest": { "...": "from /manifest.json" },
  "paths": ["/", "/pricing", "/checkout?step=payment"]
}'
该操作会返回
designId
connectionId
bridgeToken
screens
urlPath
以及无需凭证的
openUrl
。其MCP App元数据单独携带一次性编辑器启动器,因此主机可在不向模型展示权限或在操作链接中保留权限的情况下兑换它。将
designId
/
connectionId
保留在聊天上下文中以便后续操作,并将
bridgeToken
传递给
design connect
(步骤3)以启动桥接器。在复用现有
connectionId
的后续调用中,会返回相同的令牌(令牌仅生成一次并复用),因此运行中的桥接器保持有效。

Desktop and mobile side by side

桌面端与移动端并排展示

Pass
viewports
to place every requested route once per viewport. Frames lay out as a grid: one row per route, one column per viewport. Presets are
desktop
(1280x900),
laptop
(1440x900),
tablet
(834x1112), and
mobile
(390x844); an explicit
{ "label": "...", "width": N, "height": N }
also works.
bash
pnpm action open-visual-edit '{
  "title": "Tasks responsive visual edit",
  "devServerUrl": "http://localhost:5173",
  "bridgeUrl": "http://127.0.0.1:7331",
  "rootPath": "/absolute/path/to/app",
  "paths": ["/tasks", "/inbox"],
  "viewports": ["desktop", "mobile"]
}'
Prefer this over two separate calls with
defaultWidth
/
defaultHeight
: it keeps each route's viewports aligned in a row and titles them
Tasks — Desktop
/
Tasks — Mobile
so the canvas reads clearly.
viewports
overrides
defaultWidth
/
defaultHeight
. With no
routes
/
paths
, it expands every route in the localhost manifest, which is usually far more frames than the user wants — name the paths.
传入
viewports
可为每个请求的路由按每个视口放置一次屏幕。框架会以网格布局排列:每行对应一个路由,每列对应一个视口。预设包括
desktop
(1280x900)、
laptop
(1440x900)、
tablet
(834x1112)和
mobile
(390x844);显式的
{ "label": "...", "width": N, "height": N }
格式也适用。
bash
pnpm action open-visual-edit '{
  "title": "Tasks responsive visual edit",
  "devServerUrl": "http://localhost:5173",
  "bridgeUrl": "http://127.0.0.1:7331",
  "rootPath": "/absolute/path/to/app",
  "paths": ["/tasks", "/inbox"],
  "viewports": ["desktop", "mobile"]
}'
优先使用此方式,而非两次单独调用并传入
defaultWidth
/
defaultHeight
:它会将每个路由的视口在一行中对齐,并将其命名为
Tasks — Desktop
/
Tasks — Mobile
,使画布清晰易读。
viewports
会覆盖
defaultWidth
/
defaultHeight
。如果未提供
routes
/
paths
,它会展开localhost清单中的每个路由,这通常会生成远多于用户所需的框架——请明确指定路径。

Adding more page frames later

后续添加更多页面框架

Call
open-visual-edit
again with the same
designId
and
connectionId
and only the new paths. Existing frames for the same route and viewport are refreshed in place rather than duplicated, and a frame the user has dragged or resized keeps its position unless you explicitly pass
x
/
y
/
width
/
height
.
bash
pnpm action open-visual-edit '{
  "designId": "<existing-design-id>",
  "connectionId": "<existing-connection-id>",
  "devServerUrl": "http://localhost:5173",
  "paths": ["/settings", "/team"],
  "startY": 2200
}'
Do NOT add
defaultWidth
/
defaultHeight
just to restate the default size: supplying either one marks the viewport as explicitly requested, which overwrites frame sizes the user has already adjusted on the canvas.
For a numbered flow the user describes in chat, keep the labels and order:
bash
pnpm action open-visual-edit '{
  "designId": "<existing-design-id>",
  "connectionId": "<existing-connection-id>",
  "devServerUrl": "http://localhost:1234",
  "routes": [
    { "url": "localhost:1234/onboarding/1", "title": "Screen 1" },
    { "url": "localhost:1234/onboarding/2", "title": "Screen 2" },
    { "url": "localhost:1234/onboarding/3", "title": "Screen 3" }
  ]
}'
If no
routes
or
paths
are supplied,
open-visual-edit
uses every route from the localhost manifest.
Fallback, only when
open-visual-edit
is unavailable:
  1. Register or refresh the bridge with
    connect-localhost
    , passing the
    /manifest.json
    result as
    routeManifest
    and
    capabilities
    .
  2. Create or reuse a Design project with
    create-design
    .
  3. Place URL-backed screens with
    add-localhost-screens
    .
  4. Navigate to overview mode with
    navigate
    .
再次调用
open-visual-edit
,传入相同的
designId
connectionId
以及仅新增的路径。同一路由和视口的现有框架会在原地刷新,用户已拖动或调整大小的框架会保持其位置,除非您显式传入
x
/
y
/
width
/
height
bash
pnpm action open-visual-edit '{
  "designId": "<existing-design-id>",
  "connectionId": "<existing-connection-id>",
  "devServerUrl": "http://localhost:5173",
  "paths": ["/settings", "/team"],
  "startY": 2200
}'
不要仅为了重申默认大小而添加
defaultWidth
/
defaultHeight
:提供其中任何一个都会将视口标记为显式请求,这会覆盖用户已在画布上调整的框架大小。
对于用户在聊天中描述的编号流程,保留其标签和顺序:
bash
pnpm action open-visual-edit '{
  "designId": "<existing-design-id>",
  "connectionId": "<existing-connection-id>",
  "devServerUrl": "http://localhost:1234",
  "routes": [
    { "url": "localhost:1234/onboarding/1", "title": "Screen 1" },
    { "url": "localhost:1234/onboarding/2", "title": "Screen 2" },
    { "url": "localhost:1234/onboarding/3", "title": "Screen 3" }
  ]
}'
如果未提供
routes
paths
open-visual-edit
会使用localhost清单中的每个路由。
仅当
open-visual-edit
不可用时使用回退方案:
  1. 使用
    connect-localhost
    注册或刷新桥接器,传入
    /manifest.json
    的结果作为
    routeManifest
    capabilities
  2. 使用
    create-design
    创建或复用Design项目。
  3. 使用
    add-localhost-screens
    放置基于URL的屏幕。
  4. 使用
    navigate
    导航到概览模式。

Open The Design Surface

打开Design界面

  • Use the
    link
    ,
    deepLink
    , or MCP App embed returned by Design actions so the user sees the canvas. Follow Put Design Beside The Chat: prefer the MCP App; otherwise surface the credential-free Open design link.
  • Return or open the MCP App first. Its host-managed launcher carries the one-time local-editor capability. The credential-free
    openUrl
    / action link is the safe read-only fallback; never build a capability URL yourself.
  • Never return or open a hand-built
    /design/:id?_session=...
    URL.
  • If the user is working in VS Code, the Agent Native extension can open the same URL via
    vscode://builder.agent-native/open?url=<encoded-design-url>
    . Its
    Agent Native: Open Design Canvas
    command also starts the local bridge and opens hosted Design in the VS Code side panel.
  • After
    open-visual-edit
    , confirm the Design editor is in overview mode with the requested URL-backed frames visible, and that they render the app rather than a spinner. Do not stop at "screens added" when the user asked to inspect or edit visually.
  • 使用Design操作返回的
    link
    deepLink
    或MCP App嵌入,让用户看到画布。遵循将Design置于聊天窗口旁:优先选择MCP App;否则展示无需凭证的打开设计链接。
  • 优先返回或打开MCP App。其主机管理的启动器携带一次性本地编辑器权限。无需凭证的
    openUrl
    /操作链接是安全的只读回退方案;绝不要自行构建权限URL。
  • 绝不要返回或打开手动构建的
    /design/:id?_session=...
    URL。
  • 如果用户在VS Code中工作,Agent Native扩展可通过
    vscode://builder.agent-native/open?url=<encoded-design-url>
    打开相同的URL。其
    Agent Native: Open Design Canvas
    命令还会启动本地桥接器并在VS Code侧边面板中打开托管的Design。
  • open-visual-edit
    之后,确认Design编辑器处于概览模式,且请求的基于URL的框架可见,并渲染应用而非加载动画。当用户要求可视化检查或编辑时,不要仅停留在“已添加屏幕”的状态。

Applying Visual Edits Back To Source

将可视化编辑应用回源码

Canvas edits on a localhost screen do not write source as you make them. They accumulate as pending edits and the editor shows an Apply design updates button on the canvas. In an MCP App, clicking it hands the bounded structured prompt to the current host coding conversation. In an ordinary browser or standalone Design page, it falls back to the local Design agent. The dropdown's Copy prompt to your agent action is the universal manual fallback.
  • Style, text, and drag/drop structure edits all collect into the same pending batch, so the user can make several changes and apply once.
  • After the write lands, the target app's own dev-server HMR refreshes the frames — no manual reload. If frames do not refresh, the write did not land; say so rather than assuming.
  • The separate disk-icon "Apply to source" button is the deterministic whole-file HTML/CSS writer. It is intentionally disabled for compiled
    .jsx
    /
    .tsx
    routes — those must go through the agent path above.
对localhost屏幕的画布编辑不会在您进行编辑时写入源码。它们会累积为待处理的编辑,编辑器会在画布上显示应用设计更新按钮。在MCP App中,点击该按钮会将受限的结构化提示交回当前主机编码对话。在普通浏览器或独立Design页面中,它会回退到本地Design代理。下拉菜单中的将提示复制到您的代理操作是通用的手动回退方案。
  • 样式、文本和拖放结构编辑都会收集到同一个待处理批次中,因此用户可进行多项更改后一次性应用。
  • 写入完成后,目标应用自身的开发服务器HMR会刷新框架——无需手动重新加载。如果框架未刷新,则表示写入未完成,请告知用户,而非假设已完成。
  • 单独的磁盘图标“应用到源码”按钮是确定性的全文件HTML/CSS写入器。对于编译后的
    .jsx
    /
    .tsx
    路由,它会被故意禁用——这些路由必须通过上述代理路径处理。

Editing URLs

编辑URL

Keep localhost screens as URL files plus
screenMetadata[fileId]
. Do not replace them with copied
srcdoc
HTML unless the user explicitly asks for a frozen snapshot. To change a state, rerun
open-visual-edit
with the new path/query or duplicate the screen and update the copy's URL metadata.
将localhost屏幕保留为URL文件加上
screenMetadata[fileId]
。除非用户明确要求冻结快照,否则不要用复制的
srcdoc
HTML替换它们。要更改状态,请使用新的路径/查询重新运行
open-visual-edit
,或复制屏幕并更新副本的URL元数据。

Local Files in the Code Tab

代码标签页中的本地文件

Once a connection is registered, the design editor's Code panel (left rail → Code, or
navigate --view editor --designId <id> --leftPanel code
) shows a local-files workspace root for that connection next to the design's own files. Treat that root like VS Code opened at the connected project directory: file tree, search, open/edit, and save are backed by the real local files. It lists the connected app's text/code files through the bridge (
list-local-files
/
read-local-file
); build output,
node_modules
,
.git
, and secret-looking paths (
.env*
, key files) are always excluded.
  • Browsing and reading need only editor access on the design plus the running bridge.
  • Saving goes through
    write-local-file
    : the first save opens the write-consent dialog (an 8-hour, folder-scoped grant) and retries automatically once granted. Only text/code files are writable; secret paths are always blocked.
  • If the agent calls
    write-local-file
    directly (not through a UI save) and it fails with "no write-consent grant", call
    request-localhost-write-consent
    . It opens the write-consent dialog in the editor, or reports
    alreadyGranted
    if one already exists. Granting is human-only —
    grant-localhost-write-consent
    is hidden from agents, so you cannot approve it yourself. Tell the user to click "Allow writes", then retry
    write-local-file
    once. Do not keep retrying blindly: the write stays blocked until the user approves.
  • Saves are conflict-checked against the file's on-disk version — a file that changed since it was read fails with a version conflict instead of being overwritten.
注册连接后,设计编辑器的代码面板(左侧边栏 → 代码,或
navigate --view editor --designId <id> --leftPanel code
)会在设计自身文件旁显示该连接的本地文件工作区根目录。将该根目录视为VS Code在连接的项目目录中打开:文件树、搜索、打开/编辑和保存都基于真实的本地文件。它通过桥接器列出连接应用的文本/代码文件(
list-local-files
/
read-local-file
);构建输出、
node_modules
.git
和类似秘密的路径(
.env*
、密钥文件)始终被排除。
  • 浏览和读取仅需设计的编辑器权限以及运行中的桥接器。
  • 保存通过
    write-local-file
    执行:首次保存会打开写入许可对话框(8小时有效期,文件夹范围的授权),并在获得授权后自动重试。仅文本/代码文件可写入;秘密路径始终被阻止。
  • 如果代理直接调用
    write-local-file
    (而非通过UI保存)并因“无写入许可授权”失败,请调用
    request-localhost-write-consent
    。它会在编辑器中打开写入许可对话框,或在已有授权时返回
    alreadyGranted
    。授权仅可由人工完成——
    grant-localhost-write-consent
    对代理隐藏,因此您无法自行批准。告知用户点击“允许写入”,然后重试一次
    write-local-file
    。不要盲目重试:在用户批准之前,写入会一直被阻止。
  • 保存会与文件的磁盘版本进行冲突检查——自读取以来已更改的文件会因版本冲突而失败,而非被覆盖。

React Source Writeback

React源码回写

  • Use compiler/debug provenance (project-relative file, line, column, component, and runtime multiplicity) to locate React/TSX source. Treat it as evidence, not as permission for a generic AST structural transform.
  • Read
    positionPrecision
    on every anchor before you trust
    line
    /
    column
    .
    authored
    means those are the real JSX coordinates.
    transformed
    means they are the dev server's own output coordinates — React 19 removed
    _debugSource
    and exposes only an owner stack, so this is the normal case on a Vite/Next dev server, and the line will not match the file.
    unknown
    means no tier was reported. On anything but
    authored
    , use the file and component to find the element by its JSX shape and re-derive the line from the file you read; never edit at the reported line.
  • A single-instance leaf text edit, literal
    className
    /
    class
    edit, or flat literal
    style={{ ... }}
    property may use
    apply-visual-edit
    with a
    local-file
    source and a complete
    target.sourceAnchor
    . Forward the anchor's
    positionPrecision
    with it — the action refuses a
    transformed
    anchor with
    status: "needsAgent"
    instead of seeking to a line that means something else in the authored file. Preview first (omit
    persist
    ), inspect
    proposedDiff
    , then call with
    persist: true
    .
  • Reparenting, grouping/ungrouping, wrappers, dynamic expressions, repeated
    .map()
    instances, shared components, breakpoint-scoped edits, and cross-file changes go through the coding agent with complete subject/target anchors and their runtime relationship.
    apply-visual-edit
    refuses these with
    status: "needsAgent"
    rather than guessing.
  • Before each write, read the file and pass its exact
    versionHash
    to
    write-local-file
    with
    requireExpectedVersionHash: true
    ; on conflict, re-read and re-plan. Keep the optimistic preview until HMR/runtime confirms the result. Human write consent remains mandatory and agents cannot grant it.
  • 使用编译器/调试来源(项目相对文件、行、列、组件和运行时多样性)定位React/TSX源码。将其视为证据,而非通用AST结构转换的许可。
  • 在信任
    line
    /
    column
    之前,读取每个锚点的
    positionPrecision
    authored
    表示这些是真实的JSX坐标。
    transformed
    表示这些是开发服务器自身的输出坐标——React 19移除了
    _debugSource
    ,仅暴露所有者堆栈,因此这是Vite/Next开发服务器上的正常情况,且行号与文件不匹配。
    unknown
    表示未报告任何层级。对于除
    authored
    之外的任何情况,使用文件和组件通过其JSX形状查找元素,并从您读取的文件中重新推导行号;绝不要在报告的行号处进行编辑。
  • 单实例叶子文本编辑、字面量
    className
    /
    class
    编辑或平字面量
    style={{ ... }}
    属性可使用
    apply-visual-edit
    ,传入
    local-file
    源和完整的
    target.sourceAnchor
    。同时传递锚点的
    positionPrecision
    ——如果锚点为
    transformed
    ,操作会拒绝并返回
    status: "needsAgent"
    ,而非尝试定位到在原始文件中无意义的行号。先预览(省略
    persist
    ),检查
    proposedDiff
    ,然后传入
    persist: true
    调用。
  • 重父级、分组/取消分组、包装器、动态表达式、重复的
    .map()
    实例、共享组件、断点范围编辑和跨文件更改需通过编码代理处理,传入完整的主体/目标锚点及其运行时关系。
    apply-visual-edit
    会拒绝这些操作并返回
    status: "needsAgent"
    ,而非猜测。
  • 每次写入前,读取文件并将其精确的
    versionHash
    传递给
    write-local-file
    ,并设置
    requireExpectedVersionHash: true
    ;发生冲突时,重新读取并重新规划。在HMR/运行时确认结果之前,保持乐观预览。人工写入许可仍然是必需的,代理无法批准。

Verification

验证

  • list-localhost-connections
    returns the expected connection and routes.
  • The Design editor opens in overview mode.
  • Every requested screen renders the intended localhost URL, showing real app content rather than an endless loading spinner.
  • The screen iframe carries a
    src
    , not a
    srcdoc
    . A localhost screen with a
    srcdoc
    is a bug, not a slow load — check it in the browser devtools before reporting the canvas as working.
  • Alt-dragging a screen copies the URL-backed frame, not an inline HTML clone.
  • A query/path edit changes only the target screen's URL metadata and iframe.
  • The Code tab shows a local-files root for the connection and opens its files.
  • list-localhost-connections
    返回预期的连接和路由。
  • Design编辑器在概览模式下打开。
  • 每个请求的屏幕都渲染了预期的localhost URL,显示真实的应用内容而非无限加载动画。
  • 屏幕iframe带有
    src
    ,而非
    srcdoc
    。带有
    srcdoc
    的localhost屏幕是错误,而非加载缓慢——在报告画布正常工作之前,请在浏览器开发者工具中检查它。
  • 按住Alt键拖动屏幕会复制基于URL的框架,而非内联HTML克隆。
  • 查询/路径编辑仅更改目标屏幕的URL元数据和iframe。
  • 代码标签页显示连接的本地文件根目录并可打开其文件。