Amba

CLI Reference

The Amba CLI for project initialization, status, and management.

The Amba CLI helps you initialize projects, check status, test push notifications, and manage remote config from your terminal.

Installation

Use directly with npx — no install required:

npx @layers/amba init

Or install it globally:

npm install -g @layers/amba
amba init

All examples below use the amba <command> form once the CLI is on your PATH. If you prefer npx, prefix every command with npx @layers/amba — the arguments are identical.

Project configuration lookup

Project-scoped commands resolve AMBA_PROJECT_ID from the process environment first, then .env.local or .env in the current working directory. The CLI does not walk into parent directories: doing so could silently select a different workspace's credentials in a monorepo or nested checkout.

From a subdirectory, either export AMBA_PROJECT_ID, use --project <id> on commands that expose it, or run the command from the directory containing the intended env file. CI should inject variables from its secret store rather than creating an env file.

Project-scoped CI credentials

For CI that only needs to operate on one existing project, use that project's server key (amb_dev_sk_… / amb_live_sk_…) instead of a developer PAT. The CLI forwards --token verbatim, and project-scoped commands such as sites deploy and functions deploy accept a server key:

amba sites deploy ./dist --name my-site --token "$AMBA_SERVER_KEY"

The API verifies that the project id in the command matches the key's project; a different project returns 403 WRONG_PROJECT. Server keys cannot list or create projects. The --token <pat> placeholder in command help is historical shorthand—the flag also accepts a project server key for these project-scoped commands. Keep server keys in your CI secret store and never commit them.

Commands

amba init

Initialize Amba in your current project. Walks you through:

  • Creating an account or logging in
  • Creating a new project
  • Generating API keys
  • Writing config to your project
amba init

Signup is open, so init needs no invite code. If you have one from an invite email, pass it with amba init --invite <code> (or set AMBA_INVITE_CODE); --invite runs the headless signup. If a code is not valid, or signups are limited, init stops with INVITE_REQUIRED, INVITE_INVALID, or SIGNUPS_CLOSED and prints where to request access. See Getting access.

When the install steps you were given carry a signup source (an AMBA_SIGNUP_SOURCE value from amba.dev, such as t_…, or a short tag such as docs), keep it: init sends it with a new account's signup so Amba knows which page the install came from. It changes nothing about the account. From CLI 4.1.32, amba init --src <source> does the same; an earlier CLI ignores AMBA_SIGNUP_SOURCE and refuses --src.

What init writes into your project directory holds no secret your repository should not carry:

  • .env.local gets AMBA_PROJECT_ID, AMBA_CLIENT_KEY, and AMBA_API_URL, and .amba/project.json links the directory to the project. Both are written with mode 0600.
  • The project's server key goes to the OS keychain next to your token (see Project server keys). amba server-key prints it.
  • init adds .amba/ and .env*.local to the project's .gitignore, creating the file when there is none, and warns when git already tracks a file that holds or held a credential: .amba/project.json, an .env*.local file, or an MCP config backup an earlier version left in the project. Remove such a file from the index with git rm --cached <file> and rotate any key a commit published.
  • Every request goes to AMBA_API_URL, else https://api.amba.dev. An api_url in a .amba/project.json (one from a cloned repository, for example) never chooses where your token goes; init prints a warning when it differs.

init --sandbox --no-mcp-config prints a paste-ready MCP snippet whose bearer is the <your-pat> placeholder, followed by a masked form of the PAT and where it is stored. amba token prints the PAT itself.

amba login

Authenticate with your Amba account in the browser. The session is stored in your operating system's credential store and renews itself; see Authentication and Session renewal.

amba login

The CLI opens app.amba.dev with a one-time state value. Click Connect CLI on that page: the console sends your session to the CLI's listener on 127.0.0.1 in a form POST that carries the same state, and the CLI accepts it only on the port it opened and only with the state it generated. The tokens travel in the request body, so they stay out of URLs and browser history. A sign-in page opened without a state value (one from a CLI older than 4.1.17) asks you to update the CLI with npx @layers/amba@latest login.

amba whoami

Show the account the active credential belongs to, where that credential is stored, and when its token expires. For a browser-login session it also says whether this run renewed the session.

amba whoami

amba token

Print the active token to stdout and nothing else, for scripts that call the API or the MCP endpoint directly. For a browser-login session, amba token first renews the session when its access token has expired or expires within five minutes, so the printed token works. It exits 1 when no token is stored or the session cannot be renewed (one line on stderr says to run amba login), and 2 when the OS keychain holds a token it cannot read right now (locked, or access denied).

