@usewax/cli
v0.2.5
Published
Wax CLI -- agent.toml is the source of truth; wax deploy is one command.
Readme
@usewax/cli
Wax CLI — agent.toml is the source of truth. wax deploy is one command.
Install
# Global install (pinned)
bun add -g @usewax/[email protected]
# or
npm install -g @usewax/[email protected]
# Companion SDK for in-app agents
bun add @usewax/[email protected]Quickstart
# Install dependencies and build (from a checkout)
bun install && bun run build
# Authenticate (opens a browser; see Authentication below)
wax login
# Create a new agent
wax init my-agent
# Edit my-agent.toml, then validate
wax validate my-agent.toml
# Run offline simulation (no API call)
wax dev my-agent.toml --offline
# Deploy (requires WAX_ADMIN_TOKEN — see Wave 3 note below)
WAX_ADMIN_TOKEN=your-token wax deploy my-agent.tomlFrom a local checkout, every
waxinvocation maps to./dist/index.jsafterbun run build, orbun run src/index.tsfor dev (no build needed).
Commands
Authentication and identity
| Command | Description |
|---------|-------------|
| wax login | Browser OAuth via the Device Authorization Grant (RFC 8628) — opens a browser, prints a confirmation code, polls until approved |
| wax login --token <wax_live_...> | Save a raw Bearer key directly (the supported path for CLI/SDK/MCP). Reads from stdin or an interactive hidden prompt if the value is omitted |
| wax login --service-account <file> | Advanced/CI: exchange a service-account key file (workspace_id + key_id + private_key) for a short-lived token using HMAC proof-of-possession |
| wax login --api-url <url> | Override the API base URL for the login (default https://wax-agent.fly.dev) |
| wax logout [--all] | Remove saved credentials from the OS keychain (--all clears every workspace) |
| wax whoami [--no-verify] | Show the authenticated workspace and user (calls GET /v1/auth/me; --no-verify prints stored info only) |
| wax workspace list \| use <id> \| current | List, switch, or show the active workspace |
Authoring and shipping agents
| Command | Description |
|---------|-------------|
| wax init <name> | Scaffold a new agent project (--template, --medium phone\|in-app, --provider voxtral\|elevenlabs\|cartesia, --from-el <id>) |
| wax validate [path] | Validate schema; report errors with field paths |
| wax deploy [path] | Validate, compile, and deploy; version is stored but NOT activated (traffic unchanged) |
| wax deploy [path] --activate | Deploy AND immediately activate the new version (makes it live in one step) |
| wax deploy [path] --dry-run | Validate and compile only; no API calls |
| wax rollback [hash] | List or re-apply a previously deployed plan |
| wax agents list | List agents in the active workspace |
| wax agents get <name> | Show agent config + deployment metadata |
| wax agents create --from <file> | Create an agent from a local agent.toml |
| wax agents delete <name> [--yes] | Delete (archive) an agent, with confirmation |
| wax agents set-voice <id> --primary <provider:voice_id> | Set primary/secondary voice and the cross-provider-clone flag |
| wax tail --agent <name> | Stream production session logs (requires Wave 3 — not yet available) |
Testing locally
| Command | Description |
|---------|-------------|
| wax dev [path] | Offline simulation using agent.toml prompt (single-turn) |
| wax dev [path] --offline | Force offline stub (no API call) |
| wax dev [path] --turns N --persona "..." | Drive N alternating turns with a tester persona |
| wax dev [path] --turns N --persona "..." --judge | Add an end-of-call pass/fail LLM verdict |
Migration and onboarding
| Command | Description |
|---------|-------------|
| wax migrate <el-export.json> | Convert an ElevenLabs agent export to agent.toml (writes to stdout) |
| wax migrate <el-export.json> --out agent.toml | Write the generated agent.toml to a file (-o alias) |
| wax migrate <el-export.json> --strict | Treat warnings/dropped fields as errors (non-zero exit) |
| wax onboard | Migrate plus scaffold from a source provider (ElevenLabs in v1) |
Provider keys and billing (BYOK)
| Command | Description |
|---------|-------------|
| wax byok list | List configured provider keys (status + prefix only — never plaintext) |
| wax byok set <provider> | Add or replace a key for a provider (e.g. wax byok set groq); paste hidden or pipe with --from-stdin |
| wax byok remove <provider> [--yes] | Remove a provider key (confirmation unless --yes) |
| wax billing status | Show billing mode, balance, and auto-reload config |
| wax billing mode <prepaid\|byok> | Switch billing mode |
| wax billing topup <usd> | Add prepaid credits |
| wax pipeline get \| set \| list-models | Read/write an agent's STT/LLM/TTS pipeline slots |
| wax voice list \| preview \| clone \| clones \| status | Browse the voice catalog, preview, and manage voice clones |
Diagnostics and maintenance
| Command | Description |
|---------|-------------|
| wax doctor [--verbose] [--config <path>] | Diagnose environment: credentials, network, workspace, agent.toml, version compatibility |
| wax update [--check-only] [--yes] | Check for and install a newer CLI version |
| wax completion <bash\|zsh\|fish> | Print a shell completion script |
--json is accepted globally (or set WAX_OUTPUT=json) for machine-readable output.
Authentication
wax login supports three paths, in order of how most users reach them:
- Browser OAuth (default). Run
wax loginwith no flags. The CLI POSTs to/v1/cli/device/authorize, opens your browser to the server-returnedverification_uri_complete, prints a confirmation code, and polls/v1/cli/tokenuntil you approve. This is the Device Authorization Grant (RFC 8628). On success the short-lived token is written to the OS keychain. - Raw Bearer key (
wax login --token <wax_live_...>). This is the supported path for the CLI, SDK, and MCP server — paste a long-lived workspace key and it is stored for all subsequent commands. If you omit the value (--token), the key is read from stdin (piped) or a hidden interactive prompt so it never lands in shell history. - Service account (
wax login --service-account <file>, advanced/CI). The key file is JSON withworkspace_id,key_id, andprivate_key. The raw private key is never sent over the wire: the CLI computes an HMAC proof-of-possession signature over a nonce and exchanges it at/v1/auth/service-account-exchange. The CLI warns if the key file lives inside a git repository.
The resolved token precedence at call time is: WAX_TOKEN env var (also
WAX_ADMIN_TOKEN for back-compat) > OS keychain entry for the active workspace >
flat-file fallback. Set WAX_TOKEN in CI to override stored credentials. Run
wax whoami to confirm your identity, or wax doctor to diagnose credential and
network issues.
Note:
wax deploycurrently gates specifically on theWAX_ADMIN_TOKENenv var (see the Wave 3 note), so set it explicitly when deploying.
BYOK (bring your own provider keys)
Attach per-workspace provider keys so sessions run on your own upstream accounts:
# Interactive hidden paste
wax byok set groq
# CI-friendly: pipe from an env var (avoids shell history)
echo "$GROQ_KEY" | wax byok set groq --from-stdin
# Review and remove
wax byok list
wax byok remove groq --yesValid providers: anthropic, baseten, cartesia, cerebras, deepgram,
elevenlabs, fireworks, google, groq, mistral, openai,
openai_compatible, openai_realtime, together. The CLI never prints the
plaintext of a stored key — only the prefix, status, and last-used/validated
timestamps.
Migrating from ElevenLabs
# Convert an exported ElevenLabs agent to agent.toml
wax migrate el-export.json --out agent.toml
# Then validate and deploy
wax validate agent.toml
wax deploy agent.toml--strict exits non-zero if the conversion produces any warnings or drops fields
that have no Wax equivalent. Warnings and dropped-field notes print to stderr so
piping stdout to a file yields clean TOML.
Multi-turn dev mode
wax dev defaults to single-turn: one user message, one assistant reply. For comparison runs and fixture exercise, pass --turns N together with a --persona "..." description and the CLI will drive N alternating turns — the tester-persona LLM drafts each user message conditioned on the full prior transcript, the backend /simulate endpoint returns the agent reply, and the loop repeats. Add --judge to get a one-line pass/fail verdict at the end. Multi-turn and judge calls require ANTHROPIC_API_KEY for the tester/judge LLM (override the model with WAX_DEV_PERSONA_MODEL). Example: wax dev my-agent.toml --turns 3 --persona "First-time caller asking about pricing tiers" --judge.
agent.toml Schema
Eight sections — no more, no less:
name = "my-agent" # 3-64 chars, lowercase alphanumeric + hyphens
# IMPORTANT: prompt must come before any [section] headers in the file,
# because TOML assigns bare keys to the most recently opened section.
prompt = """
Your system prompt here.
"""
[voice]
primary = { provider = "voxtral", voice_id = "..." }
# optional: secondary = { provider = "elevenlabs", voice_id = "..." }
cross_provider_clone = true
[llm]
primary = { provider = "anthropic", model = "claude-sonnet-4-6", temperature = 0.5 }
# optional: secondary = { provider = "mistral", model = "mistral-medium-3" }
[[knowledge]] # repeatable; default empty
type = "folder" # "folder" | "url" | "git"
source = "./kb"
citation_required = true
[[tools]] # repeatable; default empty
name = "lookup_procedure" # ^[a-z_][a-z0-9_]*$
runtime = "server" # "server" | "client"
timeout_ms = 5000
# Exactly ONE of [telephony] or [sdk]:
[telephony]
region = "us"
inbound = true
outbound = false
# OR:
[sdk]
app_id = "app-001"
domains = []
transparent_reconnect = true
[governance]
capture_retention_hours = 72
refusals = ["bypass safety"]
allowed_languages = ["en"]Deploy and Activate
wax deploy compiles a content-addressed plan and POSTs it to
POST /v1/agents/{id}/deploy, creating a new agent version. By default the version
is stored but not activated — traffic continues to whatever version is currently
live, giving you time to inspect or promote at will.
To deploy and activate in a single command:
wax deploy my-agent.toml --activateThis calls POST /v1/agents/{id}/versions/{vid}/activate immediately after a
successful deploy, atomically swapping the live version. The CLI prints:
Deployed: my-agent version_id: <uuid>
Activated version <uuid> — now serving.To activate a version independently (e.g. after a staged rollout review):
curl -X POST https://wax-agent.fly.dev/v1/agents/<id>/versions/<vid>/activate \
-H "Authorization: Bearer $WAX_ADMIN_TOKEN"The deploy command compiles a content-addressed plan (verifiable via plan_hash),
writes the plan to a local cache for rollback, and records the version_id in its
JSON output for scripting.
Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| WAX_TOKEN | — | Auth token; highest precedence (overrides keychain and flat file). Preferred in CI |
| WAX_ADMIN_TOKEN | — | Back-compat alias for WAX_TOKEN; wax deploy reads this name specifically |
| WAX_API_URL | https://wax-agent.fly.dev | Override API base URL |
| WAX_OUTPUT | — | Set to json for machine-readable output (same as --json) |
| WAX_SIM_OFFLINE | — | Set to 1 to force offline simulation |
| ELEVENLABS_API_KEY | — | Fallback key for wax init --from-el when --el-key is not passed |
| ANTHROPIC_API_KEY | — | Required for wax dev --turns N and --judge (tester-persona and judge LLM calls) |
| WAX_DEV_PERSONA_MODEL | claude-haiku-4-5 | Override the Anthropic model used for tester/judge calls |
Development
# Run tests
bun test
# Type-check without emitting
bun run lint
# Build to dist/
bun run build
# Run the CLI in dev (no build needed)
bun run src/index.ts --help