Waterglass Waves CLI
waves is the command-line tool for the Waves API. It covers everything a
workspace member can do: agents, environments, runs, schedules, triggers, vaults,
memory, skills, knowledge bases, usage and billing.
It is made for scripts and AI coding agents as well as for people:
- A command that works prints the API's answer as JSON on stdout.
- An error prints one JSON object on stderr.
- Every exit code has a meaning, so a script or an agent can act on the result without reading any prose.
--followstreams a run's events as NDJSON.waves schema <Name>prints exactly what the API checks.
This reference describes the version of the CLI you have. The same text is in three places:
- the web page https://waves.waterglass.ai/cli
- plain Markdown at https://waves.waterglass.ai/cli/CLI.md, for use as agent context
- the output of
waves docs
Install
curl -fsSL https://waves.waterglass.ai/cli/install.sh | bash
waves --version # {"version":"…"}
- The script installs one file into
~/.local/bin, after checking its SHA-256. - It needs Node 22 or newer, and nothing else: no package manager, no sudo, and nothing outside $HOME.
WAVES_INSTALL_DIRinstalls it somewhere else.- Install Waves CLI, on the console's Dashboard, shows the same command for the address you are signed in to.
You can also download the file without the script. Then nothing checks the file,
or whether it runs:
curl -fsSL https://waves.waterglass.ai/cli/waves -o ~/.local/bin/waves && chmod +x ~/.local/bin/waves.
Setup
At a terminal, log in:
waves login
- It asks for the API key without showing it, and checks it against
/v1/mebefore it stores anything. - It writes
~/.config/waves/config.json, readable only by you, with this profile as the default. - There is no
--keyflag on purpose. Arguments show up inpsand in your shell history. - Scripts pipe the key in:
printf %s "$KEY" | waves login --key-stdin. - The CLI talks to the production API,
https://api.waves.waterglass.ai.--api-urlorWAVES_API_URLpicks another address.
An agent or a CI system is usually set up with environment variables instead:
export WAVES_API_KEY=waves_live_… # an API key from the console
export WAVES_API_URL=… # only for another address, the production API is the default
waves me # check it works: prints {via, tenant_id, …}
You can also set up profiles by hand:
waves config set profiles.prod.api_url https://api.waves.waterglass.ai
printf %s "$KEY" | waves config set profiles.prod.api_key -
waves config set default_profile prod
The CLI takes each setting from the first of these that has it:
- the flags
--api-urland--profile - the environment variables
WAVES_API_URL,WAVES_API_KEYandWAVES_PROFILE - the profile
- the production API
Only the key has no default. Without one, a command fails with missing_api_key.
Output and errors
- A command that works prints the API's answer unchanged, as formatted JSON, and
exits with 0.
-qprints only the main id, such asses_…. - An error prints one JSON line on stderr:
{"error":"<code>","status":…, …}.erroris the server's code, unchanged. Some codes come with more fields:version_conflictcarriescurrent_version. - The CLI has a few codes of its own:
usage_error,local_validation_failed,network_error,missing_api_url,missing_api_key,wait_timeout,not_supportedandconfig_invalid. - A 429 is retried automatically, up to 3 times, after the wait in
Retry-After.--no-retryturns this off. - After a network error, only GET requests are retried. A request that changes something is never retried automatically.
Exit codes
| code | meaning |
|---|---|
| 0 | success, including --wait or --follow on a run that succeeded |
| 1 | an unexpected CLI error |
| 2 | a usage error, or the local check failed |
| 3 | a network failure |
| 4 | not allowed (401 or 403, or no API key) |
| 5 | not found (404) |
| 6 | a conflict (409, such as version_conflict, stale_version or session_not_active) |
| 7 | an invalid request (400) |
| 8 | rate limited (429, after the retries) |
| 9 | a server error (5xx) |
| 10 | the run ended failed (--wait or --follow) |
| 11 | the run ended interrupted: someone stopped it, or it reached one of its limits |
| 12 | the run ended deleted |
| 13 | waiting timed out, and the run keeps going |
| 14 | the run waits for approval. --wait and --follow stop, and the run continues once someone decides |
Streaming (--follow)
--follow prints NDJSON frames on stdout until the run ends. It reads the
events endpoint every second, and --after <seq> resumes without losing any
events.
{"kind":"session","session":{…}} (runs create --follow: the new run)
{"kind":"event","seq":3,"type":"…",…} (each event, in seq order)
{"kind":"status","status":"running"} (each change of status)
{"kind":"approval","approval_id":"apr_…","status":"waiting"} (a request is open: the stream stops, exit 14)
{"kind":"end","status":"succeeded","session":{…}} (the last frame)
Conventions
- In the API, a run is called a session. The path is
/v1/sessions, and run ids start withses_. The CLI accepts bothwaves runs …andwaves sessions …. - Secrets never go into an argument. A credential's value comes from stdin (the
default when you pipe it), from
--value-fileor from--value-env NAME. - Agent configs are YAML, sent exactly as written, so their comments are kept in the version history. The CLI checks them locally with the server's own schema first.
waves agents initprints a starter config.waves agents get <id> --yamlprints the stored YAML, ready to edit and send back withupdate -f.- To update safely, pass the version you edited:
waves agents update <id> -f agent.yaml --expected-version N.--if-currentfetches the current version and tries once. A 409 means someone else saved first, and the CLI never retries that for you. - For an endpoint without its own command, use
waves api <METHOD> <path> [--data @f|-].
Global flags
| flag | description |
|---|---|
--api-url <url> | API base url (overrides WAVES_API_URL/profile) |
--profile <name> | config profile (overrides WAVES_PROFILE) |
-q, --quiet | print only the primary id of the result |
--verbose | log requests to stderr (secrets redacted) |
--no-retry | disable automatic retries (429/network) |
-h, --help | show help |
Commands
waves agents
waves agents archive <id>
Archive an agent. Archiving it again changes nothing.
Wire: POST /v1/agents/:id/archive
waves agents create [flags]
Create an agent from a YAML or JSON config. This saves version 1.
Wire: POST /v1/agents
| flag | description |
|---|---|
-f, --file <path|-> | YAML config file, sent as config_yaml exactly as written ('-' = stdin) |
waves agents delete <id>
Delete an agent for good. Fails with 409 while a schedule, a trigger or an active run uses it.
Wire: DELETE /v1/agents/:id
waves agents get <id> [flags]
Get an agent. With --yaml, print only its stored YAML config, ready to edit and update.
Wire: GET /v1/agents/:id
| flag | description |
|---|---|
--version <n> | return this older config version instead |
--yaml | print only config_yaml (pipe to a file, edit, update) |
waves agents get agt_x
waves agents get agt_x --yaml > agent.yaml # edit, then: waves agents update agt_x -f agent.yaml --if-current
waves agents init [flags]
Print a starter agent config with comments. It passes the AgentConfig schema.
| flag | description |
|---|---|
-o, --output <path> | write to a file instead of stdout |
waves agents init -o agent.yaml
waves agents list [flags]
List agents.
Wire: GET /v1/agents
| flag | description |
|---|---|
--include_archived | set to true to include archived rows |
waves agents update <id> [flags]
Update an agent. Each update saves a new version. Pass the version you edited as expected_version.
Wire: POST /v1/agents/:id
| flag | description |
|---|---|
-f, --file <path|-> | YAML config file, sent as config_yaml exactly as written ('-' = stdin) |
--expected-version <n> | the version this change is based on |
--if-current | fetch the current version and try once with it (a 409 still fails, and nothing is retried) |
waves agents validate [flags]
Check an agent config locally against the server's own schema, without calling the API.
| flag | description |
|---|---|
-f, --file <path|-> | the YAML config ('-' = stdin) |
waves agents validate -f agent.yaml
waves agents versions <id>
List an agent's versions.
Wire: GET /v1/agents/:id/versions
waves agents webhook get <id>
Get an agent's webhook: its address, its status and its last delivery. Returns null when the agent sends none.
Wire: GET /v1/agents/:id/webhook
waves agents webhook reveal <id>
Show an agent's webhook signing secret. Workspace owners only.
Wire: POST /v1/agents/:id/webhook/reveal
waves agents webhook rotate-secret <id>
Replace an agent's webhook signing secret. The old one stops working right away. Workspace owners only.
Wire: POST /v1/agents/:id/webhook/rotate-secret
waves agents webhook test <id>
Send a signed test message to an agent's webhook now, and show the reply.
Wire: POST /v1/agents/:id/webhook/test
waves agents webhook update <id> [flags]
Turn an agent's webhook off, or on again. Turning it on clears its failures.
Wire: PATCH /v1/agents/:id/webhook
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe agents.webhook.update) |
waves api
waves api <method> <path> [flags]
Call any endpoint directly. Auth, errors and retries are handled for you.
<method>: GET|POST|PUT|PATCH|DELETE<path>: such as /v1/agents
| flag | description |
|---|---|
-d, --data <json|@file|-> | JSON request body |
waves api GET /v1/models
waves api POST /v1/vaults --data '{"name":"ci"}'
waves approvals
waves approvals decide <id> [flags]
Approve or decline a waiting request. Only members the agent allows can decide, and a key that can write decides as the member who created it. A message of up to 2,000 characters reaches the agent when you decline, or when you approve a question.
Wire: POST /v1/approvals/:id/decide
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe approvals.decide) |
waves approvals get <id>
Get one approval request: what the run wants to do, and whether you may decide.
Wire: GET /v1/approvals/:id
waves approvals list [flags]
List approval requests, newest first, a page at a time.
Wire: GET /v1/approvals
| flag | description |
|---|---|
--status <enum> | filter by status (pending|approved|declined|expired|cancelled) |
--session <string> | filter by run id |
--limit <int> | page size, 1-100 (default 100) |
--cursor <string> | next_cursor from the previous page (leave out for the first) |
waves billing
waves billing balance
Your credit balance in cents, split into given and bought credit.
Wire: GET /v1/billing/balance
waves billing current
Spend so far this month, per model, with a projection for the whole month.
Wire: GET /v1/billing/current
waves billing invoices
List your invoices, newest first. Each one links to its page at Stripe.
Wire: GET /v1/billing/invoices
waves billing topup [flags]
Start a Stripe checkout to buy credit. Returns the address to open.
Wire: POST /v1/billing/topup
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe billing.topup) |
waves config
waves config list
Show the config file and its path, with API keys hidden.
waves config set <key> <value>
Set a config value by its dot path. Use '-' to read the value from stdin, as for api_key.
<key>: such as profiles.prod.api_url or default_profile<value>: '-' = stdin
waves config set profiles.prod.api_url https://api.waves.waterglass.ai
waves config set default_profile prod
printf %s "$KEY" | waves config set profiles.prod.api_key -
waves describe
waves describe <operation>
Describe one operation: its route, auth, query parameters, and request and response JSON Schemas.
<operation>: an id fromwaves ops, such as agents.create
waves describe agents.create
waves docs
waves docs
Print the full CLI reference, the same text as waves.waterglass.ai/cli.
waves environments
waves environments archive <id>
Archive an environment. Archiving it again changes nothing.
Wire: POST /v1/environments/:id/archive
waves environments create [flags]
Create an environment: the sandbox size and its network access.
Wire: POST /v1/environments
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe environments.create) |
waves environments delete <id>
Delete an environment for good. Fails with 409 while a schedule, a trigger or an active run uses it.
Wire: DELETE /v1/environments/:id
waves environments get <id>
Get an environment.
Wire: GET /v1/environments/:id
waves environments list [flags]
List environments.
Wire: GET /v1/environments
| flag | description |
|---|---|
--include_archived | set to true to include archived rows |
waves environments update <id> [flags]
Update an environment. Send only the fields you change.
Wire: POST /v1/environments/:id
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe environments.update) |
waves health
waves health
Check that the API is up.
Wire: GET /healthz
waves knowledge
waves knowledge bases archive <id>
Archive a knowledge base. Reads still work, and writes fail with 409.
Wire: POST /v1/knowledge-bases/:id/archive
waves knowledge bases create [flags]
Create a knowledge base.
Wire: POST /v1/knowledge-bases
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe knowledge.bases.create) |
waves knowledge bases delete <id>
Delete a knowledge base and its documents for good. Fails with 409 while an agent uses it.
Wire: DELETE /v1/knowledge-bases/:id
waves knowledge bases get <id>
Get a knowledge base.
Wire: GET /v1/knowledge-bases/:id
waves knowledge bases list [flags]
List knowledge bases.
Wire: GET /v1/knowledge-bases
| flag | description |
|---|---|
--include_archived | set to true to include archived rows |
waves knowledge bases update <id> [flags]
Rename a knowledge base or change its description.
Wire: POST /v1/knowledge-bases/:id
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe knowledge.bases.update) |
waves knowledge documents create <id> [flags]
Add a document: Markdown or plain text, or a PDF in base64 to take the text from.
Wire: POST /v1/knowledge-bases/:id/documents
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe knowledge.documents.create) |
waves knowledge documents delete <id> <documentId>
Delete a document for good.
Wire: DELETE /v1/knowledge-bases/:id/documents/:documentId
waves knowledge documents get <id> <documentId>
Get one document: its full text and its version.
Wire: GET /v1/knowledge-bases/:id/documents/:documentId
waves knowledge documents list <id>
List a base's documents, without their text. Get one by id to read it.
Wire: GET /v1/knowledge-bases/:id/documents
waves knowledge documents update <id> <documentId> [flags]
Update a document. Pass its expected_version.
Wire: POST /v1/knowledge-bases/:id/documents/:documentId
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe knowledge.documents.update) |
--expected-version <n> | the version this change is based on |
--if-current | fetch the current version and try once with it (a 409 still fails, and nothing is retried) |
waves knowledge search <id> [flags]
Search a knowledge base by keyword and meaning, the same way agents search it.
Wire: GET /v1/knowledge-bases/:id/search
| flag | description |
|---|---|
--q <string> | search terms, in web search syntax |
--limit <int> | max results, 1-20 (default 10) |
waves login
waves login [flags]
Check an API key against the API, then store it in a config profile.
| flag | description |
|---|---|
--key-stdin | read the key from stdin instead of prompting (for scripts) |
waves login --api-url https://api.waves.waterglass.ai
printf %s "$KEY" | waves login --api-url https://api.waves.waterglass.ai --key-stdin
waves logout
waves logout
Remove a stored profile: its API key, its address, and the default if it pointed here.
waves logout
waves logout --profile staging
waves mcp
waves mcp test [flags]
Test an MCP server by connecting to it from the sandbox host.
Wire: POST /v1/mcp/test
| flag | description |
|---|---|
--url <https://…/mcp> | the MCP server URL (required) |
--auth <none|from_vault> | where the token comes from (default none) |
--vault <vlt_id> | vaults to take the token from (with --auth from_vault) |
waves mcp test --url https://mcp.deepwiki.com/mcp
waves mcp test --url https://mcp.example.com/mcp --auth from_vault --vault vlt_x
waves me
waves me
Show who you are: the kind of credential, the user and the workspace.
Wire: GET /v1/me
waves memory
waves memory entries delete <id> <key>
Delete an entry for good.
Wire: DELETE /v1/memory-stores/:id/entries/:key
waves memory entries get <id> <key>
Get one entry: its value and its version.
Wire: GET /v1/memory-stores/:id/entries/:key
waves memory entries list <id>
List a store's entries, without their values. Read a value by its key.
Wire: GET /v1/memory-stores/:id/entries
waves memory entries put <id> <key> [flags]
Create or update a memory entry. Choose exactly one way to handle its version.
Wire: PUT /v1/memory-stores/:id/entries/:key
<id>: store id
| flag | description |
|---|---|
--value <json> | the value inline, as JSON (bare text is sent as a string, with a warning) |
--value-file <path> | read the value from a file |
--value-stdin | read the value from stdin (default when piped) |
--expected-version <n> | replace exactly this version (otherwise 409 stale_version) |
--create | the key must be new (otherwise 409 version_required) |
--force | fetch the current version and try once with it (the last write wins) |
waves memory entries put mem_x report-cursor --value '{"day":"2026-07-23"}' --expected-version 4
cat state.json | waves memory entries put mem_x state --create
waves memory stores archive <id>
Archive a memory store. Reads still work, and writes fail with 409.
Wire: POST /v1/memory-stores/:id/archive
waves memory stores create [flags]
Create a memory store.
Wire: POST /v1/memory-stores
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe memory.stores.create) |
waves memory stores delete <id>
Delete a memory store and all its entries for good. Fails with 409 while an agent uses it.
Wire: DELETE /v1/memory-stores/:id
waves memory stores get <id>
Get a memory store.
Wire: GET /v1/memory-stores/:id
waves memory stores list [flags]
List memory stores.
Wire: GET /v1/memory-stores
| flag | description |
|---|---|
--include_archived | set to true to include archived rows |
waves memory stores update <id> [flags]
Rename a memory store or change its description.
Wire: POST /v1/memory-stores/:id
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe memory.stores.update) |
waves models
waves models list
List the models you can use: id, provider, name, where each is processed, and its price in euro per million tokens, markup included.
Wire: GET /v1/models
waves ops
waves ops
List every API operation the CLI knows: id, route, auth and summary.
waves org
waves org data-use get
Get what Waves may analyse in this workspace: content, metadata or off.
Wire: GET /v1/org/data-use
waves org get
Get your workspace: its id, its name and its permanent slug.
Wire: GET /v1/org
waves overview
waves overview
Summarise the workspace: how many of each resource, run figures, and recent and failed runs.
Wire: GET /v1/overview
waves run-webhook
waves run-webhook get
Get the start of the secret that signs run.finished messages. Null until the first signed message makes one.
Wire: GET /v1/run-webhook
waves run-webhook reveal
Show the secret that signs run.finished messages. Workspace owners only.
Wire: POST /v1/run-webhook/reveal
waves run-webhook rotate-secret
Make a new secret that signs run.finished messages, the first one or a replacement. The old one stops working right away. Workspace owners only.
Wire: POST /v1/run-webhook/rotate-secret
waves run-webhook test [flags]
Send a test message to an address now, and show the reply.
Wire: POST /v1/run-webhook/test
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe run-webhook.test) |
waves runs
waves runs approvals <id> [flags]
List a run's approval requests, newest first.
Wire: GET /v1/sessions/:id/approvals
| flag | description |
|---|---|
--status <enum> | filter by status (pending|approved|declined|expired|cancelled) |
--limit <int> | page size, 1-100 (default 100) |
--cursor <string> | next_cursor from the previous page (leave out for the first) |
waves runs artifacts delete <id> <artifactId>
Delete one artifact for good. Without its output files, a run can no longer be resumed.
Wire: DELETE /v1/sessions/:id/artifacts/:artifactId
waves runs artifacts download <id> <artifactId> [flags]
Download an artifact to a file with -o, or to stdout with -o -.
Wire: GET /v1/sessions/:id/artifacts/:artifactId/download (302)
| flag | description |
|---|---|
-o, --output <path|-> | write the artifact here ('-' writes the raw bytes to stdout). Without it, the download link is printed. |
waves runs artifacts download ses_x art_y -o workspace.tar.gz
waves runs artifacts list <id>
List a run's artifacts: the files it was sent and the archive of its output files.
Wire: GET /v1/sessions/:id/artifacts
waves runs create [flags]
Create and start a run. The command returns right away. Add --follow or --wait to wait for the result.
Wire: POST /v1/sessions
| flag | description |
|---|---|
--agent <agt_id> | agent id (required) |
--environment <env_id> | environment id (required) |
--prompt <text> | the prompt text inline |
--prompt-file <path> | read the prompt from a file |
--prompt-stdin | read the prompt from stdin |
--title <text> | run title |
--vault <vlt_id> | attach a vault (repeatable, max 10) |
--model <provider/model> | override the agent's model for this run |
--fallback-model <provider/model> | override the fallback model for this run (requires --model) |
--max-turns <n> | override limits.max_turns |
--max-runtime-min <n> | override limits.max_runtime_minutes |
--max-cost-eur <eur> | override limits.max_cost_eur |
--file <path> | send a file with the run into ./inputs/ (repeatable, up to 10 files and 25 MB in total). The agent needs input_files.enabled. |
--webhook-url <https-url> | send a run.finished message to this address when the run ends |
--webhook-signed | sign that message with the workspace's webhook secret (default: unsigned) |
--follow | stream events as NDJSON until the run ends, then exit with its result |
--wait | wait until the run ends, print the final run, then exit with its result |
--timeout <seconds> | stop waiting after this long (exit 13, the run keeps going) |
--interval <seconds> | poll interval (default 1s follow / 5s wait) |
waves runs create --agent agt_x --environment env_y --prompt "Summarize yesterday's items" --follow
waves runs create --agent agt_x --environment env_y --prompt-file task.md -q
waves runs create --agent agt_x --environment env_y --prompt "Extract the totals" --file invoice.pdf --file data.csv
waves runs delete <id>
Delete a finished run's log and output files for good. Fails with 409 while the run is active.
Wire: DELETE /v1/sessions/:id
waves runs events <id> [flags]
Read a run's events as JSON, or stream them live as NDJSON with --follow.
Wire: GET /v1/sessions/:id/events[?after,limit] · stream: --follow
| flag | description |
|---|---|
--after <seq> | start after this seq (default -1, the beginning) |
--limit <n> | page size, 1-1000, without --follow |
-f, --follow | stream NDJSON frames until the run ends |
--timeout <seconds> | with --follow: give up after this long (exit 13) |
--interval <seconds> | with --follow: poll interval (default 1s) |
waves runs events ses_x --after -1
waves runs events ses_x --follow
waves runs events list <id> [flags]
Read a run's events, a page at a time, by seq.
Wire: GET /v1/sessions/:id/events
| flag | description |
|---|---|
--after <int> | start after this seq (default -1, the beginning) |
--limit <int> | page size, 1-1000 (default 100) |
waves runs get <id>
Get a run.
Wire: GET /v1/sessions/:id
waves runs interrupt <id>
Stop a run that is working or idle. Returns 202 right away, and the run stops after its current step.
Wire: POST /v1/sessions/:id/interrupt
waves runs list [flags]
List runs, newest first, a page at a time.
Wire: GET /v1/sessions
| flag | description |
|---|---|
--agent <string> | filter by agent id |
--status <enum> | filter by status (queued|provisioning|running|idle|waiting|interrupted|succeeded|failed|deleted) |
--limit <int> | page size, 1-100 (default 100) |
--cursor <string> | next_cursor from the previous page (leave out for the first) |
waves runs report <id> [flags]
Get a run's report. With --markdown, print it as Markdown, facts first.
Wire: GET /v1/sessions/:id/report
| flag | description |
|---|---|
--markdown | print the report as Markdown: the run's facts, then the body (pipe to a file or a pager) |
waves runs report ses_x
waves runs report ses_x --markdown > report.md
waves runs resume <id> [flags]
Resume a finished run. This starts a new run from its saved output files.
Wire: POST /v1/sessions/:id/resume
<id>: the finished run to continue
| flag | description |
|---|---|
--prompt <text> | the prompt text inline |
--prompt-file <path> | read the prompt from a file |
--prompt-stdin | read the prompt from stdin |
--title <text> | run title |
--webhook-url <https-url> | send a run.finished message to this address (default: the finished run's own address) |
--webhook-signed | sign that message with the workspace's webhook secret (default: as the finished run did) |
--no-webhook | send no run.finished message, even if the finished run had an address |
--webhook-unsigned | send the message unsigned, even if the finished run signed it |
--follow | stream events as NDJSON until the run ends, then exit with its result |
--wait | wait until the run ends, print the final run, then exit with its result |
--timeout <seconds> | stop waiting after this long (exit 13, the run keeps going) |
--interval <seconds> | poll interval (default 1s follow / 5s wait) |
waves runs resume ses_x --prompt "Continue: also cover the edge cases" --follow
waves runs steer <id> [flags]
Send a message to a run that is working or idle.
Wire: POST /v1/sessions/:id/steer
| flag | description |
|---|---|
--message <text> | the message inline |
--message-file <path> | read the message from a file |
--message-stdin | read the message from stdin |
waves runs steer ses_x --message "Focus on the API changes only"
waves runs wait <id> [flags]
Wait until a run ends, then exit with its result.
| flag | description |
|---|---|
--timeout <seconds> | give up after this long (exit 13) |
--interval <seconds> | poll interval (default 5s) |
waves runs wait ses_x --timeout 1800
waves schedules
waves schedules create [flags]
Create a schedule that starts runs of an agent in an environment, on a cron expression.
Wire: POST /v1/schedules
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe schedules.create) |
waves schedules delete <id>
Delete a schedule. Fails with 409 once it has started runs, so turn it off instead.
Wire: DELETE /v1/schedules/:id
waves schedules get <id>
Get a schedule.
Wire: GET /v1/schedules/:id
waves schedules list
List schedules.
Wire: GET /v1/schedules
waves schedules run <id>
Start a run of a schedule now. This ignores its overlap and catch-up settings. Returns the new run.
Wire: POST /v1/schedules/:id/run
waves schedules update <id> [flags]
Update a schedule. Its next run time is worked out again.
Wire: POST /v1/schedules/:id
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe schedules.update) |
waves schema
waves schema <name> [flags]
Print a JSON Schema exactly as the API checks it.
<name>: such as AgentConfig (leave out with --list)
| flag | description |
|---|---|
--list | list all schema names |
waves schema AgentConfig
waves schema --list
waves services
waves services access <slug> [flags]
Set whether agents may change things through a connected service
Wire: POST /v1/services/:slug/access
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe services.access) |
waves services connect <slug> [flags]
Connect a service with a token from the provider, and test it. The token can never be read back.
Wire: POST /v1/services/:slug/connect
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe services.connect) |
waves services disconnect <slug>
Disconnect a service. Its stored token is erased.
Wire: POST /v1/services/:slug/disconnect
waves services files access <slug> <fileId> [flags]
Set whether agents may change one allowed file.
Wire: POST /v1/services/:slug/files/:fileId/access
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe services.files.access) |
waves services files add <slug> [flags]
Let agents use files picked in the provider's own file picker.
Wire: POST /v1/services/:slug/files
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe services.files.add) |
waves services files list <slug>
List the files agents may use through a connected service.
Wire: GET /v1/services/:slug/files
waves services files remove <slug> <fileId>
Stop agents using one file. This applies from the next run.
Wire: DELETE /v1/services/:slug/files/:fileId
waves services list
List the services you can connect, and which ones this workspace has connected.
Wire: GET /v1/services
waves services scope <slug> [flags]
Limit a connected service to one project, team or organisation at the provider. A scope of null removes the limit.
Wire: POST /v1/services/:slug/scope
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe services.scope) |
waves services test <slug>
Check whether a connected service works, and say why if it does not.
Wire: POST /v1/services/:slug/test
waves skills
waves skills archive <id>
Archive a skill. Reads still work, and writes fail with 409.
Wire: POST /v1/skills/:id/archive
waves skills create [flags]
Create a skill: a procedure agents read when they need it. The body can be up to 100,000 characters.
Wire: POST /v1/skills
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe skills.create) |
waves skills delete <id>
Delete a skill for good. Fails with 409 while an agent uses it.
Wire: DELETE /v1/skills/:id
waves skills get <id>
Get one skill: its full body, its version, and size_chars against the limit of 100,000 characters.
Wire: GET /v1/skills/:id
waves skills list [flags]
List skills, without their bodies. size_chars counts toward the limit of 100,000 characters. Get one by id to read its body.
Wire: GET /v1/skills
| flag | description |
|---|---|
--include_archived | set to true to include archived rows |
waves skills update <id> [flags]
Update a skill. Pass its expected_version. The body can be up to 100,000 characters.
Wire: POST /v1/skills/:id
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe skills.update) |
--expected-version <n> | the version this change is based on |
--if-current | fetch the current version and try once with it (a 409 still fails, and nothing is retried) |
waves starters
waves starters get <slug>
Describe a starter bundle and whether it can be installed here: its tools, web access, cost limit and schedule.
Wire: GET /v1/starters/:slug
waves starters install <slug> [flags]
Install a starter bundle in one step: an environment, a memory store, a skill, an agent and a weekly schedule. Fails with 409 if its agent already exists.
Wire: POST /v1/starters/:slug/install
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe starters.install) |
waves triggers
waves triggers create [flags]
Create a webhook trigger for an agent and an environment. The secret is returned once. With accept_files, callers can send files.
Wire: POST /v1/triggers
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe triggers.create) |
waves triggers delete <id>
Delete a trigger. Fails with 409 once it has started runs, so turn it off instead.
Wire: DELETE /v1/triggers/:id
waves triggers get <id>
Get a trigger.
Wire: GET /v1/triggers/:id
waves triggers list
List triggers. A trigger with accept_files on and agent_receives_files false refuses calls with files.
Wire: GET /v1/triggers
waves triggers rotate-secret <id>
Replace a trigger's secret. The old one stops working, and the new one is returned once.
Wire: POST /v1/triggers/:id/rotate-secret
waves triggers run <id> [flags]
Start a run of a trigger now, with an optional test payload for {{payload}}. This works while the trigger is off and ignores its overlap setting. Returns the new run.
Wire: POST /v1/triggers/:id/run
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON, optional (schema: waves describe triggers.run) |
waves triggers update <id> [flags]
Update a trigger. To turn on accept_files, the agent needs input_files.enabled.
Wire: POST /v1/triggers/:id
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe triggers.update) |
waves upgrade
waves upgrade [flags]
Check the console for a newer CLI build and replace this binary with it
| flag | description |
|---|---|
--check | report what is published and change nothing |
--base <url> | console origin to check (default: the one the installer recorded) |
waves upgrade --check
waves upgrade
waves upgrade --base https://waves.example.com
waves usage
waves usage export [flags]
Usage as CSV, to stdout or to a file with -o. The sums match waves usage get.
Wire: GET /v1/usage/export.csv
| flag | description |
|---|---|
--from <YYYY-MM-DD> | UTC day (default: current month start) |
--to <YYYY-MM-DD> | UTC day (default: today) |
-o, --output <path> | write the CSV to a file |
waves usage export --from 2026-07-01 --to 2026-07-23 -o usage.csv
waves usage get [flags]
Usage per day and model, with totals of the billed cost.
Wire: GET /v1/usage
| flag | description |
|---|---|
--from <string> | UTC day YYYY-MM-DD (default: current month start) |
--to <string> | UTC day YYYY-MM-DD (default: today) |
waves vaults
waves vaults archive <id>
Archive a vault. Runs can no longer use it.
Wire: POST /v1/vaults/:id/archive
waves vaults create [flags]
Create a vault.
Wire: POST /v1/vaults
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe vaults.create) |
waves vaults credentials create <id> [flags]
Add a credential to a vault. The value comes from stdin, a file or an environment variable, never from an argument.
Wire: POST /v1/vaults/:id/credentials
<id>: vault id
| flag | description |
|---|---|
--type <env_var|mcp_bearer> | credential type (required) |
--key <name|url> | the environment variable name (env_var), or the MCP server address (mcp_bearer) it is matched by |
--name <text> | the credential's name |
--value-stdin | read the value from stdin (default when piped) |
--value-file <path> | read the value from a file |
--value-env <NAME> | read the value from this env var |
--keep-newline | keep a trailing newline in the value |
printf %s "$TOKEN" | waves vaults credentials create vlt_x --type env_var --key GH_TOKEN
waves vaults credentials create vlt_x --type mcp_bearer --key https://mcp.example.com/mcp --value-env MCP_TOKEN
waves vaults credentials delete <id> <credentialId>
Delete a credential. Its value is erased right away.
Wire: DELETE /v1/vaults/:id/credentials/:credentialId
waves vaults credentials list <id>
List a vault's credentials. Their values are never returned.
Wire: GET /v1/vaults/:id/credentials
waves vaults credentials update <id> <credentialId> [flags]
Change a credential's value, its name, or both. Its type and key cannot change.
Wire: POST /v1/vaults/:id/credentials/:credentialId
<id>: vault id
| flag | description |
|---|---|
--name <text> | a new name |
--value | replace the value (reads it from stdin/file/env) |
--value-stdin | read the value from stdin (default when piped) |
--value-file <path> | read the value from a file |
--value-env <NAME> | read the value from this env var |
--keep-newline | keep a trailing newline in the value |
printf %s "$NEW_TOKEN" | waves vaults credentials update vlt_x cred_y --value
waves vaults delete <id>
Delete a vault and its credentials for good. Fails with 409 while it is in use.
Wire: DELETE /v1/vaults/:id
waves vaults get <id>
Get a vault.
Wire: GET /v1/vaults/:id
waves vaults list [flags]
List vaults.
Wire: GET /v1/vaults
| flag | description |
|---|---|
--include_archived | set to true to include archived rows |
waves vaults update <id> [flags]
Rename a vault or change its description.
Wire: POST /v1/vaults/:id
| flag | description |
|---|---|
-d, --data <json|@file|-> | request body as JSON (schema: waves describe vaults.update) |
waves webhooks
waves webhooks list
List the agents that send a webhook, and how each one is doing.
Wire: GET /v1/webhooks
API operations not exposed as commands
These operations need a person signed in to the console, and an API key cannot
call them. So you use them in the console, not from the command line. They are
listed here because waves ops and waves describe cover the whole API, not
only the part the CLI wraps:
| operation | route | auth |
|---|---|---|
org.update | PATCH /v1/org | session_tenant |
org.data-use.update | PATCH /v1/org/data-use | session_tenant |
services.authorize | POST /v1/services/:slug/authorize | session_tenant |
billing.subscribe | POST /v1/billing/subscribe | session_tenant |
billing.portal | POST /v1/billing/portal | session_tenant |
billing.claim-free-credits | POST /v1/billing/claim-free-credits | session_tenant |
billing.auto-recharge | PUT /v1/billing/auto-recharge | session_tenant |
api-keys.create | POST /v1/api-keys | session_tenant |
api-keys.list | GET /v1/api-keys | session_tenant |
api-keys.revoke | POST /v1/api-keys/:id/revoke | session_tenant |
assistant.conversations.create | POST /v1/assistant/conversations | session_tenant |
assistant.conversations.list | GET /v1/assistant/conversations | session_tenant |
assistant.conversations.get | GET /v1/assistant/conversations/:id | session_tenant |
assistant.conversations.delete | DELETE /v1/assistant/conversations/:id | session_tenant |
assistant.messages.send | POST /v1/assistant/conversations/:id/messages | session_tenant |
assistant.memory.get | GET /v1/assistant/memory | session_tenant |
assistant.memory.put | PUT /v1/assistant/memory | session_tenant |
admin.ping | GET /admin/ping | platform_admin |
admin.overview | GET /admin/overview | platform_admin |
admin.insights.agents | GET /admin/insights/agents | platform_admin |
admin.orgs.list | GET /admin/orgs | platform_admin |
admin.orgs.create | POST /admin/orgs | platform_admin |
admin.orgs.delete | DELETE /admin/orgs/:id | platform_admin |
admin.orgs.billing.get | GET /admin/orgs/:id/billing | platform_admin |
admin.orgs.billing.update | PUT /admin/orgs/:id/billing | platform_admin |
admin.orgs.models.get | GET /admin/orgs/:id/models | platform_admin |
admin.orgs.models.update | PUT /admin/orgs/:id/models | platform_admin |
admin.users.list | GET /admin/users | platform_admin |
admin.users.create | POST /admin/users | platform_admin |
admin.users.delete | DELETE /admin/users/:id | platform_admin |
admin.models.list | GET /admin/models | platform_admin |
admin.models.gateway | GET /admin/models/gateway | platform_admin |
admin.models.create | POST /admin/models | platform_admin |
admin.models.update | POST /admin/models/:id | platform_admin |
admin.models.grants.list | GET /admin/models/:id/grants | platform_admin |
admin.pricing.get | GET /admin/pricing | platform_admin |
admin.pricing.update | PUT /admin/pricing | platform_admin |
admin.orgs.sessions.list | GET /admin/orgs/:id/sessions | platform_admin |
admin.sessions.get | GET /admin/sessions/:id | platform_admin |
admin.sessions.events.list | GET /admin/sessions/:id/events | platform_admin |
Finding everything else
waves ops: every operation, with its id, route, auth and summarywaves describe <op>: one operation, with its request and response JSON Schemaswaves schema <Name>andwaves schema --list: the API's schemas, exactly as the API checks them