PAT=$(amba token)

amba server-key

Print the server key of the project linked in the current directory to stdout and nothing else. amba init keeps the key in the OS keychain (see Project server keys). Pass it to server code through the process environment:

AMBA_SERVER_KEY=$(amba server-key) node server.js

--project <id> picks another project. Without it the project comes from .amba/project.json, else AMBA_PROJECT_ID. It exits 1 when this machine stores no server key for the project; run amba init in the project's directory to store one.

amba logout

Remove the stored credential for the active endpoint: the OS keychain entry and any entry in the fallback file. Project server keys stay stored; they belong to their projects, and amba server-key keeps working after you sign in again.

amba logout

amba claim <email>

Bind a sandbox account to a real email address via an emailed confirmation link. Sandbox accounts are minted with an auto-generated address (sandbox-<epoch>-<nonce>@layers.com) and capped at 100 MAU / 10 MB DB until claimed. Running amba claim <email> emails a single-use link to the address you pass in; opening it and pressing Confirm updates developers.email AND flips the project tier from agent_sandbox to verified_free (1,000 MAU, 500 MB DB).

amba claim me@example.com

The CLI prints a single confirmation line and exits — the click in the email is the whole flow. No copy-paste tokens, no follow-up commands, no console UI. The link expires in 15 minutes.

Error responses surface as terse one-liners:

  • EMAIL_TAKEN — that address already owns another Amba account. Sign in with amba login instead, or pick a different email.
  • EMAIL_EXISTS — another Amba account already uses an alias of the same mailbox (a +tag variant, or for Gmail a variant with different dots). Sign in to that account instead.
  • DISPOSABLE_EMAIL — the address is on a disposable / temporary inbox domain. Use a permanent address.
  • ALREADY_CLAIMED — this account is already verified. No claim needed.
  • 429 — too many claim attempts; wait a minute and retry.

Agents without shell access can call the underlying POST /v1/auth/developer/claim endpoint directly with Authorization: Bearer <pat> and body { "email": "<target>" }.

amba status

Show project health and integration status. The default view covers authentication, your local .env.local configuration, API key validation, project metadata, and the presence of context files (AMBA.md, Cursor rules).

amba status

Pass --detailed to add a per-project metrics block:

  • Integration health (APNS, FCM, RevenueCat, Superwall)
  • Total user count
  • Active and total segment counts
  • 24h event total + the top 5 event names by count
amba status --detailed

amba logs tail

Tail the project-wide event log. By default the command fetches the most recent 100 engagement events from the last 24 hours and prints them oldest-to-newest:

amba logs tail

Each line is <timestamp> <event_name> user=<user_id> <properties>.

Useful flags:

  • --follow — keep the connection open and poll every 2 seconds for new events. Press Ctrl-C to stop cleanly.
  • --json — emit raw NDJSON (one event per line) for piping into jq, Vector, or any downstream pipeline. Banner output is suppressed.
  • --since <iso> — only show events on or after the given ISO 8601 timestamp (default: 24h ago).
  • --event-name <name> — filter to a single event name.
  • --user-id <id> — filter to events for a single app user.
  • --limit <n> — events per page (default 100, max 1000).
  • --source <source> — engagement (default), telemetry (events tracked with { telemetry: true }), or all. With telemetry or all, each line names its source=.
  • --project <id> — override the project id from .env.local.
# follow new events for a single user
amba logs tail --user-id u_abc --follow
 
# pipe NDJSON into jq
amba logs tail --json --limit 1000 | jq 'select(.event_name == "purchase")'

amba push test

Send one test push notification to an app user or to a single device. It proves your APNs / FCM credentials work end to end.

# the user's newest active push token
amba push test --user <app_user_id>
 
# one device token, without an app user
amba push test --device-token <token> --provider apns

A user with no registered push token gets a message telling you to register one from the app through the SDK first.

amba config list

List all remote config values for your project.

amba config list

amba config set <key> <value>

Set a remote config value.

amba config set daily_limit 10
amba config set feature_paywall_v2 true

amba analytics export

Bulk-export users or events to CSV (default) or NDJSON. Both flows are backed by streaming admin endpoints, so you can dump millions of rows without buffering the result set in memory.

# Export every user as CSV to stdout (uses /admin/.../users/export stream)
amba analytics export --type=users > users.csv
 
