Waterglass Waves CLI

Version 0.4.46

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.
  • --follow streams 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:

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_DIR installs 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/me before it stores anything.
  • It writes ~/.config/waves/config.json, readable only by you, with this profile as the default.
  • There is no --key flag on purpose. Arguments show up in ps and 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-url or WAVES_API_URL picks 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:

  1. the flags --api-url and --profile
  2. the environment variables WAVES_API_URL, WAVES_API_KEY and WAVES_PROFILE
  3. the profile
  4. 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. -q prints only the main id, such as ses_….
  • An error prints one JSON line on stderr: {"error":"<code>","status":…, …}. error is the server's code, unchanged. Some codes come with more fields: version_conflict carries current_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_supported and config_invalid.
  • A 429 is retried automatically, up to 3 times, after the wait in Retry-After. --no-retry turns this off.
  • After a network error, only GET requests are retried. A request that changes something is never retried automatically.

Exit codes

codemeaning
0success, including --wait or --follow on a run that succeeded
1an unexpected CLI error
2a usage error, or the local check failed
3a network failure
4not allowed (401 or 403, or no API key)
5not found (404)
6a conflict (409, such as version_conflict, stale_version or session_not_active)
7an invalid request (400)
8rate limited (429, after the retries)
9a server error (5xx)
10the run ended failed (--wait or --follow)
11the run ended interrupted: someone stopped it, or it reached one of its limits
12the run ended deleted
13waiting timed out, and the run keeps going
14the 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 with ses_. The CLI accepts both waves runs … and waves sessions ….
  • Secrets never go into an argument. A credential's value comes from stdin (the default when you pipe it), from --value-file or 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 init prints a starter config. waves agents get <id> --yaml prints the stored YAML, ready to edit and send back with update -f.
  • To update safely, pass the version you edited: waves agents update <id> -f agent.yaml --expected-version N. --if-current fetches 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

flagdescription
--api-url <url>API base url (overrides WAVES_API_URL/profile)
--profile <name>config profile (overrides WAVES_PROFILE)
-q, --quietprint only the primary id of the result
--verboselog requests to stderr (secrets redacted)
--no-retrydisable automatic retries (429/network)
-h, --helpshow 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

flagdescription
-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

flagdescription
--version <n>return this older config version instead
--yamlprint 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.

flagdescription
-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

flagdescription
--include_archivedset 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

flagdescription
-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-currentfetch 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.

flagdescription
-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

flagdescription
-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
flagdescription
-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

flagdescription
-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

flagdescription
--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

flagdescription
-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 from waves 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

flagdescription
-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

flagdescription
--include_archivedset 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

flagdescription
-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

flagdescription
-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

flagdescription
--include_archivedset 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

flagdescription
-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

flagdescription
-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

flagdescription
-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-currentfetch 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

flagdescription
--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.

flagdescription
--key-stdinread 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

flagdescription
--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
flagdescription
--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-stdinread the value from stdin (default when piped)
--expected-version <n>replace exactly this version (otherwise 409 stale_version)
--createthe key must be new (otherwise 409 version_required)
--forcefetch 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

flagdescription
-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

flagdescription
--include_archivedset 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

flagdescription
-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

flagdescription
-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

flagdescription
--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)

flagdescription
-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

flagdescription
--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-stdinread 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-signedsign that message with the workspace's webhook secret (default: unsigned)
--followstream events as NDJSON until the run ends, then exit with its result
--waitwait 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

flagdescription
--after <seq>start after this seq (default -1, the beginning)
--limit <n>page size, 1-1000, without --follow
-f, --followstream 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

flagdescription
--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

flagdescription
--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

flagdescription
--markdownprint 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
flagdescription
--prompt <text>the prompt text inline
--prompt-file <path>read the prompt from a file
--prompt-stdinread 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-signedsign that message with the workspace's webhook secret (default: as the finished run did)
--no-webhooksend no run.finished message, even if the finished run had an address
--webhook-unsignedsend the message unsigned, even if the finished run signed it
--followstream events as NDJSON until the run ends, then exit with its result
--waitwait 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

flagdescription
--message <text>the message inline
--message-file <path>read the message from a file
--message-stdinread 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.

