---
name: brifdo-prototype-builder
description: Build, continue, verify, or selectively revise product prototypes through the Brifdo MCP service. Use whenever an Agent is asked to create or edit a Brifdo product, Screen, module, interaction, copy, or Osuki component, including long-running work resumed across sessions.
---

# Brifdo Prototype Builder

Use only the authenticated Brifdo MCP tools. Treat the MCP server's current
tool schemas and returned `nextActions` as authoritative.

## Start every task

1. Call `get_service_capabilities` and check the execution mode, scopes, Skill
   version, and available tools.
2. Do **not** read the component catalog up front. `compile_product_module`
   chooses every Library recipe itself, and a module-scoped
   `read_product_build_context` already lists the recipes the Module's
   acceptance contract needs (`currentCanvas.libraryRecipes`). Read the
   component guide and call `get_library_catalog` (once, and keep the result)
   only when you are about to hand-draw with `commit_prototype_batch` and the
   listed recipes do not cover a component.
   Catalog reading rules, for that case: each recipe entry is the write tuple.
   Copy its `recipeId` and `slot` into a `libraryRecipe`, add the node's own
   `instanceId` (plus `props` where the component takes them), and leave
   `component`/`variant`/`size`/`state`/`composition`/`library`/`version` out —
   `recipeId` determines them and the server derives them (a full tuple is
   accepted and re-derived, never refused for disagreeing). `slot` is the exact
   root slot (`"Card"` for Card, `"root"` otherwise; props sent on `root` for a
   Card are moved to `Card`); `allowedSlots` lists child-node slot values and
   sits on the component when its recipes share one list, otherwise on the
   recipe. `minWidth`, where published, is the narrowest frame content width
   the component can be drawn in — do not plan a component whose `minWidth`
   exceeds the target frame (an app frame has about 354px of content width).
3. Decide whether this is a new product or a continuation. Never reuse a
   similar-looking product for a new request.
   - New product: translate the user's request into a concrete plan and call
     `create_product_from_plan`. Use the returned public references.
     A one-line request is enough to start discovery. Do not make the user
     enumerate every field or page before helping: infer ordinary UI details
     as explicit `planning.assumptions`, and ask at most five questions whose
     answers materially change roles, module boundaries, core workflows,
     regulated data, or external integrations. Put each unresolved answer in
     `planning.scopeDecisions`; never silently choose it for a reviewable plan.
     Plan density: a module is one functional domain; its screens are the
     steps of its core flows. Cover each real step (a CRUD domain needs at
     least list, detail, and create/edit); typical 2-5 screens per module,
     more only when the flows genuinely require it.
   - Continuation: call `list_authorized_products` and select only a product
     whose `availability.writable` is true, unless the user supplied an exact
     public reference. The default listing carries every writable product plus
     the most recent others; only call it again with `includeAll: true` when
     `omittedCount` says the product you need is in the older remainder.
4. For an existing product, call `read_product_build_context`. Read the module
   index first, then only the module and Screens needed for the current task.
   Never ask for or guess database IDs. A `scope: "all"` read is
   deduplicated: the acceptance contract appears once under
   `currentCanvas.module` (the plan copy of that module lists
   `screenReferences` instead), the document's Screens live in
   `currentCanvas.screenIndex`, and nodes omit fields that carry a default or
   follow from their own ids — the rules are in `nodeDefaults` and
   `nodeDerivations`. A node read this way can be edited and written straight
   back; nothing needs to be filled in.
5. Respect the confirmed requirement and acceptance contracts. If the user
   asks for a named page that is not in the contract, or changes a Screen's
   purpose or flow, call `revise_product_plan` before drawing. Prefer an
   explicit `add_module`, `add_screen`, or `update_screen`; use
   `set_additional_screens` only when the user intentionally delegates
   unspecified additional pages. Use `update_planning_context` to record
   answered scope decisions and promote an existing sketch to reviewable.
   Restructure with `update_module` (rename / re-describe a module),
   `remove_screen`, `move_screen`, `merge_screen` and `reorder_screens`
   (see "Plan and reference contract"); never drop a page with a canvas-level
   `removeScreen` — that deletes only the frame while the contract, the
   preview navigation and the completion gate still expect the page.
   Then reread context and build with the newly returned aliases. Do not
   bypass the contract by inventing a Screen directly in a prototype batch.
   Use each acceptance item's concise `label` as visible control copy. Treat
   `evidenceText` as a verification description; never paste a full acceptance
   sentence into a Button, Badge, field label, navigation item, or other UI
   control.

