Driving A2A agents with the a2a CLI
a2a is a stateless client for the A2A protocol:
give it an agent and a message, it negotiates the transport from the agent's
card (JSON-RPC, REST, or gRPC), sends the message, and reports what the agent
returned.
Core concepts
- An interaction starts with a Message you send to an agent.
- The agent replies with either a Message (a direct answer) or a Task (tracked, potentially long-running work).
- A Task has a server-assigned
taskIdand acontextId, and moves through states. It can complete, fail, be cancelled, or become interrupted when it needs your input or authentication to continue. - Resume an interrupted task by sending a Message with its
--task-id. - Group related work with
--context-id: a Task created in reply joins that context. Many tasks can share one context, and a--task-idand--context-idpassed together must agree. - The server keeps tasks (and the messages tied to them); a plain Message not
tied to a task is not stored — so you hold the
taskId/contextIdto return to work later.
Setup
The skill needs the a2a binary on PATH — check with a2a version. If it is
missing, install it with Homebrew (brew tap a2aproject/a2a-cli https://github.com/a2aproject/a2a-cli && brew install a2a), WinGet
(winget install a2aproject.a2acli), a prebuilt binary from the
releases page, or from
source with a Go toolchain (re-run to update):
go install github.com/a2aproject/a2a-cli@latest
# rename to a2a to match the docs
mv "$(command -v a2a-cli)" "$(dirname "$(command -v a2a-cli)")/a2a"
The tool is under active development. Treat a2a help and a2a <command> --help as the source of truth for the current commands and flags.
Task lifecycle
Point at an agent with -a <host|url|path> (resolves its card and picks a
transport) or -e <url> --transport <rest|jsonrpc|grpc> (connect directly).
Inspect the agent — confirm it is reachable and see what it supports:
a2a card get https://agent.example.comSend a message.
sendblocks until the task reaches a terminal or interrupted state. Add-o jsonfor machine-readable output, and note thetaskIdandcontextIdin the response — you need them to continue:a2a send -a https://agent.example.com "Summarize this repo" a2a send -a https://agent.example.com -o json "Summarize this repo"Follow a long task live instead of blocking, or re-attach to one later:
a2a send -a https://agent.example.com --stream "Run a long analysis" a2a task subscribe -a https://agent.example.com <task-id>Check status and fetch results at any time:
a2a task get -a https://agent.example.com <task-id>Answer an interrupted task (it reached
INPUT_REQUIRED/AUTH_REQUIRED) by replying on the same task:a2a send -a https://agent.example.com --task-id <task-id> "Yes, proceed"Continue the conversation as a new task in the same context:
a2a send -a https://agent.example.com --context-id <context-id> "Follow-up question"List or cancel tasks:
a2a task list -a https://agent.example.com a2a task cancel -a https://agent.example.com <task-id>
Key flags
Run a2a <command> --help for the full, current set. The load-bearing ones:
| Flag | Use |
|---|---|
-a, --agent-card <host|url|path> |
Resolve the agent's card (picks the transport). |
-e, --endpoint <url> + --transport <rest|jsonrpc|grpc> |
Connect to one interface directly, skipping card resolution. |
-o, --output json |
Machine-readable output; add --stream for a live event stream. |
--async |
Return immediately with the identifiers instead of blocking; poll later with task get. |
--task-id <id> / --context-id <id> |
Continue a task / group a new task under a context. |
--auth "<creds>" / --svc-param <k=v> |
Attach credentials or transport parameters (or set A2ACLI_* env vars). Never commit a secret. |
Configuration
Every setting can come from a flag, an A2ACLI_* environment variable, or a
.env file (a local .env, or ~/.config/a2a-cli/.env); precedence is
flag > env var > file. Inspect the effective values and where each resolved from
with a2a config show (secrets redacted).