---
title: "Agent feature matrix"
sidebarTitle: "Feature matrix"
description: "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."
---

{/* GENERATED by docs/gen-agents.js from conformance/fixtures/mappings/*.json + docs/data/agents.json; do not edit. Edit the inputs and re-run `node docs/gen-agents.js` */}

Coverage below is **derived**, not asserted: the per-type grids come from
the [conformance mapping fixtures](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/conformance/fixtures/mappings)
that CI runs on every commit, and the capability columns come from the
reviewed record behind this page ([`docs/data/agents.json`](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/docs/data/agents.json)).
How each cell earned its place is the [vendor surfaces](/vendor-surfaces) page's job;
the control side has its own [control matrix](/agents/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](/components/adapters) | 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`](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/conformance/fixtures/mappings/claude-code.json) |
| [Codex](/components/adapters) | 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`](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/conformance/fixtures/mappings/codex.json) |
| [Gemini CLI](/components/adapters) | Agent adapter | hooks: `command` shim | n/a | n/a | fixture-proven | [`gemini-cli.json`](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/conformance/fixtures/mappings/gemini-cli.json) |
| [Qwen Code](/components/adapters) | 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`](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/conformance/fixtures/mappings/qwen-code.json) |
| [VS Code agent (Copilot)](/components/adapters) | 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`](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/conformance/fixtures/mappings/vscode.json) |
| [Kimi Code CLI](/components/adapter-kimi-code-design) | 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`](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/conformance/fixtures/mappings/kimi-code.json) |
| [OpenCode](/components/adapter-opencode-design) | 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`](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/conformance/fixtures/mappings/opencode.json) |
| [Kilo Code](/components/adapter-kilocode-design) | 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`](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/conformance/fixtures/mappings/kilocode.json) |
| [Cline](/components/adapter-cline-design) | Agent adapter | typed subprocess hooks (`--hooks-dir`) | answers `permission (hub opt-in)` | n/a | fixture-proven | [`cline.json`](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/conformance/fixtures/mappings/cline.json) |
| [Hermes](/components/adapter-hermes-design) | 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`](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/conformance/fixtures/mappings/hermes.json) |
| [Antigravity](/components/adapter-antigravity-design) | Agent adapter | hooks: `hooks.json` command registration (event name as argv) | n/a | n/a | fixture-proven | [`antigravity.json`](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/conformance/fixtures/mappings/antigravity.json) |
| [pi](/components/adapter-pi-design) | 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`](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/conformance/fixtures/mappings/pi.json) |
| [AG-UI](/components/bridge-agui-design) | Inbound bridge | HTTP tee proxy in front of any AG-UI agent | n/a | n/a | fixture-proven | [`agui.json`](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/conformance/fixtures/mappings/agui.json) |
| [ACP](/components/bridge-acp-design) | Inbound bridge | stdio tee: the bridge IS the editor's agent command | observes `permission` | n/a | fixture-proven | [`acp.json`](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/conformance/fixtures/mappings/acp.json) |
| [OpenHands](/components/bridge-openhands-design) | Inbound bridge | WebSocket observer on the agent server's events socket | answers `permission (control opt-in)` | n/a | fixture-proven | [`openhands.json`](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/conformance/fixtures/mappings/openhands.json) |
| [OTel inbound](/components/bridge-otlp-inbound-design) | Inbound bridge | OTLP/HTTP receiver (`POST /v1/logs`, JSON encoding) | n/a | n/a | fixture-proven | [`codex-otel.json`](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/conformance/fixtures/mappings/codex-otel.json) |
| [OpenCode SSE](/components/adapter-opencode-design) | 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`](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/conformance/fixtures/mappings/opencode.json) |
| [Kilo Code SSE](/components/adapter-kilocode-design) | 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`](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/conformance/fixtures/mappings/kilocode.json) |
| [Kimi web (kap-server)](/components/adapter-kimi-code-design) | 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`](https://github.com/agenteventprotocol/agent-event-protocol/blob/main/conformance/fixtures/mappings/kimi-code.json) |

## Event coverage

<Tabs>
<Tab title="By family">

| 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 |

</Tab>
<Tab title="Session and run">

| 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) |   |   |   | ● | ● |   | ● |   |   |