## One user need, one product

Continuing an existing product is the default. Before calling
`create_product_from_plan`, call `list_authorized_products`; if a product for
this need already exists and its `availability.writable` is true, read its
context with `read_product_build_context` and continue it with
`commit_prototype_batch` or `compile_product_module` instead of creating
another product. Only call `create_product_from_plan` for a genuinely new
user need. Creating a variant or a v2 of an existing product requires the
user to explicitly ask for one — never create a new product as a workaround
for an error such as a not-writable module, a revision conflict, or a failed
compile; reread context and retry the existing product instead.

## Plan and reference contract

- Every create and revision carries a planning depth:
  - `sketch` starts quickly from sparse input. It must list its assumptions and
    unresolved scope decisions. It is useful for direction and may be built,
    but it is not review-complete and must never be presented as approved
    implementation scope.
  - `reviewable` is the closed-scope contract used for stakeholder review and
    completion. It has no unresolved blocking scope decisions, does not allow
    unspecified additional Screens, and gives every Screen full structured
    acceptance evidence. The server fails closed before product creation or
    revision confirmation when this contract is incomplete.
- Do not turn normal UI details into questions. Ask no more than five concise
  architecture-changing questions in one round, then record the user's answers
  with `update_planning_context`. If a blocking answer remains unresolved,
  keep the plan at `sketch` instead of guessing.

- Two ID namespaces, never mixed: plan `screens[].id` values are plan-local
  and end at creation. After creation every tool speaks only the aliases
  returned by `read_product_build_context`: `module-ref-NNN` and
  `screen-ref-NNN`.
- Screens introduced together in one `revise_product_plan` request may declare
  unique request-local aliases such as `draft-screen-ref-001`. Acceptance
  interactions in that same request may target those aliases. The server
  resolves them before persistence; never reuse them after the revision.
- When a plan screen supplies `acceptance`, it must carry all five arrays —
  `capabilities`, `fields`, `states`, `actions`, `interactions` — even when
  empty.
- Plan acceptance `interactions[].targetScreenId` may target a screen in
  another module. Inside one compile intent, `actions[].targetScreenId` may
  only target screens of that same intent; leave cross-module navigation to
  the plan's acceptance interactions.
- In a `reviewable` plan, a screen's plain-text `interactions` and its
  structured `acceptance.interactions` must map one-to-one: every
  `acceptance.interactions[].plannedInteraction` copies exactly one
  `interactions` entry verbatim (character-for-character — no rewording,
  merging, or omission), and every `interactions` entry is used exactly once.
  `fromActionId` names an `acceptance.actions[].id` on the same screen;
  `targetScreenId` may point at another screen, including one in another
  module. A complete cross-screen example:

  ```json
  {
    "name": "订单列表",
    "purpose": "查看和跟进全部订单",
    "interactions": ["点击「查看明细」跳转到订单明细页"],
    "acceptance": {
      "capabilities": [
        {
          "id": "cap-order-list",
          "label": "订单列表",
          "component": "table",
          "evidenceText": "展示订单编号、状态与金额的表格"
        }
      ],
      "fields": [],
      "states": [],
      "actions": [
        {
          "id": "action-open-detail",
          "label": "查看明细",
          "component": "button",
          "evidenceText": "订单列表提供查看明细按钮"
        }
      ],
      "interactions": [
        {
          "id": "interaction-open-detail",
          "label": "跳转订单明细",
          "plannedInteraction": "点击「查看明细」跳转到订单明细页",
          "fromActionId": "action-open-detail",
          "targetScreenId": "draft-screen-ref-002"
        }
      ]
    }
  }
  ```

  At creation time `targetScreenId` uses the plan-local id of the target
  screen; in a `revise_product_plan` request it uses an existing
  `screen-ref-NNN` alias or a `draft-screen-ref-NNN` declared in the same
  request. If the mapping is not exact, the failure carries this same
  corrected-JSON fragment in `error.details`.

