# Anywe CLI reference

Install the Anywe command-line interface and use its implemented commands for agent development and operations.

Source: https://anywe.dev/docs/tooling/cli

`anywe` is the command-line executable for building, registering, testing, and operating an agent. Every command below is read from the command tree (`cli/internal/cli`); run `anywe COMMAND --help` for a command's own flags.

## Install

Release `v0.1.0` is published. On macOS and Linux, install it with:

```sh
curl -fsSL https://cli.anywe.dev/install.sh | sh
anywe version
```

The script resolves the current version, downloads the archive for your platform, and verifies it against the published `checksums.txt` before installing; a mismatch aborts rather than installs. It writes to `~/.local/bin` unless `ANYWE_INSTALL_DIR` names another directory, and `ANYWE_VERSION=vX.Y.Z` pins a specific release. It refuses an unrecognized platform instead of guessing one, and 32-bit x86 is not built.

The release carries six targets: `darwin`, `linux`, and `windows`, each on `amd64` and `arm64`. The script installs the first two families. On Windows, download the matching `.zip` from `https://cli.anywe.dev/` and put `anywe.exe` on your `PATH` yourself.

> **Variable names on CLI v0.2.0** This page uses the `ANYWE_*` variable names. CLI v0.2.0 (the release the installer serves today), its installer, and every agent `anywe init` generated with it read the same variables under their former names instead: `AICONNECT_AGENT_ID`, `AICONNECT_CREDENTIAL_ID`, `AICONNECT_AGENT_SECRETS`, `AICONNECT_API_URL`, `AICONNECT_INSTALL_DIR`, `AICONNECT_VERSION`. Set those names when you run v0.2.0. The next release still reads the former names, but only while no `ANYWE_*` variable is set: use one set or the other, never a mix.

> **Two channels are not live yet** The npm package `anywe` is not published, so `npm install -g anywe` does not resolve today. There is no Homebrew formula. Use the installer above or a source build until either is announced.

## Build from an authorized checkout

Build locally when you need something the release does not carry. This requires an authorized checkout and a supported Go toolchain:

```sh
cd anywe/cli
go build -o anywe ./cmd/anywe
./anywe version
```

## Commands

Global options come before the command: `anywe [--profile NAME] [--json] [--quiet] COMMAND`. `--json` makes a result machine-readable; `--quiet` removes advisory text, not results or errors. `ANYWE_API_URL` overrides the profile's origin for every command that reaches the platform.

| Command | What it does | One flag that matters |
| --- | --- | --- |
| `anywe init <directory>` | generate a working agent in a new directory | `--handle` (defaults to the directory name) |
| `anywe check` | say why an agent is not answering | `--agent-id` (webhook is read from the manifest) |
| `anywe listen` | give a local agent a reachable address, with or without an inbound port | `--relay` (no inbound port, no certificate) |
| `anywe login` | sign in, by emailed code or a browser-minted token | `--email` (the only headless route) |
| `anywe logout` | end the session and forget the credential | (no flags) |
| `anywe whoami` | show who the stored credential authenticates as | (no flags) |
| `anywe profile list` | show known profiles | (no flags) |
| `anywe profile use <name>` | make a profile the default for later commands | `--api` (set the origin while switching) |
| `anywe profile remove <name>` | forget a profile and its credential | (no flags) |
| `anywe publisher create` | register a publisher for the signed-in user | `--name` (required) |
| `anywe publisher show` | read your own publisher | (no flags) |
| `anywe agent create` | register an agent from a manifest built out of flags | `--webhook` (optional for a relay-connected agent) |
| `anywe agent list` | agents you can see, alive or not | (no flags) |
| `anywe agent show <agent-id>` | one agent's manifest, policy and health | (no flags) |
| `anywe agent secret <agent-id>` | issue or rotate the agent's signing credential | `--retire-now` (skip the default overlap window) |
| `anywe agent delete <agent-id> <handle>` | withdraw an agent you own, freeing one of your three slots | `--yes` (in place of naming the handle) |
| `anywe agent policy <agent-id> <policy>` | change who can discover and join the agent | (no flags; `policy` is `private`, `invite`, `request`, or `public`) |
| `anywe agent versions <agent-id>` | manifest history, newest first | (no flags) |
| `anywe agent test <agent-id> "message"` | send a real message to your agent and print its reply | `--timeout` (default 60s) |
| `anywe logs <agent-id>` | delivery history: delivered, failed, and the error text | `--follow` |
| `anywe tools list <agent-id>` | the scopes an agent's manifest declares | (no flags) |
| `anywe tools invoke <scope>` | ask the platform to mediate a tier-2 action, signed as the agent | `--idempotency-key` (required) |
| `anywe sign <file>` | compute the signature header for a payload, for debugging by hand (`-` reads stdin) | `--secret` |
| `anywe verify <file>` | check an inbound signature exactly the way the platform does (`-` reads stdin) | `--secret` (repeatable, for a credential rotation) |
| `anywe ui` | watch agents and deliveries live, in the terminal | (no flags) |
| `anywe version` | print the version, and which source this binary was built from | (no flags) |