</Tab>
<Tab title="Tools and attention">

| 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) | ● |   |   |   | ● | ● | ● |   |

</Tab>
<Tab title="Progress, delegation, state">

| 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) |   |   |   |   |   |   |   |   |   |

</Tab>
</Tabs>

## 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.

<AccordionGroup>
<Accordion title="Claude Code: 0 fixture-pinned extension types">

No vendor extension types are fixture-pinned for this source (the fixture file pins the two structured-input (kind `form`) mappings at both capture ceilings; the remaining coverage below is documented at the component doc and validated live).

</Accordion>
<Accordion title="Codex: 0 fixture-pinned extension types">

No vendor extension types are fixture-pinned for this source.

</Accordion>
<Accordion title="Gemini CLI: 3 fixture-pinned extension types">

- `x.gemini-cli.session.after_model`
- `x.gemini-cli.session.before_model`
- `x.gemini-cli.session.before_tool_selection`

</Accordion>
<Accordion title="Qwen Code: 0 fixture-pinned extension types">

No vendor extension types are fixture-pinned for this source.

</Accordion>
<Accordion title="VS Code agent (Copilot): 0 fixture-pinned extension types">

No vendor extension types are fixture-pinned for this source.

</Accordion>
<Accordion title="Kimi Code CLI: 14 fixture-pinned extension types">

- `x.kimi-code.run.steer_submitted`
- `x.kimi-code.session.permission_result`
- `x.kimi-code.session.pre_compact`
- `x.kimi-code.web.event.approval.requested`
- `x.kimi-code.web.event.approval.resolved`
- `x.kimi-code.web.event.question.answered`
- `x.kimi-code.web.event.question.dismissed`
- `x.kimi-code.web.event.question.requested`
- `x.kimi-code.web.event.session.work_changed`
- `x.kimi-code.web.session.meta.updated`
- `x.kimi-code.web.tool.call.started`
- `x.kimi-code.web.tool.result`
- `x.kimi-code.web.turn.ended`
- `x.kimi-code.web.turn.started`

</Accordion>
<Accordion title="OpenCode: 5 fixture-pinned extension types">

- `x.opencode.command.executed`
- `x.opencode.file.edited`
- `x.opencode.message.updated`
- `x.opencode.server.connected`
- `x.opencode.session.error`

</Accordion>
<Accordion title="Kilo Code: 16 fixture-pinned extension types">

- `x.kilocode.command.executed`
- `x.kilocode.file.edited`
- `x.kilocode.message.updated`
- `x.kilocode.permission.asked`
- `x.kilocode.permission.replied`
- `x.kilocode.permission.updated`
- `x.kilocode.question.asked`
- `x.kilocode.question.replied`
- `x.kilocode.server.connected`
- `x.kilocode.session.compacted`
- `x.kilocode.session.created`
- `x.kilocode.session.deleted`
- `x.kilocode.session.error`
- `x.kilocode.session.idle`
- `x.kilocode.session.status`
- `x.kilocode.todo.updated`

</Accordion>
<Accordion title="Cline: 1 fixture-pinned extension type">

- `x.cline.prompt.submitted`

</Accordion>
<Accordion title="Hermes: 2 fixture-pinned extension types">

- `x.hermes.api.error`
- `x.hermes.session.reset`

</Accordion>
<Accordion title="Antigravity: 1 fixture-pinned extension type">

- `x.antigravity.step.completed`

</Accordion>
<Accordion title="pi: 7 fixture-pinned extension types">

- `x.pi.agent.settled`
- `x.pi.message.replied`
- `x.pi.message.submitted`
- `x.pi.model.select`
- `x.pi.session.info`
- `x.pi.session.tree`
- `x.pi.thinking.select`

</Accordion>
<Accordion title="AG-UI: 6 fixture-pinned extension types">

