# 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 ` 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 ```sh 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: ```sh 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: ```sh 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: ```sh 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":"","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 | 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 ` 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 --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 -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 [--data @f|-]`. ## Global flags | flag | description | |---|---| | `--api-url ` | API base url (overrides WAVES_API_URL/profile) | | `--profile ` | 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 ` 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 ` | YAML config file, sent as config_yaml exactly as written ('-' = stdin) | ### `waves agents delete ` 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 [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 ` | return this older config version instead | | `--yaml` | print only config_yaml (pipe to a file, edit, update) | ```sh 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 ` | write to a file instead of stdout | ```sh 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 [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 ` | YAML config file, sent as config_yaml exactly as written ('-' = stdin) | | `--expected-version ` | 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 ` | the YAML config ('-' = stdin) | ```sh waves agents validate -f agent.yaml ``` ### `waves agents versions ` List an agent's versions. Wire: `GET /v1/agents/:id/versions` ### `waves agents webhook get ` 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 ` Show an agent's webhook signing secret. Workspace owners only. Wire: `POST /v1/agents/:id/webhook/reveal` ### `waves agents webhook rotate-secret ` 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 ` 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 [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 ` | request body as JSON (schema: waves describe agents.webhook.update) | --- ## `waves api` ### `waves api [flags]` Call any endpoint directly. Auth, errors and retries are handled for you. - ``: GET|POST|PUT|PATCH|DELETE - ``: such as /v1/agents | flag | description | |---|---| | `-d, --data ` | JSON request body | ```sh waves api GET /v1/models waves api POST /v1/vaults --data '{"name":"ci"}' ``` --- ## `waves approvals` ### `waves approvals decide [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 ` | request body as JSON (schema: waves describe approvals.decide) | ### `waves approvals get ` 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 ` | filter by status (pending\|approved\|declined\|expired\|cancelled) | | `--session ` | filter by run id | | `--limit ` | page size, 1-100 (default 100) | | `--cursor ` | 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 ` | 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 ` Set a config value by its dot path. Use '-' to read the value from stdin, as for api_key. - ``: such as profiles.prod.api_url or default_profile - ``: '-' = stdin ```sh 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 ` Describe one operation: its route, auth, query parameters, and request and response JSON Schemas. - ``: an id from `waves ops`, such as agents.create ```sh 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 ` 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 ` | request body as JSON (schema: waves describe environments.create) | ### `waves environments delete ` 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 ` 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 [flags]` Update an environment. Send only the fields you change. Wire: `POST /v1/environments/:id` | flag | description | |---|---| | `-d, --data ` | 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 ` 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 ` | request body as JSON (schema: waves describe knowledge.bases.create) | ### `waves knowledge bases delete ` 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 ` 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 [flags]` Rename a knowledge base or change its description. Wire: `POST /v1/knowledge-bases/:id` | flag | description | |---|---| | `-d, --data ` | request body as JSON (schema: waves describe knowledge.bases.update) | ### `waves knowledge documents create [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 ` | request body as JSON (schema: waves describe knowledge.documents.create) | ### `waves knowledge documents delete ` Delete a document for good. Wire: `DELETE /v1/knowledge-bases/:id/documents/:documentId` ### `waves knowledge documents get ` Get one document: its full text and its version. Wire: `GET /v1/knowledge-bases/:id/documents/:documentId` ### `waves knowledge documents list ` 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 [flags]` Update a document. Pass its expected_version. Wire: `POST /v1/knowledge-bases/:id/documents/:documentId` | flag | description | |---|---| | `-d, --data ` | request body as JSON (schema: waves describe knowledge.documents.update) | | `--expected-version ` | 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 [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 ` | search terms, in web search syntax | | `--limit ` | 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) | ```sh 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. ```sh 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 ` | the MCP server URL (required) | | `--auth ` | where the token comes from (default none) | | `--vault ` | vaults to take the token from (with --auth from_vault) | ```sh 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 ` Delete an entry for good. Wire: `DELETE /v1/memory-stores/:id/entries/:key` ### `waves memory entries get ` Get one entry: its value and its version. Wire: `GET /v1/memory-stores/:id/entries/:key` ### `waves memory entries list ` 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 [flags]` Create or update a memory entry. Choose exactly one way to handle its version. Wire: `PUT /v1/memory-stores/:id/entries/:key` - ``: store id | flag | description | |---|---| | `--value ` | the value inline, as JSON (bare text is sent as a string, with a warning) | | `--value-file ` | read the value from a file | | `--value-stdin` | read the value from stdin (default when piped) | | `--expected-version ` | 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) | ```sh 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 ` 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 ` | request body as JSON (schema: waves describe memory.stores.create) | ### `waves memory stores delete ` 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 ` 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 [flags]` Rename a memory store or change its description. Wire: `POST /v1/memory-stores/:id` | flag | description | |---|---| | `-d, --data ` | 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 ` | request body as JSON (schema: waves describe run-webhook.test) | --- ## `waves runs` ### `waves runs approvals [flags]` List a run's approval requests, newest first. Wire: `GET /v1/sessions/:id/approvals` | flag | description | |---|---| | `--status ` | filter by status (pending\|approved\|declined\|expired\|cancelled) | | `--limit ` | page size, 1-100 (default 100) | | `--cursor ` | next_cursor from the previous page (leave out for the first) | ### `waves runs artifacts delete ` 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 [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 ` | write the artifact here ('-' writes the raw bytes to stdout). Without it, the download link is printed. | ```sh waves runs artifacts download ses_x art_y -o workspace.tar.gz ``` ### `waves runs artifacts list ` 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 ` | agent id (required) | | `--environment ` | environment id (required) | | `--prompt ` | the prompt text inline | | `--prompt-file ` | read the prompt from a file | | `--prompt-stdin` | read the prompt from stdin | | `--title ` | run title | | `--vault ` | attach a vault (repeatable, max 10) | | `--model ` | override the agent's model for this run | | `--fallback-model ` | override the fallback model for this run (requires --model) | | `--max-turns ` | override limits.max_turns | | `--max-runtime-min ` | override limits.max_runtime_minutes | | `--max-cost-eur ` | override limits.max_cost_eur | | `--file ` | 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 ` | 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 ` | stop waiting after this long (exit 13, the run keeps going) | | `--interval ` | poll interval (default 1s follow / 5s wait) | ```sh 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 ` 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 [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 ` | start after this seq (default -1, the beginning) | | `--limit ` | page size, 1-1000, without --follow | | `-f, --follow` | stream NDJSON frames until the run ends | | `--timeout ` | with --follow: give up after this long (exit 13) | | `--interval ` | with --follow: poll interval (default 1s) | ```sh waves runs events ses_x --after -1 waves runs events ses_x --follow ``` ### `waves runs events list [flags]` Read a run's events, a page at a time, by seq. Wire: `GET /v1/sessions/:id/events` | flag | description | |---|---| | `--after ` | start after this seq (default -1, the beginning) | | `--limit ` | page size, 1-1000 (default 100) | ### `waves runs get ` Get a run. Wire: `GET /v1/sessions/:id` ### `waves runs interrupt ` 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 ` | filter by agent id | | `--status ` | filter by status (queued\|provisioning\|running\|idle\|waiting\|interrupted\|succeeded\|failed\|deleted) | | `--limit ` | page size, 1-100 (default 100) | | `--cursor ` | next_cursor from the previous page (leave out for the first) | ### `waves runs report [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) | ```sh waves runs report ses_x waves runs report ses_x --markdown > report.md ``` ### `waves runs resume [flags]` Resume a finished run. This starts a new run from its saved output files. Wire: `POST /v1/sessions/:id/resume` - ``: the finished run to continue | flag | description | |---|---| | `--prompt ` | the prompt text inline | | `--prompt-file ` | read the prompt from a file | | `--prompt-stdin` | read the prompt from stdin | | `--title ` | run title | | `--webhook-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 ` | stop waiting after this long (exit 13, the run keeps going) | | `--interval ` | poll interval (default 1s follow / 5s wait) | ```sh waves runs resume ses_x --prompt "Continue: also cover the edge cases" --follow ``` ### `waves runs steer [flags]` Send a message to a run that is working or idle. Wire: `POST /v1/sessions/:id/steer` | flag | description | |---|---| | `--message ` | the message inline | | `--message-file ` | read the message from a file | | `--message-stdin` | read the message from stdin | ```sh waves runs steer ses_x --message "Focus on the API changes only" ``` ### `waves runs wait [flags]` Wait until a run ends, then exit with its result. | flag | description | |---|---| | `--timeout ` | give up after this long (exit 13) | | `--interval ` | poll interval (default 5s) | ```sh 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 ` | request body as JSON (schema: waves describe schedules.create) | ### `waves schedules delete ` Delete a schedule. Fails with 409 once it has started runs, so turn it off instead. Wire: `DELETE /v1/schedules/:id` ### `waves schedules get ` Get a schedule. Wire: `GET /v1/schedules/:id` ### `waves schedules list` List schedules. Wire: `GET /v1/schedules` ### `waves schedules run ` 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 [flags]` Update a schedule. Its next run time is worked out again. Wire: `POST /v1/schedules/:id` | flag | description | |---|---| | `-d, --data ` | request body as JSON (schema: waves describe schedules.update) | --- ## `waves schema` ### `waves schema [flags]` Print a JSON Schema exactly as the API checks it. - ``: such as AgentConfig (leave out with --list) | flag | description | |---|---| | `--list` | list all schema names | ```sh waves schema AgentConfig waves schema --list ``` --- ## `waves services` ### `waves services access [flags]` Set whether agents may change things through a connected service Wire: `POST /v1/services/:slug/access` | flag | description | |---|---| | `-d, --data ` | request body as JSON (schema: waves describe services.access) | ### `waves services connect [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 ` | request body as JSON (schema: waves describe services.connect) | ### `waves services disconnect ` Disconnect a service. Its stored token is erased. Wire: `POST /v1/services/:slug/disconnect` ### `waves services files access [flags]` Set whether agents may change one allowed file. Wire: `POST /v1/services/:slug/files/:fileId/access` | flag | description | |---|---| | `-d, --data ` | request body as JSON (schema: waves describe services.files.access) | ### `waves services files add [flags]` Let agents use files picked in the provider's own file picker. Wire: `POST /v1/services/:slug/files` | flag | description | |---|---| | `-d, --data ` | request body as JSON (schema: waves describe services.files.add) | ### `waves services files list ` List the files agents may use through a connected service. Wire: `GET /v1/services/:slug/files` ### `waves services files remove ` 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 [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 ` | request body as JSON (schema: waves describe services.scope) | ### `waves services test ` Check whether a connected service works, and say why if it does not. Wire: `POST /v1/services/:slug/test` --- ## `waves skills` ### `waves skills archive ` 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 ` | request body as JSON (schema: waves describe skills.create) | ### `waves skills delete ` Delete a skill for good. Fails with 409 while an agent uses it. Wire: `DELETE /v1/skills/:id` ### `waves skills get ` 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 [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 ` | request body as JSON (schema: waves describe skills.update) | | `--expected-version ` | 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 ` 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 [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 ` | 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 ` | request body as JSON (schema: waves describe triggers.create) | ### `waves triggers delete ` Delete a trigger. Fails with 409 once it has started runs, so turn it off instead. Wire: `DELETE /v1/triggers/:id` ### `waves triggers get ` 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 ` 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 [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 ` | request body as JSON, optional (schema: waves describe triggers.run) | ### `waves triggers update [flags]` Update a trigger. To turn on accept_files, the agent needs input_files.enabled. Wire: `POST /v1/triggers/:id` | flag | description | |---|---| | `-d, --data ` | 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 ` | console origin to check (default: the one the installer recorded) | ```sh 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 ` | UTC day (default: current month start) | | `--to ` | UTC day (default: today) | | `-o, --output ` | write the CSV to a file | ```sh 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 ` | UTC day YYYY-MM-DD (default: current month start) | | `--to ` | UTC day YYYY-MM-DD (default: today) | --- ## `waves vaults` ### `waves vaults archive ` 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 ` | request body as JSON (schema: waves describe vaults.create) | ### `waves vaults credentials create [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` - ``: vault id | flag | description | |---|---| | `--type ` | credential type (required) | | `--key ` | the environment variable name (env_var), or the MCP server address (mcp_bearer) it is matched by | | `--name ` | the credential's name | | `--value-stdin` | read the value from stdin (default when piped) | | `--value-file ` | read the value from a file | | `--value-env ` | read the value from this env var | | `--keep-newline` | keep a trailing newline in the value | ```sh 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 ` Delete a credential. Its value is erased right away. Wire: `DELETE /v1/vaults/:id/credentials/:credentialId` ### `waves vaults credentials list ` List a vault's credentials. Their values are never returned. Wire: `GET /v1/vaults/:id/credentials` ### `waves vaults credentials update [flags]` Change a credential's value, its name, or both. Its type and key cannot change. Wire: `POST /v1/vaults/:id/credentials/:credentialId` - ``: vault id | flag | description | |---|---| | `--name ` | 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 ` | read the value from a file | | `--value-env ` | read the value from this env var | | `--keep-newline` | keep a trailing newline in the value | ```sh printf %s "$NEW_TOKEN" | waves vaults credentials update vlt_x cred_y --value ``` ### `waves vaults delete ` Delete a vault and its credentials for good. Fails with 409 while it is in use. Wire: `DELETE /v1/vaults/:id` ### `waves vaults get ` 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 [flags]` Rename a vault or change its description. Wire: `POST /v1/vaults/:id` | flag | description | |---|---| | `-d, --data ` | 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 summary - `waves describe `: one operation, with its request and response JSON Schemas - `waves schema ` and `waves schema --list`: the API's schemas, exactly as the API checks them