flagdescription
--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

flagdescription
-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

flagdescription
-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)
flagdescription
--listlist 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

flagdescription
-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

flagdescription
-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

flagdescription
-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

flagdescription
-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

flagdescription
-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

flagdescription
-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

flagdescription
--include_archivedset 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

flagdescription
-d, --data <json|@file|->request body as JSON (schema: waves describe skills.update)
--expected-version <n>the version this change is based on
--if-currentfetch 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

flagdescription
-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

flagdescription
-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

flagdescription
-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

flagdescription
-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

flagdescription
--checkreport 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

flagdescription
--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

flagdescription
--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

flagdescription
-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
flagdescription
--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-stdinread 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-newlinekeep 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
flagdescription
--name <text>a new name
--valuereplace the value (reads it from stdin/file/env)
--value-stdinread 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-newlinekeep 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

flagdescription
--include_archivedset to true to include archived rows

waves vaults update <id> [flags]

Rename a vault or change its description.

Wire: POST /v1/vaults/:id

flagdescription
-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:

operationrouteauth
org.updatePATCH /v1/orgsession_tenant
org.data-use.updatePATCH /v1/org/data-usesession_tenant
services.authorizePOST /v1/services/:slug/authorizesession_tenant
billing.subscribePOST /v1/billing/subscribesession_tenant
billing.portalPOST /v1/billing/portalsession_tenant
billing.claim-free-creditsPOST /v1/billing/claim-free-creditssession_tenant
billing.auto-rechargePUT /v1/billing/auto-rechargesession_tenant
api-keys.createPOST /v1/api-keyssession_tenant
api-keys.listGET /v1/api-keyssession_tenant
api-keys.revokePOST /v1/api-keys/:id/revokesession_tenant
assistant.conversations.createPOST /v1/assistant/conversationssession_tenant
assistant.conversations.listGET /v1/assistant/conversationssession_tenant
assistant.conversations.getGET /v1/assistant/conversations/:idsession_tenant
assistant.conversations.deleteDELETE /v1/assistant/conversations/:idsession_tenant
assistant.messages.sendPOST /v1/assistant/conversations/:id/messagessession_tenant
assistant.memory.getGET /v1/assistant/memorysession_tenant
assistant.memory.putPUT /v1/assistant/memorysession_tenant
admin.pingGET /admin/pingplatform_admin
admin.overviewGET /admin/overviewplatform_admin
admin.insights.agentsGET /admin/insights/agentsplatform_admin
admin.orgs.listGET /admin/orgsplatform_admin
admin.orgs.createPOST /admin/orgsplatform_admin
admin.orgs.deleteDELETE /admin/orgs/:idplatform_admin
admin.orgs.billing.getGET /admin/orgs/:id/billingplatform_admin
admin.orgs.billing.updatePUT /admin/orgs/:id/billingplatform_admin
admin.orgs.models.getGET /admin/orgs/:id/modelsplatform_admin
admin.orgs.models.updatePUT /admin/orgs/:id/modelsplatform_admin
admin.users.listGET /admin/usersplatform_admin
admin.users.createPOST /admin/usersplatform_admin
admin.users.deleteDELETE /admin/users/:idplatform_admin
admin.models.listGET /admin/modelsplatform_admin
admin.models.gatewayGET /admin/models/gatewayplatform_admin
admin.models.createPOST /admin/modelsplatform_admin
admin.models.updatePOST /admin/models/:idplatform_admin
admin.models.grants.listGET /admin/models/:id/grantsplatform_admin
admin.pricing.getGET /admin/pricingplatform_admin
admin.pricing.updatePUT /admin/pricingplatform_admin
admin.orgs.sessions.listGET /admin/orgs/:id/sessionsplatform_admin
admin.sessions.getGET /admin/sessions/:idplatform_admin
admin.sessions.events.listGET /admin/sessions/:id/eventsplatform_admin

Finding everything else

  • waves ops: every operation, with its id, route, auth and summary
  • waves describe <op>: one operation, with its request and response JSON Schemas
  • waves schema <Name> and waves schema --list: the API's schemas, exactly as the API checks them