Native CLI
Sign in from a terminal, call the twelve tools, move verified files and run hosted productions with the wavemaker CLI. The CLI has no public release yet.
Updated
The wavemaker command-line tool signs you in to Wavemaker, calls the twelve tools, uploads and downloads verified files, runs hosted productions from a brief, and opens a local agent terminal. It is a single native executable for macOS, Linux and Windows. This page covers availability, sign-in, every command group with its flags, JSON output, exit codes and where the CLI keeps its files.
Availability
Releases are built for six targets:
| System | Processor |
|---|---|
| macOS 11 or later | Apple silicon, Intel |
| Linux (static build) | x86-64, Arm64 |
| Windows 10 1903 or later | x64 |
| Windows 11 | Arm64 |
When a release exists, the installers download the archive and its checksum from the same release, check the digest, target, version and publisher signature, and only then replace the binary. They install for your user only, without administrator rights. Homebrew, Scoop and WinGet commands appear on the Download page once those channels are published.
Once installed, these commands manage the installation:
wavemaker --version
wavemaker self status --json
wavemaker self updateself statusshows the version, target, install channel and, when the release is reachable, the latest published version.self update [--version X]replaces a script-installed binary after the same digest and publisher checks. It refuses while a local session supervisor from this configuration is running.- A Homebrew, Scoop or WinGet install is updated by its manager:
self updateexits with code 2 and prints the manager's upgrade command. - Interactive chat offers Update now, Skip or Skip until next version when a newer release is published. Pass
--no-update-checkor setWAVEMAKER_NO_UPDATE_CHECK=1to skip that check.
Sign in
- Select the production service once:
wavemaker service select https://api.wavemaker.io. - Run
wavemaker login. Your browser opens Wavemaker's sign-in and consent page. - Approve the requested permissions. The terminal reports that it is connected.
- Run
wavemaker auth status --jsonto confirm the saved credential.
wavemaker service select https://api.wavemaker.io
wavemaker login
wavemaker auth status --json
# → {"schema":"wmlab.result/1","ok":true,"data":{"service":"https://api.wavemaker.io",
# "credential_source":"local_file","state":"locally_unexpired","expires_at":1793000000.0,
# "environment_token_present":false,"scopes":["read","run","write","agent"]},"error":null}- Sign-in uses OAuth with PKCE and a callback on
127.0.0.1. If no browser opens, the CLI prints the sign-in link; open it on the same computer. - The browser step must finish within 180 seconds, or the command fails with "Sign-in timed out".
loginrequestsread run write agent.login --publishalso requestspublish.- Normal commands renew an expired access token on their own and replay the rejected request once. If renewal is refused, the command fails with
login_required: runwavemaker loginagain in your own terminal. An agent can't complete that browser step for you.
Credential states
auth status reads the saved credential without contacting the service, so a locally valid credential is not proof the service still accepts it.
state | Meaning |
|---|---|
missing | No saved credential for the selected service |
locally_unexpired | A saved credential whose expiry has not passed |
expired | The saved access token has expired; the next service command renews it |
invalid | The saved file can't be read as a credential |
insecure_permissions | The credential file is readable by other users; fix its permissions or sign in again |
present_unverified | WAVEMAKER_TOKEN is set and is used instead of the saved file |
wavemaker auth logout removes the selected service's saved credential. It does not revoke the grant on the server; revoke it in Connections › App grants.
Use a developer credential instead
For CI and other non-interactive use, set WAVEMAKER_TOKEN to a developer credential from Connections › Developer setup. It overrides the saved sign-in and is never renewed: when it expires, commands fail until you replace it. See Client credentials and provider keys.
export WAVEMAKER_SERVICE=https://api.wavemaker.io
export WAVEMAKER_TOKEN="$(cat /path/to/private/credential)"
wavemaker api call read --arguments '{"uri":"wm://credits"}' --jsonGlobal options
These work with every command:
| Option | Environment variable | Meaning |
|---|---|---|
--service ORIGIN | WAVEMAKER_SERVICE | The Wavemaker service for this command; overrides the saved selection |
--json | none | Print the versioned JSON envelope instead of formatted text |
--project PATH | WAVEMAKER_PROJECT | The local working directory; defaults to the current directory |
--config-dir PATH | WAVEMAKER_CONFIG_DIR | A different private configuration directory |
A service origin must be HTTPS, or plain HTTP on your own machine (127.0.0.1, localhost or [::1]). Running wavemaker with no command opens the chat terminal.
Commands
Account and setup
| Command | What it does |
|---|---|
login [--publish] | Sign in to the selected service in the browser |
auth status | Show the saved credential's state without contacting the service |
auth logout | Remove the saved credential for the selected service |
service show | Show the selected service and whether WAVEMAKER_SERVICE is set |
service select ORIGIN | Save the default service for later commands |
doctor [--probe] | Report installed tools, agents and sign-in state; --probe adds read-only service checks |
build-info | Show the executable's version, target and build fingerprint |
self status, self update [--version X] | Inspect or update this installation |
completions SHELL | Print shell completions |
doctor never signs in, refreshes a credential or starts a model turn. doctor --probe reports the saved credential's local state separately from what the service says about it.
Tools and operations
| Command | What it does |
|---|---|
api list [--query TEXT] | List the twelve tool names and the older operations with their scopes, without connecting |
api inspect OPERATION | Show an older operation's request and result schemas |
api call NAME | Call one tool or older operation on the selected service |
api call options:
| Flag | Default | Meaning |
|---|---|---|
--arguments JSON | {} | The arguments object inline |
--file PATH | none | Read the arguments object from a file instead |
--request-id ID | none | The call's idempotency key; required by tools that can spend, unless the arguments set quote_only or validate_only |
--remote-project ID | none | The project a tool call works in |
--timeout SECONDS | 30 | How long to observe the call (1 to 86,400); timing out doesn't cancel or repeat the work |
A tool name sends POST /v1/tools/{tool}. Any other name must be an older operation the CLI knows; an unknown name is refused before anything is sent. --request-id and --remote-project apply only to tools; operations take those values inside their own arguments.
Models
wavemaker models searches the service catalog for models Wavemaker runs and provider routes.
| Flag | Default | Meaning |
|---|---|---|
--query TEXT | none | Case-insensitive name or category search |
--limit N | 25 | Results per page, 1 to 100 |
--cursor NEXT | none | The next page, from the previous page's next |
--timeout SECONDS | 180 | How long to wait; catalog discovery can take over a minute |
--offset, --include-mature and --source self-hosted apply only to a direct Comfy connection; against the service they are refused with argument_invalid, and you page with --cursor instead. A listed model doesn't prove you have credits or provider access for it.
Hosted productions
make asks the hosted Wavemaker agent to produce something from a brief. It creates a session, posts the brief as its first turn, and follows the run until it ends or asks for an approval.
| Flag | Default | Meaning |
|---|---|---|
BRIEF | required | What to make, in plain words |
--quote-only | off | Show the price and start nothing |
--deliverables FILE | none | A JSON array of deliverable specs (id, kind, size or aspect, duration_s and more) |
--attach SHA256 | none | An uploaded input to use; repeatable |
--conversation ID | none | An existing project to continue |
--max-microcredits N | workspace policy | One spending ceiling for the whole run |
--step-by-step | off | The agent asks before each consequential step |
--agent NAME | claude | The hosted agent: claude, codex or opencode on production; staging also runs qwen and deepseek. grok is retired. The service refuses an agent it doesn't run and names the ones it does |
--model NAME | the agent's own | A model the hosted agent offers, such as claude-opus-5-5 (Claude's default), claude-sonnet-5-5 or claude-haiku-5-5; another is refused with the agent's own list |
--request-id ID | a new id | Repeating the same id returns the same run instead of starting another |
--no-wait | off | Return once the run has started |
--timeout SECONDS | 3600 | How long to follow; timing out or Ctrl-C never stops the run |
The run id is the session id. Manage a run with production:
| Command | What it does |
|---|---|
production list | List runs, newest updated first: --state (active or closed), --conversation ID, --limit (1 to 200, default 50) and --before (the previous page's next_before) |
production watch RUN_ID | Show events after --cursor N; --follow waits until the run ends or needs input, up to --timeout SECONDS (default 3600) |
production steer RUN_ID TEXT | Send a follow-up message to the run; options --request-id ID, --attach SHA256 |
production approve RUN_ID APPROVAL_ID | Accept a step-by-step approval, or decline it with --decline; add --note TEXT for the agent |
production interrupt RUN_ID | Stop the run at its current step; running jobs are kept. Refused when the run has no turn running |
steer, approve and interrupt take over the run's controller lease first, so they work from any terminal signed in to the same workspace.
Jobs and files
| Command | What it does |
|---|---|
watch JOB_ID | Follow a job without cancelling it; options --jsonl, --timeout SECONDS (default 600) |
outputs JOB_ID --out DIR | Collect a finished job's files, verified, without overwriting existing files |
cancel JOB_ID | Request cancellation of a job you own |
files upload PATH | Upload a file and print its sha256; options --resumable, --resume-file FILE |
files download KIND ID --out PATH | Download a file you own and verify its full hash |
files download takes KIND artifact, input, package, project or model (a model also needs --version). Other flags: --file, --revision, --chunked, --timeout (default 600 seconds), and --resume or --discard with --workspace-scope for resumable transfers. Downloads refuse an existing destination. File transfers allow 600 seconds each by default.
When a resumable upload fails after the service acknowledged part of it, keep the error.details.resume object from the reply privately and pass it back with --resume-file.
Projects, inputs and artifacts
| Command | What it does |
|---|---|
projects list | List projects; filters include --query, --state (active, archived, trash or all), --pinned, --limit (default 25) and --cursor |
projects inspect ID [--revision N] | Read a project at its current or an earlier revision |
projects rename ID --name NAME --revision N --request-id ID | Rename a project |
projects save GRAPH --name NAME [--id ID --revision N] | Create a project from a graph, or save its next revision |
inputs list, inputs inspect SHA256 | Inspect uploaded inputs |
artifacts inspect SHA256 | Inspect an output artifact |
Graphs and Comfy
| Command | What it does |
|---|---|
graph inspect, validate, diff, slice, bind, import, fragment | Inspect, check, compare and edit Comfy API graphs without running them |
run GRAPH --request-id ID | Submit a graph with its inputs and request identity; options --set, --input, --wait, --max-microcredits N, --timeout SECONDS (default 600) |
nodes search [QUERY], nodes inspect NAME | Read the selected runtime's node schemas |
runtime connect URL, runtime inspect, runtime disconnect | Select or forget a direct Comfy connection |
Without a direct Comfy connection, these commands use the selected Wavemaker service. With one, run and models work against your own Comfy and need no Wavemaker sign-in. See Graph portability.
Local agent terminal
| Command | What it does |
|---|---|
chat [PROMPT] | Open Wavemaker's terminal with an agent installed on this computer |
setup, init | Install Wavemaker's guidance in the project without overwriting your edits |
session start, turn, events, approve, interrupt, stop and more | Drive a local agent session from scripts |
workspace inspect, import PATH, export FILE --out PATH | Copy files into or out of a session's working folder |
chat options include --agent codex|grok|claude (default codex), --model, --native to open the agent's own interface, --print-command to show what would run, --shared-workspace to edit the project directory in place, --import FILE, --no-splash and --permission-mode oneshot|accept-edits|plan|auto.
chat --agent picks a program installed on your computer, signed in with its own provider account; that is separate from your Wavemaker account and from make --agent, which picks the hosted agent. wavemaker doctor lists the agents it finds. Chat needs an interactive terminal; use session commands for automation.
Other commands
runs lists a direct Comfy connection's runs. media, provider voices, assets voice, agent-models, tools and exec cover local media rendering, voice catalogs, saved voices, self-hosted agent model profiles, the command catalog and explicit native programs. Run wavemaker COMMAND --help for each one's flags.
JSON output
With --json, every command prints one line of JSON on stdout:
{"schema": "wmlab.result/1", "ok": true, "data": {}, "error": null}- On success,
dataholds the result. A tool call'sdatais the service's{data, job, cost, hints}, so a job id is atdata.job.id. - On failure,
okisfalseanderroris{code, message, details}. Branch onerror.code. - Invalid arguments with
--jsonalso produce an envelope, with codeargument_invalid. - Without
--json, results are formatted for reading and errors go to stderr. --jsoncan't wrap the chat terminal,execorcompletions; usechat --print-command --jsonto inspect chat.
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | The command failed: a service refusal, a network or sign-in failure, a check that reported not valid or not ready, or a result whose state is failed, cancelled, indeterminate or deleted |
| 2 | Invalid arguments or JSON, a local check that failed before anything was sent (such as an invalid graph or a missing input), or an install a package manager owns |
| 130 | Interrupted with Ctrl-C; work already sent may still be running |
chat exits with the agent program's own exit code.
Common error codes
| Code | What happened | What to do |
|---|---|---|
login_required | The saved sign-in was refused and couldn't be renewed | Run wavemaker login in your own terminal |
auth_renewal_failed | Renewing the sign-in didn't finish | Run the command again |
credential_changed | The saved sign-in changed while the command ran | Run the command again |
observation_stopped | The --timeout passed or you pressed Ctrl-C | The work continues; watch it again or repeat with the same --request-id |
transport_error | The connection failed; the request was not replayed | Repeat with the same --request-id, or read the original result |
request_conflict | A --request-id was reused for different work | Use a new id for new work |
install_managed | A package manager owns this install | Run the printed upgrade command |
argument_invalid | A flag or argument is invalid | Check wavemaker COMMAND --help |
Service errors such as insufficient_credits, scope_denied or rate_limited pass through with their own codes. See Errors and retries.
Configuration files
| System | Directory |
|---|---|
| macOS and Linux | ~/.config/wavemaker |
| Windows | %LOCALAPPDATA%\Wavemaker |
settings.jsonholds the service saved withservice selectorlogin.- One credential file per service origin, kept outside your projects. The directory is private to your user.
update-check.jsoncaches the latest published version for a day.- Use
--config-dirorWAVEMAKER_CONFIG_DIRto keep a separate set, for example per CI job.
The service is chosen in this order: --service, then WAVEMAKER_SERVICE, then the saved selection, then the build's default. Never put credentials in graphs, command arguments, source control or shared logs.
Worked examples
Search the catalog and read a route's request schema:
wavemaker api call search --arguments '{"query":"vertical video ad","kinds":["card","format"],"limit":5}' --json
wavemaker models --query kling --json
wavemaker api call read --arguments '{"uri":"wm://route/kling.video"}' --jsonPrice a call, run it, then collect the result:
wavemaker api call generate --file still.json --json # still.json sets "quote_only": true
wavemaker api call generate --file still-run.json --request-id hero-still-v1 --json
# → {"schema":"wmlab.result/1","ok":true,"data":{"data":{...},"job":{"id":"9b1e...","state":"queued"},"cost":{...},"hints":[]},"error":null}
wavemaker watch 9b1e... --timeout 600
wavemaker outputs 9b1e... --out ./outputsIf the observation times out, repeat the api call with the same --request-id. The service returns the original job and never runs it twice.
Have the hosted agent make an ad:
wavemaker make "A 15-second vertical video ad for a coffee shop" --quote-only --json
wavemaker files upload logo.png --json
wavemaker make "A 15-second vertical video ad for a coffee shop" \
--deliverables deliverables.json --attach SHA256 --request-id coffee-ad-1
wavemaker production steer RUN_ID "Make the end card brighter."Cancel a job explicitly:
wavemaker api call write --arguments '{"uri":"wm://job/JOB_ID","cancel":true}' --json