A command-line client for the A2A (Agent-to-Agent)
Protocol, built on the official a2a-go
SDK.
Install the latest released binary:
curl -fsSL https://raw.githubusercontent.com/kynoproj/a2acli/main/install.sh | bashOr install via Go:
go install github.com/kynoproj/a2acli@latestOr build from source:
make buildAll commands take --url (-u) pointing at the A2A server's base URL. When
--url is omitted, a2acli falls back to the A2A_SERVER environment
variable. The AgentCard is fetched from <url>/.well-known/agent-card.json and
the client connects using the transport selected by --protocol (default
jsonrpc).
Supported --protocol values:
jsonrpc— JSON-RPC over HTTP (default).rest— REST / HTTP+JSON.grpc— gRPC.
a2acli [command]
Commands:
card Fetch and print the AgentCard
send Send a message to the agent and print the response
task get Fetch a task by ID
task list List tasks
task cancel Cancel a task by ID
task subscribe Re-subscribe to an existing task and stream events
version Print binary version and build metadata
Global flags:
-u, --url string Base URL of the A2A agent server (falls back to $A2A_SERVER)
-p, --protocol string Transport protocol: jsonrpc, rest, or grpc (default jsonrpc)
-k, --insecure Skip TLS certificate verification
--plaintext Disable TLS entirely (gRPC only)
--tenant string Optional agent-owner tenant ID applied to every request
--timeout duration HTTP timeout (default 30s)
-H, --header stringArray Extra header to send with every request, including the agent-card fetch and protocol calls (repeatable)
-v, --verbose Log request URL, request body, and response body to stderr
--override-host string Override the host[:port] of every URL in the resolved AgentCard (e.g. 127.0.0.1:9001)
--endpoint string Direct endpoint URL for the chosen --protocol; bypasses the AgentCard fetch
-o, --output string Output format: text or json (default text)
--no-color Disable ANSI colors in terminal output (also honors $NO_COLOR)
send flags:
--accept strings Accepted output MIME types (repeatable or comma-separated)
--history-length int Number of history messages to include in the response
--return-immediately Return as soon as the task is created instead of waiting for completion (incompatible with --stream)
--task string Task ID to continue an existing task
--context string Context ID to associate the message with an existing conversation
-f, --file string Read the message from a JSON file (an a2a.Message object) instead of positional text
--json string Raw JSON a2a.Message object to send instead of positional text
--parts string Raw JSON array of content parts to send as a user message
--stream Stream events as they arrive instead of waiting for the final response
--polling-interval duration (--stream) Duration between GetTask requests when falling back to polling (default 5s)
task get flags:
--history-length int Maximum number of history messages to retrieve
task list flags:
--context-id string Filter by context ID
--status string Filter by task state (e.g. submitted, working, completed)
--page-size int Max tasks per page (1-100, server default if 0)
--page-token string Page token from a previous response
--history-length int History messages to include per task
--include-artifacts Include task artifacts in the response
--since string Only list tasks with status updates after this RFC 3339 timestamp
version flags:
--short Print only the version string
The message source is chosen by precedence --json > --parts > --file >
positional text; only one may be combined with positional text.
--task/--context, when set, override any values carried in the chosen
source.
--stream always attempts real streaming first. If the agent's AgentCard
doesn't advertise streaming support (or the attempt fails for the same reason),
it falls back to polling GetTask every --polling-interval and synthesizes
streaming-like events from the task's state changes.
Every command that prints a result honors -o/--output:
text(default) — a compact, human-readable rendering of cards, tasks, messages, and streamed events.json— the raw A2A protocol objects as indented JSON, for scripting.
Breaking change: the default is now
text. Previous releases always emitted JSON. Add-o json(or--output json) to any command that feeds a JSON parser — for examplea2acli task get -o json <id> | jq ..
| Variable | Effect |
|---|---|
A2A_SERVER |
Default for --url when the flag is not provided. The flag, when set, always wins. |
NO_COLOR |
Disables ANSI colors in terminal output, same as --no-color. |
export A2A_SERVER=http://127.0.0.1:9001
a2acli card # uses $A2A_SERVER
a2acli card --url http://other:9001 # flag winsFetch an AgentCard:
a2acli card -u http://127.0.0.1:9001Send a message:
a2acli send -u http://127.0.0.1:9001 "Hello, what can you do?"Stream a message and watch task updates:
a2acli send --stream -u http://127.0.0.1:9001 "Summarize the latest news"Inspect a task:
a2acli task get -u http://127.0.0.1:9001 <task-id>
a2acli task list -u http://127.0.0.1:9001 --status working
a2acli task list -u http://127.0.0.1:9001 --since 2026-08-01T00:00:00Z
a2acli task cancel -u http://127.0.0.1:9001 <task-id>
a2acli task subscribe -u http://127.0.0.1:9001 <task-id>task list --status takes the short state names (submitted, working,
completed, failed, canceled, rejected, input-required,
auth-required); --since takes an RFC 3339 timestamp and lists only tasks
with status updates after it.
Constrain the response with SendMessageConfig knobs:
a2acli send -u http://127.0.0.1:9001 \
--accept application/json --history-length 5 --return-immediately \
"Summarize this"Continue an existing task or conversation. Take the task ID / context ID
returned by a prior send (shown as Task:/Context: in text output, or
taskId/contextId under -o json) and pass them to the next turn:
a2acli send -u http://127.0.0.1:9001 --task <task-id> "And translate it to French"
a2acli send -u http://127.0.0.1:9001 --context <context-id> "What did I just ask?"Send a message from a file. The file holds a JSON a2a.Message object, which
lets you send multi-part or non-text messages that positional text can't express
(a missing messageId is generated automatically). --task/--context, when
set, override any values in the file:
cat > message.json <<'EOF'
{ "role": "ROLE_USER", "parts": [{ "text": "Describe this diagram" }] }
EOF
a2acli send -u http://127.0.0.1:9001 -f message.json
a2acli send --stream -u http://127.0.0.1:9001 -f message.json --task <task-id>Pass a message inline as raw JSON, either a full a2a.Message (--json) or
just its content parts (--parts, wrapped in a user message for you):
a2acli send -u http://127.0.0.1:9001 \
--json '{"role":"ROLE_USER","parts":[{"text":"Hello"}]}'
a2acli send -u http://127.0.0.1:9001 --parts '[{"text":"one"},{"text":"two"}]'Address a tenant on multi-tenant agents:
a2acli send -u https://agent.example.com --tenant acme "Hello"Trace traffic with -v (verbose output goes to stderr, so the command's stdout
output stays pipeable):
a2acli -v send -u http://127.0.0.1:9001 "Hello"
# → AgentCard http://127.0.0.1:9001/.well-known/agent-card.json
# ← AgentCard http://127.0.0.1:9001
# → SendMessage http://127.0.0.1:9001
# request: {"messageId":"...","parts":[{"text":"Hello"}],"role":"ROLE_USER"}
# ← SendMessage http://127.0.0.1:9001
# response: {...}Pass authentication via -H:
a2acli card -u https://agent.example.com -H "Authorization: Bearer $TOKEN"Talk to a gRPC server (plaintext, e.g. local dev):
a2acli send -u http://127.0.0.1:9001 -p grpc --plaintext "Hello"Talk to a gRPC server over TLS, skipping certificate verification (e.g. self-signed cert):
a2acli send -u https://agent.example.com -p grpc -k "Hello"Talk to a REST server:
a2acli send -u http://127.0.0.1:9001 -p rest "Hello"Override the host[:port] returned in the AgentCard (e.g. when the agent advertises an internal address but you've port-forwarded it locally):
a2acli send -u http://agent.internal -p grpc --plaintext --override-host 127.0.0.1:9001 "Hello"Bypass the AgentCard entirely with --endpoint. Use this when the server either
does not expose /.well-known/agent-card.json, or its AgentCard is missing or
misreports supportedInterfaces — a2acli will skip resolution and connect
straight to the endpoint you supply with the chosen --protocol:
# JSON-RPC over HTTP
a2acli send -p jsonrpc --endpoint http://127.0.0.1:9001 "Hello"
# REST / HTTP+JSON
a2acli send -p rest --endpoint http://127.0.0.1:9001 "Hello"
# gRPC (plaintext)
a2acli send -p grpc --plaintext --endpoint 127.0.0.1:9001 "Hello"--endpoint is incompatible with --override-host (set the endpoint URL
directly) and with a2acli card (which has nothing to fetch).
Run interactively inside a cluster:
kubectl run a2acli-debug --rm -it --restart=Never \
--image=quay.io/kynoproj/a2acli:v0.1.0 \
--command -- bash
# then, inside the pod:
a2acli card -u http://my-agent.default.svc:9001Or as an ephemeral debug container against an existing pod:
kubectl debug -it some-pod --image=quay.io/kynoproj/a2acli:v0.1.0 -- bashApache-2.0. See LICENSE.