# Export the last 7 days of events to a file as NDJSON
amba analytics export \
  --type=events \
  --since 2026-04-17T00:00:00Z \
  --format=ndjson \
  --out events.ndjson

Flags:

  • --type=users|events — required. Switches between the two exporters.
  • --since <iso> / --until <iso> — time window for events (defaults: last 24 hours). The users export honors --since against created_at.
  • --format=csv|ndjson — output encoding. CSV is the default.
  • --out <file> — write to disk instead of stdout. The command tees a progress counter to stderr so it stays usable when redirecting stdout.
  • --limit <n> — per-page row limit when paginating events (default 1000). The command keeps walking cursors until the server reports no more rows.
  • --source <source> — which events --type=events exports: engagement (default), telemetry (events tracked with { telemetry: true }), or all. With telemetry or all, CSV output gains a trailing source column and NDJSON rows carry a source field.
  • --project <id> — override the project id from .env.local.
# Export the last 7 days of telemetry events (page views, funnel steps)
amba analytics export \
  --type=events \
  --source=telemetry \
  --since 2026-09-29T00:00:00Z \
  --out telemetry.csv

amba functions dev <file>

Run a local development server for an Amba function with hot reload on file changes. The dev server reproduces the production request shape so you can iterate before deploying. See Functions → Local dev.

amba functions dev ./functions/hello.ts
# Listening on http://127.0.0.1:8787
# Watching ./functions/hello.ts — save to reload.

Flags:

  • --port <n> — port to listen on (default 8787).
  • --no-watch — disable file-change hot reload.
  • --allow-host <hosts> — also answer these host names (comma-separated), such as a tunnel's public name. The server answers local names and IP addresses, and browser requests from local pages, and refuses everything else with 403.

amba functions deploy <target>

Bundle a function and deploy it to your project's edge runtime. <target> is either a single file or a directory — a directory resolves its entry by convention (index.ts / index.js / index.mjs) or via --entry. See Functions → Deploy.

amba functions deploy ./functions/hello.ts
amba functions deploy ./functions/hello.ts --name greet
amba functions deploy ./functions/hello.ts --dry-run
 
# Deploy a directory (entry resolved by convention)
amba functions deploy ./functions/checkout
amba functions deploy ./functions/checkout --entry handler.ts --name checkout

Flags:

  • --name <name> — function name (default: the file name without extension, or the directory leaf name).
  • --entry <file> — entry file when <target> is a directory (relative to it). Default: index.ts/js/mjs.
  • --dry-run — bundle and report size without uploading.
  • --public — deploy without the X-Api-Key gate so external webhook senders can call it. You must verify the webhook signature in your handler. Default: private.
  • --forward-authorization — forward the verified caller's bearer Authorization header to this function. Off by default; X-Api-Key and internal trigger credentials are always stripped.
  • --rate-limit-window <60s|5m|1h> — per-function rate-limit window (all three rate-limit flags must be set together or all omitted).
  • --rate-limit-max <int> — max requests per window.
  • --rate-limit-key <user_id|ip> — bucket key for the rate limit.

amba functions list

List active functions for the current project.

amba functions list

amba functions deploy-status

Check whether platform maintenance has paused function deploys before starting a release. A paused response includes the same retry interval used by deploy.

amba functions deploy-status

amba functions delete <name>

Remove a function from your project's edge runtime.

amba functions delete greet --confirm greet

--confirm must exactly match the function name. This prevents a typo in a destructive command from deleting a different function.

amba functions schedule <name> <cron>

Register a cron schedule that invokes a deployed function.

amba functions schedule daily-digest "0 9 * * *" --tz America/New_York

Flags:

  • --tz <iana> — IANA timezone for the schedule (default UTC).

amba functions schedules

List every schedule with its cron expression, timezone, pause state, and last/next fire times.

amba functions schedules

amba functions logs <name>

Stream log events for a deployed function.

amba functions logs greet --tail
amba functions logs greet --since 2026-05-15T00:00:00Z --json | jq '.level == "error"'
amba functions logs greet --since-request-id r_019e55ef1f46 --tail

