CLI

Agents & MCP

Drive the AirStrings CLI from scripts and AI agents: JSON output, exit codes, env-var auth, paging, and the MCP server.

The CLI is built to be driven by scripts and AI agents: every command has structured output, stable exit codes, and a headless auth path. This page is the contract.

Prompt, don't type

Once a workspace exists (airstrings init, once, at the repo root), you don't run these commands yourself. You describe the change and let your agent drive the CLI. A real Claude Code session, given only this prompt:

We're adding a free-trial CTA button to the pricing section. Add the string pricing.cta_trial with en="Start your free trial" plus translations for all our locales, using the airstrings CLI. Don't publish yet.

The agent first read the project's existing strings to match each locale's register (informal in Italian, German, and Spanish; formal vous in French), then set all five locales in one command:

airstrings strings set pricing.cta_trial --format text --push \
  en="Start your free trial" it="Inizia la tua prova gratuita" \
  de="Starte deine kostenlose Testphase" es="Empieza tu prueba gratuita" \
  fr="Commencez votre essai gratuit"
✓ Set pricing.cta_trial — 5 locale(s) [text] (pushed)

and verified its own work before reporting back:

airstrings strings get pricing.cta_trial
Key:    pricing.cta_trial
Format: text
Values:
  de: Starte deine kostenlose Testphase
  en: Start your free trial
  es: Empieza tu prueba gratuita
  fr: Commencez votre essai gratuit
  it: Inizia la tua prova gratuita

The contract on the rest of this page is what makes sessions like this converge instead of flail. In the same session, the agent's first set attempt omitted --format: the CLI exited 2 with --format is required — must be 'text' or 'icu', and the agent fixed the command on the next try. A deterministic error costs one correction, not a guessing loop.

To make this the default way strings get edited in your repo, add one line to your project's CLAUDE.md or AGENTS.md:

All user-visible copy lives in AirStrings — manage it with
`airstrings strings set <key> --format text|icu --push`. Never hardcode strings.

After that, "using the airstrings CLI" in the prompt becomes optional: the workspace and the agent file carry the context.

Structured output

Add --json to any command for machine-readable stdout. Human-readable text goes to stdout; errors and progress go to stderr. With --json, an error is one JSON object on stderr:

{"error":{"message":"publish: API error 403: Production is protected: changes reach it only by promotion.","next_step":"Publish to staging, then ask a human to promote: https://app.airstrings.com/projects/…/promote","exit_code":7}}

next_step is the single action that unblocks you. MCP tool errors carry the same message and Next step: text.

airstrings strings ls --json
airstrings project --json | jq '.name'

Exit codes

Branch on the exit code, not on message text:

CodeMeaningRetry?
0okn/a
1generic errorno
2usage / bad inputno, fix the command
3auth: bad or expired key, read key used for a write, or no key in this workspace for an open environmentno, fix credentials
4not foundno
5networkyes, with backoff
6rate limitedyes, with backoff
7environment protectedno, publish to staging; a human promotes
8plan limit reachedno, a human upgrades
9login pendingyes, after the user approves the printed URL

Only 5 and 6 are retryable; everything else is deterministic and will fail the same way again.

Login from an agent

airstrings init --json with no key opens the browser and waits up to 90 seconds for an owner of the organization to approve, then finishes. With --no-browser or CI set, or if nobody approves in time, it exits 9 and prints:

{"status":"pending","verification_uri_complete":"https://app.airstrings.com/cli/approve?code=BCDF-GHJK","user_code":"BCDF-GHJK","expires_in":600,"next_step":"Approve in the browser at https://app.airstrings.com/cli/approve?code=BCDF-GHJK, then run the same command again"}

Give the URL to the user, then re-run the same command; the re-run waits up to 90 seconds for the approval. On success the org key is stored in ~/.config/airstrings/credentials.json, a project named after the folder is created (never reused by name) and staging becomes the active environment.

