Agent feature matrix
What every adopted source emits, at several granularities; derived from the conformance fixture corpus plus the reviewed capability record, regenerated by docs/gen-agents.js.
Coverage below is derived, not asserted: the per-type grids come from
the conformance mapping fixtures
that CI runs on every commit, and the capability columns come from the
reviewed record behind this page (docs/data/agents.json).
How each cell earned its place is the vendor surfaces page's job;
the control side has its own control matrix.
Legend: ● fixture-pinned (the mapping table in conformance/fixtures/mappings/ asserts it) · ○ shipped and documented at the component doc, not fixture-pinned · blank = not emitted by this source.
One reading note: the grids assert what each source's mapping tables
pin: vendor moments landing on AEP types. The fixture fallback tables
(how a wholly novel vendor moment would map) pin a mechanism, not feature
span, so they are excluded. A blank family cell is itself feature-span
information: it means the vendor surface exposes no moment of that family
for the mapping to ride.
Coverage at a glance
| Source | Class | Channel | Control loop | Forms | Validation | Mapping fixture |
|---|---|---|---|---|---|---|
| Claude Code | Agent adapter | hooks: native http type or command shim |
answers permission (typed text follows the AEP-0008 receiver rule: an option word counts as that option, other free text is a deny WITH the text as the hook message, the vendor's own custom-reply path), form |
form (AEP-0006) |
live-validated | claude-code.json |
| Codex | Agent adapter | hooks: command shim |
answers permission (typed text follows the AEP-0008 receiver rule: an option word counts as that option, other free text is a deny WITH the text as the decision message, the guidance path) |
n/a | live-validated | codex.json |
| Gemini CLI | Agent adapter | hooks: command shim |
n/a | n/a | fixture-proven | gemini-cli.json |
| Qwen Code | Agent adapter | hooks: native http type (shimless) or command shim |
answers permission (typed text follows the AEP-0008 receiver rule: an option word counts as that option, other free text is a deny WITH the text as the decision message, the vendor's guidance path) |
n/a | fixture-proven | qwen-code.json |
| VS Code agent (Copilot) | Agent adapter | agent hooks (Preview): command shim |
answers permission (control opt-in: the held PreToolUse gate; an ask answer escalates to VS Code's own user-approval flow; typed text follows the AEP-0008 receiver rule: an option word incl. ask counts as that option, other free text denies with the text as the rendered reason) |
n/a | fixture-proven | vscode.json |
| Kimi Code CLI | Agent adapter | external hooks: command shim ([[hooks]] in the ONE global config.toml; strict four-field schema, no per-project hook file) |
answers permission (control opt-in: the held PreToolUse gate, binary allow/deny; typed text follows the AEP-0008 receiver rule: an option word counts as that option, other free text denies with the text as the rendered reason) |
n/a | live-validated | kimi-code.json |
| OpenCode | Agent adapter | plugin: runs inside the agent's Bun runtime | answers permission (typed text follows the AEP-0008 receiver rule: an option word counts as that option; unmatched free text applies the refusing status; the hook output carries status only, so guidance stays stream-visible) |
n/a | fixture-proven | opencode.json |
| Kilo Code | Agent adapter | plugin: same shape as OpenCode (verified fork; runtime DIVERGED from the upstream at from 7.4.6) | answers permission (dual surface; through 7.4.5: the held hook, typed text follows the AEP-0008 receiver rule, an option word counts as that option, unmatched free text applies the refusing status with guidance stream-visible only; from 7.4.6: options mirror the vendor reply enum once/always/reject verbatim and a reject's free text REACHES the vendor as the reply message), form (questions, from 7.4.6) |
form (AEP-0006) |
fixture-proven | kilocode.json |
| Cline | Agent adapter | typed subprocess hooks (--hooks-dir) |
answers permission (hub opt-in) |
n/a | fixture-proven | cline.json |
| Hermes | Agent adapter | shell hooks: command shim |
answers permission (control opt-in: the held tool gate; typed text follows the AEP-0008 receiver rule: an option word counts as that option, other free text is a deny with the text as the reason; the vendor's own approval gate stays observed read-only in every posture) |
form (AEP-0006) |
fixture-proven | hermes.json |
| Antigravity | Agent adapter | hooks: hooks.json command registration (event name as argv) |
n/a | n/a | fixture-proven | antigravity.json |
| pi | Agent adapter | in-process extension (per-event subscription) | answers permission (control opt-in: the held tool gate; a deny rides the vendor's own block result and the observed skip stays the pinned tool.failed, never recast) |
n/a | fixture-proven | pi.json |
| AG-UI | Inbound bridge | HTTP tee proxy in front of any AG-UI agent | n/a | n/a | fixture-proven | agui.json |
| ACP | Inbound bridge | stdio tee: the bridge IS the editor's agent command | observes permission |
n/a | fixture-proven | acp.json |
| OpenHands | Inbound bridge | WebSocket observer on the agent server's events socket | answers permission (control opt-in) |
n/a | fixture-proven | openhands.json |
| OTel inbound | Inbound bridge | OTLP/HTTP receiver (POST /v1/logs, JSON encoding) |
n/a | n/a | fixture-proven | codex-otel.json |
| OpenCode SSE | Inbound bridge | SSE client on a running OpenCode server's event stream | answers permission (control opt-in, primary mode) |
n/a | fixture-proven | opencode.json |
| Kilo Code SSE | Inbound bridge | SSE client on a running Kilo server's event stream (kilo serve) |
answers permission (control opt-in, primary mode) |
n/a | fixture-proven | kilocode.json |
| Kimi web (kap-server) | Inbound bridge | WS client on a running kap-server event stream (kimi web; REST /api/v1 + WS /api/v1/ws, bearer subprotocol) |
answers permission (control opt-in, primary mode: approvals only; question answering is deferred, reason recorded) |
n/a | fixture-proven | kimi-code.json |
Event coverage
| Source | session |
run |
tool |
attention |
progress |
delegation |
state |
error |
agent |
vendor x.* |
|---|---|---|---|---|---|---|---|---|---|---|
| Claude Code | ○ | ○ | ○ | ● | ○ | ○ | ○ | |||
| Codex | ● | ● | ● | ● | ● | |||||
| Gemini CLI | ● | ● | ● | ● | 3 | |||||
| Qwen Code | ● | ● | ● | ● | ● | ● | ||||
| VS Code agent (Copilot) | ● | ● | ● | ● | ||||||
| Kimi Code CLI | ● | ● | ● | ● | ● | ● | 14 | |||
| OpenCode | ● | ● | ● | ● | ● | 5 | ||||
| Kilo Code | ● | ● | ● | ● | ● | 16 | ||||
| Cline | ● | ● | ● | ● | 1 | |||||
| Hermes | ● | ● | ● | ● | ● | 2 | ||||
| Antigravity | ● | ● | 1 | |||||||
| pi | ● | ● | ● | 7 | ||||||
| AG-UI | ● | ● | ● | 6 | ||||||
| ACP | ● | ● | ● | ● | 7 | |||||
| OpenHands | ● | ● | ● | ● | ● | ● | 8 | |||
| OTel inbound | ● | ● | 7 | |||||||
| OpenCode SSE | ● | ● | ● | ● | 13 | |||||
| Kilo Code SSE | ● | ● | ● | ● | 16 | |||||
| Kimi web (kap-server) | ● | ● | ● | 11 |
| Source | session.started |
session.ended |
session.compacted |
run.started |
run.finished |
run.failed |
run.cancelled |
run.step.started |
run.step.finished |
|---|---|---|---|---|---|---|---|---|---|
| Claude Code | ○ | ○ | ○ | ○ | ○ | ○ | |||
| Codex | ● | ● | ● | ● | |||||
| Gemini CLI | ● | ● | ● | ● | ● | ||||
| Qwen Code | ● | ● | ● | ● | ● | ● | |||
| VS Code agent (Copilot) | ● | ● | ● | ● | |||||
| Kimi Code CLI | ● | ● | ● | ● | ● | ● | ● | ||
| OpenCode | ● | ● | ● | ● | ● | ||||
| Kilo Code | ● | ● | ● | ● | ● | ||||
| Cline | ● | ● | ● | ● | ● | ● | |||
| Hermes | ● | ● | ● | ● | ● | ||||
| Antigravity | ● | ● | ● | ● | |||||
| pi | ● | ● | ● | ● | ● | ● | ● | ● | ● |
| AG-UI | ● | ● | ● | ● | ● | ||||
| ACP | ● | ● | ● | ● | ● | ||||
| OpenHands | ● | ● | ● | ● | ● | ● | |||
| OTel inbound | ● | ||||||||
| OpenCode SSE | ● | ● | ● | ● | ● | ||||
| Kilo Code SSE | ● | ● | ● | ● | ● | ||||
| Kimi web (kap-server) | ● | ● | ● |
| Source | tool.requested |
tool.completed |
tool.failed |
tool.denied |
attention.requested |
attention.answered |
attention.resolved |
attention.timeout |
|---|---|---|---|---|---|---|---|---|
| Claude Code | ○ | ○ | ○ | ○ | ● | ○ | ○ | ○ |
| Codex | ● | ● | ● | |||||
| Gemini CLI | ● | ● | ● | |||||
| Qwen Code | ● | ● | ● | ● | ||||
| VS Code agent (Copilot) | ● | ● | ||||||
| Kimi Code CLI | ● | ● | ● | ● | ● | ● | ||
| OpenCode | ● | ● | ● | ● | ||||
| Kilo Code | ● | ● | ● | ● | ||||
| Cline | ● | ● | ● | |||||
| Hermes | ● | ● | ● | ● | ● | ● | ● | ● |
| Antigravity | ● | ● | ● | |||||
| pi | ● | ● | ● | |||||
| AG-UI | ● | ● | ||||||
| ACP | ● | ● | ● | ● | ● | ● | ||
| OpenHands | ● | ● | ● | ● | ● | ● | ||
| OTel inbound | ● | ● | ● | |||||
| OpenCode SSE | ● | ● | ||||||
| Kilo Code SSE | ● | ● | ||||||
| Kimi web (kap-server) | ● | ● | ● | ● |
| Source | progress.status |
progress.task.planned |
progress.task.completed |
delegation.subagent.started |
delegation.subagent.stopped |
state.snapshot |
state.delta |
error.raised |
agent.idle |
|---|---|---|---|---|---|---|---|---|---|
| Claude Code | ○ | ○ | ○ | ○ | ○ | ○ | |||
| Codex | ● | ● | |||||||
| Gemini CLI | ● | ||||||||
| Qwen Code | ● | ● | ● | ● | ● | ||||
| VS Code agent (Copilot) | ● | ● | |||||||
| Kimi Code CLI | ● | ● | ● | ||||||
| OpenCode | ● | ● | ● | ||||||
| Kilo Code | ● | ● | ● | ||||||
| Cline | ● | ● | |||||||
| Hermes | ● | ● | |||||||
| Antigravity | |||||||||
| pi | |||||||||
| AG-UI | ● | ● | |||||||
| ACP | |||||||||
| OpenHands | ● | ● | ● | ||||||
| OTel inbound | |||||||||
| OpenCode SSE | ● | ||||||||
| Kilo Code SSE | ● | ||||||||
| Kimi web (kap-server) |
Vendor extension types, per source
Everything a source exposes beyond the core taxonomy rides its vendor namespace unchanged; the count is a feature-span signal, not noise.