UX DiffusionNOTES FROM THE LAB
← all resources

002 / prompts ·

Figma Agent Library-Safe Prompts + Audit

Six tested agent prompts for form states, each with the instance audit that catches detached layers.

Before you run anything

Set this up first. Each prompt below assumes it's in place.

RequirementWhat to check
Seat and planFull seat on Professional, Organization or Enterprise. Collab and Dev seats get the agent in drafts only. Starter, Education and Government plans don't have it. (Figma blog)
CreditsStarting October 6, 2026 the agent uses AI credits from the same pool as Figma Make. Figma says usage "will vary based on the complexity of your prompt, the actions the agent takes to complete it, and any context you provide." (AI credit updates FAQ)
LibraryThe library with your form components is enabled in the file (Assets panel → Libraries). Write down the exact component names. You'll paste them into the prompts.
A safe copyDuplicate the frame before each run so you can compare before and after.
Credit logHave an admin note the reading under Admin → AI credits → View usage before and after each run (FAQ). Use the log at the bottom of this page.

Why name components: Figma says the agent uses your "most frequently and recently used components as a starting point" and lets you @mention components, tokens and variables (Figma blog). A starting point is not a guarantee. Name the components with @mentions and you have a list to audit against.

All six prompts are also in prompts.txt. The audit is in instance-audit-checklist.md.


The rule each prompt follows

  1. Use only components that already exist. List them by @mention.
  2. Ban new primitives. No new rectangles, text or frames that copy a component's look.
  3. Ask for a gap report. If a part is missing, the agent should say so and not draw it.
  4. Audit before trusting. Run the instance audit (below) after every prompt.

Prompt 1: Error state (the task from the reel)

Select frame: [FRAME_NAME]

Add an error state to this form. Use ONLY these library components:
- Field: @[INPUT_COMPONENT] with its error variant ([ERROR_VARIANT_PROPERTY]=[ERROR_VALUE])
- Message: @[HELPER_TEXT_COMPONENT] set to its error style
- Optional banner: @[INLINE_ALERT_COMPONENT]

Error to show: [FIELD_LABEL] is invalid. Message text: "[ERROR_MESSAGE]".

Constraints:
- Swap variants on the existing instances. Do not detach any instance.
- Do not create new rectangles, text layers, icons or frames to imitate a component.
- Use colors only from the variable [ERROR_COLOR_VARIABLE]. No hex values.
- Put the result in a new frame named "[FRAME_NAME] / Error".

When finished, reply with:
1. A list of every layer you changed or added, and the component each one is an instance of.
2. Anything you couldn't build from the listed components, marked "MISSING".

Example inputs: [FRAME_NAME] = Sign-up / Default · [INPUT_COMPONENT] = Text Field · [ERROR_VARIANT_PROPERTY]=[ERROR_VALUE] = State=Error · [HELPER_TEXT_COMPONENT] = Helper Text · [INLINE_ALERT_COMPONENT] = Inline Alert · [FIELD_LABEL] = Email · [ERROR_MESSAGE] = Enter a valid email address · [ERROR_COLOR_VARIABLE] = color/text/danger

Example of a useful reply (illustrative, not a recorded result):

Changed: "Email" → Text Field, State=Error
Changed: "Email helper" → Helper Text, Style=Error, text "Enter a valid email address"
Added: none
MISSING: none

Is it useful? Pass only if the reply lists every edit and the audit finds 0 detached or new primitive layers.


Prompt 2: Submitting / loading state

Select frame: [FRAME_NAME]

Create the submitting state of this form in a new frame named "[FRAME_NAME] / Submitting".
Use ONLY:
- @[BUTTON_COMPONENT] with [LOADING_VARIANT_PROPERTY]=[LOADING_VALUE]
- @[INPUT_COMPONENT] with [DISABLED_VARIANT_PROPERTY]=[DISABLED_VALUE] for every field

Constraints:
- If the button has no loading variant, do not draw a spinner. Report "MISSING: button loading variant".
- Do not detach instances or add new shapes, icons or text layers.
- Keep the field values from the original frame.

Reply with: the layer → component list, then any MISSING items.