- `x.agui.custom.event`
- `x.agui.messages.snapshot`
- `x.agui.raw.event`
- `x.agui.reasoning.start`
- `x.agui.text_message.end`
- `x.agui.text_message.start`

</Accordion>
<Accordion title="ACP: 7 fixture-pinned extension types">

- `x.acp.current.mode.update`
- `x.acp.fs.read.text.file`
- `x.acp.initialize.event`
- `x.acp.plan.updated`
- `x.acp.session.cancel`
- `x.acp.tool_call.update`
- `x.acp.usage.updated`

</Accordion>
<Accordion title="OpenHands: 8 fixture-pinned extension types">

- `x.openhands.acp_tool.call`
- `x.openhands.condensation.request`
- `x.openhands.condensation.summary`
- `x.openhands.interrupt.event`
- `x.openhands.message.event`
- `x.openhands.pause.event`
- `x.openhands.system.prompt`
- `x.openhands.user_reject.observation`

</Accordion>
<Accordion title="OTel inbound: 7 fixture-pinned extension types">

- `x.codex.otel.api_request`
- `x.codex.otel.conversation_starts`
- `x.codex.otel.sse_event`
- `x.codex.otel.tool_decision`
- `x.codex.otel.tool_result`
- `x.codex.otel.user_prompt`
- `x.codex.otel.websocket_event`

Note: two vendor profiles ride one receiver: Codex's native OTel log export (`codex-otel.json`, the default) and the VS Code agent's `copilot_chat.*` LogRecord family (`--vendor vscode`, `vscode-otel.json`); one vendor per process, each with its own pure mapper.

</Accordion>
<Accordion title="OpenCode SSE: 13 fixture-pinned extension types">

- `x.opencode.command.executed`
- `x.opencode.file.edited`
- `x.opencode.message.updated`
- `x.opencode.permission.replied`
- `x.opencode.permission.updated`
- `x.opencode.server.connected`
- `x.opencode.session.compacted`
- `x.opencode.session.created`
- `x.opencode.session.deleted`
- `x.opencode.session.error`
- `x.opencode.session.idle`
- `x.opencode.session.status`
- `x.opencode.todo.updated`

Note: pinned by the `sse_modes` table in the OpenCode fixture file (companion and primary postures).

</Accordion>
<Accordion title="Kilo Code SSE: 16 fixture-pinned extension types">

- `x.kilocode.command.executed`
- `x.kilocode.file.edited`
- `x.kilocode.message.updated`
- `x.kilocode.permission.asked`
- `x.kilocode.permission.replied`
- `x.kilocode.permission.updated`
- `x.kilocode.question.asked`
- `x.kilocode.question.replied`
- `x.kilocode.server.connected`
- `x.kilocode.session.compacted`
- `x.kilocode.session.created`
- `x.kilocode.session.deleted`
- `x.kilocode.session.error`
- `x.kilocode.session.idle`
- `x.kilocode.session.status`
- `x.kilocode.todo.updated`

Note: pinned by the `sse_modes` table in the Kilo Code fixture file (companion and primary postures; the OpenCode channel mirrored on `x.kilocode.*`; the bus union byte-identical at the re-verified pins).

</Accordion>
<Accordion title="Kimi web (kap-server): 11 fixture-pinned extension types">

- `x.kimi-code.web.event.approval.requested`
- `x.kimi-code.web.event.approval.resolved`
- `x.kimi-code.web.event.question.answered`
- `x.kimi-code.web.event.question.dismissed`
- `x.kimi-code.web.event.question.requested`
- `x.kimi-code.web.event.session.work_changed`
- `x.kimi-code.web.session.meta.updated`
- `x.kimi-code.web.tool.call.started`
- `x.kimi-code.web.tool.result`
- `x.kimi-code.web.turn.ended`
- `x.kimi-code.web.turn.started`

Note: pinned by the `ws_modes` table in the Kimi Code fixture file (companion and primary postures; lifecycle/approval shapes oracle-captured from the shipped 0.28.1, the question loop source-derived and labeled).

</Accordion>
</AccordionGroup>
