Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Build LLM-powered apps with the Anthropic Claude API or SDK across Python, TypeScript, Java, Go, Ruby, C#, and PHP.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
shared/anthropic-cli.md
1# Anthropic CLI (`ant`)23The `ant` CLI exposes every Claude API resource as a shell subcommand. Compared to `curl`: request bodies are built from typed flags or piped YAML instead of hand-written JSON, `@path` inlines file contents into any string field, `--transform` extracts fields with a GJSON path (no `jq`), list endpoints auto-paginate (cap total results with `--max-items N`; `--limit` only sets the server page size), and the `beta:` prefix auto-sets the right `anthropic-beta` header.45## When to use the CLI vs the SDK67**CLI for the control plane, SDK for the data plane.** Agents and environments are relatively static resources you define, configure, and debug with `ant` — check the YAML into your repo, apply from CI, inspect from a terminal. Sessions are dynamic and driven by your application through the SDK — create per task, stream events, react to tool calls, integrate into your product. Both hit the same API; the split is about where the call lives, not what's possible.89| | Control plane → `ant` | Data plane → SDK |10|---|---|---|11| Resources | agents, environments, skills, vaults, files | sessions, events |12| Cadence | Once per deploy / ad-hoc | Every task / every turn |13| Lives in | `*.yaml` in your repo + CI + terminal | Application code |14| Typical calls | `create < agent.yaml`, `update --version N`, `list`, `retrieve`, `archive`, `--debug` | `sessions.create()`, `events.stream()`, `events.send()` |1516## Install and auth1718```sh19# macOS20brew install anthropics/tap/ant21xattr -d com.apple.quarantine "$(brew --prefix)/bin/ant"2223# Linux / WSL — pick the release from github.com/anthropics/anthropic-cli/releases24curl -fsSL "https://github.com/anthropics/anthropic-cli/releases/download/v${VERSION}/ant_${VERSION}_$(uname -s | tr A-Z a-z)_$(uname -m | sed -e s/x86_64/amd64/ -e s/aarch64/arm64/).tar.gz" \25| sudo tar -xz -C /usr/local/bin ant2627# Or from source (Go 1.22+)28go install github.com/anthropics/anthropic-cli/cmd/ant@latest29```3031**Auth** — the CLI resolves credentials the same way the SDKs do (first match wins): explicit flags, then `ANTHROPIC_API_KEY`, then `ANTHROPIC_AUTH_TOKEN`, then the `ANTHROPIC_PROFILE`-selected or active profile, then Workload Identity Federation env vars, then the default profile on disk. Override the host with `ANTHROPIC_BASE_URL` or `--base-url`.3233- **API key**: set `ANTHROPIC_API_KEY` in the environment.34- **OAuth profile** (no static key to manage): `ant auth login` opens a browser, exchanges for a short-lived token, and stores a profile under `$ANTHROPIC_CONFIG_DIR` (default `~/.config/anthropic/` on Linux/macOS, `%APPDATA%\Anthropic` on Windows — `configs/<profile>.json` for settings, `credentials/<profile>.json` for tokens). Subsequent `ant` (and SDK) calls pick it up automatically — a bare `Anthropic()` client works after login, but scripts that read `ANTHROPIC_API_KEY` directly do not. Claude Code and the Claude Agent SDK honor the same profile resolution. `ant auth status` shows which credential source and profile won (it reports status only — don't script against its exit code as a health check); `ant auth logout` clears the active profile (`--all` for every profile). On a remote host without a browser, `ant auth login --no-browser` prints the authorize URL and accepts the code back in the terminal.35- **Non-interactive workloads** (CI, servers, containers): interactive login is for development on your own machine — use Workload Identity Federation instead (see the authentication docs via `shared/live-sources.md`).3637> **The #1 auth trap:** profiles are only consulted when no API key is set. A stale exported `ANTHROPIC_API_KEY` silently overrides every profile — requests hit whatever org/workspace that key is scoped to. `ant auth status` shows which source won; unset the key (or per-command: `env -u ANTHROPIC_API_KEY ant …`) before relying on a profile. Truly **unset** it — an empty `ANTHROPIC_API_KEY=""` still wins its precedence slot and authenticates with an empty key. The same shadowing applies in reverse to Claude Code: after `ant auth login`, Claude Code may warn about an auth conflict between the profile and its own `/login` credential — keep one (use the profile and `/logout` in Claude Code, or `ant auth logout` to keep Claude Code's own login).3839**Named profiles** — an interactive-login token is bound to a single org+workspace, and the API only shows resources belonging to that workspace. If an agent, session, or file you created "disappears", the usual cause is a token scoped to a different workspace than the one that created it (`ant auth status` shows the active workspace). Multi-workspace work means one profile per workspace:4041```sh42ant auth login --profile <name> # creates the profile if it doesn't exist; org/workspace picker in browser43ant auth login --profile <name> --workspace-id wrkspc_01... # bind directly, skip the picker44ant profile activate <name> # switch the default profile45ant --profile <name> models list # one-off; equivalent: ANTHROPIC_PROFILE=<name> ant models list46ant profile list # inspect47ant profile set workspace_id wrkspc_01... --profile <name> # edit config keys (workspace_id, base_url, organization_id, …)48```4950`ant profile set` edits an existing profile's config — it never creates one, and it does **not** rebind already-issued credentials; run `ant auth login` again under that profile to mint a token for the new target. Pointing `ANTHROPIC_PROFILE` at a profile that doesn't exist is an error, not a fall-through. Refresh tokens eventually hard-expire (they don't slide with use) — when a previously working profile starts failing auth, re-run `ant auth login` before debugging anything else.5152**Scopes** — a profile's OAuth scope set is requested at login (`--scope`) and persists on the profile (`scope` is also a `profile set` config key; like other config edits, changing it requires a fresh `ant auth login` to take effect). Privileged scopes — e.g. `org:admin` for organization-administration endpoints — are **not** in the default scope set: pass the full set you want explicitly (`ant auth login --profile admin --scope "... org:admin"`), and the server grants a privileged scope only if your role actually has it. Because the scope set rides on every token the profile mints, keep privileged work on a dedicated profile (`admin` vs `default`) and do day-to-day inference on the unprivileged one, switching with `--profile`/`ANTHROPIC_PROFILE`. Check `ant auth login --help` for the current scope list, and `ant auth status` to see what the active token carries.5354To hand the active credential to a subprocess or raw-HTTP script:5556```sh57# Bare access token — for curl's Authorization header58curl https://api.anthropic.com/v1/messages \59-H "Authorization: Bearer $(ant auth print-credentials --access-token)" \60-H "anthropic-version: 2023-06-01" \61-H "anthropic-beta: oauth-2025-04-20" \62-H "content-type: application/json" \63-d '{"model": "claude-opus-4-8", "max_tokens": 1024, "messages": [{"role": "user", "content": "Hello"}]}'6465# .env format — sets ANTHROPIC_AUTH_TOKEN (and ANTHROPIC_BASE_URL if the profile has one).66# Output is bare KEY=value (no `export`), so use `set -a` to auto-export for child processes:67set -a; eval "$(ant auth print-credentials --env)"; set +a68python my_script.py # SDK picks up ANTHROPIC_AUTH_TOKEN69```7071OAuth tokens go on `Authorization: Bearer` (not `x-api-key:`) **plus the `anthropic-beta: oauth-2025-04-20` header** — converting a raw curl/httpx script from an API key is a header change, not a key swap. The beta header requirement is endpoint-dependent (some endpoints happen to work without it; `/v1/messages` does not) — always send it so requests don't break when you switch endpoints. The token is short-lived and not auto-refreshed when passed via env var, so re-run `print-credentials` before it expires for long-running scripts (`print-credentials` itself refreshes the token if needed). If both `ANTHROPIC_API_KEY` and `ANTHROPIC_AUTH_TOKEN` are set, the SDKs send both and the API rejects the request — unset `ANTHROPIC_API_KEY` before `eval`ing the `--env` output.7273**Foot-gun:** `ant auth print-credentials` with **no flags** prints the entire credentials JSON, not the bare token — putting that in an `Authorization` header yields an empty response or HTTP/2 protocol error. Always use `--access-token` for headers (it always reads the named/active profile; a set `ANTHROPIC_API_KEY` doesn't override credential printing).7475## Command structure7677```78ant <resource>[:<subresource>] <action> [flags]79```8081Beta resources (agents, sessions, environments, deployments, skills, vaults, memory stores) live under `beta:` — the CLI auto-sends the right `anthropic-beta` header, so don't pass it yourself unless overriding with `--beta <header>`. For self-hosted environments, `ant beta:worker poll/run` and `ant beta:environments:work stats/stop` drive and monitor the work queue — see `shared/managed-agents-self-hosted-sandboxes.md`.8283```sh84ant models list85ant messages create --model claude-opus-4-8 --max-tokens 1024 --message '{role: user, content: "Hello"}'86ant beta:agents retrieve --agent-id agent_01...87ant beta:sessions:events list --session-id session_01...88```8990`ant --help` lists resources; append `--help` to any subcommand for its flags.9192## Global flags9394| Flag | Purpose |95| --- | --- |96| `--format` | `auto` (default: pretty if TTY, compact if piped), `json`, `jsonl`, `yaml`, `pretty`, `raw`, `explore` (interactive TUI) |97| `--transform` | GJSON path applied to the response (per-item on list endpoints). Not applied when `--format raw`. |98| `-r`, `--raw-output` | If the transformed result is a string, print it without quotes (jq semantics). Pair with `--transform` for scalar capture. |99| `--max-items` | Cap total results returned from auto-paginating list endpoints (distinct from `--limit`, which is the server page size). |100| `--format-error` / `--transform-error` | Same as `--format`/`--transform`, applied to error responses. `-r` does not apply to the error path — use `--format-error yaml` for unquoted error scalars. |101| `--base-url` | Override API host |102| `--debug` | Print full HTTP request + response to stderr (API key redacted) |103104## Output — `--transform` + `--format`105106`--transform` takes a [GJSON path](https://github.com/tidwall/gjson/blob/master/SYNTAX.md). On list endpoints it runs **per item**, not on the envelope.107108```sh109ant beta:agents list --transform '{id,name,model}' --format jsonl110```111112**Extract a scalar for shell use:** pair `--transform` with `-r` (`--raw-output` — prints strings unquoted, jq-style):113114```sh115AGENT_ID=$(ant beta:agents create --name "My Agent" --model '{id: claude-sonnet-4-6}' \116--transform id -r)117```118119## Input — flags, stdin, `@file`120121**Flags** — scalar fields map directly. Structured fields accept relaxed-YAML syntax (unquoted keys) or strict JSON. Repeatable flags build arrays (each `--tool`, `--event`, `--message` appends one element):122123```sh124ant beta:agents create \125--name "Research Agent" \126--model '{id: claude-opus-4-8}' \127--tool '{type: agent_toolset_20260401}' \128--tool '{type: custom, name: search_docs, input_schema: {type: object, properties: {query: {type: string}}}}'129```130131**Stdin** — pipe a full JSON or YAML body. Merged with flags; flags win on conflict (for array fields, any flag **replaces** the stdin array entirely — it does not append). Quote the heredoc delimiter (`<<'YAML'`) to disable shell expansion inside the body:132133```sh134ant beta:agents create <<'YAML'135name: Research Agent136model: claude-opus-4-8137system: |138You are a research assistant. Cite sources for every claim.139tools:140- type: agent_toolset_20260401141YAML142```143144**`@file` references** — inline a file's contents into any string-valued field. Inside structured flag values, quote the path. Binary files are auto-base64'd; force with `@file://` (text) or `@data://` (base64). Escape a literal leading `@` as `\@`.145146```sh147ant beta:agents create --name "Researcher" --model '{id: claude-sonnet-4-6}' --system @./prompts/researcher.txt148149ant messages create --model claude-opus-4-8 --max-tokens 1024 \150--message '{role: user, content: [151{type: document, source: {type: base64, media_type: application/pdf, data: "@./scan.pdf"}},152{type: text, text: "Extract the text from this scanned document."}153]}' \154--transform 'content.0.text' -r155```156157Flags that natively take a file path (e.g. `--file` on `beta:files upload`) accept a bare path without `@`.158159## Version-controlled Managed Agents resources160161This is the recommended flow for defining agents and environments — check the YAML into your repo and sync via `create` (first time) / `update` (thereafter). See `shared/managed-agents-core.md` for the field reference.162163```yaml164# summarizer.agent.yaml165name: Summarizer166model: claude-sonnet-4-6167system: |168You are a helpful assistant that writes concise summaries.169tools:170- type: agent_toolset_20260401171```172173```sh174# Create (once) — capture the ID175AGENT_ID=$(ant beta:agents create < summarizer.agent.yaml --transform id -r)176177# Update (CI) — needs ID + current version (optimistic lock)178ant beta:agents update --agent-id "$AGENT_ID" --version 1 < summarizer.agent.yaml179```180181Same pattern for environments (`ant beta:environments create|update < env.yaml`), then start a session with both IDs:182183```sh184ant beta:sessions create --agent "$AGENT_ID" --environment-id "$ENV_ID" --title "Task"185ant beta:sessions:events send --session-id "$SID" \186--event '{type: user.message, content: [{type: text, text: "Summarize X"}]}'187ant beta:sessions:events list --session-id "$SID" --transform 'content.0.text' -r188ant beta:sessions:events stream --session-id "$SID" # live event stream189```190191### Interactive session loop (stream-before-send)192193`ant beta:sessions:events stream` only delivers events emitted *after* the stream opens — so open it **before** sending the kickoff to avoid missing early events. Use process substitution to hold the stream on a file descriptor, send, then read:194195```sh196exec {stream}< <(ant beta:sessions:events stream --session-id "$SID" \197--transform '{type,text:content.#(type=="text").text,err:error.message}' --format yaml)198199ant beta:sessions:events send --session-id "$SID" > /dev/null <<'YAML'200events:201- type: user.message202content:203- type: text204text: Summarize the repo README205YAML206207type=208while IFS= read -r -u "$stream" line; do209case "$line" in210type:\ session.status_idle) break ;;211type:\ session.error)212IFS= read -r -u "$stream" next || next=213case "$next" in err:\ *) msg=${next#err: } ;; *) msg=unknown ;; esac214printf '\n[Error: %s]\n' "$msg"; break ;;215type:\ *) type=${line#type: } ;;216text:*)217[[ $type == agent.message ]] || continue218val=${line#text: }219case "$val" in '|-'|'|') ;; *) printf '%s' "$val" ;; esac ;;220\ \ *)221if [[ $type == agent.message ]]; then printf '%s\n' "${line# }"; fi ;;222esac223done224exec {stream}<&-225```226227This works for interactive exploration and demos. For application code that needs to react to `agent.tool_use` / `agent.custom_tool_use` events, reconnect after drops, or dedup against `events.list`, use the SDK — see `shared/managed-agents-client-patterns.md`.228229## Scripting patterns230231`--transform id -r` on a list endpoint emits one bare ID per line — compose with `xargs`, or use `--max-items N` to bound the result set without piping through `head`:232233```sh234FIRST=$(ant beta:agents list --transform id -r --max-items 1)235ant beta:agents:versions list --agent-id "$FIRST" --transform '{version,created_at}' --format jsonl236```237238Error shaping mirrors the success path (note: `-r` does not apply to error output — use `--format-error yaml` for an unquoted scalar here):239240```sh241ant beta:agents retrieve --agent-id bogus --transform-error error.message --format-error yaml 2>&1242```243244Shell completion: `ant @completion {zsh|bash|fish|powershell}`.245246For the full, always-current reference (including per-endpoint flags), WebFetch the **Anthropic CLI** URL in `shared/live-sources.md`.247