Example inputs: [BUTTON_COMPONENT] = Button · [LOADING_VARIANT_PROPERTY]=[LOADING_VALUE] = State=Loading · [DISABLED_VARIANT_PROPERTY]=[DISABLED_VALUE] = State=Disabled

Is it useful? Watch for a spinner. A spinner that isn't an instance means the agent drew one. That's the most likely failure here.


Prompt 3: Success state

Select frame: [FRAME_NAME]

Create the success state after submission in a new frame named "[FRAME_NAME] / Success".
Use ONLY:
- @[INLINE_ALERT_COMPONENT] with [SUCCESS_VARIANT_PROPERTY]=[SUCCESS_VALUE]
- @[BUTTON_COMPONENT] for the next action, label "[NEXT_ACTION_LABEL]"
- Existing heading style: [HEADING_TEXT_STYLE]

Message: "[SUCCESS_MESSAGE]"

Constraints:
- Any icon must be an instance of @[ICON_COMPONENT]. No new vectors.
- Text layers are allowed only for the heading, and they must use [HEADING_TEXT_STYLE].
- No detached instances.

Reply with: the layer → component/style list, then any MISSING items.

Example inputs: [SUCCESS_VARIANT_PROPERTY]=[SUCCESS_VALUE] = Type=Success · [NEXT_ACTION_LABEL] = Go to dashboard · [HEADING_TEXT_STYLE] = Heading/M · [SUCCESS_MESSAGE] = Check your inbox to confirm your email · [ICON_COMPONENT] = Icon/Check

Is it useful? Every text layer has a text style applied (the right sidebar shows a style name, not raw font settings).


Prompt 4: Disabled state

Select frame: [FRAME_NAME]

Create a disabled version of this form in "[FRAME_NAME] / Disabled".
Switch every @[INPUT_COMPONENT], @[CHECKBOX_COMPONENT] and @[BUTTON_COMPONENT] instance
to [DISABLED_VARIANT_PROPERTY]=[DISABLED_VALUE].

Constraints:
- Only change variant properties. Don't change opacity, fills or strokes by hand.
- If a component has no disabled variant, leave it unchanged and report it as MISSING.

Reply with: each instance and the variant it now uses, then any MISSING items.

Example inputs: [CHECKBOX_COMPONENT] = Checkbox · [DISABLED_VARIANT_PROPERTY]=[DISABLED_VALUE] = State=Disabled

Is it useful? Select a few changed instances. Instance overrides should show variant changes only. A manual opacity override counts as a fail: it looks right on the canvas and breaks in code.


Prompt 5: Inline validation on focus

Select frame: [FRAME_NAME]

Show [FIELD_LABEL] focused and failing a live rule, in "[FRAME_NAME] / Inline validation".
Use ONLY:
- @[INPUT_COMPONENT] with [FOCUS_VARIANT_PROPERTY]=[FOCUS_VALUE] and [ERROR_VARIANT_PROPERTY]=[ERROR_VALUE] if that combination exists
- @[HELPER_TEXT_COMPONENT] for the rule text: "[RULE_TEXT]"

Constraints:
- If no variant combines focus and error, say so and pick the closest existing variant. Don't layer extra strokes on top.
- No detached instances, no new shapes.

Reply with: the variant combination you used, whether it exists in the library, then any MISSING items.

Example inputs: [FIELD_LABEL] = Password · [FOCUS_VARIANT_PROPERTY]=[FOCUS_VALUE] = State=Focus · [RULE_TEXT] = At least 12 characters

Is it useful? This prompt checks whether the agent fakes a variant combination by stacking a second stroke. Open the instance and confirm it has no extra child layers.


Prompt 6: Default state with helper and optional labels

Select frame: [FRAME_NAME]

Tidy the default state of this form in "[FRAME_NAME] / Default".
- Add helper text under [FIELD_LIST] using @[HELPER_TEXT_COMPONENT].
- Mark [OPTIONAL_FIELDS] as optional using the field's built-in property [OPTIONAL_PROPERTY], if it exists.
- Spacing between fields: variable [SPACING_VARIABLE].

Constraints:
- Use auto layout with [SPACING_VARIABLE]. No hard-coded gap numbers.
- If [OPTIONAL_PROPERTY] doesn't exist, report MISSING. Don't type "(optional)" into the label by hand.
- No detached instances.