Flags:

  • --since <iso> / --until <iso> — time range (default: last hour, up to 24 hours).
  • --limit <n> — max events per fetch (default 100, max 1000). When more events match, the newest ones print (oldest of them first) and the command prints the full amba functions logs … line that reads the older ones.
  • --tail (alias --follow) — keep streaming new events; polls every 3s over the last five minutes and prints each event once, so an invocation whose logs land a couple of minutes late still appears. Keep the tail open through that ingestion window. Ctrl-C to stop. Successful invocations without console.* output are printed as [outcome] ok.
  • --request-id <id> — only show events whose logs mention this request id (e.g. r_...); works with --tail.
  • --since-request-id <id> — start the range at the oldest event mentioning this request id and show everything from there onward (searches the last 24h, or your --since/--until window). Composes with --request-id (which filters) and --tail (which anchors the backfill, then streams).
  • --json — emit NDJSON to stdout for piping into jq.

When a stored log batch in the range cannot be read, the command still prints every other event and says how many batches were skipped (their events are missing until a retry succeeds).

amba functions domains attach|list|refresh|remove

Manage one exact custom hostname for a deployed function:

amba functions domains attach feed feeds.example.com
amba functions domains list feed
amba functions domains refresh feed feeds.example.com
amba functions domains remove feed feeds.example.com

Attach prints the CNAME target plus ownership and certificate validation records. Publish all returned DNS records, then refresh until both statuses are active and routing reconciliation succeeds (live=true). Paths and query strings are preserved exactly.

This MVP does not support wildcards, path rewrites, or automatic www.feeds.example.com creation. Podcast/feed clients cannot send an Amba API key, so deploy their function with --public and validate any private application token in the handler. See Function Custom Domains.

Effective-tier caps are free 1, pro 5, scale 20, and enterprise/comped 50. Attach allows five attempts per project per hour. An unverified claim becomes eligible for exact-host reclaim after 24 hours; pending claims do not allocate Worker route/KV resources.

amba functions consume <queue-name> <function-name>

Bind a function as the consumer for a queue.

amba functions consume orders process-order
amba functions consume orders process-order --paused

Flags:

  • --paused — create the binding paused (messages dead-letter until you resume).

amba functions consumers list

List queue bindings for the current project.

amba functions consumers list

amba functions consumers unbind <queue-name>

Remove the binding for a queue.

amba functions consumers unbind orders

Infrastructure as code

amba export / amba diff / amba apply manage your project's reusable configuration declaratively — the entities you hand-build once and want to stand up identically elsewhere (dev → prod): remote configs, collection schemas, content libraries + items, currencies, achievements, streaks, challenges, leaderboards, and XP rules. The bundle is configuration only — no secrets, no per-user data — so it's safe to check into version control and diff in a pull request. The default bundle file is amba.config.json (JSON only).

amba export [file]

Write the current project's configuration bundle to disk.

amba export                  # → amba.config.json
amba export prod.config.json

amba diff [file]

Show what amba apply would change (created / updated / skipped per section) without writing. Computed locally by exporting the current project and comparing — there's no server-side dry-run.

amba diff
amba diff --mode merge       # preview what merge mode would update

amba apply [file]

Apply a bundle to the current project. Prints the server's authoritative { created, updated, skipped } per section.

amba apply                   # skip_existing (default — no-op on conflict)
amba apply --mode merge      # refresh existing definitions
amba apply prod.config.json --project <id>

--mode skip_existing (default) no-ops on any definition that already exists; --mode merge refreshes existing definitions. Collections are always create-if-absent (never merged in place). All three commands take --project <id> to target a project other than the one in .env.local.

Authentication

amba login and amba init store your token in the operating system's credential store: macOS Keychain, Windows Credential Manager, or the Linux Secret Service. Every command that needs authentication reads it from there.

  • Service: amba
  • Account: developer:<api host>, for example developer:api.amba.dev. Each API endpoint (AMBA_API_URL) has its own entry, so a production login and a staging login stay separate.
  • Previous tokens: when a login replaces a different token for the same endpoint, the replaced one moves to developer:<api host>:previous. The CLI keeps the last three.
  • Non-secret details (developer id, email, endpoint, token expiry, which store holds the token, and a 16-character SHA-256 fingerprint that ties the record to its token) live in ~/.amba/config.json.

amba login (and the browser step of an interactive amba init) signs in through app.amba.dev, so it stores a production session. For another endpoint, set AMBA_PAT to a token from that endpoint, or run amba init --sandbox with AMBA_API_URL set to create an account there. The MCP client configs that amba init writes point at the MCP server for that same endpoint; set AMBA_MCP_URL to choose a different one.