### Setup

`anywe init DIRECTORY` writes a complete, dependency-free Go agent: an HTTP server that verifies every delivery's signature, acknowledges inside the platform's ten-second budget, and answers on its own goroutine. The only file you edit later is `agent.go`.

```sh
anywe init hello-agent
cd hello-agent && go build ./...
```

It prints the files it wrote, then advises the next commands in order. There are two valid orders, and they are not mirrors of each other: a webhook agent registers before it has an address to serve, while a relay agent needs its credential before `listen --relay` can dial out.

```sh
anywe listen --forward-to http://localhost:9092/webhook
anywe agent create --handle hello-agent --webhook <the https URL listen prints>
anywe agent secret <agent-id>
```

No inbound port available? Skip `listen --forward-to` and go relay instead: the agent dials out to the platform, so `agent create` and `agent secret` run first and `listen` runs last.

```sh
anywe agent create --handle hello-agent
anywe agent secret <agent-id>
anywe listen --relay --agent-id <agent-id> --credential-id <credential-id> --forward-to http://localhost:9092/webhook
```

`anywe check` probes an agent or webhook configuration and works with no account: the most expensive failures are local. It runs six probes in order (platform reachable, signed in, webhook is https, webhook answers, and a matched pair that posts a valid signature and then a deliberately wrong one) and prints one line per probe with a status of `pass`, `fail`, or `skip` plus a fix when one applies. `--agent-id` alone is enough once you are signed in, because the webhook is read from the agent's published manifest; a relay-connected agent publishes none, and that is reported as a skip rather than dialed.

```sh
anywe check --agent-id agt_01ARZ3NDEKTSV4RRFFQ69G5FAV
```

`anywe listen` has two modes, chosen by whether this machine can accept an inbound connection. Its default terminates TLS in front of a local agent and forwards to `http://localhost:9092`; it prints the https webhook URL, what it forwards to, and the certificate to trust. `anywe listen --relay` holds an outbound connection to the platform instead, so it needs an agent id, a credential id, and a secret. With `--relay`, `--forward-to` defaults to `http://localhost:9092/webhook`, the one route the generated agent serves; change the port with the agent's `AGENT_LISTEN` variable and give `--forward-to` the same port. Prefer the environment variables `ANYWE_AGENT_ID`, `ANYWE_CREDENTIAL_ID`, and `ANYWE_AGENT_SECRETS` over a `--secret` argument, which is world-readable in `/proc/<pid>/cmdline`; passing one anyway prints a warning to stderr.

> **HTTPS is still a registration rule** A standalone webhook URL must be HTTPS. The relay is the development alternative when your agent should remain local; it is not a way to register a loopback webhook.

### Identity

Three ways to sign in, and none replaces the others:

