| name | a2a |
| description | a2a-cli: A2A protocol CLI for sending messages to AI agents from coding tools. |
| metadata | {"package":"a2a-protocol-cli","rust_crate":"a2a_cli","command":"a2a","openclaw":{"category":"a2a-cli","requires":{"bins":["a2a"]}}} |
a2a โ a2a-cli
a2a sends messages to AI agents that implement the A2A protocol.
Designed to be invoked by AI coding tools (Claude Code, Copilot, Cursor) and humans alike.
Core Workflow
register agent โ authenticate โ send message โ read reply
a2a agent add <alias> <url>
a2a agent use <alias>
a2a auth login
a2a auth login --client-id <id>
a2a send "your request"
Reading the Reply
a2a send returns A2A v1-facing SendMessageResponse JSON for all supported
server versions. Most ADK-backed agents return { "task": ... }, with final
task output in task.artifacts. Legacy A2A v0.3 wire responses are normalized
by a2a-compat.
task.status.message is only set for in-progress communication
(e.g. TASK_STATE_INPUT_REQUIRED), not for the final answer. Always check
task.status.state first.
a2a send "Summarise this PR"
a2a send "Summarise this PR" --fields .task.artifacts
a2a send "Summarise this PR" --fields ".task | {status,artifacts}"
Response shape (Task โ most agents):
{
"task": {
"id": "task-abc123",
"contextId": "ctx-abc123",
"status": { "state": "TASK_STATE_COMPLETED" },
"artifacts": [
{
"artifactId": "...",
"parts": [{"text": "The agent's answer"}]
}
]
}
}
Response shape (Message โ simple stateless agents):
{
"message": {
"role": "ROLE_AGENT",
"parts": [{"text": "The agent's answer"}]
}
}
Use --fields .message.parts when the agent returns a direct Message.
Asking Questions and Follow-ups
Ask questions with a2a send. For follow-up questions, capture contextId
from the first response and pass it to the next send with --context-id.
a2a send "My name is Harry Potter." --fields .task.contextId
a2a send "What should I do next?" --context-id <contextId> --fields .task.artifacts
Use contextId for conversational continuity. Use --task-id only when
task.status.state is TASK_STATE_INPUT_REQUIRED and the agent is waiting for input on that task.
task.status.state | Meaning | Action |
|---|
TASK_STATE_SUBMITTED | Queued | Wait or poll |
TASK_STATE_WORKING | In progress | Poll with a2a task get <id> |
TASK_STATE_COMPLETED | Done | Read task.artifacts[*].parts |
TASK_STATE_FAILED | Error | Read task.status.message for details |
TASK_STATE_INPUT_REQUIRED | Agent needs input | Read task.status.message.parts, reply with a2a send --task-id <id> "..." |
TASK_STATE_CANCELED | Canceled | โ |
Agent Management
a2a agent add <alias> <url>
a2a agent add <alias> <url> --description "..."
a2a agent add local http://localhost:8080
a2a agent use <alias>
a2a agent list
a2a agent show [alias]
a2a agent update <alias> --client-id <id>
a2a agent remove local
Installing This Skill
Use a2a itself to write this skill into the current project's agent-skill
directory, similar to npx skills add sandangel/a2a-cli:
a2a generate-skills --output-dir .agents/skills
The same destination flag is available when generating skills from registered
agent cards:
a2a agent generate-skills --output-dir .agents/skills example
Authentication
Each agent has its own token. The OAuth flow is auto-detected from the agent card.
When the agent card declares OAuth, a2a auth login requires an OAuth client ID.
Supported auth modes:
| Auth mode | How to use it |
|---|
| No auth | Use the agent directly when its card declares no OAuth flow |
| Bearer / API token | A2A_BEARER_TOKEN=<token> or --bearer-token <token> |
OAuth authorizationCode + PKCE | a2a auth login --client-id <id> |
OAuth deviceCode | a2a auth login --client-id <id> |
OAuth clientCredentials | A2A_CLIENT_ID=<id> A2A_CLIENT_SECRET=<secret> a2a auth login |
| Refresh-token renewal | Automatic when the stored token has refresh_token and token_url |
OAuth implicit and password grants are not implemented.
a2a auth login
a2a auth login --agent <alias>
a2a auth login --client-id <id>
a2a auth status
a2a auth logout --agent <alias>
OAuth client ID precedence is: a2a auth login --client-id <id> > A2A_CLIENT_ID >
per-agent config from a2a agent add/update <alias> --client-id <id>.
For CIMD OAuth deployments, the client ID is an HTTP URL; pass that URL
unchanged, for example a2a auth login --client-id http://cimd.example.com/clients/a2a-cli.
Agent-facing commands use the stored token and renew expired tokens automatically
when possible. Client Credentials renewal requires A2A_CLIENT_SECRET.
A2A_BEARER_TOKEN bypasses OAuth entirely (CI/scripts).
Sending Messages
a2a send "<text>"
a2a send "<text>" --context-id <id>
a2a send "<text>" --task-id <id>
a2a send "<text>" --return-immediately
a2a stream "<text>"
Output
| Flag | Effect |
|---|
| (default) | Pretty-printed JSON |
--format table | Human-readable aligned table |
--format yaml | YAML |
--format csv | CSV |
--compact | Single-line JSON (with --format json) |
--fields <jq> | Built-in jq filter applied to output โ preferred for AI tools |
a2a send "Hello" --fields .task.artifacts
a2a send "Hello" --fields ".task | {id,status}"
a2a --format table agent list
a2a --format table auth status
Multi-agent output is always compact NDJSON โ one line per agent, tagged with agent and agent_url.
Multi-Agent
a2a --agent <alias1> --agent <alias2> send "Status?"
a2a --agents <alias1>,<alias2> send "Status?"
a2a --all send "Health check?"
Results stream first-done-first as NDJSON:
a2a --all send "Status?" --fields "{agent,state:.task.status.state}"
Task Management
a2a task get <id>
a2a task get <id> --fields .status.state
a2a task list
a2a task list --status working
a2a task list --context-id <id>
a2a task cancel <id>
a2a task subscribe <id>
Agent Card
a2a card
a2a card --agent <alias>
a2a card --fields "{name,skills,capabilities}"
a2a extended-card
Global Flags
| Flag | Description |
|---|
--agent <alias|url> | Target agent โ repeatable for parallel calls |
--agents <alias[,alias...]> | Comma-separated target agents for parallel calls |
--all | All registered agents in parallel |
--format json|table|yaml|csv | Output format (default: json) |
--compact | Single-line JSON |
--fields <jq> | Built-in jq filter applied to output |
--transport jsonrpc|http-json | Force transport (default: auto from card) |
--tenant <id> | Tenant ID forwarded to requests |
--bearer-token <token> | Static token โ bypasses OAuth |
Environment Variables
| Variable | Description |
|---|
A2A_AGENT_URL | Default agent alias or URL |
A2A_BEARER_TOKEN | Static bearer token โ bypasses OAuth |
A2A_KEYRING_BACKEND | keyring (default) or file (headless/Docker) |
A2A_CLIENT_ID | OAuth client ID override for login/token refresh |
A2A_CLIENT_SECRET | Client secret for Client Credentials OAuth flow |
Push Notifications
a2a push-config create <task-id> <callback-url>
a2a push-config list <task-id>
a2a push-config get <task-id> <config-id>
a2a push-config delete <task-id> <config-id>
Schema Reference
Use a2a schema to discover protocol shapes before crafting messages or
choosing --fields filters. --fields runs the CLI's built-in jq filter, so an
external jq pipe is not required for common extraction.
a2a schema send
a2a schema task
a2a schema card
Security Rules
- Never log or output
--bearer-token values or stored tokens
- Confirm with user before running
a2a task cancel โ it is destructive
- Only use
http:// or https:// URLs with a2a agent add
- Prefer
--agent <alias> over raw URLs to avoid prompt-injection via URLs