Where no OS keychain is usable (headless CI, containers, Linux without a Secret Service, or a platform with no prebuilt keyring binary), the token goes to ~/.amba/credentials.json with mode 0600, and the CLI prints one line to stderr naming that file. If the keychain holds your token but cannot be read right now (locked, or access denied), commands stop with an error that names the entry; unlock the keychain or allow access and retry.

Earlier CLI versions kept the token in ~/.amba/credentials.json. The first command that reads credentials after an upgrade moves the token into the keychain, reads it back to confirm, and then deletes the file. If the keychain write fails, the file stays as it was and the CLI keeps using it. Earlier versions may also have left ~/.amba/credentials.json.bak-<timestamp> copies; they hold plaintext tokens, so delete them once you no longer need them.

The CLI picks a token in this order:

  1. --token <pat>
  2. The AMBA_PAT environment variable
  3. The OS keychain entry for the active endpoint
  4. ~/.amba/credentials.json, used only where no keychain is usable

The CLI never stores --token or AMBA_PAT in the keychain or the credential file, and never refreshes them.

Project server keys

A project's server key grants admin access to that project, so amba init keeps it in the same OS keychain as your token:

  • Service: amba
  • Account: server-key:<api host>:<project id>, for example server-key:api.amba.dev:4b40438d-….

Where no OS keychain is usable, the key goes to ~/.amba/server-keys.json with mode 0600. That file also records which projects have a key in the keychain, without the key itself. amba server-key prints the key for the linked project.

CLI versions before 4.1.17 wrote the server key into .amba/project.json and .env.local. The next amba init or amba server-key in that directory moves the key from .amba/project.json into the keychain and rewrites the file without it. When the keychain already holds a different key for the project, that key stays, and the file's key is kept in ~/.amba/backups/ (mode 0600) so you can revoke it. On a machine that stores no key for a linked project, amba init mints one; a key it mints and cannot store is revoked again. An AMBA_SERVER_KEY line in .env.local stays where it is, because your server code may read it; init prints a note, and the line belongs in your server's environment or secret store.

Session renewal

amba login stores a browser session: an access token valid for 24 hours from when it was issued (for the token amba login receives, that is when you signed in to the console), and a refresh token that lasts 30 days and is replaced each time it is used. The CLI keeps that session alive on its own:

  • Before a command calls the API, it renews the session when the access token expires within five minutes. The expiry comes from the token itself.
  • When the API answers 401 INVALID_DEVELOPER_TOKEN, it renews the session once and retries the request once.
  • The new tokens go back to the same place (the OS keychain, or ~/.amba/credentials.json where no keychain is usable), and the new expiry goes to ~/.amba/config.json.
  • Two commands running at the same moment renew the session only once: they share a lock file in ~/.amba, and the second one uses the tokens the first one saved. amba login and amba logout take the same lock, so a renewal in another terminal never undoes them.
  • When a renewal fails while the access token still has a few minutes left, the command uses that token and prints one line saying the session could not be renewed.

Any command run at least once every 30 days keeps the session alive. When the refresh token has expired or was revoked (for example by signing out of the console before the CLI first renewed the session), the command prints one line telling you to run amba login. Personal Access Tokens (amb_dpat_…) never expire on their own and are never renewed.

MCP client configs

amba init writes a Personal Access Token into the user-scope MCP client configs it sets up (~/.claude.json, ~/.cursor/mcp.json, Windsurf), with mode 0600. A project-scope config (.mcp.json, .cursor/mcp.json) is committed with the repository, so an amba entry in one is rewritten to reference the AMBA_PAT environment variable: Bearer ${AMBA_PAT:-} for Claude Code and Bearer ${env:AMBA_PAT} for Cursor. A project config without an amba entry stays as it is, and the user-scope entry serves that project. Where a project config does reference AMBA_PAT, set it to your Personal Access Token (amb_dpat_…) in the environment your editor starts from. AMBA_PAT also authenticates every amba command, so it must hold the PAT; a browser-login session token stops working within a day.

When init replaces a different amba entry, it first copies the old file to ~/.amba/backups/ (mode 0600). Backups that earlier versions left inside the project (.mcp.json.bak-<time>, .cursor/mcp.json.bak-<time>) hold a PAT; init moves them to ~/.amba/backups/ too.

A config file holds a fixed bearer that its client cannot renew, so amba init never writes a browser-login session there; it leaves existing entries as they are and tells you to run amba init --token <pat>. See Browser login and MCP.