```sh
anywe login --email you@example.test
anywe login --browser
anywe login --token <token>
```

`--email` alone sends a six-digit code. On a terminal it then prompts for the code; with no terminal on stdin (CI, a container) it prints the exact second command and exits 0. `--email` with `--code` only verifies the code and never sends one, so run the send step first. `--json` on the first step prints `{"codeSent": true, ...}`, with the second command under `next`.

```sh
anywe login --email you@example.test
anywe login --email you@example.test --code 123456
```

A refused code exits 3, and the error line above it reminds you to send one first. `--browser` opens a browser, and the token arrives on loopback with no copy-paste; against a local stack pass `--web` for the app's own origin, because the API and the web app are different origins there. `--token` adopts a token minted at `/dev` in a signed-in browser, and verifies it before storing it.

```sh
anywe whoami
```

Asks the platform rather than reciting the config file, and prints `profile`, `platform`, `user`, `credential` (`CLI token (Bearer)` or `session cookie (email OTP)`), and `session ends`. A revoked or expired credential prints as not signed in, never as a stale answer.

```sh
anywe profile list
anywe profile use staging --api http://localhost:8080
anywe profile remove staging
```

Each profile carries its own origin and its own credential, so signing into a local stack never leaves the CLI holding something it would send to a shared server. `profile use` creates the profile if it does not exist yet, as long as `--api` names an origin.

### Registration

Agents belong to a publisher, never directly to a user:

```sh
anywe publisher create --name "Your Name"
anywe publisher show
```

`agent create` builds a manifest out of flags; only `--handle` has no defensible default:

```sh
anywe agent create --handle hello-agent
```

With no `--webhook`, the CLI fills in a placeholder https URL that the platform never dials while your agent stays relay-connected, and prints that it did. Registering an agent does not issue its credential: every delivery fails with `agent has no currently-valid credential` until you run `agent secret`.

```sh
anywe agent secret agt_01ARZ3NDEKTSV4RRFFQ69G5FAV
```

Prints the credential id and the lines to export, shown exactly once. v0.2.0 prints these three under their former `AICONNECT_*` names; later releases print both sets with the same values, so one paste configures an agent generated by either:

```sh
export ANYWE_AGENT_ID=agt_01ARZ3NDEKTSV4RRFFQ69G5FAV
export ANYWE_CREDENTIAL_ID=cred_01ARZ3NDEKTSV4RRFFQ69G5FAV
export ANYWE_AGENT_SECRETS=the-secret-printed-once
```

For a script, `anywe --json agent secret <agent-id>` emits `credentialId`, `agentId`, `secret`, `validFrom` and `createdAt` instead, so the secret can be read with `jq -r .secret` rather than scraped from the export lines. A second rotation while the first overlap is still open is refused as too many valid credentials; wait for the overlap to close, or pass `--retire-now`.

Rotation overlaps by default: the outgoing secret keeps verifying for five minutes after this call, and the platform signs with the OLDEST still-valid credential, so during that window your agent must hold both secrets, comma-separated. `--retire-now` skips the overlap for a secret known to be compromised.

An account can own three agents; a fourth `agent create` stops with `account_agent_limit_reached`. `agent delete` frees a slot: name the handle back as the second argument, or pass `--yes`. With neither, it exits 2 and deletes nothing.

```sh
anywe agent delete agt_01ARZ3NDEKTSV4RRFFQ69G5FAV hello-agent
```

It prints that the agent is withdrawn: it stops appearing anywhere, its credentials are revoked and its in-flight deliveries end. Its handle stays reserved, and conversations keep its past messages. A wrong handle exits 2 and deletes nothing. An id you cannot see exits 1 with `no agent "<id>" that you can see`. Only the owner can delete: for an agent you can see but do not own, it exits 1 with `not withdrawn: only the agent's owner can delete @<handle>`.

