@animaapp/cli
v0.7.1
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, edit them over git, publish them to a live URL, 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 four ways. Door 3 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. Pre-issued token — ANIMA_API_TOKEN
For CI or a fully headless agent with no human in the loop, skip login and provide a token directly:
export ANIMA_API_TOKEN=<agent-or-personal-token>
export ANIMA_TEAM_ID=<team-id> # optional
export FIGMA_TOKEN=<token> # only for codegen / f2cResolution priority: ANIMA_API_TOKEN env var → stored credentials file → error.
3. 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 claim 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 |
| Fully headless / CI, no human | set ANIMA_API_TOKEN — no login step |
| You want to lead: share something first, no account needed on their side | anima create --anonymous … → send artifactUrl → anima login --handoff |
| Your human led: they sent you an invite link to join | anima login --invite <url-or-code> — one exchange, no approval step |
Quick start
# 1. Connect (once)
npx @animaapp/cli@latest login
# 2. Create from a prompt / URL / Figma
npx @animaapp/cli@latest create -t p2c -p "E-commerce product page with cart"
npx @animaapp/cli@latest create -t l2c -u https://linear.app
npx @animaapp/cli@latest create -t f2c --file-key <key> --nodes 42:15
# 3. Or bring YOUR OWN code: import it in one step -> publish
npx @animaapp/cli@latest create -t import --from ./my-project
npx @animaapp/cli@latest publish <sessionId>
# ...or start empty and push over git
npx @animaapp/cli@latest create -t empty --framework react --name "My project"
npx @animaapp/cli@latest get-git-token <sessionId> # then: git clone <url>, add code, git push
# ...or create an independent copy of an existing artifact
npx @animaapp/cli@latest duplicate <artifactUrl-or-sessionId> --name "My copy"Commands
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 |
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.
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 -t empty --framework react --name "My project" # empty repo you push to (instant)
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 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).
--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.
| 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) |
¹ The valid styling / UI-library set depends on --type; the server validates and
returns a clear error for unsupported combinations.
duplicate — copy an existing artifact
npx @animaapp/cli@latest duplicate <artifactUrl-or-sessionId>
npx @animaapp/cli@latest duplicate <artifactUrl-or-sessionId> --name "My copy"Creates a new, independent artifact in the current team's Default workspace.
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, duplicate name,
playgroundUrl, previewUrl, 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 playgroundUrl.
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.
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 the git flow (get-git-token).
get-git-token — read/edit an artifact's code over git
npx @animaapp/cli@latest get-git-token https://dev.animaapp.com/chat/<sessionId>An artifact is a git repository, and git is the only way to read or edit its code. 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 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 cloneIn --json mode the output is { gitRemoteUrl, access: "ro"|"rw", expiresAt }.
The token expires within an hour and cannot be renewed — treat the URL as a
secret, and re-mint rather than store it.
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
Available on the network commands (login, create, duplicate, codegen,
publish, get-git-token):
| Flag | Description | Default |
|------|-------------|---------|
| --json | Emit a single JSON object to stdout (for agents) | off (pretty in a TTY) |
| --verbose | Stream progress to stderr in JSON mode¹ | off |
| --api-url <url> | API base URL (point at local/staging)³ | https://api.agentgrid.io |
| --log-file <path> | Append a JSON debug log of each step to a file | off |
| --timeout <ms> | Request timeout² | 600000 (10 min) |
¹ --verbose applies to create / duplicate / codegen / publish /
get-git-token.
² --timeout applies to create / codegen. Don't lower it — generation takes
minutes.
³ Falls back to ANIMA_API_URL, then anima config set api-url, then the
default. Set it once with config instead of passing --api-url every time.
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 .playgroundUrlDebugging
--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 (--api-url) or use ANIMA_API_TOKEN.
License
MIT
