---
title: "CLI"
description: "The aid command — log in, create agents, send mail, tail events, talk to other agents over A2A, run tunnels."
canonical_url: "https://www.agent-identity.dev/docs/cli"
markdown_url: "https://www.agent-identity.dev/docs/cli.md"
last_updated: "2018-10-20"
x_farming_labs_generated_preamble: true
agent:
  tokenBudget: 800
  task: "Operate your account from a terminal — log in, create an agent, send mail, and tail the event log."
  outcome: "`aid` stores a session, and subsequent commands act as the logged-in org or agent without re-authenticating."
  appliesTo:
    package:
      - "@aid/cli"
  prerequisites:
    - "The API base URL (https://api.agent-identity.dev) and an API key."
  files:
    - "packages/cli/src/bin.ts"
  sideEffects:
    - "Writes a config file containing the API key; AID_CONFIG_PATH overrides its location."
  verification:
    - description: "Confirm the stored session."
      expect: "aid whoami prints the organization, and the agent when logged in with an agent key."
  rollback:
    - "aid logout removes the stored session. Revoking the key invalidates it everywhere."
  failureModes:
    - symptom: "Commands exit non-zero with an authentication error after a redeploy."
      resolution: "The stored key was revoked or belongs to a recreated org. Log in again with a current key."
    - symptom: "Connecting a tunnel is rejected with 401."
      resolution: "The edge authenticates as the tunnel's owning agent, so log in with an agent key rather than an org key."
---

# CLI
URL: /docs/cli
LLM index: /llms.txt
Description: The aid command — log in, create agents, send mail, tail events, talk to other agents over A2A, run tunnels.
Related: /docs/sdk, /docs/getting-started/quickstart, /docs/tunnels

<!-- farming-labs:agent-contract:start -->
## Agent Contract

Task: Operate your account from a terminal — log in, create an agent, send mail, and tail the event log.
Outcome: `aid` stores a session, and subsequent commands act as the logged-in org or agent without re-authenticating.

### Applies To

- Package: `@aid/cli`

### Prerequisites