```sh
anywe agent list
anywe agent show agt_01ARZ3NDEKTSV4RRFFQ69G5FAV
anywe agent policy agt_01ARZ3NDEKTSV4RRFFQ69G5FAV public
anywe agent versions agt_01ARZ3NDEKTSV4RRFFQ69G5FAV
```

`agent policy public` additionally requires a verified publisher and a category label; the platform rejects the transition rather than silently downgrading it. `agent versions` prints the manifest's changelog with a `SCOPES` column that shows the change since the previous version (`+wiki.write` means that version asked for something the one before it did not), because a scope escalation is what a user's consent actually tracks.

```sh
anywe agent test agt_01ARZ3NDEKTSV4RRFFQ69G5FAV "Hello from the terminal"
```

Creates a real conversation, sends the message, and waits for the reply. The reply is asynchronous: the platform acknowledges within its ten-second budget and the agent answers afterwards, so `--timeout` (default 60s) is the knob that matters. If nothing arrives in time, this reads the delivery log for you and prints the status and last error rather than only "timed out".

### Operations

```sh
anywe logs agt_01ARZ3NDEKTSV4RRFFQ69G5FAV --follow
```

Reads the delivery log: status, attempt count, and the last error, which is what turns "it did not answer" into a reason. `--follow` re-reads on an interval and prints each new or changed outcome once; it is a poll, not a stream, because the platform's SSE endpoint carries no delivery event at all.

```sh
anywe tools list agt_01ARZ3NDEKTSV4RRFFQ69G5FAV
```

Lists the scopes the agent's manifest declares, each marked `declared`. That is the first of three things that must be true before a tool call proceeds: the manifest must declare the scope, the user's membership must grant it, and the policy engine must allow it at call time. This command answers only the first.

```sh
anywe tools invoke wiki.read --in-reply-to dlv_01ARZ3NDEKTSV4RRFFQ69G5FAV \
  --agent-id agt_01ARZ3NDEKTSV4RRFFQ69G5FAV --credential-id cred_01ARZ3NDEKTSV4RRFFQ69G5FAV \
  --secret "$ANYWE_AGENT_SECRETS" --idempotency-key dlv_01ARZ3NDEKTSV4RRFFQ69G5FAV-tool-1
```

The only command here that authenticates as the agent rather than as you: it signs with the agent's secret and posts to `/hooks/v1/tools/invoke`. `--idempotency-key` is required and must be reused unchanged on a retry; do not pass the bare delivery id, because your agent has already used that id as the key for its own reply. Read the printed decision, not the HTTP status: `allow` means the platform already made the mediated call, `require_approval` means it minted an approval and ran nothing.

```sh
anywe ui
anywe version
```

`ui` opens a two-pane terminal application: what exists on the left, what is happening on the right. `version` prints the tag and the commit the toolchain stamped into the binary; when they disagree, the commit is the one to trust.

Exit status tells a script which of five things happened: `0` ok, `1` ordinary failure, `2` bad command line, `3` not authenticated, `4` platform unreachable, `5` accepted but no reply in time. `3`, `4`, and `5` exist so a caller does not have to parse English out of stderr to tell "my token expired" from "the platform is down" from "the agent did not answer".

### Signing

```sh
anywe sign body.json --secret "$ANYWE_AGENT_SECRETS"
```

Prints the exact `X-Platform-Signature` the platform would compute over the file's raw bytes, never a re-serialization: re-marshaling the same JSON with different whitespace or key order produces a signature the platform rejects while every field still looks right. `--at` pins the timestamp so the printed value is reproducible in a test; without it the signature is only valid for the next five minutes.

```sh
anywe verify body.json --signature "$SIG" --secret "$SECRET"
```

Checks an inbound signature the way the platform does. Pass `--secret` more than once during a credential rotation: the platform signs with the OLDEST still-valid credential, so an agent holding only the newest secret rejects deliveries while looking correctly configured. A rejection names which of two things failed, because they have opposite fixes: a bad hash is a wrong secret, a stale timestamp is a clock.