- Modules are independent, each with its own revision and CAS. An Agent that
  can parallelize may build multiple modules concurrently — one module per
  worker, never two workers on one module.
- `revise_product_plan` is the only MCP path for changing a confirmed Screen
  contract. It requires the current plan revision, public aliases, and a
  stable idempotency key; an exact retry is safe. It preserves unaffected
  modules and reopens only the modules whose requirements changed. Revision
  confirmation reruns the same trusted readiness gate used at creation.
- Structural changes, all inside one `revise_product_plan` request and
  applied in order (so a later change sees an earlier one's result):
  - `update_module { moduleReference, patch: { name?, purpose? } }` renames
    or re-describes a module; the preview navigation reflects it.
  - `remove_screen { screenReference, reason }` removes the page from the
    contract AND, in the same transaction, its frame, nodes and every
    connection or hotspot pointing at it on any module canvas.
  - `move_screen { screenReference, toModuleReference, position? }` moves the
    page (plan entry, drawn frame and nodes) to another module; `position` is
    the 0-based index in the target module, omitted appends. Ids are stable,
    so existing connections keep working; both modules reopen.
  - `merge_screen { sourceScreenReference, targetScreenReference }` folds a
    duplicate page into the one that stays: every interaction and hotspot
    that pointed at the source now points at the target, acceptance items
    are merged (deduplicated by id or label), then the source is removed.
  - `reorder_screens { moduleReference, screenReferences }` sets the page
    order of one module; `screenReferences` must list every page of that
    module exactly once (`SCREEN_ORDER_INVALID` otherwise).
  - A page cannot be removed or merged away when it is the plan entry page
    (`SCREEN_IS_ENTRY`: the first page of the first module — reorder or move
    another page in front first), when it is the only page of its module
    (`SCREEN_IS_ONLY_PAGE`: add or move a page in first), or — for
    `remove_screen` only — while other pages' acceptance interactions still
    target it (`SCREEN_REFERENCED`: use `merge_screen` for a duplicate, or
    `update_screen` the referrers earlier in the same request).
  - Modules whose pages were removed, moved, merged or reordered reopen and
    must pass `complete_product_module` again.
- Page numbers (`pageNumber`) follow plan order: module order, then page order
  inside the module. They are recomputed after every revision and are the
  same in the preview navigation, the user-flow view, this tool's context and
  the execution handoff. `screen-ref-NNN` aliases are allocated once, when a
  page enters the contract, and never change or get reused afterwards —
  removing, moving, merging or reordering pages renumbers pages, not refs.

## Choose the shortest safe write path

- `compile_product_module` is the PRIMARY way to satisfy a Screen's
  acceptance contract. For every new module or whole-Screen build, supply
  business structure and copy and let Brifdo choose exact Osuki recipes,
  geometry, and batches locally — deterministic, faster, and at zero Brifdo
  model cost. Never hand-draw a whole Screen from scratch with
  `commit_prototype_batch` while the compile tool is available.
- **Rebuilding one Screen is also the compile path**, not a hand-drawing job.
  Send `compile_product_module` with `screenIds` naming just the Screens you
  are changing, and an `intent` covering exactly those Screens:
  - every other Screen keeps its nodes, connections, and recorded acceptance
    evidence byte-for-byte, and none of them are moved on the canvas;
  - a hotspot another Screen aims at the recompiled Screen survives; a hotspot
    the recompiled Screen aims at a Screen that no longer exists fails the
    call instead of disappearing;
  - a Screen the module plans but has never drawn can be compiled this way
    too — it is appended to the right of the canvas;
  - `expectedRevision`/`nextExpectedRevision` and `idempotencyKey` work exactly
    as in a whole-module compile; an exact replay is a no-op.
    Two rejections are specific to this mode, and both mean "omit `screenIds`
    and recompile the whole module": `SCREEN_SCOPE_FRAME_SLOT` (the Screen
    changed viewport width and no longer fits the canvas slot it holds) and
    `SCREEN_SCOPE_ORPHANS_CONNECTION` (the recompile would delete a node another
    Screen's interaction still points at).
- A screen-scoped recompile moves the Scene revision, so the module's last
  acceptance stamp becomes older than the canvas. Call
  `complete_product_module` afterwards: it re-verifies the whole module against
  the current document and re-stamps it. It does not erase the other Screens'
  evidence.
- If a compile fails (`COMPILE_FAILED`, `PLAN_NOT_BUILDABLE`), the fix is in
  the plan or intent, not in the write path: repair everything listed in
  `error.details` and recall the compile tool. Do not switch to manual
  batching as a workaround for a failed compile.
- Manual batching with `commit_prototype_batch` is the right tool only for:
  - pixel-level refinement — nudging one node, rewording one label, adding or
    removing a single connection at the current revision with stable semantic
    IDs. Redoing a Screen's structure is a `screenIds` compile, not a batch;
  - free-form compositions genuinely outside the compiler's section grammar
    (metrics/table/form/list/gantt/chart sections plus actions and acceptance
    evidence), which the compiler cannot express.
- When capabilities list `compile_product_module` as unavailable, an
  administrator has temporarily switched the compiler off (it is on by
  default). Tell the user so they can ask the administrator to re-enable it;
  fall back to manual batching only while it stays off.
- Use the already-loaded complete catalog before a low-level write that adds a
  recognizable UI control. `find_library_recipes` is only a compatibility
  fallback for narrowing an unusually large candidate set. If no supported
  recipe exists, fail closed; do not draw a generic rectangle that pretends to
  be a component.

## Write safely

- Use the module and Screen aliases returned by MCP.
- Send the current `expectedRevision` and a stable idempotency key on every
  write. Successful `commit_prototype_batch`, `compile_product_module`, and
  `complete_product_module` responses state `nextExpectedRevision` — send
  exactly that value on the next write instead of deriving it. On a revision
  conflict, reread context and rebase only the intended change.
- Keep a Screen inside its viewport; preserve container padding, repeated-row
  alignment, label/control alignment, and at most one primary action per region.
- Reuse existing semantic IDs for edits. Do not delete or rebuild unaffected
  modules merely because one requirement changed.
- Never mark work complete from narration or node counts. Call
  `complete_product_module`; completion is valid only when Brifdo returns real
  acceptance evidence for every required capability, field, state, action, and
  interaction.

## What the completion gate accepts as evidence

The gate judges the real business UI on each Screen. Do not draw separate
placeholder "acceptance" cards (状态卡, "可用/相关信息") next to the UI that
already covers a requirement — they are not needed and they hurt the page.

- A requirement is satisfied by a published Library root on the same Screen
  whose component family matches and whose text — its own, its child nodes
  (a CardTitle slot, a label), a sibling heading named `<root>.heading` or
  `<root>.title` drawn above it, or its structured `props` (card title, table
  column labels and cells, chart caption and series labels, field labels) —
  contains the requirement's `label` or `evidenceText`. Matching is by
  component family, not exact recipe: any Button variant proves a `button`
  action; a Field carrying `control: "input"` proves an `input` field. A
  heading that merely sits near a root is not that root's heading: bind it by
  id.
- A chart card is a card. A `card` requirement such as "销售趋势" is proven by
  a chart root captioned "销售趋势"; do not add an empty Card beside it. The
  compiler binds the requirement to your chart the same way.
- A form Card's submit Button may sit inside the Card (`parentId` = the Card)
  or beside it — a footer row under the Card, an action bar above it — when it
  is explicitly bound to the Card by naming it `<card semanticId>.submit`. Any
  other Button on the Screen is never assumed to be that form's action.
- Interaction checks are not relaxed: an acceptance interaction still needs a
  `presentation: "hotspot"` connection from the verified action Button to the
  target Screen, and the gate never renames or rebinds a control to make a
  requirement pass.

When the gate refuses, `incompleteReason` is the readable list and
`missingItems` is the same list with a `category` per item. All three
categories block completion; they differ in what you do next:

- `business-ui-missing` — nothing on the Screen plausibly is this item. Draw
  the UI, or revise the requirement if the plan's component is wrong (the
  message names a root that carries the wording on a different component).
