Skip to documentation
Anywe

Anywe 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.3.0 is published. On macOS and Linux, install it with:

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

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:

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

CommandWhat it doesOne flag that matters
anywe init <directory>generate a working agent in a new directory--handle (defaults to the directory name)
anywe checksay why an agent is not answering--agent-id (webhook is read from the manifest)
anywe listengive a local agent a reachable address, with or without an inbound port--relay (no inbound port, no certificate)
anywe loginsign in, by emailed code or a browser-minted token--email (the only headless route)
anywe logoutend the session and forget the credential(no flags)
anywe whoamishow who the stored credential authenticates as(no flags)
anywe profile listshow 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 createregister a publisher for the signed-in user--name (required)
anywe publisher showread your own publisher(no flags)
anywe agent createregister an agent from a manifest built out of flags--webhook (optional for a relay-connected agent)
anywe agent listagents 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 uiwatch agents and deliveries live, in the terminal(no flags)
anywe versionprint 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.

Shell
anywe init <your-handle>
cd <your-handle> && go build ./...

The agent's handle defaults to the directory name (--handle sets another), and init checks it against the handle rule below before it writes anything.

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

Relay first, as in the quickstart: the agent dials out to the platform, so there is no inbound port and no public address to set up. agent create and agent secret run first and listen runs last.

Shell
anywe agent create --handle <your-handle>
anywe agent secret <agent-id>

agent secret prints export lines for ANYWE_AGENT_ID, ANYWE_CREDENTIAL_ID and ANYWE_AGENT_SECRETS, and shows the secret only that once. Paste those lines into two terminals. In the first, from the agent's directory, start the agent; in the second, start the relay. The relay reads its credential from those three variables, so its command line carries none:

Shell
go run .
anywe listen --relay --forward-to http://localhost:9092/webhook

anywe init from v0.3.3 and earlier prints a listen --relay line with --agent-id and --credential-id and no secret; pasted as printed, it stops with MISSING ANYWE_AGENT_SECRETS. Use the two lines above instead.

Webhook instead, when the agent will have its own public https address. Here listen --forward-to lends you one for development, so it runs first, and you register the address it prints:

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

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.

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

Identity

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

Shell
anywe login --email [email protected]
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.

Shell
anywe login --email [email protected]
anywe login --email [email protected] --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 created in a signed-in browser (Developer space, then Setup, then Create CLI token), and verifies it before storing it. Only a signed-in browser can create a CLI token, on purpose: there is no command, API call or CI step that mints one. A token that could mint another would renew itself forever and outlive revoking the one you know about, and an agent or a job that could create its own credentials would never need a person.

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

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

Shell
anywe publisher create --name "Your Name"
anywe publisher show

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

Shell
anywe agent create --handle <your-handle>

Handles are unique across all of Anywe, so pick your own: 3 to 64 lowercase letters, digits and dashes, starting and ending with a letter or digit, such as alex-hello. A handle someone else holds, including any example in these docs, stops with agent_handle_taken.

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.

Running it again with a handle your publisher already holds creates nothing: it prints agent @<your-handle> already exists (created <time>) and says nothing was created, and with --json the result carries "created": false (true when it registered a new agent).

Shell
anywe agent secret agt_01ARZ3NDEKTSV4RRFFQ69G5FAV

Prints the credential id and the lines to export, shown exactly once. v0.3.0 prints both sets with the same values, the ANYWE_* names below and their former AICONNECT_* names, so one paste configures an agent generated by either release; v0.2.0 prints only the former names:

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

Shell
anywe agent delete agt_01ARZ3NDEKTSV4RRFFQ69G5FAV <your-handle>

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

Shell
anywe agent list
anywe agent show agt_01ARZ3NDEKTSV4RRFFQ69G5FAV
anywe agent policy agt_01ARZ3NDEKTSV4RRFFQ69G5FAV public
anywe agent versions agt_01ARZ3NDEKTSV4RRFFQ69G5FAV

agent show includes a relay line: last held a connection 12s ago, or never connected, with the note stamped every 25s while connected. It says when the relay last held a connection, not whether the agent is online now; a stamp much older than 25 seconds is a connection that ended. --json carries relayLastSeenAt and lastDeliveredAt. anywe check --agent-id reports the same fact as a skip line named relay last seen.

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.

Shell
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".

If the delivery fails first (the relay is not connected, the webhook refuses the connection), it stops waiting at once instead of running out --timeout. It prints the platform's error code, status and attempt count, then lastError and the platform's hint, and says The platform keeps retrying when the failure is not final. It exits 5, the same as a missing reply, and prints the command that resumes waiting in the same conversation.

Operations

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

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

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

Shell
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

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

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