diff --git a/specification/COMPLIANCE.md b/specification/COMPLIANCE.md new file mode 100644 index 0000000..fccd0f9 --- /dev/null +++ b/specification/COMPLIANCE.md @@ -0,0 +1,329 @@ +# a2a-cli Compliance Report + +**Status:** Review — a pre-Proposed state (`SPEC.md` §15.1). +**Last updated:** 2026-08-17 +**Applies to:** `SPEC.md` v0.2 (revised 2026-08-17) + +## About this document + +This file is **self-contained**: it defines the conformance model, the registry of requirement identifiers, and the report an implementation fills in. `SPEC.md` remains the normative authority for behavior; each row below cites the section that governs it. + +It serves two roles at once: + +- the **authoritative registry of requirement identifiers** — `A2ACLI__` and the `A2ACLI_ERR_*` error codes are *defined* by the tables below, under the scheme in **Requirement identifiers**; +- the **acceptance checklist** for an `a2a-cli` — the list a build is measured against, showing what a tool does, what it does not do yet, and which gaps are open for a contributor to pick up. + +**Fill order.** (1) `§1` identity; (2) each tier table `§4`–`§6`, completing the `DEFAULT_001` breakdown in `§4a`; (3) tally `§3` last, though it appears first; (4) set **Tier claimed** to the highest tier fully satisfied; (5) list error-code coverage `§8`; (6) sign `§9`. The machine-readable form is **Appendix A**, shipped as `compliance-report.template.yaml` beside this file. + + + +> **Numbers already spent.** `A2ACLI_OUT_008` (shell completions) was renumbered to `A2ACLI_CLI_002` while pre-Proposed, when the `CLI` area was added for the tool's own surface; `A2ACLI_SERVE_001` was renamed to `A2ACLI_DEMO_SERVER_001` when the command it covers was renamed `serve` → `demo-server` to avoid reading as a generic "server" area. Neither `OUT_008` nor `SERVE` is reused; both are retired for good. +> +> **The list is expected to grow.** If you are building a tool and hit a real use case that no requirement covers, open a request against the specification repository; it can be added in a future revision. Adding requirements never changes existing identifiers, so reports and test suites that cite them keep working. +> +> **On authentication.** Authentication, security, and compliance are large topics a checklist row cannot fully treat. The `A2ACLI_AUTH_*` requirements cover the ground the specification defines today and are expected to expand. Treat current coverage as a starting point, not a complete security review. +> +> **On errors.** Failures come in two layers (`SPEC.md` §11.4). A tool that renames protocol errors into a vocabulary of its own does not satisfy `A2ACLI_OUT_004`. + + + +## Conformance model + +An implementation declares what it supports **per tier**. The tiers themselves — which requirements belong to Tier 1, 2, and 3 — are scope decisions defined in `SPEC.md` §5; this document defines what claiming one *means* and what evidence a claim needs. + +**Satisfying a tier.** A tier is satisfied only when **every applicable requirement listed for it** is satisfied. Claiming a tier holds the implementation to all of that tier's requirements, including any expressed as SHOULD in the specification's prose, which the claim promotes to required for that tier. A requirement that is inapplicable (the Agent Skill rows, when the tool ships no skill) does not count against the tier; one that applies but could not be exercised is **not** thereby satisfied. Tiers are cumulative: Tier 2 requires Tier 1, Tier 3 requires Tier 2. + +**Evidence.** A tier claim MUST be demonstrated by a completed report: the tool exercised against a **live A2A agent**, with an outcome recorded for every requirement identifier in the tier claimed. An implementation MUST NOT advertise a tier it has not demonstrated. A reporter SHOULD state that the agent tested against is itself TCK-conformant, so a failure can be attributed to the CLI rather than to the agent. *Why: the A2A Technology Compatibility Kit validates agents, not clients, so it cannot grade an `a2a-cli`; reporting against a non-conformant agent measures two unknowns instead of one.* + +**Version pinning.** §1 records the specification version and — while that version is pre-Proposed (`SPEC.md` §15.1) — the revision date measured against. A pre-Proposed requirement can change between revisions, so a result that does not say which revision it measured cannot be interpreted later. + +## Requirement identifiers + +Each testable requirement carries a stable identifier of the form: + +``` +A2ACLI__ +``` + +where `` names the command or cross-cutting concern and `` is a zero-padded sequence number within that area — for example `A2ACLI_SEND_002`, `A2ACLI_INTERACT_001`, `A2ACLI_OUT_003`. + +Defined areas (section references are to `SPEC.md`): + +| Area | Covers | Area | Covers | +| --- | --- | --- | --- | +| `DEFAULT` | Default behavior (§6.5) | `OUT` | Output & error contract (§11.1–11.5) | +| `CARD_GET` | Agent Card retrieval (§10.1) | `EXIT` | Exit codes (§11.6) | +| `SEND` | Sending messages (§10.2) | `AUTH` | Authentication (§12) | +| `TASK_GET` | Task retrieval (§10.3) | `TX` | Transport selection (§13.1) | +| `TASK_CANCEL` | Task cancellation (§10.4) | `VER` | Protocol versioning (§13.2, §13.3) | +| `TASK_LIST` | Task listing (§7.1, App. A) | `SKILL` | Agent skill descriptor (§14) | +| `TASK_SUBSCRIBE` | Subscription / streaming (§9.2, §9.4) | `CHAT` | Interactive session (§8.1) | +| `INTERACT` | Interaction state (§8) | `CONFIG` | Configuration (§8.3) | +| `TASK_POLL` | Task status polling (§9.1, §9.3) | `DOWNLOAD` | Artifact retrieval (§7.1) | +| `PUSH` | Push notifications (§9.2, App. A) | `CONFORM` | TCK conformance check (§7.1) | +| `DEMO_SERVER` | Local demo agent for CLI practice (§7.1, §3) | `CLI` | Tool surface: `help`, `--version`, `completion` (§7.1, §7.2) | + +`ERR` is **reserved** and is never used as a requirement area: `A2ACLI_ERR_*` identifiers denote **error codes** (`SPEC.md` Appendix D), which carry a symbolic suffix rather than a number. Requirements about error handling live under `OUT`. + +Stability rules — these make the identifiers safe to cite in tooling, test suites, and reports: + +- An identifier MUST NOT be **reused**: a retired number never returns meaning something else. This holds at every status. +- **Renumbering** is permitted while the specification is **pre-Proposed** (Draft or Review, `SPEC.md` §15.1), and is frozen from the first **Proposed** version onward. +- **Tier membership is not encoded in the identifier.** A requirement may move between tiers across specification versions while keeping its identifier. +- New requirements take the next unused number in their area. Numbers need not be contiguous. +- From **Proposed** onward, a withdrawn requirement MUST be marked `Withdrawn` rather than deleted, and its number MUST NOT be reused. +- New areas MAY be added; existing area names MUST NOT be repurposed. + +## 1. Summary + +| Field | Value | +| --- | --- | +| Tool name | `` | +| Tool version | `` | +| Implementation language | `` | +| Repository | `` | +| Maintainer / contact | `` | +| Report date | `` | +| Specification version targeted | `0.2` | +| Specification revision (Last updated) | `` | +| **Tier claimed** | `` | +| A2A protocol version(s) | `` | +| Agent exercised against | `` | +| That agent is TCK-conformant? | `` | +| Transports covered | `` | + +## 2. Legend + +| Mark | Meaning | +| --- | --- | +| `✅ Pass` | Implemented and verified | +| `◐ Partial` | Partially implemented — state what is missing | +| `❌ Fail` | Not implemented, or does not behave as specified | +| `⊘ Not measured` | Applicable, but could not be exercised (e.g. the agent never produced the required state). **Not a pass** — it blocks a clean tier claim (**Conformance model**, above) | +| `— N/A` | Inapplicable to this tool (e.g. it ships no skill); state why. Does **not** block tier satisfaction | +| `⊗ Withdrawn` | A retired requirement, kept listed so its ID is never reused (**Requirement identifiers**, above). Applies only from the first **Proposed** version; unused while the spec is pre-Proposed. Excluded from tier totals; never counted for or against satisfaction | + +Every `◐`, `❌`, `⊘`, `—`, or `⊗` MUST carry a note. A requirement the reporter could not provoke — an agent that never returns `INPUT_REQUIRED`, say — MUST be recorded with that reason, never assumed to pass: an unobservable requirement and a satisfied one are different results, so never mark `⊘` as `✅`. + +`— N/A` hinges on the **tool**, not the **agent**: use it only for a requirement that does not apply to the tool itself (e.g. skill rows when it ships no skill). A requirement the tool implements but the **test agent** could not exercise (it never emits push notifications, files, or an interrupted state) stays `⊘`. The fix is to report against an agent that can exercise the tier's requirements (**Conformance model**, above), not to downgrade it to `— N/A`. + +**Requirement kinds.** Every listed requirement is one of: + +- **Gating** (default) — MUST be `✅` (or a correct `— N/A`, for a conditional one) for its tier to be satisfied. +- **Conditional** — tagged in its row as *(Conditional — `— N/A` if …)*; a correct `— N/A` does not block the tier. + +A future revision MAY introduce **optional (capability-badge)** requirements — claimable but non-gating — should the Tier-3 model move to a base-plus-badges shape (an open question). None exist today, so every requirement currently listed **gates** its tier (`SPEC.md` §5). + +## 3. Results at a glance + +| Tier | Requirements | `✅` | `◐` | `❌` | `⊘` | `—` | Tier satisfied? | +| --- | --- | --- | --- | --- | --- | --- | --- | +| Tier 1 — Core | 39 | `<>` | `<>` | `<>` | `<>` | `<>` | `` | +| Tier 2 — Standard | 15 | `<>` | `<>` | `<>` | `<>` | `<>` | `` | +| Tier 3 — Advanced | 12 | `<>` | `<>` | `<>` | `<>` | `<>` | `` | + +Use `yes`/`no` in the last column and integer counts elsewhere. Each row's five mark-counts MUST sum to its **Requirements** total. Withdrawn requirements (once any exist) are retired from the registry's active set and are excluded from that total, so they neither help nor block a tier. + +A tier is satisfied when every **applicable** requirement in it is `✅` (**Conformance model**, above). A conditional requirement marked `— N/A` does not block satisfaction; a `⊘`, `◐`, or `❌` does. + +## 4. Tier 1 — Core (required) + +| ID | Requirement | Spec § | Status | Notes | +| --- | --- | --- | --- | --- | +| `A2ACLI_CARD_GET_001` | `card get` — resolve and parse an Agent Card from a host, an explicit URL, or a `file://` path, and use it to select a transport | §10.1, §13 | `<>` | | +| `A2ACLI_SEND_001` | Send a message to start an interaction | §10.2 | `<>` | | +| `A2ACLI_SEND_002` | Blocking by default; `--async` returns identifiers immediately (`--return-immediately` / `--no-wait` are OPTIONAL aliases) | §10.2, §6.5 | `<>` | | +| `A2ACLI_SEND_003` | `--stream` consumes SSE when supported and never hangs when unsupported; a `Message`-only response (no task created) exits cleanly rather than erroring | §10.2, §9.2 | `<>` | | +| `A2ACLI_SEND_004` | Renders produced artifacts; never silently discards a part | §10.2 | `<>` | | +| `A2ACLI_SEND_005` | Lets the caller set a message part's media type explicitly with `--media-type`, bound to the part flag it follows; infers the type only when none was given | §10.2 | `<>` | | +| `A2ACLI_SEND_006` | Message-part flags `--text` / `--file` / `--data` are repeatable and order-preserving, so one message can carry multiple ordered parts (`--data -` reads stdin) | §10.2 | `<>` | | +| `A2ACLI_TASK_GET_001` | `task get` — retrieve task state, artifacts, and history by identifier; renders returned artifacts and never silently strips them | §10.3 | `<>` | | +| `A2ACLI_TASK_CANCEL_001` | `task cancel` — cancel a task; idempotent; reports the resulting state | §10.4 | `<>` | | +| `A2ACLI_INTERACT_001` | Continue an interaction via `--context-id` | §8.1 | `<>` | | +| `A2ACLI_INTERACT_002` | Continue a task via `--task-id`, supplied with or without `--context-id` (the server resolves the task's context); when both are given they MUST correspond; a rejected identifier fails non-zero and creates no new task, surfacing the protocol error and pointing at `--debug` | §8.1 | `<>` | | +| `A2ACLI_INTERACT_003` | Never invents server-assigned identifiers, and never assumes `contextId` denotes a chat session | §4.1, §4 | `<>` | | +| `A2ACLI_INTERACT_004` | Reports `taskId` / `contextId` / `state` on completion and interruption, in copy-pasteable form, and prints the exact command to resume | §8.2 | `<>` | | +| `A2ACLI_INTERACT_005` | Stateless: never stores the last `taskId` / `contextId` to replay on the caller's behalf; provides no `--continue`; interaction state never lives only in process memory | §6.3, §4.1, §8.3 | `<>` | | +| `A2ACLI_TASK_POLL_001` | Polling path available — one-shot `task get`, plus `task get --wait` polling to a terminal or interrupted state | §9.3 | `<>` | | +| `A2ACLI_TASK_POLL_002` | `--poll-interval` and `--timeout` honored; bounded backoff; no busy-loop; remains interruptible without losing the already-printed `taskId` | §9.3 | `<>` | | +| `A2ACLI_TASK_POLL_003` | Stops immediately on interrupted states (`INPUT_REQUIRED` / `AUTH_REQUIRED`) without deadlock; treats `TASK_STATE_UNSPECIFIED` as neither terminal nor interrupted, continuing to poll under `--timeout` | §9.1, §9.3 | `<>` | | +| `A2ACLI_TASK_POLL_004` | When a wait prefers streaming, falls back to polling on stream failure and drives the task to a terminal/interrupted state | §9.3 | `<>` | | +| `A2ACLI_OUT_001` | **Standard output** — every response about a task names its context, its task, and its state, in every output mode; the payload goes to stdout and diagnostics to stderr, never mixed | §11.1, §11.5, §8.2 | `<>` | | +| `A2ACLI_OUT_002` | `-o json` (no `--stream`) — exactly one document, the **terminal** protocol object rather than an event log, and never switched implicitly to its streamed JSONL form | §11.3, App. B | `<>` | | +| `A2ACLI_OUT_003` | `-o json --stream` — JSONL: one complete JSON object per line, flushed as produced, final line carrying the terminal object; a stream-terminating error is emitted as a final error object on its own line | §11.3, §11.4, App. B | `<>` | | +| `A2ACLI_OUT_004` | Errors are machine-readable and consistent across transports: protocol failures carry the A2A error name, CLI-local failures an `A2ACLI_ERR_*` code; the tool never invents codes in the `A2ACLI_ERR_*` namespace (vendor codes use a distinct prefix) and SHOULD populate the `hint` field | §11.4, App. B, App. D | `<>` | | +| `A2ACLI_OUT_005` | **`text` floor** — one `Label: value` field per line, the same labels across invocations, no terminal control sequences; block content (a rendered artifact, a formatted data part) sits under its own `Label:` line, closed by a blank line and never interleaved with field lines; any interactive mode auto-degrades to `text` when stdout is not a TTY and never blocks on interactive input there | §11.2, §6.1 | `<>` | | +| `A2ACLI_OUT_006` | When the caller does not wait (`--async`), still emits a result object carrying at least `taskId` and `contextId` for later polling | §11.5 | `<>` | | +| `A2ACLI_EXIT_001` | Implements the three required exit statuses (`0`, `1`, `2`); any reserved status it emits carries the documented meaning and agrees with the error reported | §11.6, App. D | `<>` | | +| `A2ACLI_EXIT_002` | Tool execution and agent outcome stay decoupled: a turn the CLI conducted and reported exits `0` even when the task ends `FAILED`/`REJECTED` or pauses at `INPUT_REQUIRED`/`AUTH_REQUIRED`; the outcome is carried in the task state, and a non-success or paused outcome SHOULD be named in a stderr warning | §6.6, §11.6 | `<>` | | +| `A2ACLI_AUTH_001` | Scriptable credentials — bearer, API key, env equivalents, attached per the agent's declared security scheme; `--svc-param` available separately for any service parameter, and never documented as an authentication flag | §12.1 | `<>` | | +| `A2ACLI_AUTH_002` | Offers an environment-variable equivalent for each credential flag and documents that a flag-supplied credential is exposed via the process table and shell history; this guidance does not alter the flag > environment precedence (§6.5) | §12.1, §6.5 | `<>` | | +| `A2ACLI_AUTH_003` | Emits a prominent security warning to stderr when a credential is sent over a connection with certificate verification disabled (`--insecure`); never disables TLS verification silently | §12.1, §6.5 | `<>` | | +| `A2ACLI_AUTH_004` | Redacts credential material from diagnostic output, including `--debug` raw-wire logging; the redaction is not defeasible by a verbosity flag | §12.1, §7.2 | `<>` | | +| `A2ACLI_TX_001` | Transport selected from the Agent Card, honoring declared preference order | §13.1 | `<>` | | +| `A2ACLI_TX_002` | Uses the first `supportedInterfaces` entry it supports absent a client preference; `--transport` is repeatable and ordered | §13.1, §6.5 | `<>` | | +| `A2ACLI_TX_003` | *(Conditional — `— N/A` if the selected interface declares no `tenant`.)* Sets the selected `AgentInterface`'s routing identifier (`tenant`) in every request message, exactly as declared, and omits the field when the entry declares none | §13.1 | `<>` | | +| `A2ACLI_VER_001` | `A2A-Version` signaled explicitly on every request (never left empty, which A2A reads as 0.3); negotiates down only within 1.x, never below 1.0; no silent downgrade | §13.2 | `<>` | | +| `A2ACLI_DEFAULT_001` | Ships the baseline defaults, each overridable by an explicit flag, and exposes its effective defaults (e.g. via `--help`). **Complete the breakdown in §4a** — a bare pass hides which default is missing | §6.5 | `<>` | | +| `A2ACLI_CONFIG_001` | Persisted configuration *(if any)*: conventional path, secrets not world-readable (mode `0600` or platform equivalent), inspectable via the read-only `config show` and directly editable and removable by the user; never records session state (`taskId` / `contextId`) to offer resume | §8.3 | `<>` | | +| `A2ACLI_CLI_001` | `help` and ` --help` print usage and exit; `-v/--version` prints the tool version; `--help` shows the effective defaults so a caller can see them before overriding | §7.1, §7.2, §6.5 | `<>` | | +| `A2ACLI_SKILL_001` | *(Conditional — mark `— N/A` if the tool ships no skill.)* Ships **exactly one** Agent Skill, generic and token-efficient, deferring to runtime `help` rather than inlining the command surface | §14.1, §14.2 | `<>` | | +| `A2ACLI_SKILL_002` | *(Conditional — mark `— N/A` if the tool ships no skill.)* Skill and specification kept as distinct layers; the skill does not restate normative requirements | §14.3 | `<>` | | + +### 4a. `A2ACLI_DEFAULT_001` breakdown + +`DEFAULT_001` passes only when every row is present and overridable. Report each one; "mostly defaults" is not a result anyone can act on. This sub-table is the evidence behind the `DEFAULT_001` status cell above — keep the two consistent. + +| Default (§6.5) | Shipped? (yes/no) | Overridable by flag? (yes/no) | Notes | +| --- | --- | --- | --- | +| Transport — server preference order | `<>` | `<>` | | +| Task completion — wait by default | `<>` | `<>` | | +| Output — human-readable `text` | `<>` | `<>` | | +| Detail level — concise | `<>` | `<>` | | +| Protocol version — highest mutually supported, never below 1.0 | `<>` | `<>` | | +| Transport security — TLS verification on | `<>` | `<>` | MUST warn when `--insecure` disables it | + +## 5. Tier 2 — Standard + +| ID | Requirement | Spec § | Status | Notes | +| --- | --- | --- | --- | --- | +| `A2ACLI_CARD_GET_002` | `card get --validate` — validate the Agent Card against the A2A schema | §10.1 | `<>` | | +| `A2ACLI_TASK_LIST_001` | `task list` — cursor-paginated, filterable by status and context | §7.1, App. A | `<>` | | +| `A2ACLI_TASK_SUBSCRIBE_001` | `task subscribe` — (re)subscribe to a task's event stream | §7.1, §9.2 | `<>` | | +| `A2ACLI_TASK_SUBSCRIBE_002` | Stream resumption after disconnect; the first event re-delivers the full `Task`, so no separate `get` is required | §9.4, §9.2 | `<>` | | +| `A2ACLI_AUTH_005` | `auth login` — OAuth 2.1 device-code flow | §12.2 | `<>` | | +| `A2ACLI_AUTH_006` | `auth login` — OAuth 2.1 client-credentials flow | §12.2 | `<>` | | +| `A2ACLI_AUTH_007` | Secure token storage with automatic attachment on later calls | §12.2 | `<>` | | +| `A2ACLI_TX_004` | At least two transports supported and selectable | §13.1 | `<>` | | +| `A2ACLI_VER_003` | Verifies a capability on the Agent Card before invoking a capability-gated operation (streaming, push, extended card) | §13.3 | `<>` | | +| `A2ACLI_CONFIG_002` | Configuration precedence (flag → env → local → global → built-in), scopeable by agent-card reference; `config show` reports each effective value with the source it resolved from | §8.3 | `<>` | | +| `A2ACLI_DOWNLOAD_001` | `task download` — save task artifacts to disk | §7.1 | `<>` | | +| `A2ACLI_OUT_007` | `--debug` enables diagnostic logging to stderr, including the raw protocol messages exchanged on the wire | §7.2 | `<>` | | +| `A2ACLI_CONFORM_001` | `conformance` — smoke-check a live agent against the A2A TCK | §7.1 | `<>` | | +| `A2ACLI_CLI_002` | `completion ` — emits a shell completion script for the named shell | §7.1 | `<>` | | +| `A2ACLI_PUSH_001` | `task push-config` create / get / list / delete | §7.1, App. A | `<>` | | + +## 6. Tier 3 — Advanced + +| ID | Requirement | Spec § | Status | Notes | +| --- | --- | --- | --- | --- | +| `A2ACLI_CARD_GET_003` | Authenticated extended Agent Card, fetched only via a security scheme advertised on the public card | §10.1, §12.4 | `<>` | | +| `A2ACLI_AUTH_008` | Never presents a credential to an Agent Card endpoint that has not declared a scheme accepting it | §12.4 | `<>` | | +| `A2ACLI_CARD_GET_004` | Agent Card signature verification per A2A §8.4.3 — verifies signatures when the card carries them and reports the outcome (verified / unverifiable / absent); never presents an unverified card as verified, and does not fail on an absent signature (A2A §8.4 makes signing optional) | §10.1 | `<>` | | +| `A2ACLI_CARD_GET_005` | Catalog / registry resolution — accepts a catalog or registry entry wherever `--agent-card` takes a reference and resolves it to an Agent Card before any other operation | §10.1 | `<>` | | +| `A2ACLI_PUSH_002` | Local webhook receiver able to accept push notifications | §9.2 | `<>` | | +| `A2ACLI_CHAT_001` | Interactive `chat` carrying context and task across turns | §8.1, §7.1 | `<>` | | +| `A2ACLI_TX_005` | gRPC transport | §13.1 | `<>` | | +| `A2ACLI_AUTH_009` | Mutual TLS | §12.3 | `<>` | | +| `A2ACLI_AUTH_010` | OpenID Connect | §12.3 | `<>` | | +| `A2ACLI_AUTH_011` | Handles in-task `AUTH_REQUIRED` resolution | §12.3 | `<>` | | +| `A2ACLI_DEMO_SERVER_001` | `demo-server` / mock agent mode | §7.1, §3 | `<>` | | +| `A2ACLI_VER_002` | Declares server-required protocol extensions | §13.3, A2A §4.6 | `<>` | | + +## 7. Test evidence + +- **How the tool was exercised:** `` +- **Results / logs:** `` +- **Environment:** `` +- **Known gaps / caveats:** `` + +## 8. Error code coverage *(optional but recommended)* + +Which `A2ACLI_ERR_*` codes (`SPEC.md` Appendix D) the tool can emit. Helps consumers write reliable error handling. Mark `Emitted` as `yes`/`no`. + +| Code | Emitted (yes/no) | Notes | +| --- | --- | --- | +| `A2ACLI_ERR_USAGE` | `<>` | | +| `A2ACLI_ERR_CARD_NOT_FOUND` | `<>` | | +| `A2ACLI_ERR_CARD_INVALID` | `<>` | | +| `A2ACLI_ERR_UNREACHABLE` | `<>` | | +| `A2ACLI_ERR_CREDENTIALS_MISSING` | `<>` | | +| `A2ACLI_ERR_AUTH_FAILED` | `<>` | | +| `A2ACLI_ERR_TIMEOUT` | `<>` | | +| `A2ACLI_ERR_INTERNAL` | `<>` | | + +## 9. Attestation + +Reported by `` on ``. The tier claimed in §1 and §3 reflects the evidence above. + +--- + +## Appendix A — Machine-readable report (the published artifact) + +A published report MUST also be available as a **single, self-contained YAML file**: the one artifact an implementation publishes alongside itself. The Markdown registry above stays canonical; the YAML is the same measurement in machine form. A ready-to-fill copy ships beside this file as **`compliance-report.template.yaml`**. + +*Producing the file is out of scope* — how an implementation runs its checks and assembles the result is its own concern. + +### A.1 Structure + +- **Top `report:` block** — identity: tool, version, language, repository, maintainer, report date, spec version, **spec revision date**, A2A versions, agent tested + its TCK status, transports covered, and tier claimed. +- **`summary:`** — aggregator-produced per-tier rollup (counts + `satisfied`). +- **`requirements:`** — an **ID-keyed mapping**: each requirement identifier is a key, carrying `tier`, `area`, `spec`, a short human-readable `requirement` line, `status`, `note`, and optional `evidence`. +- **`default_001_breakdown:`**, **`error_codes:`**, **`attestation:`** — as in §4a, §8, §9. + +### A.2 Closed status vocabulary (words) + +`pass` · `partial` · `fail` · `not_measured` · `na` · `withdrawn` — mapping 1:1 to the legend (§4): `✅ ◐ ❌ ⊘ — ⊗`. Every status other than `pass` MUST carry a `note`. `withdrawn` applies only from the first Proposed version and is excluded from tier totals and from satisfaction (§A.3). + +### A.3 Fail-closed rules (a broken or empty report is never a pass) + +These make a missing or malformed report impossible to mistake for a compliant tool (mirrors the **Conformance model** above): + +1. **Every requirement identifier for the claimed tier — and every lower tier, since tiers are cumulative — MUST be present** in `requirements:`. A missing key, an empty `requirements:` mapping, or an all-`not_measured` report MUST roll up to `satisfied: false`, never a pass. +2. **Only `pass` (and a genuine `na`) satisfies.** `partial`, `fail`, `not_measured`, and **any unrecognized status value** MUST be treated as not-satisfied — never silently skipped. +3. **`DEFAULT_001` cannot pass without its breakdown.** `A2ACLI_DEFAULT_001: pass` is invalid unless every `default_001_breakdown` row is `shipped: yes` and `overridable: yes`. +4. **The file is published.** Fill with placeholders only — never a real filled example — and keep `note`/`evidence` publication-safe: no secrets, no internal-only URLs. +5. **Withdrawn is retirement, not a result.** A `withdrawn` requirement (from the first Proposed version onward) keeps its identifier forever, is excluded from its tier's `total`, and is counted neither as a pass nor as a not-satisfied — it is exempt from rule 2. Its ID MUST NOT be reused (**Requirement identifiers**, above). + +### A.4 Schema sketch + +The shape in brief; the complete, fill-in copy ships as `compliance-report.template.yaml`. Repeated blocks are shown once and elided. + +```yaml +report: + tool: + tool_version: + language: + repository: + maintainer: + report_date: # when this report was produced + spec_version: "0.2" # SPEC.md "Version" + spec_revision: # SPEC.md "Last updated" — pins a pre-Proposed (Draft/Review) result + a2a_versions: ["1.0"] + agent_tested: + agent_tck_conformant: unknown # yes | no | unknown + transports_covered: [HTTP+JSON, JSON-RPC] + tier_claimed: <1 | 2 | 3> + +summary: # aggregator-produced; only pass/na satisfy (§A.3) + tier_1: {total: 39, pass: 0, partial: 0, fail: 0, not_measured: 39, na: 0, satisfied: false} + # tier_2 (15) and tier_3 (12): same shape + +requirements: # ID-keyed; every ID of the claimed tier MUST appear + A2ACLI_CARD_GET_001: + tier: 1 + area: CARD_GET + spec: "§10.1, §13" + requirement: "card get — resolve/parse an Agent Card; select a transport" + status: not_measured # closed vocabulary: §A.2 + note: "" + evidence: null # optional: log path / CI link + # … one block per identifier; full set in compliance-report.template.yaml + +default_001_breakdown: # all six §6.5 defaults (see §4a) + transport_server_preference_order: {shipped: no, overridable: no, note: null} + # … five more rows, same shape … + +error_codes: # all eight A2ACLI_ERR_* (see §10) + A2ACLI_ERR_USAGE: {emitted: no, note: null} + # … seven more, same shape … + +attestation: + reported_by: + date: + statement: "The tier claimed reflects the evidence recorded above." +``` diff --git a/specification/README.md b/specification/README.md new file mode 100644 index 0000000..df8ad89 --- /dev/null +++ b/specification/README.md @@ -0,0 +1,46 @@ +# a2a-cli Specification + +This directory holds the specification for **`a2a-cli`** — the command-line client for the [Agent2Agent (A2A) Protocol](https://a2a-protocol.org/latest/specification/) — together with the material used to verify an implementation against it. + +`a2a-cli` lets developers and AI coding agents fetch Agent Cards, send messages, stream and poll tasks, and read artifacts from the terminal. `SPEC.md` defines how the tool behaves, in terms an implementation in any language can follow. + +## Contents + +| File | Description | +| --- | --- | +| [`SPEC.md`](./SPEC.md) | The behavior specification (normative). Self-contained: everything needed to build the tool. | +| [`COMPLIANCE.md`](./COMPLIANCE.md) | The conformance model, the requirement-identifier registry, and the report form an implementation completes. | +| [`compliance-report.template.yaml`](./compliance-report.template.yaml) | The same report in machine form — the artifact an implementation publishes. | + +## Capability tiers at a glance + +`SPEC.md` §3 groups its requirements into three **cumulative** tiers. A tier describes *scope* — what the tool does first, next, and later — not a rank awarded to an implementation. + +| Tier | Name | Summary | +| --- | --- | --- | +| **Tier 1** | Core | `card get`, `send`, `task get`, `task cancel`, `help`; explicit interaction state; task polling; the output contract and exit codes; token auth; version signaling. | +| **Tier 2** | Standard | `task list`, `task subscribe`, `auth login`, multiple transports, configuration precedence, `task push-config`, `task download`, wire debug, `conformance`, `completion`. | +| **Tier 3** | Advanced | Push-notification webhook receiver, interactive `chat`, gRPC, extended card, signature verification, mTLS, OpenID Connect, `demo-server`/mock, catalog resolution, extensions. | + +See [`SPEC.md`](./SPEC.md) for the normative detail. + +## Verifying an implementation + +Tier membership is a scope decision and lives in `SPEC.md`. Everything about *claiming* a tier — what counts as satisfying a requirement, and the evidence a claim needs — lives in [`COMPLIANCE.md`](./COMPLIANCE.md). + +1. Implement a tier of the specification. +2. Exercise the tool against a live A2A agent — ideally one that is itself TCK-conformant, so a failure can be attributed to the client rather than to the agent. The TCK validates *agents*, not clients, so it cannot grade a CLI directly. +3. Complete [`COMPLIANCE.md`](./COMPLIANCE.md), recording an outcome for every requirement identifier in the tier claimed. +4. Publish the machine-readable report alongside the implementation. + +The registry is open: any implementation, in any language, can measure itself against it and publish the result. + +## Status + +**v0.2 — Review.** Open for comment; pre-Proposed and not yet ratified, so normative requirements may still change (`SPEC.md` §14.1, §14.3). Feedback is welcome via issues and pull requests. + +## References + +- A2A Protocol Specification v1.0 — https://a2a-protocol.org/latest/specification/ +- A2A Agent Discovery — https://a2a-protocol.org/latest/topics/agent-discovery/ +- A2A Streaming & Asynchronous Operations — https://a2a-protocol.org/latest/topics/streaming-and-async/ diff --git a/specification/SPEC.md b/specification/SPEC.md new file mode 100644 index 0000000..59f8d37 --- /dev/null +++ b/specification/SPEC.md @@ -0,0 +1,644 @@ +# a2a-cli Specification + +**Version:** 0.2 +**Status:** Review — a pre-Proposed state (§15.1). +**Last updated:** 2026-08-17 +**Applies to:** A2A Protocol v1.0 — built against [A2A v1.0.0](https://a2a-protocol.org/v1.0.0/specification/) as its baseline. +**Verification:** `COMPLIANCE.md` + +## Abstract + +This document specifies **`a2a-cli`**: the command-line client for the [Agent2Agent (A2A) Protocol](https://a2a-protocol.org/latest/specification/). It defines the tool's command surface, output contract, and interaction model — how an `a2a-cli` behaves — in terms an implementation in any language can follow. + +It is self-contained: everything needed to build the tool is here. How an implementation *demonstrates* that it meets this specification — the requirement identifiers, the evidence rules, and the report format — is defined separately in `COMPLIANCE.md`. + +This is an **implementer's specification**. Its audience is engineers building or improving an `a2a-cli`. It constrains CLI behavior only and never modifies A2A wire semantics. + +> **Naming.** For ease of reference, this document refers to the tool as `a2a-cli` throughout. + +## Notational conventions + +The key words **MUST**, **MUST NOT**, **REQUIRED**, **SHALL**, **SHALL NOT**, **SHOULD**, **SHOULD NOT**, **RECOMMENDED**, **MAY**, and **OPTIONAL** are to be interpreted as described in [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119). + +References of the form "A2A §x" point to the A2A Protocol Specification v1.0. Where an A2A rule is load-bearing for the CLI it is restated here so this document is self-contained; the A2A specification remains authoritative for protocol semantics. + +--- + +## 1. Problem statement + +A2A has a stable protocol and a growing set of agents. What it does not yet have is one agreed way to talk to them from a command line. + +**Eleven CLIs already exist, and they rebuild the same five commands.** Across six languages, every one of them sends a message and fetches an Agent Card, ten stream, nine read task status, nine cancel — and only four list tasks, only three configure push notifications ([A2A#1929](https://github.com/a2aproject/A2A/issues/1929#issuecomment-5326727779)). The common path has been settled by practice; the harder half of the protocol is unbuilt in nearly all of them. This document writes down what implementers already converged on rather than inventing a design, and names the surface that fragmentation has left unfinished. + +**A2A's developer-tooling layer is still forming, and a command line is the shortest way in.** The protocol reached a stable [v1.0](https://github.com/a2aproject/A2A/releases) in March 2026, and support has kept growing — from more than 100 organisations at the Linux Foundation launch to [169 listed today](https://a2a-protocol.org/latest/partners/), with the Python SDK alone pulling over 16 million downloads a month. That growth has landed mainly in agent frameworks and enterprise platforms: among coding harnesses, adoption is comparatively close to nonexistent — one or two document A2A support today, and where it exists it is described as experimental. A single specified CLI, shipped with one skill descriptor, offers both audiences the same low-friction entry point: a developer can exercise a deployed agent in one command, and a coding agent can drive that same command from its [skill file](https://agentskills.io/skill-creation/using-scripts.md). + + + +This specification writes that common path down once — the core client behavior every implementation can share — so a caller gets the same experience whichever tool they reach for. Anything more specialised builds on top of it (Appendix E, experimental). + +--- + +## 2. Goals + +An `a2a-cli` is an **A2A client**: a unified command-line tool that lets human developers, automated workflows, and AI coding harnesses send tasks, stream updates, and fetch artifacts from any A2A-supported agent instance. This specification sets out four core goals to resolve the fragmentation, tooling gaps, and lack of standard guidance described in §1. They state the outcomes this specification achieves, not the operative rules (which are defined in §6–§14): + +2.1 **Deliver complete protocol coverage and multi-transport support.** Go beyond the fragmented basic commands (`card get`, `send`) that existing ad-hoc tools re-invented to specify the full breadth of the A2A Protocol. An `a2a-cli` covers all A2A transport bindings (JSON-RPC, HTTP+JSON, and gRPC), lifecycle event streaming and polling, push notifications, and enterprise security across cumulative capability tiers (§5), ensuring a unified, predictable command surface across languages. + +2.2 **Maximize developer convenience, learnability, and ergonomics.** Make discovering, learning, and driving the tool effortless from day one. The CLI provides opinionated, sensible defaults — such as blocking waits on task completion, automatic server-preference transport negotiation, and well-known card resolution — that minimize boilerplate flags while keeping every behavior overridable (§6.5) and discoverable via built-in `--help`. + +2.3 **Built for the AI era: seamless for both human developers and AI coding agents.** With the rapid adoption of AI coding agents, autonomous agentic harnesses, and human-in-the-loop workflows, the CLI is designed from the ground up to serve humans and AI agents as first-class peers (§6.1). It provides a human-friendly, pipe-safe `text` format for interactive terminal use, protocol-native `json`/JSONL streaming for automated consumption (§11.3), and ships with a lean, standardized Agent Skill descriptor (`SKILL.md`, §14) so coding harnesses can delegate tasks to A2A instances with zero friction. + +2.4 **Serve as a definitive implementation guide and capability roadmap.** Provide an authoritative, language-agnostic blueprint that guides engineers building or enhancing an `a2a-cli`. Through a structured, cumulative capability roadmap (Tier 1 Core, Tier 2 Standard, Tier 3 Advanced; §5) paired with a companion verification checklist (`COMPLIANCE.md`), it gives implementers a clear path for what to build first, next, and later, while making it straightforward to measure and demonstrate progress. + +--- + +## 3. Non-goals + +This specification does not: + +- **define server or agent behavior** — an `a2a-cli` is a client; acting *as* a server (publishing an Agent Card, minting server-side identifiers, serving inbound requests) is outside the client baseline, and `demo-server` mode is Tier 3 (§7.1); +- **alter A2A wire semantics**; or +- **mandate an implementation language or framework**. + +--- + +## 4. Object model + +Restated from A2A §4 so this document stands alone: + +- **Message** — a single turn. Has a `role` (`user` or `agent`) and one or more **Parts** (`text`, `file`, or `data`). Carries a client-assigned **`messageId`**. +- **Task** — the stateful unit of work a message may create. Identified by a server-assigned **`taskId`**; advances through a **TaskState** (§9.1); may emit **Artifacts**. +- **Artifact** — a task output (text, structured data, or file). Task outputs are delivered as Artifacts, not Messages; an `a2a-cli` MUST render Artifacts. +- **`contextId`** — a server-assigned, opaque identifier that groups related tasks and messages. A2A does not define what the grouping *means*; that is the agent author's decision, and an `a2a-cli` MUST NOT assume it denotes a chat session. +- **AgentCard** — the server's machine-readable description of identity, capabilities, interfaces (transports), security schemes, and skills, obtained by resolving an Agent Card reference (§10.1). + +### 4.1 Identifiers + +| Identifier | Assigned by | Role | Constraints | +| --- | --- | --- | --- | +| `messageId` | Client | Turn identity / idempotency | SHOULD be reused when retrying a turn: Send is not guaranteed idempotent (A2A §3.3.1 makes idempotency OPTIONAL), so reuse MAY avoid duplicated work with agents that deduplicate on `messageId`. | +| `taskId` | Server | Unit of work | A tool MUST NOT invent a `taskId` for a new task. A client-supplied `taskId` MUST reference an existing task; otherwise the server returns a not-found error. | +| `contextId` | Server | Context grouping | Opaque; a tool SHOULD NOT fabricate one. A `contextId` and `taskId` that do not correspond MUST be rejected by the server; a tool MUST NOT attempt to reconcile them. | + +An `a2a-cli` never *creates* server identifiers. It reports the ones the server assigned (§8.2) and accepts them back as explicit input (§8.1); it MUST NOT store them and replay them on the caller's behalf. + +--- + +## 5. Capability tiers + +This specification groups its requirements into three **cumulative** tiers. A tier describes *scope* — what an `a2a-cli` does first, next, and later — and is a property of the requirement, not a rank awarded to an implementation. Tier 2 includes everything in Tier 1; Tier 3 includes everything in Tier 2. + +| Tier | Name | Requirements | +| --- | --- | --- | +| **Tier 1** | Core | §6.5 default behavior · §8 interaction/session handling · §9 polling · §10.1–10.4 commands (`card get`, `send`, `task get`, `task cancel`) · `help` and `--version` (§7.1, §7.2) · §11 output & exit codes · §12.1 auth · §13 transport & versioning · §14 SKILL.md (conditional — applies only if the tool ships a skill, §14.1) | +| **Tier 2** | Standard | Tier 1 + `task list`, `task subscribe`, OAuth `auth login`, ≥2 transports, configuration scoping, `task push-config` CRUD, `task download`, wire debug, `conformance`, `completion` | +| **Tier 3** | Advanced | Tier 2 + a push-notification webhook receiver, interactive `chat`, gRPC transport, authenticated extended Agent Card, Agent Card signature verification, mTLS, OpenID Connect, `demo-server`/mock mode, catalog/registry, protocol extensions | + +Tier membership is stated here because it is a scope decision: it determines what belongs in the baseline tool and what is deferred. Everything about *claiming* a tier — the requirement identifiers, what counts as satisfying one, and the evidence a claim needs — is defined in `COMPLIANCE.md`. + +--- + +## 6. Design principles + +Six principles the rest of this document implements. They are normative where they use RFC 2119 keywords; §7–§14 carry the operative rules, and a principle is a statement of shape, not a second place to look up a requirement. + +6.1 **Dual-consumer, agent-first core.** An `a2a-cli` is driven by two kinds of consumer at once — a person at a terminal, and a program: a shell script, a CI job, or an AI coding agent. Neither is second-class. `text` and `json` are peer formats, each with its own contract (§11.2, §11.3): `text` is the default and MUST stay parseable and pipe-safe, `json` carries the protocol's own types for a program to consume. **Where the two pull apart, the programmatic consumer sets the default** — hence *agent-first*: no interactive prompts, no terminal control sequences, and output whose shape does not vary with the environment it runs in. An interactive mode (for example `chat`, Tier 3) MUST be gated by terminal detection and MUST NOT be the default. *Why: Human affordances are added on top of the machine contract, never carved out of it. A tool that prompts, colorizes, or reshapes its output when it detects a terminal has two behaviors to test and one of them is invisible to CI.* + +6.2 **Protocol-native, minimal invention.** Where A2A already defines a shape, this specification does not redefine it: `json` output emits the protocol's own response types unmodified (Appendix B), and a failure carries A2A's own error name wherever one applies (§11.4). Everything a consumer parses on success is A2A's own. This document owns only what the protocol has no opinion on, because it happens outside a request: the error envelope (§11.4, Appendix B), the CLI-local error codes (Appendix D), and the exit-code scheme (§11.6) — each with its own stability rule, and each kept as small as the job allows. + +6.3 **Completely stateless interaction.** The CLI remembers nothing from one invocation to the next. It MUST NOT invent a server-owned identifier (§4.1), MUST NOT store the last `taskId`/`contextId` and replay it on the caller's behalf, and offers no "resume where I left off" mode. Interaction state MUST NOT exist only in process memory: every identifier needed to continue MUST be reported in output (§8.2) and MUST be accepted back as explicit input (§8.1). What persists between runs is *configuration*, never session state (§8.3). *Why: a stateless tool is safe to run concurrently — from CI, from several shells, from an agent harness — because no two invocations can disagree about which interaction is "current." It also keeps resumption auditable: the command line names the exact task it will touch, so nothing is inferred from hidden state.* + +6.4 **Transport- and language-agnostic.** Observable behavior MUST be identical across the JSON-RPC, HTTP+JSON, and gRPC bindings (this document uses *binding* and *transport* interchangeably), and across implementation languages, so a script never has to know which binding was negotiated or what the tool was written in. + +6.5 **Opinionated defaults, always overridable.** Common tasks MUST work with minimal flags. An `a2a-cli` MUST ship the baseline defaults below, and MUST make **every** default overridable: by an explicit flag at all times, and MAY additionally be settable via an environment variable or a configuration file. An explicit flag MUST take precedence over a configured default, which MUST take precedence over the built-in default. A tool SHOULD expose its effective defaults (e.g. via `--help`) so a user can see what will happen before overriding. + +| Behavior | Default | Override | +| --- | --- | --- | +| Transport | The **first supported interface in the Agent Card's `supportedInterfaces`** — the list is declared in server preference order (§13.1; A2A §8.3.1 makes ordering a SHOULD) | `--transport `, repeatable, highest preference first | +| Task completion | **Wait** (block) until the task reaches a terminal or interrupted state | `--async` (return identifiers immediately); `--return-immediately` and `--no-wait` are OPTIONAL aliases (§7.2) | +| Output presentation | **Human-readable `text`** — labeled fields, one field per line, no control sequences (§11.2) | `--output ` sets the format; `--stream` follows live delivery (JSONL for `json`, §11.3) | +| Detail level | **Concise** | `--verbose` for a full, human-readable view of the data exchanged with the agent | +| Protocol version | The **highest version supported by both** tool and agent, signaled explicitly, never below 1.0 (§13.2) | `--a2a-version ` | +| Transport security | **TLS verification enabled** | `--insecure` (development only; MUST warn) | + +6.6 **Decoupled tool execution vs. agent outcome.** Whether the CLI did its job and what the agent decided are two separate results, and an `a2a-cli` MUST NOT collapse them. The **exit code** reports only the first (§11.6): a turn the CLI faithfully conducted and reported exits `0` whether the task completed, ended `FAILED` or `REJECTED`, or paused at `INPUT_REQUIRED`/`AUTH_REQUIRED`. The **outcome** lives in the task state and the output (§8.2). The same split governs failures: a protocol error carries A2A's own name, a CLI-local error an `A2ACLI_ERR_*` code, and the two layers MUST NOT be blurred (§11.4). *Why: A caller needs "did the command work?" answerable without parsing anything, and "what did the agent decide?" answerable without inferring it from an exit status. Fold the agent's verdict into the exit code and both questions become unanswerable: a non-zero status no longer distinguishes an unreachable agent from a working one that said no.* + +--- + +## 7. Command surface & global options + +7.1 The command surface is `a2a-cli [arguments] [options]`. + +| Command | Tier | Purpose | +| --- | --- | --- | +| `auth login` | 2 | Interactive credential acquisition (OAuth) | +| `card get` | 1 | Fetch and render an Agent Card | +| `chat` | 3 | Interactive multi-turn session | +| `completion` | 2 | Emit a shell completion script for the named shell | +| `config show` | 2 | Inspect configuration (read-only): show the effective settings and the source each value resolved from (§8.3) | +| `conformance` | 2 | Smoke-check a live agent against the A2A TCK | +| `demo-server` | 3 | Run a local demo agent to practise CLI commands (out of client baseline) | +| `help` | 1 | Show usage for the tool or a specific command | +| `send` | 1 | Send a message to start or continue an interaction | +| `task cancel` | 1 | Cancel an active task | +| `task download` | 2 | Save task artifacts | +| `task get` | 1 | Retrieve a task's status and artifacts | +| `task list` | 2 | List tasks | +| `task push-config` | 2 | Manage push-notification configurations | +| `task subscribe` | 2 | (Re)subscribe to a task's event stream | + +**Naming.** A command that acts on a protocol resource is namespaced by that resource — `card …`, `task …`, `config …`, `auth …` — so a reader can predict where an operation lives. A bare verb is reserved for `send`, the primary operation, and for actions with no resource behind them (`chat`, `completion`, `conformance`, `demo-server`, `help`). + +Task-status **polling** is not a separate command: it is `task get --wait` — repeated polling until a terminal or interrupted state — and the default blocking wait on `send` (§9.3). To follow a job started with `--async`, poll it with `task get --wait `. *(Requirements for it are registered under the `TASK_POLL` area in `COMPLIANCE.md`.)* + +7.2 Global options. Unless noted, an option is available from Tier 1; where an option controls a higher-tier feature (for example `--metadata`), its availability follows that feature's tier (§5). + +| Option | Meaning | +| --- | --- | +| `--a2a-version ` | Protocol version to signal to the server on every request (§13). | +| `-a, --agent-card ` | The agent to talk to, given as an Agent Card reference: a bare host or origin (the well-known path is appended), a full card URL (used as-is), or a local file path (`file://…` or a plain path). | +| `--async` | Do not wait; return the task identifiers immediately for later polling (default is to wait, §6.5 / §9.3). `--return-immediately` and `--no-wait` are OPTIONAL aliases. | +| `--bearer ` / `--api-key ` | Pass a bearer token or an API key as the request credential (§12.1). | +| `--config ` | Load configuration from an explicit `.env` file in place of the local `.env` in the working directory (§8.3). Environment variables still take precedence over it (§6.5). | +| `--context-id ` | Group this turn with an existing interaction: the message starts a new task under the given server-assigned context, alongside the tasks already in it (§8.1). | +| `--debug` | **Developer diagnostics:** verbose logging to stderr for troubleshooting the tool's own behavior — request/response timing, retries, transport and version negotiation; at Tier 2 this includes the raw protocol messages exchanged on the wire. For *how the tool is performing the action*, not for reading the data itself (`--verbose`). | +| `-h, --help` | Show usage for the tool or the given command, and exit. | +| `--insecure` | Disable TLS verification for the negotiated transport (development only; MUST emit a warning). Transport security is on unless this is passed. | +| `--metadata ` | Attach caller-supplied metadata to the message/request as an inline JSON object string (e.g. `'{"k":"v"}'`); values may be any JSON. Sent in the request **payload** (A2A §3.2.5); distinct from `--svc-param`, which sets transport-level parameters (A2A §3.2.6). | +| `-o, --output ` | Output **format** only: `text` (default, §6.5, §11.2) or `json`, the protocol's own types (Appendix B). Whether `json` is one document or JSONL is set by `--stream`, not this flag (§11.3). | +| `--poll-interval ` / `--timeout ` | How often to re-check task status while waiting, and how long to wait before giving up (§9.3). | +| `--stream` | Follow the agent's live event stream instead of blocking, on `send` and `task subscribe`. Sets output **delivery** (peer of `-o`); with `-o json`, emits JSONL (§11.3). Explicit-only. | +| `--svc-param ` | Add an A2A **service parameter** (A2A §3.2.6): a transport-level key-value pair the binding carries in its own mechanism — an HTTP header or gRPC metadata — repeatable; general-purpose, not authentication-specific (§12.1). Keys and values are strings. Distinct from `--metadata`, which travels in the request payload (A2A §3.2.5). | +| `--task-id ` | Continue a specific existing task — for example, to reply to one waiting in `INPUT_REQUIRED`. `--context-id` is optional (the server resolves the task's context) but MUST correspond when given; a rejected identifier fails rather than starting a new task (§8.1). | +| `--transport ` | Client transport preference, **repeatable and ordered** (highest first). Overrides the card's preference order (§13.1); a binding absent from the card is skipped. | +| `--verbose` | **User-facing presentation:** show the full, human-readable breakdown of message parts and the data exchanged with the agent, rather than collapsing parts into one representation. For understanding *what was sent and received*, not how the tool got there. | +| `-v, --version` | Print the tool version and exit. | +| `--wait` | Block until the task reaches a terminal or interrupted state. This is the default for `send` (§6.5); stating it explicitly overrides a configured default. On `task get` it turns the one-shot read into a poll loop (§9.3). `--watch` is an OPTIONAL alias. | + +`--metadata` and `--svc-param` are two different layers and are not interchangeable: `--metadata '{"tenant":"acme"}'` embeds a key in the request **payload** (A2A §3.2.5), whereas `--svc-param x-trace-id:abc123` sets a **transport** parameter the binding sends as an HTTP header or gRPC metadata (A2A §3.2.6). + +`-o/--output` and `--stream` are orthogonal peers: the first chooses the **format** (`text`/`json`), the second the **delivery** (block vs. follow live). `--stream` is meaningful only on the streaming-capable commands `send` and `task subscribe`; to follow an existing task use `task subscribe` (live) or `task get --wait` (polling, §9.3), not `--stream` on `task get`. + +**Canonical spellings.** An `a2a-cli` MUST accept the canonical long flag named in the left column. Where a row names an OPTIONAL alias, a tool MAY accept it as well, but never instead: a script written against the canonical spelling works on every implementation. + +Other command-specific flags are defined with their commands: + +- **`--history `** — on `task get`. +- **`--validate`**, **`--extended`** — on `card get` (§10.1). +- **`--text`**, **`--file`**, **`--data`**, **`--media-type`** — on `send` (§10.2). + +**Setting options from the environment or a config file.** Where §6.5 allows an option's value to come from the environment or a configuration file, the environment variable is named `A2ACLI_` followed by the long flag in upper snake case: `--agent-card` → `A2ACLI_AGENT_CARD`, `--context-id` → `A2ACLI_CONTEXT_ID`, `--task-id` → `A2ACLI_TASK_ID`, `--a2a-version` → `A2ACLI_A2A_VERSION`, `--bearer` → `A2ACLI_BEARER` (credential variables are REQUIRED at Tier 1, §12.1). The same names MAY instead live in a `.env` (dotenv) file (one `A2ACLI_KEY=value` per line), loaded per §8.3 (`~/.config/a2a-cli/.env`, then a local `.env`) or from an explicit file via `--config `. Precedence is fixed (§6.5, §8.3): flag > environment variable > `.env` file > built-in default. `--stream` is excluded: it MUST be an explicit flag, never read from the environment or a file (§11.3), as are the action flags `-h/--help` and `-v/--version`. An OPTIONAL alias never names a variable of its own — the canonical flag does (`--async` → `A2ACLI_ASYNC`). + +--- + +## 8. Interaction state & configuration + +A2A interactions MAY span multiple invocations. **The CLI itself is stateless**: it reports every identifier it receives and accepts every identifier as input, but it does not remember one invocation in the next. What persists is *configuration* (§8.3), not session state. The identifiers it passes through — `messageId`, `taskId`, `contextId` — are defined in §4.1. + +### 8.1 Continuing an interaction (MUST) + +An `a2a-cli` MUST allow continuation via explicit options: + +- **`--context-id `** attaches this turn to an existing context (a new task within that context). +- **`--task-id `** continues an existing task — for example, to respond to a task waiting in `INPUT_REQUIRED` (§9.1). + +Rules: +- `--task-id` MAY be supplied with or without `--context-id`. A `taskId` already identifies its task uniquely, so when only `--task-id` is given the server resolves the task's context (A2A §3.4.3: an agent MUST infer `contextId` from the task when only `taskId` is provided). Supplying `--context-id` alongside is therefore optional, not required. +- When both are supplied they MUST correspond. A2A requires the server to reject a mismatched `contextId`/`taskId` pair (A2A §3.4.3); the tool MUST surface that error and MUST NOT attempt to reconcile the two. +- When `--task-id` is supplied, the tool MUST send the message against that task. If the server rejects the identifier (not found, a terminal-state conflict per A2A §3.1.1, or a mismatched `--context-id`), the tool MUST surface the protocol error, exit non-zero (§11.6), and **MUST NOT silently create a new task**. Starting a fresh task would risk writing into a context the caller did not intend; a rejected identifier is an error to surface, not a condition to work around. The tool MUST point the caller at `--debug` for the underlying protocol error. +- When only `--context-id` is supplied, the tool starts a **new task within that context**, which MAY return a `Message` or a `Task`. This is how a caller continues a conversation across tasks: `contextId` groups related tasks (A2A §3.4.1), so once one task reaches a terminal state, raising the next turn under the same `--context-id` keeps it grouped with the earlier work. +- Interactive `chat` (Tier 3) MUST carry the `contextId` (and the active `taskId` while a task is interrupted) across turns automatically. + +### 8.2 Reporting identifiers back (MUST) + +Because the next invocation depends on them, every command that touches a task MUST expose, on completion and on interruption: + +- the **`taskId`**, the **`contextId`**, and the current **task state**; +- in `-o json` (a single document or streamed as JSONL under `--stream`), these are carried by the protocol response type itself (Appendix B) — a tool MUST NOT flatten or rename them into fields of its own; +- in human-facing modes, these MUST be printed in a copy-pasteable form, and the tool SHOULD print the exact command required to resume (for example, `a2a-cli send --task-id ""`). + +### 8.3 Configuration (SHOULD) + +A tool persists **configuration**, never session state. It MUST NOT record the last `contextId` or `taskId` and offer to resume from them; a caller that wants to continue supplies the identifier (§8.1). + +Configuration values resolve in one fixed order, highest wins: + +1. an explicit flag, +2. an environment variable, +3. a local configuration file (a local `.env`, or the file given by `--config`), +4. a global configuration file (`~/.config/a2a-cli/.env`), +5. the built-in default (§6.5). + +> **Informative.** Highest-precedence source wins; each level overrides the ones below it. + +```mermaid +flowchart TD + A([1. Explicit Flag]) + B([2. Environment Variable]) + C([3. Local Config File]) + D([4. Global Config File]) + E([5. Built-in Default]) + + A -->|Overrides| B + B -->|Overrides| C + C -->|Overrides| D + D -->|Overrides| E + +``` + +Files use the `.env` (dotenv) format: one `A2ACLI_