- `evidence-only-missing` — a root of the right component family with similar
  wording exists; `candidateSemanticId` names it. Make that root's title or
  text carry the requirement `label`. No new UI.
- `interaction-missing` — the UI exists; add the hotspot, bind the form's
  Button, or link the page (see below).

`missingSummary` counts the items per category. The same verdict is available
before you ask: a module-scoped `read_product_build_context` returns
`completionReadiness` (`ready`, `missingItems`, `missingSummary`,
`navigationGaps`) computed from the current canvas.

## Navigation inside a module is your job

The plan says which Screens a module has and which acceptance interactions
lead where; it does not say how a user reaches every page. The completion gate
walks the drawn `hotspot` connections from the product's entry page (and from
the module's own first page while the entry belongs to a module not drawn
yet); every drawn page of the module must be reachable that way. Planned
interactions on undrawn pages do not count, and `arrow` connections never
navigate.

- Give every page an inbound hotspot from a page that is itself reachable —
  a row action, a "查看详情" Button, a back link from a detail page, a menu
  entry. Any reachable page of the same module is a valid source; there is no
  need to hang every page off the entry page or to add a navigation bar of
  links to satisfy the gate.
- `read_product_build_context` (module-scoped) and `compile_product_module`
  return `navigationGaps`: each unreachable page with a `suggestedSource`
  (the module's hub page — most hotspots leaving it — or its first page) and a
  `hint`. Fix gaps while drawing; `complete_product_module` reports the same
  gaps as `interaction-missing` items and refuses until they are closed.
- In a compile intent, `actions[].targetScreenId` on the source Screen is the
  simplest way to draw such a hotspot deterministically.

## Error handling

- `compile_product_module`, `create_product_from_plan`, and a whole-batch
  rejection of `commit_prototype_batch` all report layout failures the same
  way: `error.details` is an array of diagnostics (each with `code`,
  `screenId`, the failing widths/heights, and `suggestedFix`) covering every
  failure of that call in one round-trip, not just the first. When the list
  was capped, `error.truncated=true` marks that more remain past `details`;
  fix what is listed and recall the same tool to see the rest. A layout
  failure is never a reason to abandon the compile path and redraw the
  Screen manually.
- `commit_prototype_batch` additionally returns per-operation layout problems
  on its _success_ payload as `rejections[]` (each with `message`/`fix`): the
  rest of that batch still committed, so this is not a call failure — resend
  only the rejected operations after applying `fix`.

## Long-running work

- Treat saved Scene revisions and completion evidence as durable checkpoints.
- On a later session, reread context and continue incomplete modules. Preserve
  completed modules whose requirement and Scene evidence are still current.
- If a completed Screen changes, expect it to become stale and revalidate only
  the affected module.

## Privacy and billing

- Never send cookies, sessions, OAuth tokens, API keys, database/Redis
  addresses, balances, billing data, internal IDs, other products, private
  discussions, or unselected attachments to another model.
- In `user-agent` mode, reasoning tokens belong to the user's Agent. Brifdo
  performs deterministic validation, compilation, persistence, and realtime
  events without calling a Brifdo AI model; Brifdo AI model charge is zero.
- Do not switch execution mode or silently fall back to a platform model. If
  the user-Agent build is not writable, report the returned reason.
- A `user-agent` build that receives no MCP write for 30 minutes is paused by
  Brifdo (`progress.paused.reason` = `external-agent-idle`; the workspace
  shows "外部 Agent 已 N 小时没有写入，构建已暂停"). It is not a failure and
  needs no new call: `read_product_build_context` lists the undrawn Screens in
  `progress.paused.undrawnScreens`, and the next `commit_prototype_batch`,
  `compile_product_module`, or `complete_product_module` resumes the build
  automatically. Keep writing at least every few minutes while a Module is in
  progress, and read the context first when resuming after a break.
