figma-cli
Headless Figma CLI for AI coding agents and automated design inspection.
Requires Python 3.11 or newer. Licensed under MIT.
Commands
The package installs two console scripts that run the same entrypoint:
figma-clifigma(short alias)
Each reports its own name in --help and --version:
$ figma-cli --version
figma-cli 0.1.0
$ figma --version
figma 0.1.0
The npm package silships/figma-cli also installs a figma-cli executable. If both are installed, whichever directory comes first on PATH wins. Run command -v figma-cli to check which one you get, or use the figma alias.
Usage
Every command talks to the Figma REST API with a personal access token. Create one under Figma account settings (Security > Personal access tokens) with these scopes, the minimum the commands below need per Figma's scope reference:
| Scope | Used by |
|---|---|
current_user:read |
auth check, auth login (GET /v1/me) |
file_content:read |
file get, export |
file_comments:read |
comment list |
file_comments:write |
comment post, comment delete |
Then store it once with figma auth login:
figma auth login # interactive: prints the steps, opens settings, hidden prompt
echo "$TOKEN" | figma auth login # agents and CI: piped stdin
figma auth login --token - < token.txt # same, explicit
auth login validates the token against GET /v1/me before writing anything. A rejected token exits 3 and leaves any existing token file untouched. A valid one is written to ~/.config/figma/token with mode 0600 (its directory 0700), through a temporary file renamed into place, so a failed write keeps the previous token, and the command reports the authenticated id, handle and email plus the file path. Prefer stdin over --token <value>, which exposes the token in process listings and shell history. Empty stdin exits 2. Add --no-browser to skip opening the settings page.
Alternatively, export the token. FIGMA_TOKEN takes precedence over the stored file whenever it is set and non-empty:
export FIGMA_TOKEN=figd_...
export FIGMA_API_BASE=https://api.figma.com # optional, this is the default
With neither set, commands fail with {"error": "missing_token"} and exit code 3.
Every subcommand prints human-readable text by default and a JSON document on stdout with --json.
| Command | Figma endpoint |
|---|---|
figma auth login [--token TOKEN|-] [--no-browser] |
GET /v1/me, then writes ~/.config/figma/token |
figma auth check |
GET /v1/me |
figma file get <file_key> [--depth N] |
GET /v1/files/{file_key}?depth=N |
figma export <file_key> --nodes <ids> [--format png|svg] [--output DIR] |
GET /v1/images/{file_key}, then the asset URLs |
figma comment list <file_key> |
GET /v1/files/{file_key}/comments |
figma comment post <file_key> --message TEXT [--comment-id ID] [--node-id ID] |
POST /v1/files/{file_key}/comments |
figma comment delete <file_key> <comment_id> |
DELETE /v1/files/{file_key}/comments/{comment_id} |
The file key is the segment after /design/ (or /file/) in a Figma URL. Node ids use the 1:2 form; a URL shows them as node-id=1-2.
Examples
Check the token:
$ figma auth check --json
{
"id": "123456789",
"handle": "Design Bot",
"email": "bot@example.com"
}
Inspect only the pages of a file. --depth is passed to Figma, so the server trims the tree before it is sent:
figma file get AbCdEf123 --depth 1
figma file get AbCdEf123 --depth 2 --json | jq '.document.children[].name'
Render two frames to PNG and print where they were written. Files are named <file_key>_<node_id>.<format> with : and other unsafe characters replaced by -; re-exporting the same node overwrites its file:
$ figma export AbCdEf123 --nodes 1:2,1:3 --output shots
shots/AbCdEf123_1-2.png
shots/AbCdEf123_1-3.png
Post a comment pinned to a frame, reply to it, list the thread, then clean up:
id=$(figma comment post AbCdEf123 --message "Spacing is off" --node-id 1:2 --json | jq -r .id)
figma comment post AbCdEf123 --message "Fixed in the next build" --comment-id "$id"
figma comment list AbCdEf123
figma comment delete AbCdEf123 "$id"
Errors and exit codes
| Exit code | Meaning |
|---|---|
| 0 | Success |
| 2 | Usage error (bad or missing arguments) |
| 3 | Figma API, network, or local write failure |
With --json, a failure prints a JSON object on stdout; without it, a one-line message goes to stderr. HTTP 401, 403, 404 and 5xx become unauthorized, forbidden, not_found and server_error:
{"error": "forbidden", "status": 403, "message": "Invalid token"}
HTTP 429 is reported at once, never retried, so the caller decides when to try again. retry_after comes from the Retry-After header and is null when Figma sends none:
{"error": "rate_limit_exceeded", "status": 429, "retry_after": 30}
Token safety
A request carrying X-Figma-Token follows no redirects. Any 3xx answer is refused with {"error": "redirect_refused"} and exit code 3 before a second request is made, so the token never reaches another host. Exported images are downloaded from the pre-signed URLs Figma returns with a separate request that carries no token; only that request follows redirects.
Installation and quick run
Run on-demand without installing via uv:
uvx figma-cli --help
uvx figma-cli auth check --json
Or install from PyPI:
pip install figma-cli
From a local checkout:
uvx --from . figma-cli --version
Development
python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
ruff check .
ruff format --check .
pytest tests/
The tests are hermetic: no network access and no Figma token are needed, and HOME points at a temporary directory so a stored token never leaks in. The redirect tests use real sockets on 127.0.0.1.
tests/test_live.py runs against the real API only when FIGMA_TOKEN is set. With the token alone it checks auth check and runs auth login from stdin into a temporary HOME; the file, comment and export checks also need FIGMA_TEST_FILE_KEY (add FIGMA_TEST_NODE_ID to exercise export). The comment check posts one comment and deletes it. CI runs it in the live job from the FIGMA_TOKEN secret and the FIGMA_TEST_FILE_KEY / FIGMA_TEST_NODE_ID repository variables, and skips it when they are absent.
Release
Bump __version__ in src/figma_cli/__init__.py, merge, then push a matching tag (v0.1.0 for 0.1.0). The release workflow refuses a tag that does not match __version__, builds the sdist and wheel, runs twine check, and publishes to PyPI through trusted publishing (OIDC, the pypi environment).
License
MIT, see LICENSE.
Metadata
Release files for figma-cli 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| figma_cli-0.3.0.tar.gz | 18.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| figma_cli-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 32.1 kB
Release files / figma_cli-0.3.0.tar.gz
| Download URL | figma_cli-0.3.0.tar.gz |
|---|---|
| Size | 18.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
631b32bb1d9801d9559472901401099ae7d2cb58095fec55b9d617a920ac1ba2
|
|
BLAKE2b-256 checksum How to use checksums |
cef16089556eeea02b7d51b590b81dc95119f9dd4c4eefbbbc76a344c3e9ea7e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.
Transparency logRelease files / figma_cli-0.3.0-py3-none-any.whl
| Download URL | figma_cli-0.3.0-py3-none-any.whl |
|---|---|
| Size | 13.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
30f288afc441b37920fcb0e141a0c008691d24c276da65a1856017626785805f
|
|
BLAKE2b-256 checksum How to use checksums |
b294631829ded146aa4eac4a4105fbb65266288533f1f28a72e44fa8bb282034
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.
Transparency log