ensure_variable
Create or reuse a Figma variable idempotently by specifying collection, name, type, and mode values. Handles duplicates and ensures mode coverage.
Instructions
Idempotent variable creation — populates values_by_mode in one shot.
Prefer this over create_variable — re-running with the same args returns the existing variable instead of creating a duplicate.
Behavior (spec §3.1):
Exactly 1 variable with (collection_id, name, type) in target collection → idempotent reuse.
0 in target, matches in OTHER collections → create new in target + warning NAME_EXISTS_OUTSIDE_TARGET_COLLECTION.
0 anywhere → create new.
2+ in target collection (Figma allows duplicates) → fail SAME_COLLECTION_NAME_DUPLICATE.
values_by_mode keys can be either mode NAMES (e.g. "Light") or modeIds (e.g. "1:0"). Each value must match the variable type (hex/RGBA for COLOR, number for FLOAT, string for STRING, boolean for BOOLEAN).
Omit idempotency_key — the handler computes it canonically from (collection_id, name, type, values_by_mode). Pass it only if you need strict concurrency-safety validation (LLMs should not try to compute SHA-256 inline; placeholder strings are rejected).
Mode coverage policy (spec §6.2):
mode_coverage_required: 'all' (default) — every mode in the collection must have an explicit value. set_fill / bind_variable will REJECT bindings that fall through to a missing mode (MISSING_MODE_VALUES).
mode_coverage_required: 'opt-in-fallback' — fallback to default mode is intended. Bindings emit FALLBACK_BINDING warning instead of failing. Caller MUST provide fallback_reason containing the structured phrase "fallback to <mode_name>" (machine-greppable).
Returns {data: {variable_id, name, type, collection_id, mode_coverage[], mode_coverage_required, reused?: true}, warnings?: [...]}.
Examples: ensure_variable({collection_id: "VariableCollectionId:1:2", name: "Text/Primary", type: "COLOR", values_by_mode: {Light: "#111", Dark: "#EEE"}}) ensure_variable({collection_id: "VariableCollectionId:1:2", name: "Spacing/desktop", type: "FLOAT", values_by_mode: {Desktop: 24}, mode_coverage_required: "opt-in-fallback", fallback_reason: "Desktop-only metric; fallback to Desktop in Mobile mode."})
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| collection_id | Yes | Target VariableCollectionId — strict ID, no name lookup. | |
| name | Yes | Variable name (slashes denote hierarchy). | |
| type | Yes | Variable type | |
| values_by_mode | Yes | Map of mode name OR modeId → value. Hex strings allowed for COLOR. | |
| idempotency_key | No | Optional. Handler auto-computes canonically if omitted. Pass only if you need strict concurrency-safety validation against the SHA-256 formula in spec §3.1. | |
| mode_coverage_required | No | Mode coverage policy — "all" (default; every mode must have explicit value) or "opt-in-fallback" (allow fallback, requires fallback_reason). | |
| fallback_reason | No | REQUIRED iff mode_coverage_required="opt-in-fallback". Must contain the structured phrase "fallback to <mode_name>". Persisted on the variable for audit trail. |