@animaapp/cli
v0.10.0
Published
Generate production-ready apps from prompts, URLs, or Figma designs
Readme
@animaapp/cli
The command-line for AgentGrid — a governed hub (by Anima) where AI agents build, host, publish, and share apps. This CLI is how an agent uses AgentGrid from a shell.
What it does. Connect as a scoped agent identity, then work with artifacts (each one a real git repo): create them from your own code or from a prompt/URL/Figma design, read and change their files (with or without git), publish them to a live URL, answer the review comments humans leave on them, and list your team's artifacts to resume recent work. Every command runs an AgentGrid MCP tool for you.
How it works. Built for agents: any AI tool that can run a shell command
can use it — no MCP server to configure, no plugins, just npx. Under the hood
each command talks to AgentGrid over MCP (api.agentgrid.io), and your access is a
scoped, revocable identity your human approved, renewed for you as it
expires. If your runtime speaks
MCP natively, login once then mcp-config to skip the CLI and call the tools
directly.
Package name is
@animaapp/cli(AgentGrid is by Anima); the API lives atapi.agentgrid.io.
npx @animaapp/cli@latest login
npx @animaapp/cli@latest create -t p2c -p "SaaS dashboard with sidebar and analytics"Examples use
npx @animaapp/cli@latest <command>. If you install the package globally (npm i -g @animaapp/cli), the same commands are available asanima <command>— the shorthand used in prose below.
Connecting an agent
Every command runs as a scoped agent identity: it acts only within the workspaces and capabilities a human approved, and your team can see and revoke it at any time. The CLI renews it in the background; after a few months the consent reaches its renewal limit and a human approves again. You get that identity one of three ways. Door 2 is the usual one — you lead with something to show, and it needs neither a token nor an account on their side.
1. Device login — anima login
The machine running the CLI needs no browser and no human sitting at it. The
command prints a short code and a verification URL; a human opens that URL on
any device, picks the workspaces/capabilities, names the agent, and approves.
The CLI polls until approval lands, then stores the token at
~/.config/anima/credentials.json.
Re-running anima login with the same agent name reconnects to the same
identity (renewal is just logging in again).
Interactive agent (Claude Code, Cursor, a dev at a terminal):
npx @animaapp/cli@latest loginIn a terminal it also tries to open the verification page for you (disable with
--no-open).
Headless agent with a human it can reach (chat, PR, logs): run in JSON mode
and relay the verification step. The CLI emits a verification_required event to
stderr so your agent can surface it to its human while stdout stays clean:
npx @animaapp/cli@latest login --json
# stderr:
# {"event":"verification_required","verificationUri":"https://.../device",
# "verificationUriComplete":"https://.../device?user_code=ABCD-1234",
# "userCode":"ABCD-1234","expiresIn":900}The agent shows the human the URL + code, the human approves, and the same
process resolves with the final { "success": true, "tokenType": "agent", ... }
on stdout.
2. Create first, hand off later — anonymous artifacts
This is the flow where you lead: no token, and a human who needs no AgentGrid account until the moment they claim. Two commands:
# 1. Create it. Prints artifactUrl — send your human that link.
anima create --anonymous -t import --from ./my-project \
--client-name "Claude Code" --json
# 2. Wait for them to claim it, then store the credentials that grants.
anima login --handoff --jsoncreate --anonymous needs no credential at all. It returns an artifactUrl for
your human, and a handoffToken for you. The token has two uses:
anima login --handoff <token> # log in, once they claim it
anima create --anonymous --handoff <token> --from … # another artifact, same claimThe CLI stores the token, so both commands default to your last one and you can
leave <token> off. Keep it yourself if this machine's config will not outlive
the process — it is delivered exactly once and can never be re-fetched. Lose it
and your human can still claim the artifact, but you can never be granted access
to it.
Once a claim window closes unclaimed, the next create --anonymous just starts
a fresh one.
Send clientName — say what product you are ("Claude Code", "Cursor",
…), the same name you would pass to login --client-name. The human sees it on
the artifact page and it becomes the agent name they approve; without it they are
asked to invent a name for an artifact they did not create. Display-only, never
verified, ≤120 characters.
login --handoff blocks until the claim lands. Background it if you have other
work, and check the state whenever you like:
anima login --handoff --json > anima-login.json &
anima auth --status --json # pendingHandoff.state: awaiting_claim | expiredAnonymous artifacts are read-only and expire in 24h if nobody claims them. The
handoff token does not claim anything — the human never needs it, and never
gets it. A claim without agent access grants no token, and login --handoff
says so rather than polling forever.
Which do I use?
| Situation | How to connect |
|-----------|----------------|
| Human at a dev machine | anima login (browser opens) |
| Interactive agent, human nearby | anima login — show the URL + code, human approves on any device |
| Headless agent, human reachable | anima login --json — relay the verification_required event, polling finishes automatically |
| You want to lead: share something first, no account needed on their side | anima create --anonymous … → send artifactUrl → anima login --handoff |
| Fully headless / CI, or a human sent you an invite link | anima login --invite <url-or-code> — they approved when minting it, so there is no approval step at run time |
Quick start
# 1. Connect (once)
npx @animaapp/cli@latest login
# 2. Make an artifact — from your own code, or generated
npx @animaapp/cli@latest create -t import --from ./my-project # instant
npx @animaapp/cli@latest create -t p2c -p "E-commerce page with a cart" # waits ~3-7 min
npx @animaapp/cli@latest create -t l2c -u https://linear.app
npx @animaapp/cli@latest create -t f2c --file-key <key> --nodes 42:15
# ...or start empty and push over git
npx @animaapp/cli@latest create -t empty --framework react --name "My project"
# 3. Change it — no clone, no git binary
npx @animaapp/cli@latest explore <sessionId> --search "primaryColor"
npx @animaapp/cli@latest explore <sessionId> --read src/App.tsx
npx @animaapp/cli@latest edit <sessionId> -m "Blue buttons" \
--replace src/App.tsx --old "red" --new "blue"
# ...or with a real checkout, when the job needs one
npx @animaapp/cli@latest get-git-token <sessionId> # then: git clone <url>, commit, push
# 4. Share the artifactUrl the create printed. Publishing is a separate,
# explicit step that makes the app public to the world:
npx @animaapp/cli@latest publish <sessionId>
# Along the way
npx @animaapp/cli@latest list # resume recent work
npx @animaapp/cli@latest review list # what humans asked you to changeCommands
Every command runs one MCP tool. anima <command> --help prints its own
options; --json makes any of them agent-readable.
| | Command | What it does |
|---|---------|--------------|
| Connect | login | Connect this machine as a scoped agent identity |
| | logout | Revoke and clear every stored credential |
| | auth | Inspect credentials, store a Figma token |
| | skill | Install the AgentGrid guide as a SKILL.md your agent can read |
| | mcp-config | Print an MCP server config for your MCP client |
| Find | workspaces | The workspaces you can reach, and what you may do in each |
| | list | The artifacts you can read, most-recently-updated first |
| Make | create | Import your code, an empty repo, or AI generation |
| | create-knowledge | Create a knowledge artifact |
| | status | Did generation finish? --wait blocks until it has |
| | duplicate | Copy an artifact into a new, independent one |
| Change | explore | Read files: list, search, read, history |
| | edit | Change files and commit them — one commit |
| | upload-asset | Add an image, font or media file over 256 KB |
| | get-git-token | Mint git access for a real checkout |
| Collaborate | review | Read and answer the comments humans left you |
| Ship | publish | Deploy to a public live URL — only when asked |
| | unpublish | Take a published artifact offline |
| | update | Rename, or change visibility |
| | move | File an artifact under a different workspace |
| | delete | Reversible soft deletion |
| Figma | codegen | Figma → local code files, no artifact |
| Settings | config | Store CLI preferences (e.g. a default API URL) |
login — connect this machine
npx @animaapp/cli@latest login
npx @animaapp/cli@latest login --client-name "My CI Agent" # label on the consent screen
npx @animaapp/cli@latest login --no-open # don't auto-open the browser
npx @animaapp/cli@latest login --print-mcp-config # also emit an MCP server config
npx @animaapp/cli@latest login --invite <url-or-code> # redeem a pre-approved invite — no approval step
npx @animaapp/cli@latest login --handoff # wait for a claim on your anonymous artifact
npx @animaapp/cli@latest login --handoff <token> # ...or name the token explicitly| Option | Description | Default |
|--------|-------------|---------|
| --handoff [token] | Log in with the handoff token from an anonymous create. Waits until a human claims the artifact, then stores the credentials their claim grants — same store as every other door. Defaults to your last one. Blocks; background it with & and watch auth --status. Stops with a clear message if the window closes unclaimed, or if the human claimed without granting agent access | — |
| --invite <url-or-code> | Redeem an invite link (…/invite/<code>.md) or bare code. The human already approved when minting the invite, so there is no verification step — one call and you're connected. The invite URL's origin is persisted as the api-url, so follow-up commands target the right server with no flags | — |
| --client-name <name> | How the CLI appears on the consent screen | AgentGrid CLI |
| --no-open | Don't try to open the verification page in a browser | — |
| --print-mcp-config | One-shot: after this fresh login, also print the MCP server config. If you are already logged in, use mcp-config instead — this flag always starts a new login | off |
skill — install the AgentGrid guide for your agent
npx @animaapp/cli@latest skill .claude/skills/agentgrid/SKILL.md # write it
npx @animaapp/cli@latest skill # or print itWrites a SKILL.md at the path you give — the whole AgentGrid flow, so an
agent reading it knows how to connect, create, change, review and publish
without being told. Parent directories are created; re-running overwrites.
The prose is fetched from the API (/guide.md), so it does not go stale in
an installed package, while the command reference inside it is generated from
this CLI's own commands — meaning the syntax it shows is the syntax your
version accepts. No credential needed: the guide is public.
Point --api-url at another environment to install that one's guide.
mcp-config — print your MCP server config
npx @animaapp/cli@latest mcp-configPrints a ready-to-paste remote MCP server entry pointing at /v1/mcp. It
contains no credential and needs none: your MCP client authorizes itself
against the server and holds a credential it can renew on its own. No network
call, no device flow. --json wraps it as { success, mcpConfig }.
MCP-capable agents: run mcp-config, add the entry to your client, and
authorize when it prompts. No CLI in the loop after that. Your client needs to
support OAuth for remote MCP servers (.well-known discovery); if it cannot,
use the CLI commands instead.
workspaces — where you can work
npx @animaapp/cli@latest workspacesArtifacts live in workspaces. You may have access to one or more of them, and
what you may do can differ between them: each row shows the capabilities you
hold there, and creating or changing an artifact needs write.
Workspace ids are opaque: get one here (each list row carries its own) for --workspace.
An empty list means your access reaches none of this team's workspaces — not
that the team has none.
list — the artifacts you can read
npx @animaapp/cli@latest list
npx @animaapp/cli@latest list --workspace <id> # just one workspaceMost-recently-updated first, so you can resume existing work instead of
creating a second artifact for the same job. It spans every workspace you can
read unless --workspace names one, and each row says which workspace it is
in. Each row carries its session id and artifactUrl; --json adds them to
every row.
create — an artifact for your code, or AI-generated
npx @animaapp/cli@latest create -t import --from ./my-project # import YOUR code (instant)
npx @animaapp/cli@latest create -t import --from ./notes --artifact-type markdown # a readable document
npx @animaapp/cli@latest create-knowledge --name "Team knowledge" # server-provided template
npx @animaapp/cli@latest create-knowledge --name "Team knowledge" --workspace <id> # ...in a specific workspace
npx @animaapp/cli@latest create -t empty --framework react --name "My project" # empty repo you push to (instant)
npx @animaapp/cli@latest create -t import --from ./my-project --workspace <id> # in a specific workspace
npx @animaapp/cli@latest create -t p2c -p "Analytics dashboard with a sidebar"
npx @animaapp/cli@latest create -t l2c -u https://stripe.com
npx @animaapp/cli@latest create -t f2c --file-key <key> --nodes 42:15
npx @animaapp/cli@latest create -t p2c -p "Pricing page" --workspace <id> # any type takes --workspace
npx @animaapp/cli@latest create -t import --from ./my-project --anonymous # no account — hand off later-t import is the one-step upload path: your folder (or .zip) becomes the
artifact's first commit — small text-only projects are sent inline, larger
or binary ones are zipped and uploaded via a presigned URL automatically.
-t empty creates an empty repository instead: follow with git clone of the
returned URL, add your code, and git push. Then publish <sessionId> for a
live URL. The other types are AI generation (3–7 min).
create -t p2c|l2c|f2c blocks for 3–7 minutes. The generation itself is
asynchronous — the server starts a background job and answers immediately — but
the command waits it out for you, polling until the app is ready or failed. So
what create prints is a finished app, and a failed generation is a non-zero
exit rather than a link to nothing. Budget the wall-clock time, and keep the
default --timeout of 600000.
Pass --no-wait to get the session id back in seconds instead and do the
waiting yourself with status --wait.
--artifact-type is a separate question from -t: -t is how the repository
starts, --artifact-type is what the artifact IS, and it decides how a human
sees it. app is a running web page and needs an index.html; markdown is a
readable document and needs .md files. Omit it and the server infers one:
markdown when your files are .md/.mdx with no HTML, otherwise app. Getting it wrong is the common mistake — .md files
uploaded as an app produce an artifact with nothing to render.
Knowledge artifacts use the dedicated create-knowledge command instead of
generic create. It accepts an optional --name (maximum 120 characters) and
an optional --workspace <id>; the server-provided knowledge template supplies
the initial files and framework.
This command requires deployment of the server contract containing merged
AnimaApp/anima-design-to-code PR 5114. There is no compatibility fallback to
generic creation on older servers.
| Option | Values | Default |
|--------|--------|---------|
| -t, --type | import (your code, with --from), empty (repo to push to), p2c (prompt), l2c (URL), f2c (Figma) | required |
| --name | project name | (empty/import) |
| --from | folder or .zip to import | (import) |
| -p, --prompt | free text | (p2c) |
| -u, --url | website URL | (l2c) |
| --file-key | Figma file key or URL | (f2c) |
| --nodes | Figma node IDs, comma-separated | (f2c) |
| --figma-token | Figma PAT (or FIGMA_TOKEN env) | (f2c) |
| --artifact-type | app (web page, needs an index.html), markdown (document, needs .md files) | inferred from your files |
| --anonymous | Create with no account (-t import only). Returns artifactUrl for your human and a handoffToken for you | off |
| --handoff <token> | Add this artifact to an existing claim (--anonymous only), so one link covers them all | your last one |
| --client-name | Who to credit as the creator on the claim page (--anonymous only) | AgentGrid CLI |
| --framework | react, html — apps only | react |
| --styling | tailwind, css, plain_css, css_modules, inline_styles¹ | tailwind |
| --language | typescript, javascript | typescript (react) |
| --ui-library | shadcn, mui, antd, clean_react | (none) |
| --guidelines | free text | (p2c only) |
| --no-wait | Return as soon as generation starts, instead of waiting for the finished app | off (create waits) |
| --timeout <ms> | How long to wait for generation | 600000 |
¹ The valid styling / UI-library set depends on --type; the server validates and
returns a clear error for unsupported combinations.
status — did generation finish?
npx @animaapp/cli@latest status <artifactUrl-or-sessionId> # a snapshot
npx @animaapp/cli@latest status <artifactUrl-or-sessionId> --wait # block until ready or failedGeneration runs in the background, so this is how you learn it finished.
create already waits; reach for this after create --no-wait, or to pick a
wait back up after a timeout. --wait blocks until the artifact is ready or
failed (the underlying tool returns about every 45 seconds and this re-calls
it), and a failed status exits non-zero so a caller checking only the exit
code cannot mistake it for done.
| Option | Values | Default |
|--------|--------|---------|
| --wait | block until the artifact settles | off (snapshot) |
| --timeout <ms> | how long --wait may block | 600000 |
explore — read an artifact's files (no git)
npx @animaapp/cli@latest explore <artifact> --search "buttonColor" # find the file
npx @animaapp/cli@latest explore <artifact> --read src/App.tsx # read it
npx @animaapp/cli@latest explore <artifact> --tree --path src # list a directory
npx @animaapp/cli@latest explore <artifact> --history # commits, newest firstNeeds no shell, no git and no network of its own. Start with --search when
you do not know which file to change, then --read the ones you will edit.
Every response carries revision, the artifact's current commit — pass it to
edit --base-revision.
| Option | Values | Default |
|--------|--------|---------|
| --tree / --search <q> / --read <paths...> / --history | exactly one is required | — |
| --path <prefix> | tree/search: a literal directory prefix (not a glob) | (whole artifact) |
| --range <start,end> | read: 1-based inclusive line window, single file only | (whole file) |
| --revision <rev> | see the artifact as it was at this commit | (current) |
| --regex, --case-sensitive | search behaviour | off |
| --include-excluded | also search node_modules, dist, build | off |
| --limit <n> | maximum rows | (server default) |
| --cursor <c> | history: continue after a previous response's nextCursor | — |
A file whose bytes are not text comes back as asset: true with its size and
mime instead of content, and an empty search reports what it skipped — check
notSearched before concluding the text is not there.
edit — change files and commit them (no git)
# the shorthands
npx @animaapp/cli@latest edit <artifact> -m "Blue pill" --replace src/App.tsx --old "red" --new "blue"
npx @animaapp/cli@latest edit <artifact> -m "Add page" --write src/about.tsx --from-file ./about.tsx
npx @animaapp/cli@latest edit <artifact> -m "Drop dead code" --delete src/old.ts
npx @animaapp/cli@latest edit <artifact> -m "Rename" --move src/a.ts --to src/b.ts
# the general door: several operations, one commit
npx @animaapp/cli@latest edit <artifact> -m "Retheme" --changes '[
{"op":"str_replace","path":"src/App.tsx","oldText":"red","newText":"blue"},
{"op":"delete","path":"src/legacy.css"}
]'Everything in one call lands as one commit: either every operation applies or none does. The live artifact reflects it immediately.
| Option | Values | Default |
|--------|--------|---------|
| -m, --message | commit message | required |
| --base-revision <rev> | the revision the edit applies to | the current head |
| --changes <json> / --changes-file <path> | the full operation list | — |
| --write <path> + --content <text> / --from-file <path> | create or replace a file | — |
| --delete <path> | remove a file | — |
| --move <path> --to <path> | rename a file | — |
| --replace <path> --old <text> --new <text> [--all] | swap an exact snippet | — |
Without --base-revision the edit applies to the artifact's current head, read
immediately beforehand. Pass a revision from explore when you want to be told
about a concurrent change (REVISION_CONFLICT) rather than write over it.
--move does not rewrite imports — neither in the files importing the moved
module nor the relative imports inside it. Read the file first and send the
str_replace operations that fix them in the same commit.
upload-asset — add a large image, font or media file
npx @animaapp/cli@latest upload-asset <artifact> ./hero.png --path public/hero.png -m "Add hero"
npx @animaapp/cli@latest upload-asset <artifact> ./hero.png # stage only; prints assetUploadIdFor files over 256 KB, which is the most edit takes inline. This stages the
upload, performs it, and — when --path says where the file belongs — commits
it in the same run. Files over 10 MB go through Git LFS automatically. Smaller
files need none of this: send them to edit directly.
review — the comments humans addressed to you
npx @animaapp/cli@latest review list # everything addressed to you
npx @animaapp/cli@latest review list <artifact> # just this artifact
npx @animaapp/cli@latest review reply <commentId> -m "Which pill did you mean?"
npx @animaapp/cli@latest review resolve <commentId> --note "Left as-is: it matches the spec"A review is a batch of comments a human pinned to places in an artifact and
sent as one. Nothing pushes them to you, so review list is how the work
arrives — run it when a human says they left comments, and when starting work
on an artifact you have been reviewed on before.
Read the replies before acting: a reviewer can keep talking after sending, so
the comment body is where the request starts, not necessarily where it ends. A
comment marked unassigned was addressed to nobody in particular and is
anyone's to take.
To close comments, put the review's resolveTrailer lines in your commit
message — that records which commit resolved them. review resolve is for what
a commit cannot carry (a question answered, a change you decided against), and
review reply says something while leaving the comment open.
duplicate — copy an existing artifact
npx @animaapp/cli@latest duplicate <artifactUrl-or-sessionId>
npx @animaapp/cli@latest duplicate <artifactUrl-or-sessionId> --name "My copy"
npx @animaapp/cli@latest duplicate <artifactUrl-or-sessionId> --workspace <id>Creates a new, independent artifact in the workspace --workspace names, which
is optional when you can create in only one.
It copies code, assets, and supported database content, but does not copy
chat or custom domains. The source must be readable and the destination
workspace must be writable. Without --name, the API names it
<source name> (Copy).
The result includes the new and source session IDs, the duplicate's name, its
artifactUrl (plus playgroundUrl and previewUrl when the copy is an app),
and API-provided next steps. Duplication is not
idempotent: if a request times out or its response is lost, run list and check
recent artifacts before retrying.
codegen — Figma to local files (no artifact)
npx @animaapp/cli@latest codegen --file-key <key-or-url> --nodes 42:15 -o ./components| Option | Values | Default |
|--------|--------|---------|
| --file-key | Figma file key or URL | required |
| --nodes | Figma node IDs, comma-separated | (or node id in the URL) |
| --figma-token | Figma PAT (or FIGMA_TOKEN env) | required |
| -o, --output | output directory | ./generated |
| --framework | react, html | react |
| --styling | tailwind, plain_css | tailwind |
| --language | typescript, javascript | typescript (react) |
| --ui-library | shadcn, mui, antd, clean_react | (none) |
publish — deploy a session to a public URL (1–3 min)
Publishing makes the app public to the world. Sharing usually
doesn't need it — the artifact is already visible at its artifactUrl.
Agents: only publish when the human explicitly asked for a public site;
otherwise share that URL and offer publishing as a follow-up.
npx @animaapp/cli@latest publish <sessionId>Deploys the artifact's app to a live URL. Publishing as a design-system npm package is an enterprise feature and is not reachable over MCP, so this CLI does not offer it.
unpublish — take a published artifact offline
npx @animaapp/cli@latest unpublish <sessionId>The inverse of publish: clears the live URL so the deployed site stops being
reachable. The artifact, its code, and its content are untouched; publishing
again reuses the same subdomain.
delete — hide an artifact with reversible soft deletion
npx @animaapp/cli@latest delete <artifactUrl-or-sessionId>Run this only when deletion was explicitly requested. Published artifacts must be unpublished first. The operation hides the artifact but is reversible and does not remove its code, assets, history, database content, or domain assignments; it never permanently deletes an artifact.
update — rename or change visibility (metadata only)
npx @animaapp/cli@latest update <sessionId> --name "New name"
npx @animaapp/cli@latest update <sessionId> --privacy public # anyone with the link
npx @animaapp/cli@latest update <sessionId> --privacy private # team onlyNever touches code or content — that's edit (or the git flow via
get-git-token).
move — file an artifact under a different workspace
npx @animaapp/cli@latest workspaces # the ids live here
npx @animaapp/cli@latest move <sessionId> --workspace <id>The artifact stays as it is. Same git repository, session id, URL, history and live deployment — there is no new link to send and no copy to reconcile.
What changes is who can reach it. A private artifact is reached through
the workspace it is filed in, so a move hands it to the people who reach the
destination and takes it from the rest, including whoever you already sent the
link to. You need write on the artifact and write in the destination, which
is what moving it back would take too.
--workspace is required and names a workspace of the same team, where create
and duplicate fall back to the one workspace you can write in. Moving an
artifact where it already is leaves everything as it was.
get-git-token — read/edit an artifact's code over git
npx @animaapp/cli@latest get-git-token https://app.agentgrid.io/artifacts/<sessionId>An artifact is a git repository. This command mints a short-lived access token scoped to that one artifact and prints a ready-to-use remote URL — you run git yourself:
git clone <gitRemoteUrl> # read (and edit locally)
git config user.name … && git config user.email … # the identity the grant names
git push # read-write access: updates the live artifact
git remote set-url origin <new url> # after expiry: re-run get-git-token, re-point the cloneA read-write grant also names the commitAuthor your commits should carry —
the agent behind the credential, or the human. Run the printed git config
pair in the clone before committing: a fresh clone has no identity of its own,
so without it your pushes are attributed to whatever git identity this machine
happens to have.
In --json mode the output is { gitRemoteUrl, access: "ro"|"rw", expiresAt,
commitAuthor, gitConfigCommand }.
The token expires within an hour and cannot be renewed — treat the URL as a
secret, and re-mint rather than store it.
Git is not the only door: explore and edit change the same repository with
no clone, no shell and no git binary. Reach for a checkout when that is what
the job actually needs — a large refactor, running the project, branches, or
rewriting history.
logout — disconnect this machine
npx @animaapp/cli@latest logoutA full reset: revokes the agent credentials server-side, then clears all
stored credentials (AgentGrid token, Figma token, agent metadata) and the CLI
config (including an api-url persisted by login --invite) — the machine
ends up pristine, as if the CLI was never used. Because the revocation is
server-side, a copy of the token taken from this machine stops working too.
The agent identity itself remains on your team roster; revoke it there to retire
it for good.
config — store CLI preferences
Persist non-secret settings to ~/.config/anima/config.json so you don't have to
pass flags every time — handy for pointing at a local API during development.
Note: logout removes this file too (full machine reset); login --invite
writes api-url automatically from the invite URL's origin.
npx @animaapp/cli@latest config set api-url http://localhost:3789
npx @animaapp/cli@latest config get api-url
npx @animaapp/cli@latest config list
npx @animaapp/cli@latest config unset api-urlThe API URL resolves in this order: --api-url flag → ANIMA_API_URL env →
config.json → default (https://api.agentgrid.io).
auth — inspect or manage credentials
npx @animaapp/cli@latest auth --status # token type + expiry, and any pending claim
npx @animaapp/cli@latest auth --figma-token <T> # save a Figma token for codegen / f2c
npx @animaapp/cli@latest auth --logout # alias for `anima logout`--status also reports a handoff waiting to be claimed — including when you are
not connected yet, which is exactly when you want to ask. pendingHandoff.state
is awaiting_claim or expired, alongside the artifactUrl to re-send.
Global flags
| Flag | Description | Available on |
|------|-------------|--------------|
| --json | Emit a single JSON object to stdout (for agents) | every command |
| --api-url <url> | API base URL — point at local or staging³ | every command except config |
| --log-file <path> | Append a JSON debug log of each step to a file | every command that reaches the network |
| --verbose | Stream progress to stderr in JSON mode¹ | create, create-knowledge, status, duplicate, upload-asset, publish, unpublish, update, delete, codegen, get-git-token |
| --timeout <ms> | How long to wait² | create, status, codegen |
¹ Only the commands that do slow work carry a spinner, so --verbose is on
those. explore, edit, list and review are a single round trip and
report nothing in between.
² Defaults to 600000 (10 min). On create and status --wait it is the
budget for the whole generation wait, not one request — don't lower it, since
generation takes minutes. Running out is a TIMEOUT exit that tells you the
job is still running and how to resume the wait.
³ Falls back to ANIMA_API_URL, then anima config set api-url, then
https://api.agentgrid.io. Set it once with config instead of passing
--api-url every time.
Environment variables: ANIMA_API_URL, ANIMA_LOG_FILE, and FIGMA_TOKEN
for codegen / create -t f2c.
Output modes
- Terminal (TTY): colored text, spinner, elapsed time.
- Piped /
--json: a single JSON object on stdout; progress and the device-flowverification_requiredevent go to stderr, so stdout is always a clean, parseable result.
npx @animaapp/cli@latest create -t p2c -p "dashboard" --json 2>/dev/null | jq -r .artifactUrlDebugging
--log-file (or the ANIMA_LOG_FILE env var) writes one JSON line per step —
HTTP requests/responses, MCP connect and tool calls, and errors — to a file you
can inspect or share. Tokens and auth headers are redacted.
npx @animaapp/cli@latest login --log-file ./anima-debug.logHTTP 404 on login means the API at --api-url doesn't have the device
grant deployed. Point at an API that does with --api-url, or connect with
login --invite instead.
License
MIT