- The API base URL (https://api.agent-identity.dev) and an API key.

### Files

- `packages/cli/src/bin.ts`

### Side Effects

- Writes a config file containing the API key; AID_CONFIG_PATH overrides its location.

### Verification

- Confirm the stored session.
  - Expected: aid whoami prints the organization, and the agent when logged in with an agent key.

### Rollback

- aid logout removes the stored session. Revoking the key invalidates it everywhere.

### Failure Modes

- Commands exit non-zero with an authentication error after a redeploy. — Recovery: The stored key was revoked or belongs to a recreated org. Log in again with a current key.
- Connecting a tunnel is rejected with 401. — Recovery: The edge authenticates as the tunnel's owning agent, so log in with an agent key rather than an org key.
<!-- farming-labs:agent-contract:end -->

# CLI

`aid` is the operator-facing half of the SDK. It keeps credentials in a config file so
every later command is one line.

```bash title="terminal"
export AID_BASE_URL=https://api.agent-identity.dev
aid login --api-key aid_live_…
```

Both flags are optional: the CLI falls back to `AID_BASE_URL` and `AID_API_KEY`, and
prompts interactively when neither is set. Without `AID_BASE_URL` (or `--base-url`) it
defaults to `http://localhost:8080`, so set it to the hosted URL above. Login is not a formality — it calls
`/v1/me` and refuses to store a key that does not authenticate.

Credentials go to `$XDG_CONFIG_HOME/aid/config.json` (or `~/.config/aid/config.json`)
with mode `0600`. `AID_CONFIG_PATH` overrides the location, which is how you keep separate
profiles for separate environments.

## Commands

```
aid login    [--base-url <url>] [--api-key <key>]
aid logout
aid whoami

aid org create     --name <name> --slug <slug> [--base-url <url>]

aid agent create   --handle <handle> --display-name <name>
aid agent inspect  <identity-id>

aid mail send      --agent <identity-id> --to <email> [--to …] [--cc <email>]
                   [--subject <s>] [--text <s>] [--html <s>]
                   [--in-reply-to <message-id>] [--idempotency-key <key>]

aid events tail    --type <event-type> [--agent <identity-id>]
                   [--thread-id <id>] [--since <iso8601>]

aid a2a enable     --agent <identity-id> [--off]
aid a2a card       --handle <handle> | --agent <identity-id>
aid a2a rules      [--agent <identity-id>]
aid a2a rule add   --agent <identity-id> --handle <peer> --action allow|block
                   [--direction inbound|outbound|both]
aid a2a send       --to-handle <handle> | --to-id <identity-id> --text <s>
                   [--context <id>] [--message-id <id>]
aid a2a tasks      [--agent <identity-id>] [--q <words>] [--state <s>] [--limit <n>]
aid a2a task       <task-id>
aid a2a reply      <task-id> --intent progress|ask_caller|complete|fail --text <s>
aid a2a cancel     <task-id>
aid a2a contexts   [--agent <identity-id>]
aid a2a rename-context <context-id> --name <name>
aid a2a messages   [--agent <identity-id>] [--q <words>] [--task <id>] [--context <id>]
aid a2a call       <card-url> --text <s> [--api-key <key>] [--context <id>] [--task <id>]
                   [--message-id <id>] [--no-wait]
aid a2a check      <card-url>
aid a2a invite     --agent <identity-id> [--agent …] [--email <address>]
                   [--expires-hours <n>] [--message <s>]
aid a2a accept     --token <invitation-token> [--agent <identity-id>]

aid tunnel create  --agent <identity-id> [--hostname <name>]
aid tunnel list    --agent <identity-id>
aid tunnel connect <tunnel-id> [--local <url>]
```

## Bootstrapping

`aid org create` is the one command that works before you have a key — it creates the
organization and logs you in as its admin in a single step:

```bash title="terminal"
aid org create --name Acme --slug acme --base-url https://api.agent-identity.dev
aid agent create --handle support-agent --display-name "Support Agent"
```

```
Created agent "support-agent" (6f21…).
Mailbox: support-agent@yourdomain.com
```

## Watching the log

```bash title="terminal"
aid events tail --type mail.received --agent 6f21…
```

```
Tailing "mail.received" events... (Ctrl-C to stop)
[2026-09-27T10:04:11.221Z] mail.received (b70c…) {"messageId":"e133…","threadId":"9a04…"}
```

`events tail` re-arms the long-poll wait after each event, so it follows indefinitely
rather than timing out at 55 seconds. `--since` takes an ISO 8601 timestamp to start from
a point in the past. Ctrl-C stops it cleanly.

This is the fastest way to see whether something is happening at all — run it in one
terminal while you trigger work in another.

## Agent-to-agent

Sending, replying and cancelling act **as an agent**, so log in with that agent's key
(`aid login --api-key …`); rules, settings, invitations and `--agent` filters need an org key.

```bash title="terminal"
aid a2a enable --agent 6f21…
aid a2a send --to-handle partner-support --text "Can you refund order 1142?"
aid a2a tasks --q refund
aid a2a task 01a3…                     # the whole conversation
aid a2a reply 01a3… --intent complete --text "Refunded."   # as the worker
```

`aid a2a call` and `aid a2a check` work on **any** A2A agent, not just ours, and need no login:
`check` reads the card and says whether a client can call it, over what, and with which credential;
`call` sends a message and prints the task. The key you pass with `--api-key` goes only to the agent
you name, never anywhere else.

```bash title="terminal"
aid a2a check https://api.agent-identity.dev/a2a/partner-support/card
aid a2a call  https://api.agent-identity.dev/a2a/partner-support/card \
  --api-key aid_live_… --text "Can you refund order 1142?"
```

`aid a2a invite` without `--email` prints a hand-off prompt once — the token is not shown
again. See [Connect requests](/docs/a2a/connect-requests) for what a connect request does.

## Exit behaviour

Errors print as `Error: <message>` on stderr with a non-zero exit code. API failures carry
the server's own message, so a `409` from a mismatched idempotency key says so rather than
surfacing as a generic failure. Long-running commands — `events tail`, `tunnel connect` —
handle SIGINT and shut down in an orderly way.

## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
Docs-scoped sitemap: [/docs/sitemap.md](/docs/sitemap.md).
Well-known sitemap: [/.well-known/sitemap.md](/.well-known/sitemap.md).