Reply with: the layer → component list, the spacing variable applied, then any MISSING items.

Example inputs: [FIELD_LIST] = Email, Password · [OPTIONAL_FIELDS] = Company · [OPTIONAL_PROPERTY] = Optional=True · [SPACING_VARIABLE] = space/400

Is it useful? Select the auto layout frame. The gap field should show a variable chip, not a raw number.


The instance audit (after every prompt)

Full checkable version: instance-audit-checklist.md.

  1. Compare the agent's reply with the layers. Every layer it says it changed should be in the Layers panel. Any layer it didn't mention is a red flag.
  2. Search by layer type. Press Cmd+F (Mac) / Ctrl+F (Windows) and add layer-type filters, such as frame, text and shape (Figma Help: Find and replace). Inside the new state frame, any frame, shape or text result that isn't part of an instance needs a reason.
  3. Read the icons. In the Layers panel, instances show the instance (diamond) icon. A detached instance turns back into a plain frame and shows the frame icon, often with the original component's name. Same name with a frame icon means it was detached.
  4. Check where each instance comes from. Select an instance. The right sidebar names its main component. Check it's from your library and not a local component the agent made in this file.
  5. Check overrides. Variant swaps are fine. Hand-set fills, opacity or extra strokes inside an instance count as a fail.
  6. Log the result. Record new primitives, detached instances, MISSING items reported vs. found, and credits used.

Decision rule: ship-ready only if detached = 0, unexplained new primitives = 0 and every MISSING item was reported by the agent. If the agent drew something it didn't mention, treat the whole run as unreviewed. Don't polish it.

Most likely failure and how to diagnose it

SymptomLikely causeFix
Looks right, but the audit finds frames named like your componentsThe agent rebuilt the part instead of using the instance, or detached it to editRe-run with the exact @mention and the line "Swap variants only; do not detach"
A spinner, toast or icon that isn't in your libraryThe prompt asked for something the library lacksCheck the library first. If the part is missing, accept the MISSING report or build the component yourself
Local components appear in the Assets panelThe agent made new components in the fileDelete them, then re-run with "Do not create components"
Credit use per run jumps a lotLarge selections or extra attached contextSelect only the target frame. Figma says context and actions taken affect credit use

Credit and result log

Fill in a row only from what you actually measured. Leave cells blank if you didn't check.

DatePrompt #FrameCredits beforeCredits afterDetachedNew primitivesMISSING reported / foundVerdict
[date]1[frame][n][n][n][n][n] / [n][pass/fail]

A blank copy is in instance-audit-checklist.md.


Optional: count instances with a plugin script

If you build your own development plugin, this Plugin API snippet counts layer types inside the selected frame. It uses InstanceNode.getMainComponentAsync() and the remote flag on components (true when the component comes from a library). We haven't run it on your file. Test it on a duplicate first. It only reads layers and changes nothing.

// Select the state frame, then run.
const root = figma.currentPage.selection[0];
const counts = { libraryInstances: 0, localInstances: 0, frames: 0, text: 0, shapes: 0 };
const flagged = [];

async function walk(node, insideInstance) {
  if (node.type === "INSTANCE") {
    const main = await node.getMainComponentAsync();
    if (main && main.remote) counts.libraryInstances++;
    else { counts.localInstances++; flagged.push(`LOCAL instance: ${node.name}`); }
    return; // don't count an instance's own children
  }
  if (!insideInstance && node !== root) {
    if (node.type === "FRAME") { counts.frames++; flagged.push(`Frame: ${node.name}`); }
    if (node.type === "TEXT") { counts.text++; flagged.push(`Text: ${node.name}`); }
    if (["RECTANGLE","ELLIPSE","VECTOR","POLYGON","STAR","LINE"].includes(node.type)) {
      counts.shapes++; flagged.push(`Shape: ${node.name}`);
    }
  }
  if ("children" in node) for (const c of node.children) await walk(c, insideInstance);
}

await walk(root, false);
console.log(counts, flagged);
figma.closePlugin(`Library: ${counts.libraryInstances}, flagged: ${flagged.length}`);

Limits: wrapper auto layout frames show up as "Frame" and need a person to judge them. A library component used through a local wrapper counts as local.

Take it with you

instance-audit-checklist.md ↓ prompts.txt ↓