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.
| Requirement | What to check |
|---|---|
| Seat and plan | Full 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) |
| Credits | Starting 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) |
| Library | The 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 copy | Duplicate the frame before each run so you can compare before and after. |
| Credit log | Have 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
- Use only components that already exist. List them by @mention.
- Ban new primitives. No new rectangles, text or frames that copy a component's look.
- Ask for a gap report. If a part is missing, the agent should say so and not draw it.
- 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: noneIs 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.
- 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.
- 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.
- 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.
- 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.
- Check overrides. Variant swaps are fine. Hand-set fills, opacity or extra strokes inside an instance count as a fail.
- 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
| Symptom | Likely cause | Fix |
|---|---|---|
| Looks right, but the audit finds frames named like your components | The agent rebuilt the part instead of using the instance, or detached it to edit | Re-run with the exact @mention and the line "Swap variants only; do not detach" |
| A spinner, toast or icon that isn't in your library | The prompt asked for something the library lacks | Check the library first. If the part is missing, accept the MISSING report or build the component yourself |
| Local components appear in the Assets panel | The agent made new components in the file | Delete them, then re-run with "Do not create components" |
| Credit use per run jumps a lot | Large selections or extra attached context | Select 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.
| Date | Prompt # | Frame | Credits before | Credits after | Detached | New primitives | MISSING reported / found | Verdict |
|---|---|---|---|---|---|---|---|---|
| [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.