@contracts.design/cli
v0.1.4
Published
Local bridge and packet CLI for Contracts.design.
Maintainers
Readme
Contract CLI
Contract CLI is the local bridge and command-line companion for the Contracts Figma plugin.
It receives deterministic frame-contract/v1 packets from the plugin, prepares
compact implementation handoffs for coding agents, and records where implemented
designs landed in code.
The public V1 CLI does not require an API key. It acts as deterministic local bridge, packet formatter, validator, and implementation report-back store; the coding agent owns the AI execution layer.
Documentation: https://contracts.design/docs/
Support: [email protected]
Install
Development install from this repository:
npm install
npm run build
npm run contract -- --helpPublic npm install:
npm i -g @contracts.design/cli
contract --helpUpdate an existing global install:
npm i -g @contracts.design/cli@latest
contract --versionThe npm package name is @contracts.design/cli. The installed binary is
contract, so users run commands such as contract dev. Install it globally
for normal plugin use and start it from the project root that should receive
.contract/implementation-bindings.json. Project-local installation is
possible, but it is not required just to connect the Figma plugin to the local
bridge. The project root can be a blank folder; no package.json is required
for the bridge to accept the first contract.
Use contract --help to inspect the current command surface. Use
contract --version to print the installed CLI version.
Start The Local Bridge
Keep this process running while using the Figma plugin:
contract devThe bridge listens on http://localhost:38457 by default. The Figma plugin sends
selected design contracts to that local bridge. No extra project data is
required for normal use.
In dev mode, the CLI also writes a project-local helper:
.contract/contractTo add /contract discoverability to a specific coding agent, run:
contract install-agent-commands codex
contract install-agent-commands claude
contract install-agent-commands cursor
contract install-agent-commands copilot
contract install-agent-commands geminiYou can also install one or more helpers while starting the bridge:
contract dev --install-agent-commands codex
contract dev --install-agent-commands copilot
contract dev --install-agent-commands allThe installer writes the project-local .contract/contract helper and then
installs or updates agent-specific workflow helpers:
$CODEX_HOME/skills/contract
~/.codex/skills/contract
.claude/skills/contract/SKILL.md
.cursor/commands/contract.md
.github/prompts/contract.prompt.md
.gemini/commands/contract.tomlCodex uses $CODEX_HOME/skills/contract, or ~/.codex/skills/contract when
CODEX_HOME is not set. Claude Code, Cursor, Copilot, and Gemini helpers are
project-local so blank folders can advertise the same /contract workflow
without package scaffolding. Existing project files are overwritten only when
they contain the generated helper marker. If /contract was already missing
from an agent menu before installing helper files, restart that agent or open a
new chat.
Browser-origin requests to the bridge are accepted only from trusted Figma
origins by default: https://figma.com and https://www.figma.com. CLI and
local script requests without a browser Origin header still work. For local
plugin experiments, set CONTRACT_CLI_BRIDGE_ALLOWED_ORIGINS to a
comma-separated list of additional trusted origins.
The plugin checks bridge capabilities, not only whether the port is reachable.
If the bridge is old enough that /health does not advertise persisted
implementation bindings, the plugin shows Update CLI. Restart after updating
so the plugin can read GET /implementations and recover previous Code
location values.
Run the bridge from the project directory that should own implementation bindings. The bridge persists report-back data in:
.contract/implementation-bindings.jsonIf the bridge is started from another directory, it may not see previous bindings.
Common Agent Commands
After clicking Send contract to CLI in the plugin, paste one of the suggested
slash commands into your coding agent.
Single-design workflows:
/contract implement
/contract update
/contract visual-update
/contract applyMulti-design workflows:
/contract apply all
/contract update all
/contract visual-update allThe visible command should usually stay short. File paths, code sections, UI
area, state, trigger, and behavior travel in the retained contract packet and in
implementation reports sent back with contract implemented. You can still add
an instruction or path when you want to override the packet.
Sending from the plugin also saves a local task focus. When contract dev and
the plugin are connected, /contract slash-command packets ask the plugin to
refresh the latest contract contents for that saved focus before the agent sees
the packet. If refresh is unavailable, the CLI falls back to retained snapshot
evidence and labels the packet source mode. The local refresh waits up to 10
seconds after the plugin acknowledges the request. If no open plugin
acknowledges within 4 seconds, the CLI falls back early. The plugin polls and
retries pending refresh requests about every second before the CLI falls back.
Fallback source modes are honest stale-evidence modes. When you are testing
bidirectional freshness, snapshot-fallback-* means the live refresh did not
work for that run; resend or fix the bridge/plugin connection before treating
the packet as current Figma truth. Use --require-live with --live-frame
when a test should fail instead of producing a retained-snapshot fallback
packet.
Use /contract update when the existing implementation may need its behavior,
state, content, structure, or visuals changed to match the latest contract. Use
/contract visual-update only when the code already works and the task is
presentation-only: layout, spacing, sizing, typography, colors, borders, icons,
and static visible copy. Visual updates should preserve behavior, data flow,
routing, event handlers, API shape, and state semantics.
Implementation reports are persisted locally by default at
.contract/implementation-bindings.json when you run contract dev or
contract bridge. That lets future short commands keep using known file,
section, context, and composite owner values after the bridge restarts.
For /contract visual-update all, agents should first run:
contract frame-batch-prepare --task "/contract visual-update all" --mode visual-updateThat packet includes per-frame implementation bindings, so several frames can share one file while still pointing to different code sections. Batch packets also include deterministic state-key suggestions and per-owner mini packets to help agents split mixed batches without making the slash command longer.
For /contract update all, agents should run:
contract frame-batch-prepare --task "/contract update all" --mode updateUpdate mode uses the same retained packet idea, but tells the agent to treat the batch as existing code first: use known file+section bindings, avoid creating new screens by default, and report stale or missing bindings back after the patch.
For /contract update all and /contract apply all, a fully bound batch whose
source text anchors still match can collapse to a compact No Action Needed
packet. Treat that as the end state for that run only when the packet does not
also call out branch-sensitive state coverage. copy-anchors-matched only
confirms the current code still contains the expected UI text anchors and
obvious spacing values; it is not a pixel, interaction, or branch-activation
fidelity pass.
For single-contract commands, agents should run:
contract frame-prepare --live-frame --task "/contract update"or the matching task text. The packet carries any known binding, state-key suggestion, design context, and visual owner hint. This lets visible commands stay short:
/contract update
/contract visual-update
/contract implementAdd words to the visible slash command only when you need to override or clarify the retained packet.
When live refresh has a previous retained snapshot to compare against, small
copy, spacing, or style-only changes are promoted into a FOCUSED DELTA
section. Treat that as the preferred patch scope before broad source search or
full-screen reinterpretation.
Packets also include a completion boundary. Apply the required scoped contract
change first; mention adjacent tooling, docs, tests, refactors, behavior, or
copy issues as follow-ups instead of fixing them in the same pass.
If a single update has no persisted binding yet, the packet may include
ownerConfidence=inferred-owner from a bounded workspace scan over source
anchors. Treat that as a tentative first file/symbol to inspect, not as a
guarantee. If it is correct, run contract implemented so future short commands
start from a real binding instead of repeating owner discovery.
Report Back
After implementing a design, the coding agent should report the destination back to the bridge:
contract implemented src/ui/src/main.tsx \
--surface "Settings modal" \
--state "Default" \
--trigger "When the user opens settings" \
--behavior "Lets the user review and update account settings" \
--symbol "renderSettingsModal" \
--summary "Implemented the selected settings modal state."For retained multi-contract batches, include the live frame id from the packet:
contract implemented src/ui/src/main.tsx --live-frame-id frame-000001-10-1If one patch covers several retained frames in the same destination, repeat
--live-frame-id for each completed frame in a single report-back command.
If one design depends on multiple focused code owners, keep --symbol as the
primary display section and repeat --owner-symbol for every same-file owner:
contract implemented src/ui/src/main.tsx \
--live-frame-id frame-000042-467-120029 \
--symbol "renderMultipleContractTargetsState" \
--owner-symbol "renderMultipleContractTargetsState" \
--owner-symbol "renderSlashCommandsDialog" \
--summary "Linked the composite state to its background and popup owners."Use repeated --owner <path#symbol> values when the focused owners live in
different files. Future update packets inspect all reported owners before
deciding whether expected copy and obvious spacing anchors are still present.
Report-back paths must be relative source paths inside the current workspace. The CLI rejects absolute paths, parent-directory traversal, URLs, shell control characters, leading dashes, unsupported extensions, and oversized path values before persisting implementation bindings.
This lets the plugin show Code location and Design context the next time the same Figma contract is opened.
The bridge exposes the persisted binding list at GET /implementations. The
plugin reads that list when it reconnects so older contracts can recover Code
location even when they are no longer in the retained live-contract history.
If a design already exists in code but has no binding yet, use the same command after finding the owner. That relinks the Figma contract to the current implementation without requiring a new screen.
Troubleshooting
Plugin Says CLI Is Disconnected
Start or restart the bridge:
contract devIn this repository, use:
npm run contract:devPlugin Cannot See Old Implementations
Confirm the bridge was started from the same project directory that contains
.contract/implementation-bindings.json, then reconnect the plugin so it can
rehydrate bindings from GET /implementations. If the file is absent, ask the
agent to report the implementation again with contract implemented.
Batch Command Feels Slow
Use the most specific batch command that matches the job:
/contract update allfor existing related states./contract visual-update allfor visual-only updates./contract apply allfor mixed new/existing batches.
The CLI packet will still include per-owner mini packets and known bindings, but unrelated screens will take longer than related states of the same UI surface.
If an update batch contains loading, timeout, error, unsupported, missing, or
empty states that share one code owner, the CLI intentionally avoids a clean
No Action Needed result even when source text anchors all match. Inspect the
STATE COVERAGE CONFIDENCE section; it means the source contains the copy, but
the agent still needs to verify each branch can become active.
First Implementation Is Slow Or Inaccurate
Review the latest sent contract before rerunning the agent:
contract review-runFor saved files or CI artifacts:
contract review-run --frame-contract tmp/live-frame-contract.json --out tmp/run-review.mdThe review highlights high-risk signals such as truncated capture, missing reference screenshots, missing implementation bindings, generic layer names, vector-heavy designs, low Auto Layout coverage, and large packets.
When a command writes a packet with --out, the saved-output summary includes a
small Performance section with output size, line count, and command timings.
Use that to distinguish packet generation latency from agent implementation
time before changing prompts or rerunning a slow task.
For first-time screen implementations, assisted and interpretive packets require
the agent to run the compact inspect layout, inspect missing-details, and
inspect visual-risks preflights before editing source files. If the project is
otherwise blank, /contract implement should create the smallest runnable
production app shell for the repo, with an entrypoint, styles, behavior layer,
responsive rules, and a local run path. Standalone HTML/CSS/JS is acceptable in
that case only as the production app shell, not as a static export.
Package Boundary
The public npm package intentionally includes only the local bridge, slash-command packet, status, focused refresh, and report-back workflow.
The published contract binary points at a small public entrypoint. For public
V1, teach users only the bridge loop: contract dev, the slash-command aliases,
frame-prepare/frame-batch-prepare, and contract implemented.
Additional repo-only development commands are not included in the package. If one is needed later, it should be intentionally promoted into the public entrypoint and package whitelist in a new release.
Publishing Notes
The npm package should contain only:
dist/public.jsand its declaration file- selected
dist/frame-contract/**and public bridge/frame/report-back command dependencies slash-commands/README.mdLICENSEpackage.json
Use this before publishing:
npm run build
npm --prefix packages/contract-cli run pack:dry-runThe repo-level automated guard is:
npm run check:cli-releaseDo not publish fixture corpora, internal release docs, private repo sources, or the Figma plugin source as part of the CLI package.