Staging active, protected production

Production is protected, so an agent publishes to staging:

  • To ship, write and publish to staging, run airstrings promote preview, and hand the printed Apply in the dashboard link to a human. A full-power org key can apply it itself: airstrings promote --to production.
  • For SDK setup, airstrings sdk-config --env production returns production's IDs and public key with any key of the project.

Env-var auth (headless / CI)

For ephemeral agents and CI, skip init entirely and authenticate with environment variables. They override any workspace credentials.

VariablePurpose
AIRSTRINGS_ORG_API_KEYOrg key; wins over every other key. For CI across several projects, use a gated (non-full-power) org key created in the dashboard
AIRSTRINGS_API_KEYProject key (as_proj_…); preferred in CI, create one on the dashboard's API Keys page
AIRSTRINGS_PROJECT_IDOptional: skips project lookup (one fewer round-trip)
AIRSTRINGS_ENV_IDOptional: skips environment lookup
AIRSTRINGS_BASE_URLOptional: overrides the default base URL
AIRSTRINGS_NO_BROWSEROptional: print the login URL without opening a browser

The CLI uses the first key it finds: AIRSTRINGS_ORG_API_KEY, AIRSTRINGS_API_KEY, the workspace key, then the stored login. A project key resolves its project; staging is used when it is open, otherwise the default environment. An org key needs a workspace or --project <id|name>. Legacy 64-hex environment keys keep working for their one environment.

Confirm what you are pointed at any time with airstrings status --json, which returns source ("workspace" or "env"), project_id, env_id, base_url, protection ("protected", "open" or "unknown"), key_scope ("read", "write" or "unknown"), key_type ("org", "project", "environment" or "none"), key_source, hint ({message, next_step}), stored_keys (masked keys stored in the workspace; [] when it uses the login), and the available environments.

Paging large lists

strings ls --json returns { "data": [...], "pagination": { "has_more": bool, "next_cursor": string } }. Loop by passing next_cursor back via --cursor until has_more is false.

airstrings strings ls --limit 50 --json
airstrings strings ls --cursor <next_cursor> --json
airstrings strings ls --key-prefix home. --json

Prefer --limit/--cursor or a --key-prefix filter over an unbounded ls so results stay small.

Typical agent flow

airstrings init --json        # browser opens, user approves; on exit 9 re-run
airstrings status --json
airstrings strings set welcome.title en="Welcome" --format text --push
airstrings strings ls --key-prefix welcome. --json
airstrings publish en --json

MCP server

airstrings-mcp is a separate stdio binary that exposes workspace operations as MCP tools, for AI clients without shell access (e.g. Claude Desktop). It ships with the CLI install.

airstrings mcp install
airstrings mcp install --claude-desktop

mcp install targets Claude Code by default; pass --claude-desktop for Claude Desktop. Restart Claude and the tools are available.

The tools mirror the workspace commands (init, set/rm, ls, push, pull, publish) and your AI picks them automatically. They honor the same environment variables and stored login as the CLI. airstrings_login, and airstrings_init without a key, return status: "pending" with the approval URL; call again after the user approves. airstrings_sdk_config returns SDK setup values (IDs, public keys, per-platform snippets) for any environment, and airstrings_promote_preview includes the apply_url a human opens to apply a promotion. airstrings_status returns the same stored_keys as status --json. A separate set of variant tools — airstrings_variant_set, airstrings_variant_status, airstrings_variant_start, airstrings_variant_stop, and airstrings_variant_promote — exposes the variants workflow (set variant text, inspect status, start/stop, promote a winner) to agents without shell access. Prompt in product terms:

Translate the welcome module into all our locales.

Add a string checkout.cta with en="Place order", translated for every locale, and publish it.

Prefer the CLI when you have a shell

The MCP server exposes a subset of the CLI. If your agent has shell access, drive airstrings directly. It is more composable and supports paging, --json, and the exit codes above.

On this page