All skills
figma avatar

/figma-use

@1729207 official
by figmafigma/mcp-server-guide2k stars
194

**MANDATORY prerequisite** — you MUST invoke this skill BEFORE every `use_figma` tool call. NEVER call `use_figma` directly without loading this skill first. Skipping it causes common, hard-to-debug failures. Trigger whenever the user wants to perform a write action or a unique read action that requires JavaScript execution in the Figma file context — e.g. create/edit/delete nodes, set up variables or tokens, build components and variants, modify auto-layout or fills, bind variables to properties, or inspect file structure programmatically.

Use this Skill: https://skilld.dev/gh/figma/mcp-server-guide/figma-use

This session only. Nothing lands on disk.

SKILL.md

use_figma — Figma Plugin API Skill

Execute JavaScript in Figma files via the Plugin API. Always pass skillNames: "figma-use" when calling use_figma (logging parameter, doesn't affect execution).

If the task involves building or updating a full page, screen, or multi-section layout in Figma from code, also load figma-generate-design. It provides the workflow for discovering design system components via search_design_system, importing them, and assembling screens incrementally. Both skills work together: this one for the API rules, that one for the screen-building workflow.

If the task involves creating or building a component in Figma (even a single component), also load figma-generate-library. It owns the component-creation workflow — variable foundations first, variant sets, then design token bindings — that figma-use alone doesn't cover. Build the token/variable foundation before the component, then bind the component's fills/cornerRadius/spacing to those variables rather than inlining literals where a token exists.

IMPORTANT: Whenever you work with design systems, start with working-with-design-systems/wwds.md to understand the key concepts, processes, and guidelines for working with design systems in Figma. Then load the more specific references for components, variables, text styles, and effect styles as needed.

$fig — the plan-based builder API (ALL NODE CREATION MUST USE THIS)

$fig is a global that is responsible for all node creation. It auto-flushes at script end (no $fig.done() needed), handles font preloading, batches mutations, and orders property assignment correctly. Use it for all node creation and mutation operations. Never use figma.createFrame(), figma.createText() or any figma.create* methods. They do not exist in this environment.

Constructors queue creation, not inert templates. Every $fig node constructor like $fig.frame(...) queues a node creation in the plan, even if its returned plan node is never used, returned, or screenshotted. Unattached nodes become top-level nodes at flush. Plan nodes meant to be used as children should be appended or used in $fig.frame(opts, children) before flushing.

layoutSizingHorizontal/Vertical = 'FILL' is for auto-layout children only. Do not set FILL for top-level nodes.

Plan nodes vs real nodes

$fig.component(...), $fig.variants(...), $fig.instance(...), $fig.get(...), and $fig.frame(...) return plan nodes, not raw Plugin API nodes. await $fig.done() materializes the plan nodes and makes planNode.node available for accessing real nodes. Do not use plan nodes like real nodes.

  • Use planNode.set({ name, x, y }) and planNode.append(childPlanNode) for queued mutations. Do not make direct assignments like planNode.x = 100. Do not mix plan nodes into raw plugin APIs like node.appendChild(planNode).
  • Prefer $fig.instance(componentPlanNode, opts) or planNode.instance(componentPlanNode, opts) to create instances of plan component nodes, with no intermediate flush.
  • Use planNode.node only when you need raw state or an operation $fig or plan nodes do not expose. Flush pending changes first. Do not mix raw plugin code amongst pending changes.

Copy these patterns

Build an auto-layout frame with children — single call:

$fig.autoLayout(
  // fixed width; omit height to hug vertically
  { name: 'Todo List', layoutMode: 'VERTICAL', width: 480 },
  ['item 1', 'item 2', 'item 3'].map((item) =>
    $fig.autoLayout(
      // FILL is valid because this item is attached to the auto-layout Todo List
      { name: 'Todo Item', layoutSizingHorizontal: 'FILL' },
      [$fig.text({ characters: item, fontName: { family: 'Inter', style: 'Bold' } })],
    ),
  ),
).screenshot() // Screenshot new node trees to verify. Prefer `.screenshot()` over `get_screenshot` call after `use_figma`.

N parallel items for repeated small UI elements like swatches, list items, etc.:

const ITEMS = [
  { name: 'A', bg: '#ffffff', accent: '#0969da' },
  { name: 'B', bg: '#fff8f1', accent: '#bf5af2' },
  // ...add more here
]
ITEMS.forEach((v, i) => $fig.autoLayout({ name: v.name, x: i * 410, width: 390, fills: [figma.util.solidPaint(v.bg)] }, [
  $fig.text({ characters: v.name, fills: [figma.util.solidPaint(v.accent)] }),
]))

Update existing nodes — by query or by id:

$fig.query('FRAME[name=Header] TEXT[name=Title]').set({ characters: 'New Title', fontSize: 24 })
$fig.get('1:42').set({ opacity: 0.8, cornerRadius: 12 })

Add a node inside an existing node

$fig.get('1:42').append($fig.autoLayout({ name: 'New Frame' }))

parent.append(a, b, c) and $fig.append(parent, a, b, c) append every child in order and return the parent for chaining.

Create variants and place an instance

const SIZES = ['Small', 'Medium', 'Large']
const buttonComponentSet = $fig.variants({ name: 'Button' }, SIZES.map((size) => $fig.component({ name: `Size=${size}`, layoutMode: 'HORIZONTAL', /** other props */ })))
const buttonInst = $fig.instance(buttonComponentSet, { props: { Size: 'Medium' } })
$fig.get('DESTINATION_FRAME_ID').append(buttonInst)
// Creation and placement are queued; no intermediate done() is needed.

Select variants through props on the component set. This also works with published sets when individual variant references are unavailable. If an earlier measurement required await $fig.done(), continue using plan node .set(...) and .append(...) for changes and placement.

⚠️ $fig.variants does not position the variants — they stack at (0,0) and the set renders as one collapsed, overlapping element. You must grid the variants and resize the set afterward. See fig-builder.md for the required follow-up recipe.

Building a component — even a single one? Binding tokenized values is part of finishing the job, not a preference. A component is not complete while any value that has a corresponding design token — one that already exists in the file, or that you created from the source — is still a hardcoded literal. When a token exists for a fills color / cornerRadius / padding / itemSpacing, bind it: build a $fig.varCollection (primitive tier + semantic tier aliased to it) and pass the variable handle straight into the property. Anti-pattern to avoid: do NOT copy resolved token values into local JS constants (e.g. const VARIANTS = [{ bg: '#2c2c2c' }]) and paint with resolved literal colors — that silently bypasses variables even though the source defines tokens. This applies to a single component as much as a full design system. Only bind values that actually have a token — values with genuinely no token (one-off geometry, icon pixel sizes, static 1px dividers) correctly stay literal; don't invent tokens to bind. If you create the variables in one use_figma call and build the component in a later one, rehydrate the handles first ($fig.getVar(id) or figma.variables.getVariableByIdAsync using the IDs you returned) — a handle from a previous call isn't in scope. Worked recipe: fig-builder.md → Building a component with bound variables.

Create an instance of a component

// First arg can be a component plan wrapper, a node ID ('1:2'), OR a library asset key
// from `search_design_system` results (the `componentKey` or `componentSetKey` field, according to `assetType`).
$fig.instance('1:2', { name: 'Cancel Btn', props: { label: 'Cancel'}})

Consume styles/variables

$fig.autoLayout({ name: 'Card', itemSpacing: spacingVar, fills: fillStyle })

// Looked up by asset key from `search_design_system` (the `key` field)
$fig.autoLayout({ fills: $fig.getStyle(BG_STYLE_KEY) })
$fig.rectangle({ fills: [{ type: 'SOLID', color: $fig.getVar(BRAND_VAR_KEY) }] })

Use design-system assets by key (from search_design_system)

search_design_system returns componentKey for components, componentSetKey for component sets, and key for styles and variables. Pass these straight into the unified $fig lookup — the plan queues the library import automatically, so you don't need a separate await figma.importComponentByKeyAsync(...) / importStyleByKeyAsync(...) / importVariableByKeyAsync(...) step.

// One call site, many input shapes — node IDs, real variable/style ids,
// AND 40-char asset keys (e.g. '49c8754d4b898e176148650df612a47998a8c4a1')
const btn        = $fig.get(BUTTON_KEY)                    // component / component set
const instance   = $fig.instance(BUTTON_SET_KEY, {         // create an instance from a set
  props: { Size: 'md', Variant: 'primary' },
})
const heading    = $fig.getStyle(HEADING_TEXT_STYLE_KEY)   // paint / text / effect / grid style
const brand      = $fig.getVar(BRAND_COLOR_VAR_KEY)        // variable

$fig.text({ characters: 'Hello', textStyle: heading })
$fig.rectangle({ fills: [{ type: 'SOLID', color: brand }] })

Discover a set's variant props from its key — search_design_system returns a set's componentSetKey, not its variant properties. This is two use_figma calls: call 1 returns the set's property definitions and its variants so their props come back to you in the tool result; then, knowing the valid props, call 2 instantiates the variant you want.

const setHandle = $fig.get(BUTTON_SET_KEY)
await $fig.done()
const set = setHandle.node
if (!set || set.type !== 'COMPONENT_SET') {
  throw new Error(`Key ${BUTTON_SET_KEY} is not a COMPONENT_SET`)
}
return {
  componentPropertyDefinitions: set.componentPropertyDefinitions,
  variants: set.children
    .filter((c) => c.type === 'COMPONENT')
    .map((c) => ({ name: c.name, variantProperties: c.variantProperties })),
}
// Call 2 — instantiate with props you picked from call 1's output
$fig.instance(BUTTON_SET_KEY, { props: { Size: 'Large', Kind: 'Secondary' } })

Bulk component swap — $fig.query().set():

const chevron = $fig.get('CHEVRON_KEY')
$fig.query('INSTANCE[name=arrow_drop_down]').set({ mainComponent: chevron })

.query() and .values() for search and projecting child values

const menuArrows = $fig
  .query('PAGE[name=Menu] INSTANCE[mainComponent.name*=arrow], PAGE[name=Menu] INSTANCE[mainComponent.name*=chevron]')
  .values(['id', 'name', 'mainComponent.name', 'mainComponent.id']);

// Use quotes for multi-word selector values
const expandComponents = $fig
  .query('COMPONENT[name*=expand], COMPONENT[name*=chevron_down], COMPONENT[name*=chevron_up], COMPONENT[name*="multi word name"]')
  .values(['id', 'name']);

Perform operations on another page:

// Switch to a specific page (loads its content)
const targetPage = figma.root.children.find((p) => p.name === "My Page");
await figma.setCurrentPageAsync(targetPage);
$fig.query('INSTANCE[name=arrow_drop_down]').set({ ... })

Gradient via helper — no manual transform matrix needed:

const node = $fig.rectangle({ width: 240, height: 120 })
$fig.gradient(node, 'LINEAR', [
  { pos: 0, color: figma.util.rgba('#000000') },
  { pos: 1, color: figma.util.rgba('#ffffff') },
])

Literal colors — use the built-in utilities, available in every call:

$fig.rectangle({ fills: [figma.util.solidPaint('#2563eb80')] }) // alpha becomes paint opacity
const rgb = figma.util.rgb('#2563eb') // { r, g, b }; ignores input alpha
const rgba = figma.util.rgba('#2563eb80') // { r, g, b, a }; for gradient stops/effects

Use these utilities directly instead of defining a hex parser or relying on helpers from a previous use_figma call. For token-backed properties, keep passing the variable handle directly; converting its resolved color to a paint would lose the binding.

Chaining on plan nodes — alternative to children array:

const card = $fig.autoLayout({ name: 'Card', layoutMode: 'VERTICAL' })
card.text({ characters: 'Title', fontSize: 20 })
card.text({ characters: 'Description', fontSize: 14 })

$fig create + mutate API (full surface)

  • Create: $fig.autoLayout / .frame / .text / .rectangle / .ellipse / .polygon / .star / .line / .vector / .section / .component / .page — all (opts?, children?). Plan nodes are chainable.
  • Create from SVG — the preferred ICON path: $fig.svg(svgStr, opts?) builds a vector node tree from an SVG string. Prefer real vector icons: import the icon's SVG source (inline <svg>, the .svg asset, or the source icon-library glyph — e.g. lucide/heroicons) via $fig.svg(...) rather than approximating an icon with a typed emoji/Unicode glyph (★ ⚙ 🔍 ☰ ▾) or a plain rectangle. A simple glyph or shape is a fine fallback when the real SVG genuinely can't be obtained — just reach for the SVG first. (Don't reconstruct an icon from rotated line/rect primitives, though — that renders broken.) Full recipe (viewBox+width/height sizing, currentColor, INSTANCE_SWAP for design-system icons): figma-generate-design → Icons.
  • Create an instance of a component: $fig.instance(compRef, opts?) — compRef is a component plan node, a node ID string, OR a library asset key (componentKey or componentSetKey from search_design_system); the import is queued in the plan automatically.
  • Grouping/boolean: $fig.group / .union / .subtract / .intersect / .exclude / .variants — all (opts?, children?).
  • Read: $fig.get(id) wraps an existing SceneNode — id can be a real node ID OR a library asset key (componentKey or componentSetKey from search_design_system); the import is queued in the plan automatically. $fig.query(selector, scope?) returns { length, values(paths), first(), last(), each(fn), filter(fn), set(props), moveTo(parent, idx?), remove() }. Selectors are CSS-like (e.g. 'FRAME[name*=Card] TEXT'). $fig.getStyle(nameOrIdOrKey) and $fig.getVar(nameOrIdOrKey) accept the matching key values from search_design_system.
  • Mutate: $fig.set(target, props), .delete(...nodes), .move(target, parent, idx?), .clone(target, props?), .append(parent, child), .addAt(parent, idx, child), .replace(old, new), .reorder(parent, children), .gradient(node, type, stops, transform?), .image(node, hash, scaleMode?).
  • Plan-node methods (chainable): .set(), .remove(), .clone(), .moveTo(parent, idx?), .append(child), .query(selector), .screenshot({scale?, contentsOnly?}), and the .node getter for the materialized SceneNode (null pre-flush).

When to use the raw Figma Plugin API

Keep raw Plugin API code that reads or changes document state separate from planned creation and mutations. Run it before $fig code, or after an explicit await $fig.done() that flushes all pending changes. Do not pass plan nodes to raw methods such as regularNode.appendChild(planNode) or insertChild; use $fig.get(regularNode.id).append(planNode) or .addAt(index, planNode) instead. Planned changes are not visible to raw reads such as regularNode.children until the plan is flushed. After flushing, use planNode.node when a raw API needs the real node. Pure color helpers such as figma.util.solidPaint, .rgb, and .rgba can be used inside $fig expressions.

Use the raw API only in these cases:

  • Color conversion: figma.util.solidPaint, .rgb, and .rgba convert literal colors for $fig properties without creating or mutating nodes.
  • Mid-script async result needed: await figma.setCurrentPageAsync(...), await figma.loadFontAsync(...) — must complete before subsequent plan steps can use the result. (Importing library components is NOT one of these cases: pass the matching componentKey or componentSetKey straight into $fig.get(...) / $fig.instance(...) and pass variant property values in props. $fig queues the library import in the plan and resolves the variant for you.)
  • Mid-script real node state read: measured width / height after auto-layout, computed colors, getStyledTextSegments — materialize mid-script, then read .node on the plan node. See references/fig-builder.md for the mid-script inspection pattern.
  • Things $fig genuinely doesn't expose: node.setRangeFontName(...), etc. — access via planNode.node (see references/fig-builder.md).

Critical Rules

  1. Only use $fig for creating / bulk-editing nodes ($fig.autoLayout(...), $fig.text(...), $fig.query(...).set(...)). Raw Plugin API is the fallback — use it only when $fig can't express the operation (intermediate node-state reads, non-SceneNode types like Variables). Library components are NOT a reason to leave $fig: $fig.get(componentKey) / $fig.instance(componentSetKey, { props }) queue the library import and resolve the variant for you. See references/fig-builder.md and references/critical-rules-deep.md for worked WRONG/RIGHT examples.

  2. Do not use findOne, findAll, findAllWithCriteria, findChildren, findChild directly for node searching They are more verbose, error-prone, and less efficient than query(). Additionally, do not use recursion to search.

  3. Avoid return / $fig.done() if only using $fig — runtime auto-flushes and returns a FigDoneResult with created/updated node IDs. Use return if you need raw plugin API mid-script or other data.

  4. Build up larger designs incrementally by section. Refer to the figma-generate-design skill for the placeholder + replace workflow. Create screens with placeholders inside using the complete parent-and-child example below, then make subsequent use_figma calls to replace them and screenshot: $fig.get("PLACEHOLDER_ID_FROM_PREVIOUS_STEP").replace( ... ).screenshot(). You can make up to 5 .screenshot() calls per tool call. If you need to make more screenshots, you are doing too much work and need to break down the task into multiple use_figma calls.

    $fig.autoLayout({ name: 'Screen', layoutMode: 'VERTICAL', width: 390 }, [
      $fig.autoLayout({ name: 'Header', layoutSizingHorizontal: 'FILL', placeholder: true }),
      $fig.autoLayout({ name: 'Content', layoutSizingHorizontal: 'FILL', placeholder: true }),
    ])
  5. Plain JS with top-level await. Code is auto-wrapped in async. Do NOT wrap in (async () => {})().

  6. Use built-in utilities for literal colors. figma.util.solidPaint('#2563eb80') creates a complete solid paint with opacity. For individual color fields, use figma.util.rgb(...) for {r,g,b} (solid paints; ignores alpha) and figma.util.rgba(...) for {r,g,b,a} (gradient stops/effects). Channels are 0–1; solid-paint opacity belongs outside color. The utilities are available in every call — no custom hex parser needed. Token-backed properties still take variable handles directly. See references/critical-rules-deep.md for WRONG/RIGHT.

  7. No curl / wget / Read of Figma URLs from Bash. Figma file access ONLY via use_figma and mcp__figma__* tools. After get_screenshot, the image is inlined in the tool result — do NOT re-fetch or re-Read it.

  8. Empty / unsupported responses are terminal. Accept and move on — don't try alternative bypass paths.

  9. Verify node-type before touching a property. Only FRAME / COMPONENT / COMPONENT_SET / INSTANCE / GROUP / SECTION / PAGE have .children. GROUP has no fills / strokes / cornerRadius. TEXT has no cornerRadius / padding* / layoutMode. layoutPositioning='ABSOLUTE' needs parent with layoutMode !== 'NONE'. Check '<prop>' in node or grep references/plugin-api-standalone.d.ts. Full list in references/critical-rules-deep.md.

  10. Don't re-query the same info. get_metadata / get_comments on the same target twice yields the same result. Cache mentally.

  11. Be decisive once you have enough info. Don't keep gathering — the marginal information from a 3rd screenshot or 4th metadata call is near-zero.

  12. "An unexpected error occurred" from use_figma is server-side, not your script bug. Don't retry unchanged — change approach (smaller batch, different selector, drop one node-prop).

  13. NEVER call mcp__figma__get_design_context. FORBIDDEN. This tool requires a selection (no selection exists in this environment), so every call will fail. The error is not recoverable — calling it just burns a tool slot and forces a retry. For structured reads of the file, use mcp__figma__get_metadata (for top-level frame discovery) and use_figma with $fig.query() instead. Never call get_design_context for any reason.

  14. ≤3 codebase Read calls when the task references source code. Beyond that, grep only. The 4th codebase Read is forbidden — write your use_figma script with what you have.

  15. 3 retries of the same error → switch approach. Most often: switch to $fig (which handles ordering automatically). Patching the raw API isn't working.

  16. Must use auto-layout unless you have a compelling reason not to. Create auto-layout frames with $fig.autoLayout(...) instead of absolutely-positioning nodes. New auto-layout frames are created with both axes hugging content. Explicitly assign layoutSizingHorizontal or layoutSizingVertical to 'FILL' for auto-layout children if you want them to fill the auto-layout container's counter axis.

  17. Gradient paints need ALL fields: type, gradientStops, gradientTransform (a [[a,b,tx],[c,d,ty]] matrix). Missing any throws validation error. See references/critical-rules-deep.md.

  18. Discover available fonts, esp. for style variations. Use await figma.listAvailableFontsAsync() to discover available fonts for $fig.text({ fontName: ... }).

  19. Set variable scopes explicitly when creating variables. The default ALL_SCOPES pollutes every property picker. Use specific scopes — ['FRAME_FILL', 'SHAPE_FILL'] for backgrounds, ['TEXT_FILL'] for text, ['GAP'] for spacing, ['CORNER_RADIUS'] for radii; primitives that shouldn't appear in pickers get []. In $fig, pass scopes to colorVar / numVar; in the raw API, set variable.scopes. See references/variable-patterns.md.

Bulk mutation of existing nodes (swap/update/replace) is COMPLETE in 3 use_figma calls

For tasks like "swap N icons", "update M colors", "replace K instances":

  1. DISCOVER + MUTATE in one script (find via figma.currentPage.query(), import any components, mutate via $fig.query(...).each(...), return count).
  2. VERIFY (optional) — read-only .query() count.
  3. FINAL REPORT in assistant text, no tool call. STOP.

NO 4th call. NO chasing the last 20% of edge cases. If Call 1 errors, fix and redo — that's still your one mutation call. Full template in references/critical-rules-deep.md.

Node property gotchas

Do not guess node properties or assume CSS-like properties. Accessing non-existent properties will throw TypeError: node.foo: no such property 'foo' on TYPE node. Each throw burns a retry. plugin-api-standalone.index.md contains the list of all symbols in the API. Use that file and grep the full API typings in plugin-api-standalone.d.ts for the full definitions.

  • Only FRAME / COMPONENT / COMPONENT_SET / INSTANCE / GROUP / SECTION / PAGE have .children. RECTANGLE, TEXT, ELLIPSE, POLYGON, STAR, VECTOR, LINE, SLICE, STICKY, SHAPE_WITH_TEXT, STAMP, CONNECTOR, TABLE, WIDGET, EMBED, MEDIA do NOT. Check 'children' in node before accessing a node's children.
  • GROUP has NO fills / strokes / cornerRadius. Apply paints/radii on the child shapes inside.
  • Figma auto-layout != CSS flexbox. There is no such thing as margin.
  • TEXT DOES NOT HAVE container properties. Text has font / size / decoration / fills. Do not use container properties like padding, layout mode, item spacing, etc.
  • INSTANCE descendants are read-only for structural ops — you cannot appendChild / insertChild into an instance child. Edit the source COMPONENT or detach first.
  • **Never use primaryAxisSizingMode or counterAxisSizingMode on a node. ** Use layoutSizingHorizontal or layoutSizingVertical with 'FIXED' | 'HUG' | 'FILL'. Use 'FILL' only when the parent has auto-layout.
  • There is NO instance.swapMainComponent(...). Use instance.setProperties({...}) with the component-property variant value, OR $fig.query(...).set({props: {...}}). There IS instance.swapComponent(component) (different method name).

References

Source: SKILL.md on GitHub

No alerts8d4 checks · Risk SAFE
  • Gen Agent Trust Hub8d

    The skill provides comprehensive instructions and reference material for interacting with the Figma Plugin API. No security issues were detected.

  • Socket8d

    No alerts

  • Snyk8d

    Risk: LOW · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 1729207. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 2 weeks ago
disable-model-invocation
false
  • figma
  • plugin-api
  • design-systems
  • javascript
  • components
  • variables
  • auto-layout
  • tokens

README badge

README badge for figma/mcp-server-guide/figma-use

Loads prerequisites for the `use_figma` tool, which executes JavaScript in Figma files via the Plugin API. This skill teaches critical rules for font loading, text editing, auto-layout, pagination, async operations, and incremental work patterns that prevent hard-to-debug failures. Install this before any Figma programmatic task—creating or editing nodes, binding variables, building components, or inspecting file structure.

Generated from the current SKILL.md.

Do I need to load this skill before calling use_figma?
Yes. This skill is a mandatory prerequisite. You must load figma-use before every use_figma tool call and include it in the skillNames parameter, or the call will fail with hard-to-debug errors.
What kind of operations does this skill cover?
Write actions and unique read actions that require JavaScript execution in Figma files: creating/editing/deleting nodes, setting up variables and tokens, building components and variants, modifying auto-layout or fills, binding variables to properties, and inspecting file structure programmatically.
Can I use console.log() to debug my code?
No. console.log() output is not returned. Use return statements to send data back instead — return values are automatically JSON-serialized.
How do I switch to a different page in Figma?
Use await figma.setCurrentPageAsync(page) to switch pages and load their content. The synchronous setter figma.currentPage = page does not work and will throw an error.
What should I do if a use_figma call fails?
Stop and do not retry immediately. Failed scripts are atomic — no changes are made to the file. Read the error message carefully, fix the script, and retry.

Generated from the current SKILL.md. These answers refresh after source changes.