From 043561524a79c5b9dc1165ad7200bdbf18cacb06 Mon Sep 17 00:00:00 2001 From: Sampath Kumar Date: Tue, 1 Sep 2026 21:03:01 +0000 Subject: [PATCH 1/3] docs: add a2a-cli agent skill --- skills/a2a-cli/README.md | 102 ++++++++++++++++++++++++ skills/a2a-cli/SKILL.md | 162 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 264 insertions(+) create mode 100644 skills/a2a-cli/README.md create mode 100644 skills/a2a-cli/SKILL.md diff --git a/skills/a2a-cli/README.md b/skills/a2a-cli/README.md new file mode 100644 index 0000000..4c8d6cf --- /dev/null +++ b/skills/a2a-cli/README.md @@ -0,0 +1,102 @@ +# a2a-cli agent skill + +An [Agent Skill](https://agentskills.io/) that teaches an AI coding agent to +drive the [`a2a` CLI](https://github.com/a2aproject/a2a-cli), the command-line +client for [A2A (Agent2Agent)](https://a2a-protocol.org/) agents. + +It is one file, `SKILL.md`. Once it is installed, your agent can: + +- fetch an agent's card, +- send it a task, +- stream or poll for the result, and +- log each task it starts, so you can follow up later. + +## Prerequisite + +The skill drives the `a2a` binary; it does not install it. Install `a2a` first: + +```bash +go install github.com/a2aproject/a2a-cli@latest +``` + +Confirm it is on your `PATH`: + +```bash +a2a version +``` + +## Installation + +Fetch the one skill file into the place your agent loads skills from. Many agents +read `~/.agents/skills/`; CloudCode reads `~/.config/cloudcode/skills/`. + +```bash +mkdir -p ~/.agents/skills/a2a-cli +wget -O ~/.agents/skills/a2a-cli/SKILL.md \ + https://raw.githubusercontent.com/a2aproject/a2a-cli/main/skills/a2a-cli/SKILL.md +``` + +## Verify + +Check the file landed: + +```bash +ls ~/.agents/skills/a2a-cli # SKILL.md +``` + +Then start a new agent session. Confirm the agent lists `a2a-cli` among its +available skills. + +## Try it — confirm the skill works + +Hand these two prompts to your agent, in order. Together they exercise the whole +path: loading the skill, starting an agent, sending a message, and logging the +task. + +**1. Start a local echo agent.** + +> Using the a2a-cli skill, start a local echo A2A agent in the background on port 9090. + +Your agent should run `a2a server --echo --port 9090 &`. Confirm it is up: + +```bash +a2a card get http://localhost:9090 +# Name: Echo Agent ... Interfaces: HTTP+JSON http://127.0.0.1:9090 +``` + +**2. Send it a message and log the task.** + +> Send "hello from a2a" to the agent at http://localhost:9090, show me the reply, and log the task. + +The echo agent returns your text, and the task lands in the log: + +```bash +cat .a2a-cli-logs/tasks.jsonl +# one record: agent, taskId, contextId, state=TASK_STATE_COMPLETED, summary +``` + +Stop the background agent when done: + +```bash +pkill -f "a2a server --echo" +``` + +## Usage + +You do not run the skill yourself. Your agent loads it and follows it when a task +calls for A2A. Just ask, for example: + +> Fetch the agent card at `http://localhost:8080` and send it "summarize this repo". + +## Uninstall + +Remove the directory you created: + +```bash +rm -rf ~/.agents/skills/a2a-cli +``` + +## License + +Apache License 2.0, matching the +[a2a-cli project](https://github.com/a2aproject/a2a-cli/blob/main/LICENSE). diff --git a/skills/a2a-cli/SKILL.md b/skills/a2a-cli/SKILL.md new file mode 100644 index 0000000..2ee3fab --- /dev/null +++ b/skills/a2a-cli/SKILL.md @@ -0,0 +1,162 @@ +--- +name: a2a-cli +description: >- + Use and learn the `a2a` CLI (github.com/a2aproject/a2a-cli), a command-line + client for A2A (Agent2Agent) agents. Use when discovering an agent's card, + sending a message or task to an A2A agent, streaming or polling for the + result, or checking a task's status later. Because the CLI is stateless, this + skill records each task started — agent URL, task ID, context ID — to a local + log so it can be followed up afterwards. +compatibility: >- + Requires the `a2a` binary on PATH (github.com/a2aproject/a2a-cli). No prebuilt + releases exist yet, so install from source with Go — see Requirements. This + skill installs nothing on its own. +license: Apache-2.0 +--- + +# Using and learning the `a2a` CLI + +`a2a` is a command-line client for the [A2A protocol](https://a2a-protocol.org/): +give it an agent and a message, and it negotiates the transport from the agent's +card, sends the message, and reports what the agent returned — over JSON-RPC, +REST, or gRPC, the same way each time. + +## Requirements + +This skill drives the `a2a` binary; it does not install it. Check for it, and +install from source if missing (no prebuilt releases yet; needs a Go toolchain +from https://go.dev/doc/install): + +```bash +command -v a2a && a2a version || go install github.com/a2aproject/a2a-cli@latest +``` + +Re-run the `go install` command to update. The tool is under active development, +so the command surface can change between builds — always trust `a2a --help` +over memory. + +## Learn the tool from the tool itself + +The CLI is the source of truth for its own commands and flags — do not rely on a +memorized list, which goes stale as the tool evolves. Discover the current +surface at runtime: + +```bash +a2a help # every command +a2a send --help # flags for one command +a2a card get --help +a2a task --help # get, list, cancel, subscribe, push-config +``` + +## Model — what to know before sending + +- **Name the agent** with `-a ` (resolves its card and picks a + transport) or `-e --transport ` (connect to one + interface directly). You choose the endpoint; the CLI talks only to what you + give it. +- **Ask for JSON when scripting.** `-o json` prints one parseable object; add + `--stream` to instead emit a stream of event objects as they arrive. +- **It blocks by default** until the task finishes — no sleep loops needed. Use + `--async` only if you will follow up later with `a2a task get`. +- **Success is the task state, not the exit code.** A run the CLI completed exits + `0` even when the agent's task ended `TASK_STATE_FAILED`/`REJECTED` or paused + at `INPUT_REQUIRED`/`AUTH_REQUIRED`. In JSON read `status.state`; treat + `TASK_STATE_COMPLETED` as success. (The `text` view shows the short name, e.g. + `completed`.) +- **The CLI is stateless.** It never remembers the last task. To continue one you + must pass `--task-id`; to group a new task in an existing conversation you pass + `--context-id`. That is why every task you start must be **recorded** — below. + +## Record every task you start + +The CLI keeps no history, so the only way to check a task's status or continue it +later is to have saved its identifiers: the **agent**, the **taskId**, and the +**contextId**. After any `send` that starts a task, append a record to a local +log. + +### 1. Pick the log directory (once per working directory) + +Prefer a per-project local folder; reuse whichever already exists; only ask the +user when neither does. + +```bash +a2a_log_dir() { + if [ -d ./.a2a-cli-logs ]; then echo ./.a2a-cli-logs; return 0; fi + if [ -d "$HOME/.a2a-cli-logs" ]; then echo "$HOME/.a2a-cli-logs"; return 0; fi + return 1 # neither exists: ask the user A vs B, then create the chosen one +} +``` + +- If it returns a path, tell the user which log you are using and go on. +- If it returns non-zero, ask: **local `./.a2a-cli-logs/` (recommended)** or + **global `~/.a2a-cli-logs/`**, then `mkdir -p` the chosen one. Add a local + folder to `.gitignore` so logs are never committed. + +### 2. Send and record in one step + +`a2a send -o json` returns the protocol object. A created task is a `Task` with +`id`, `contextId`, and `status.state`; a direct `Message` reply has no `id` and +nothing to follow up on. Record a short message **summary**, never the full +content, so no secret or PII lands on disk. + +```bash +a2a_record() { # usage: | a2a_record + python3 -c ' +import json, os, sys, datetime +agent, summary, path = sys.argv[1], sys.argv[2], sys.argv[3] +task = json.load(sys.stdin) +task = task.get("task", task) # tolerate a future SendMessageResponse wrapper +tid = task.get("id") +if not tid: # a direct Message reply: nothing to track + sys.exit(0) +rec = { + "ts": datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), + "agent": agent, "taskId": tid, "contextId": task.get("contextId"), + "state": task.get("status", {}).get("state"), "summary": summary[:80], +} +os.makedirs(os.path.dirname(path) or ".", exist_ok=True) +open(path, "a").write(json.dumps(rec) + "\n") +' "$1" "$2" "$3" +} + +a2a_send_logged() { # usage: a2a_send_logged [extra a2a flags...] + local agent="$1" message="$2"; shift 2 + local dir; dir="$(a2a_log_dir)" || { echo "choose a log dir first" >&2; return 1; } + local json; json="$(a2a send -a "$agent" -o json "$message" "$@")" || return 1 + printf '%s\n' "$json" # still show the caller the real output + printf '%s' "$json" | a2a_record "$agent" "$message" "$dir/tasks.jsonl" +} +``` + +Each record is one JSON line in `/tasks.jsonl`: + +```json +{"ts":"2026-09-01T15:26:18Z","agent":"http://127.0.0.1:8080","taskId":"01a0…","contextId":"01a0…","state":"TASK_STATE_COMPLETED","summary":"Summarize this document"} +``` + +### 3. Follow up on a recorded task + +Read the record for an agent + `taskId`, then use the tool to act on it: + +```bash +dir="$(a2a_log_dir)"; tail -n 20 "$dir/tasks.jsonl" # browse recent tasks + +a2a task get -a # current status + artifacts +a2a task subscribe -a # re-attach to a live stream +a2a send -a --task-id "" # continue / answer the task +``` + +Replying with `send --task-id` resumes a task paused at `INPUT_REQUIRED` or +`AUTH_REQUIRED`; `send --context-id ` starts a new task in the same +conversation. + +## A throwaway agent for testing + +`a2a server --echo` runs a local A2A agent that echoes messages back — useful for +learning the tool or testing connectivity without a real agent: + +```bash +a2a server --echo --port 8080 & +a2a card get http://127.0.0.1:8080 +a2a send -a http://127.0.0.1:8080 "ping" +``` From e35fe3455f054e1876ee2952b68fc98a64b49a7a Mon Sep 17 00:00:00 2001 From: Sampath Kumar Date: Tue, 1 Sep 2026 21:56:29 +0000 Subject: [PATCH 2/3] docs: refine a2a-cli skill --- skills/a2a-cli/SKILL.md | 207 +++++++++++++++------------------------- 1 file changed, 75 insertions(+), 132 deletions(-) diff --git a/skills/a2a-cli/SKILL.md b/skills/a2a-cli/SKILL.md index 2ee3fab..62d21c6 100644 --- a/skills/a2a-cli/SKILL.md +++ b/skills/a2a-cli/SKILL.md @@ -1,159 +1,102 @@ --- name: a2a-cli description: >- - Use and learn the `a2a` CLI (github.com/a2aproject/a2a-cli), a command-line - client for A2A (Agent2Agent) agents. Use when discovering an agent's card, - sending a message or task to an A2A agent, streaming or polling for the - result, or checking a task's status later. Because the CLI is stateless, this - skill records each task started — agent URL, task ID, context ID — to a local - log so it can be followed up afterwards. + Drive A2A (Agent2Agent) agents from the command line with the `a2a` CLI + (github.com/a2aproject/a2a-cli): fetch an agent's card, send it a message or + task, stream or poll for the result, and save each request and response to + local files so a stateless CLI's tasks can be followed up later. Use when + talking to, testing, or scripting an A2A agent endpoint. Not for building or + serving an A2A agent, and not for calling non-A2A HTTP APIs. compatibility: >- - Requires the `a2a` binary on PATH (github.com/a2aproject/a2a-cli). No prebuilt - releases exist yet, so install from source with Go — see Requirements. This - skill installs nothing on its own. + Requires the `a2a` binary on PATH; a Go toolchain installs it from source, + since there are no prebuilt releases yet. The skill installs nothing itself. license: Apache-2.0 +metadata: + source: https://github.com/a2aproject/a2a-cli --- -# Using and learning the `a2a` CLI +# Driving A2A agents with the `a2a` CLI -`a2a` is a command-line client for the [A2A protocol](https://a2a-protocol.org/): -give it an agent and a message, and it negotiates the transport from the agent's -card, sends the message, and reports what the agent returned — over JSON-RPC, -REST, or gRPC, the same way each time. +`a2a` is a stateless command-line client for the +[A2A protocol](https://a2a-protocol.org/): 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. -## Requirements +## Setup -This skill drives the `a2a` binary; it does not install it. Check for it, and -install from source if missing (no prebuilt releases yet; needs a Go toolchain -from https://go.dev/doc/install): +Check for the binary; install from source if missing (needs a Go toolchain from +https://go.dev/doc/install); re-run to update: ```bash -command -v a2a && a2a version || go install github.com/a2aproject/a2a-cli@latest +command -v a2a || go install github.com/a2aproject/a2a-cli@latest ``` -Re-run the `go install` command to update. The tool is under active development, -so the command surface can change between builds — always trust `a2a --help` -over memory. +The tool is under active development, so **exact commands and flags change** — +discover the current surface at runtime with `a2a help` and `a2a +--help`. The **workflow below does not change**, so follow it regardless of the +current flags. -## Learn the tool from the tool itself +## Workflow -The CLI is the source of truth for its own commands and flags — do not rely on a -memorized list, which goes stale as the tool evolves. Discover the current -surface at runtime: +Every interaction is the same four steps: -```bash -a2a help # every command -a2a send --help # flags for one command -a2a card get --help -a2a task --help # get, list, cancel, subscribe, push-config -``` - -## Model — what to know before sending - -- **Name the agent** with `-a ` (resolves its card and picks a - transport) or `-e --transport ` (connect to one - interface directly). You choose the endpoint; the CLI talks only to what you - give it. -- **Ask for JSON when scripting.** `-o json` prints one parseable object; add - `--stream` to instead emit a stream of event objects as they arrive. -- **It blocks by default** until the task finishes — no sleep loops needed. Use - `--async` only if you will follow up later with `a2a task get`. -- **Success is the task state, not the exit code.** A run the CLI completed exits - `0` even when the agent's task ended `TASK_STATE_FAILED`/`REJECTED` or paused - at `INPUT_REQUIRED`/`AUTH_REQUIRED`. In JSON read `status.state`; treat - `TASK_STATE_COMPLETED` as success. (The `text` view shows the short name, e.g. - `completed`.) -- **The CLI is stateless.** It never remembers the last task. To continue one you - must pass `--task-id`; to group a new task in an existing conversation you pass - `--context-id`. That is why every task you start must be **recorded** — below. - -## Record every task you start - -The CLI keeps no history, so the only way to check a task's status or continue it -later is to have saved its identifiers: the **agent**, the **taskId**, and the -**contextId**. After any `send` that starts a task, append a record to a local -log. - -### 1. Pick the log directory (once per working directory) - -Prefer a per-project local folder; reuse whichever already exists; only ask the -user when neither does. +1. **Discover** — fetch the agent's card to confirm it is reachable and see what + it supports. *(today: `a2a card get `)* +2. **Send** — send your message and capture the full output. It blocks until the + task finishes. Ask for JSON so you can read fields back. + *(today: `a2a send -a -o json ""`)* +3. **Record** — save the request and the response as the next numbered pair in + your log directory (see below). Never rely on the CLI's memory; it has none. +4. **Follow up** — read `taskId` and `contextId` from the saved response, then + check status, stream, or continue the task. + *(today: `a2a task get`, `a2a task subscribe`, `a2a send --task-id`)* -```bash -a2a_log_dir() { - if [ -d ./.a2a-cli-logs ]; then echo ./.a2a-cli-logs; return 0; fi - if [ -d "$HOME/.a2a-cli-logs" ]; then echo "$HOME/.a2a-cli-logs"; return 0; fi - return 1 # neither exists: ask the user A vs B, then create the chosen one -} -``` +## Recording requests and responses -- If it returns a path, tell the user which log you are using and go on. -- If it returns non-zero, ask: **local `./.a2a-cli-logs/` (recommended)** or - **global `~/.a2a-cli-logs/`**, then `mkdir -p` the chosen one. Add a local - folder to `.gitignore` so logs are never committed. +Keep a log directory: prefer a per-project `./.a2a-cli-logs/`; if it or +`~/.a2a-cli-logs/` already exists, reuse it and say which; otherwise ask the user +which to create, and add a local one to `.gitignore`. -### 2. Send and record in one step - -`a2a send -o json` returns the protocol object. A created task is a `Task` with -`id`, `contextId`, and `status.state`; a direct `Message` reply has no `id` and -nothing to follow up on. Record a short message **summary**, never the full -content, so no secret or PII lands on disk. +For each interaction, write two files, numbered in order — `agent.request.N` and +`agent.response.N`: ```bash -a2a_record() { # usage: | a2a_record - python3 -c ' -import json, os, sys, datetime -agent, summary, path = sys.argv[1], sys.argv[2], sys.argv[3] -task = json.load(sys.stdin) -task = task.get("task", task) # tolerate a future SendMessageResponse wrapper -tid = task.get("id") -if not tid: # a direct Message reply: nothing to track - sys.exit(0) -rec = { - "ts": datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), - "agent": agent, "taskId": tid, "contextId": task.get("contextId"), - "state": task.get("status", {}).get("state"), "summary": summary[:80], -} -os.makedirs(os.path.dirname(path) or ".", exist_ok=True) -open(path, "a").write(json.dumps(rec) + "\n") -' "$1" "$2" "$3" -} - -a2a_send_logged() { # usage: a2a_send_logged [extra a2a flags...] - local agent="$1" message="$2"; shift 2 - local dir; dir="$(a2a_log_dir)" || { echo "choose a log dir first" >&2; return 1; } - local json; json="$(a2a send -a "$agent" -o json "$message" "$@")" || return 1 - printf '%s\n' "$json" # still show the caller the real output - printf '%s' "$json" | a2a_record "$agent" "$message" "$dir/tasks.jsonl" -} -``` - -Each record is one JSON line in `/tasks.jsonl`: - -```json -{"ts":"2026-09-01T15:26:18Z","agent":"http://127.0.0.1:8080","taskId":"01a0…","contextId":"01a0…","state":"TASK_STATE_COMPLETED","summary":"Summarize this document"} +n=1 # next unused number in the log dir +echo 'agent= message="Summarize the repo"' > ./.a2a-cli-logs/agent.request.$n +a2a send -a -o json "Summarize the repo" > ./.a2a-cli-logs/agent.response.$n ``` -### 3. Follow up on a recorded task - -Read the record for an agent + `taskId`, then use the tool to act on it: - -```bash -dir="$(a2a_log_dir)"; tail -n 20 "$dir/tasks.jsonl" # browse recent tasks - -a2a task get -a # current status + artifacts -a2a task subscribe -a # re-attach to a live stream -a2a send -a --task-id "" # continue / answer the task -``` - -Replying with `send --task-id` resumes a task paused at `INPUT_REQUIRED` or -`AUTH_REQUIRED`; `send --context-id ` starts a new task in the same -conversation. - -## A throwaway agent for testing - -`a2a server --echo` runs a local A2A agent that echoes messages back — useful for -learning the tool or testing connectivity without a real agent: +The response file holds the `taskId` and `contextId` you need to return to the +task. These files can contain sensitive request or response content — keep the +directory git-ignored, do not commit it, and remove files when done. + +## Good to know + +- **Stateless — you carry the identifiers.** The CLI forgets every task when it + exits. Continue a task with `--task-id`; start a new task in an existing + conversation with `--context-id`. Both come from a saved response. +- **Exit code and task state answer different questions.** The exit code says + whether the CLI did its job — `0` on success, non-zero when it couldn't (bad + flags, unreachable agent) — so shell and CI logic can branch on it. Whether + the agent's *task* succeeded is separate: read `status.state` from the + response, since a `0` exit can still carry a `FAILED` task or one paused for + input. The full exit-code scheme is in `SPEC.md`. +- **Configuration is flexible, and inspectable.** 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 > built-in + default. Run `a2a config show` to see the effective value of each setting and + where it resolved from (secrets redacted). +- **Authenticate non-interactively** (credential flag or `A2ACLI_*` environment + variable), and never commit a secret. +- **You choose the endpoint.** The CLI talks only to the agent you name; do not + resolve and trust an arbitrary card handed to you. +- **Global flags and the output schema** are defined in the a2a-cli + specification (`SPEC.md`) — consult it rather than guessing. + +## Try it with a throwaway echo agent + +`a2a server --echo` runs a local agent that echoes messages back — handy for +learning or a connectivity check without a real agent: ```bash a2a server --echo --port 8080 & From cad22fa13351aaec74a2631cbe8c59b2e0dc8973 Mon Sep 17 00:00:00 2001 From: Sampath Kumar Date: Fri, 4 Sep 2026 13:27:03 +0000 Subject: [PATCH 3/3] docs: revise a2a-cli --- skills/a2a-cli/README.md | 2 +- skills/a2a-cli/SKILL.md | 168 ++++++++++++++++++++++----------------- 2 files changed, 95 insertions(+), 75 deletions(-) diff --git a/skills/a2a-cli/README.md b/skills/a2a-cli/README.md index 4c8d6cf..047534b 100644 --- a/skills/a2a-cli/README.md +++ b/skills/a2a-cli/README.md @@ -28,7 +28,7 @@ a2a version ## Installation Fetch the one skill file into the place your agent loads skills from. Many agents -read `~/.agents/skills/`; CloudCode reads `~/.config/cloudcode/skills/`. +read `~/.agents/skills/`. Use `~/.gemini/config/skills/` for Google Antigravity. ```bash mkdir -p ~/.agents/skills/a2a-cli diff --git a/skills/a2a-cli/SKILL.md b/skills/a2a-cli/SKILL.md index 62d21c6..431a41a 100644 --- a/skills/a2a-cli/SKILL.md +++ b/skills/a2a-cli/SKILL.md @@ -1,26 +1,43 @@ --- name: a2a-cli description: >- - Drive A2A (Agent2Agent) agents from the command line with the `a2a` CLI - (github.com/a2aproject/a2a-cli): fetch an agent's card, send it a message or - task, stream or poll for the result, and save each request and response to - local files so a stateless CLI's tasks can be followed up later. Use when - talking to, testing, or scripting an A2A agent endpoint. Not for building or - serving an A2A agent, and not for calling non-A2A HTTP APIs. + Delegate work to A2A (Agent2Agent) agents from the command line with the `a2a` + CLI (github.com/a2aproject/a2a-cli). Use when you need to hand a task to a + specialized or remote agent, fetch an agent's card, send a message to an agent + at a URL, stream or poll a running task, or check, list, resume, or cancel an + A2A task. Not for building or serving an A2A agent, or for calling non-A2A + HTTP APIs. compatibility: >- Requires the `a2a` binary on PATH; a Go toolchain installs it from source, since there are no prebuilt releases yet. The skill installs nothing itself. license: Apache-2.0 metadata: source: https://github.com/a2aproject/a2a-cli + version: "2026.09.04" --- # Driving A2A agents with the `a2a` CLI -`a2a` is a stateless command-line client for the -[A2A protocol](https://a2a-protocol.org/): 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. +`a2a` is a stateless client for the [A2A protocol](https://a2a-protocol.org/): +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 `taskId` and a `contextId`, 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-id` and `--context-id` + passed 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`/`contextId` to + return to work later. ## Setup @@ -28,78 +45,81 @@ Check for the binary; install from source if missing (needs a Go toolchain from https://go.dev/doc/install); re-run to update: ```bash -command -v a2a || go install github.com/a2aproject/a2a-cli@latest +go install github.com/a2aproject/a2a-cli@latest ``` -The tool is under active development, so **exact commands and flags change** — -discover the current surface at runtime with `a2a help` and `a2a ---help`. The **workflow below does not change**, so follow it regardless of the -current flags. +The tool is under active development. Treat `a2a help` and `a2a +--help` as the source of truth for the current commands and flags. -## Workflow +## Task lifecycle -Every interaction is the same four steps: +Point at an agent with `-a ` (resolves its card and picks a +transport) or `-e --transport ` (connect directly). -1. **Discover** — fetch the agent's card to confirm it is reachable and see what - it supports. *(today: `a2a card get `)* -2. **Send** — send your message and capture the full output. It blocks until the - task finishes. Ask for JSON so you can read fields back. - *(today: `a2a send -a -o json ""`)* -3. **Record** — save the request and the response as the next numbered pair in - your log directory (see below). Never rely on the CLI's memory; it has none. -4. **Follow up** — read `taskId` and `contextId` from the saved response, then - check status, stream, or continue the task. - *(today: `a2a task get`, `a2a task subscribe`, `a2a send --task-id`)* +1. **Inspect the agent** — confirm it is reachable and see what it supports: -## Recording requests and responses + ```bash + a2a card get https://agent.example.com + ``` -Keep a log directory: prefer a per-project `./.a2a-cli-logs/`; if it or -`~/.a2a-cli-logs/` already exists, reuse it and say which; otherwise ask the user -which to create, and add a local one to `.gitignore`. +2. **Send a message.** `send` blocks until the task reaches a terminal or + interrupted state. Add `-o json` for machine-readable output, and note the + `taskId` and `contextId` in the response — you need them to continue: -For each interaction, write two files, numbered in order — `agent.request.N` and -`agent.response.N`: + ```bash + a2a send -a https://agent.example.com "Summarize this repo" + a2a send -a https://agent.example.com -o json "Summarize this repo" + ``` -```bash -n=1 # next unused number in the log dir -echo 'agent= message="Summarize the repo"' > ./.a2a-cli-logs/agent.request.$n -a2a send -a -o json "Summarize the repo" > ./.a2a-cli-logs/agent.response.$n -``` +3. **Follow a long task live** instead of blocking, or re-attach to one later: -The response file holds the `taskId` and `contextId` you need to return to the -task. These files can contain sensitive request or response content — keep the -directory git-ignored, do not commit it, and remove files when done. - -## Good to know - -- **Stateless — you carry the identifiers.** The CLI forgets every task when it - exits. Continue a task with `--task-id`; start a new task in an existing - conversation with `--context-id`. Both come from a saved response. -- **Exit code and task state answer different questions.** The exit code says - whether the CLI did its job — `0` on success, non-zero when it couldn't (bad - flags, unreachable agent) — so shell and CI logic can branch on it. Whether - the agent's *task* succeeded is separate: read `status.state` from the - response, since a `0` exit can still carry a `FAILED` task or one paused for - input. The full exit-code scheme is in `SPEC.md`. -- **Configuration is flexible, and inspectable.** 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 > built-in - default. Run `a2a config show` to see the effective value of each setting and - where it resolved from (secrets redacted). -- **Authenticate non-interactively** (credential flag or `A2ACLI_*` environment - variable), and never commit a secret. -- **You choose the endpoint.** The CLI talks only to the agent you name; do not - resolve and trust an arbitrary card handed to you. -- **Global flags and the output schema** are defined in the a2a-cli - specification (`SPEC.md`) — consult it rather than guessing. - -## Try it with a throwaway echo agent - -`a2a server --echo` runs a local agent that echoes messages back — handy for -learning or a connectivity check without a real agent: + ```bash + a2a send -a https://agent.example.com --stream "Run a long analysis" + a2a task subscribe -a https://agent.example.com + ``` -```bash -a2a server --echo --port 8080 & -a2a card get http://127.0.0.1:8080 -a2a send -a http://127.0.0.1:8080 "ping" -``` +4. **Check status and fetch results** at any time: + + ```bash + a2a task get -a https://agent.example.com + ``` + +5. **Answer an interrupted task** (it reached `INPUT_REQUIRED` / `AUTH_REQUIRED`) + by replying on the same task: + + ```bash + a2a send -a https://agent.example.com --task-id "Yes, proceed" + ``` + +6. **Continue the conversation** as a new task in the same context: + + ```bash + a2a send -a https://agent.example.com --context-id "Follow-up question" + ``` + +7. **List or cancel tasks:** + + ```bash + a2a task list -a https://agent.example.com + a2a task cancel -a https://agent.example.com + ``` + +## Key flags + +Run `a2a --help` for the full, current set. The load-bearing ones: + +| Flag | Use | +|---|---| +| `-a, --agent-card ` | Resolve the agent's card (picks the transport). | +| `-e, --endpoint ` + `--transport ` | 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 ` / `--context-id ` | Continue a task / group a new task under a context. | +| `--auth ""` / `--svc-param ` | 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).