Checked 2026-10-13 against this tree and the vendor pages linked below.
Agentmetry traces what an agent does on a machine you control, whichever model it runs on. It cannot see agents that live entirely in someone else's cloud.
This is a research matrix, not a support list. A row is "supported and tested" only when this repo records it and a test exercises that path. Everything else is either a path someone could build or an honest "no". An agent that is absent from the tables is not supported.
Any agent that can reach POST /api/v1/audit/ingest can be recorded into the hash-chained trail. What the detections can do with those events depends on what arrives with them:
- ATT&CK mapping is computed on the server from the tool name and its arguments (
get_mitre_mapping, called fromcore/audit/external.py) whenever the client sends none. Rules built on tactics, such as credential access followed by network egress, can fire for any integration whose tool names and arguments map. - Command traits are computed only by the client. The hooks classify the shell command before hashing it (
classify_commandinhooks/ingest.py) and send the labels. The server keeps traits it is sent and computes none of its own. An integration that posts no traits gets no trait-based detections, such asencoded-command-downloadordotfile-read-then-git-push. The CrewAI and OpenSRE adapters send no traits today. - The rules describe endpoint behaviour. The published set (detection-rules.md) is about shell commands, credential files, network egress, git, cloud CLIs, deletions, subagents and approvals. A support bot that files a ticket or a workflow that posts to Slack gets a valid record and, almost always, no detection.
The "Detections apply?" column below uses three values: yes (the integration sends what the rules read), partly (the ATT&CK mapping applies, the trait-based rules do not, or only some of the agent's actions are endpoint actions), and record only (the rules have nothing to match).
| Status | Meaning |
|---|---|
| supported and tested | An installer, mapper or adapter in this repo, and tests that exercise it. |
| proxy as above | Only the stdio MCP servers you wrap with agentmetry mcp-proxy are recorded. The app's built-in tools are not. |
| possible, not built | The vendor documents a hook, plugin, event API or structured log. This repo has no installer and no mapper for it. |
| not traceable locally | The actions run on the vendor's computers. A recorder on your machine has nothing to attach to. |
"Unverified" marks a claim that was not confirmed against a primary source. It is a note, not a fifth status.
Deny and ask are narrower than recording. ask_honoured() in core/audit/tool_policy/capability.py trusts an ask only for Claude Code PreToolUse and for Cursor beforeShellExecution and beforeMCPExecution. Everywhere else a policy ask is enforced as deny, because an ask the agent ignores is an allow.
Two lists in the code bound every "supported" claim:
SURFACESincore/diagnostics/hook_coverage.pyis whatdoctorand the heartbeat attest:cursor,claude,qwen,qoder,codebuddy,kimi,codex,copilot,antigravity.coveredmeans the hook entry exists, not that the agent runs it.doctorand the heartbeat also list every configured agent with no event in the last seven days (hooks_silent), because Codex skips hooks the developer has not approved and that approval cannot be read from disk (#300). Silence is evidence, not proof: an unused agent is silent too.KNOWN_EXTERNAL_APPSincore/audit/external.pyis what the ingest API keeps assource.app: the nine above plusmcp_proxy,trae,crewaiandopensre. Any othersource_appis recorded asunknown, with the claimed name kept insource.claimed_app. A new integration still needs an allowlisted name to be attributed properly.
Captured through the agent's own hooks. Detections apply: yes for the nine hooked surfaces, because the hook sends traits and the ATT&CK block.
| Agent | How it is or could be captured | Status | Source |
|---|---|---|---|
| Claude Code | Hooks, with deny and ask on PreToolUse. Second path: agentmetry otel, record only. |
supported and tested | Hooks |
| Cursor | Hooks. Ask honoured on beforeShellExecution and beforeMCPExecution. |
supported and tested | Hooks |
| Codex CLI | Hooks in ~/.codex/hooks.json, after /hooks trusts them. Approval applies to conversations started afterwards. On Windows the installer writes the command unquoted, and never uses Codex's commandWindows override, which Codex's approval never matches (#307). Deny, no ask. |
supported and tested | Hooks |
| Antigravity | Hooks. Windows install script only. | supported and tested | Hooks |
| Qwen Code | Claude-shaped hooks. | supported and tested | Hooks |
| Kimi Code | Hooks in ~/.kimi-code/config.toml, plus print-mode stream-json. |
supported and tested | Hooks |
| Qoder | Claude-shaped hooks. | supported and tested | Hooks |
| CodeBuddy | Claude-shaped hooks (vendor docs marked beta). | supported and tested | Hooks |
| Windsurf (Cascade) | Hooks. A pre-hook blocks with exit code 2. | possible, not built | Cascade hooks |
| Trae | Claude-shaped hooks: hookSpecificOutput.permissionDecision (allow, deny, ask), exit code 2 as deny. |
possible, not built | Hooks, reference |
| Gemini CLI | Hooks in settings.json (BeforeTool and others). A different program from Antigravity. |
possible, not built | Hooks |
| GitHub Copilot, CLI and VS Code agent mode | One hooks file in ~/.copilot/hooks/ serves both. Deny is exit code 2. --managed writes the CLI's root-owned policy hooks. |
supported and tested | Hooks reference, VS Code hooks |
| Grok Build | Local CLI. Hooks in ~/.grok/hooks/*.json. Deny is {"decision":"deny"} or exit code 2. |
possible, not built | Hooks |
| Goose | Session database that stores tool calls, plus stdio MCP extensions. | possible, not built | Logging |
Notes that keep the status honest:
- GitHub Copilot. The CLI and VS Code read the same
~/.copilot/hooks/*.jsonand disagree on the JSON: the CLI reads a flatpermissionDecision, VS Code only the nestedhookSpecificOutputone (checked in microsoft/vscodechatHookService.ts). So the deny is exit code 2, which both document as a deny; VS Code fails open on any other non-zero code. Ask is enforced as deny. VS Code hooks are marked preview, an organisation can turn them off, andchat.useHooks: falseturns them off locally, whichagentmetry posturereports. Whether VS Code reads the CLI's policy hooks is not documented. Tests check both payload shapes and the exit code; neither surface was run live. - Codex. Deny was broken until #246: Codex was sent Cursor's
{"permission": ...}, rejected it as an unknown field, and ran the tool while the trail recordeddenied. Fixed in 0.9.5. 0.9.4 and earlier fail open on Codex. The fix was first checked against Codex's parser source only; it was verified against a live runtime on 2026-10-22 (Codex CLI 0.163.0-alpha.11.1, Windows): with a block-mode tool-policy rule matching a shell command, Codex reportedCommand blocked by PreToolUse hook: tool_policy:<rule>, the command did not run (the file it would have written was never created, while a control run without the rule created it), and the trail recorded the call asoutcome: deniedwithtool_policy.blocked: true. Codex parsesaskand runs the tool, so a policy ask is sent as deny. Hosted tools such asWebSearchdo not firePreToolUse. Shell, unified exec,apply_patch, MCP and other local function tools do. - Antigravity.
agentmetry hooks installdoes not write these hooks;scripts/install_antigravity_hooks.ps1does, on Windows. A public forum thread reports that the IDE and the 2.0 desktop app do not runPreToolUsewhile the CLI does. Unverified against a vendor statement. - Qwen, Qoder, CodeBuddy. They get Claude's
hookSpecificOutput(_CLAUDE_PROTOCOL). Their docs document ask, butask_honoureddoes not include them, so a policy ask is enforced as deny. CodeBuddy has no mapping test of its own. - Kimi Code. The installer writes
~/.kimi-code/config.toml, the path on the kimi.com page. Moonshot's kimi-cli uses~/.kimi/config.toml. Whether that is the same program was not established. - Windsurf.
mcp_inventoryreads its MCP config and records nothing. Installer work is parked in issue #7. - Trae.
traeis allowlisted for the MCP proxy. No mapper and no hook installer; adapters/trae says what one needs. - Gemini CLI. It shares
~/.geminiwith Antigravity. Until the fix listed below, coverage read that directory as Antigravity being installed, so a machine with only Gemini CLI showed an uncovered Antigravity. - Grok Build. Its docs say it also reads Claude Code settings and Cursor
hooks.json. Whether an Agentmetry hook installed for those runs under Grok Build was not tested, and its deny shape differs from both, so a hook that ran would not prove a working deny. - Goose.
sessions.dbholds tool-call ids, arguments, responses and outcomes. That is an after-the-fact import, not a live hook.
Always-on or task agents that use tools on the computer where their process lives. None of these names is allowlisted. Detections apply: partly if one were built today on the ingest API (ATT&CK from tool names, no traits), yes if its mapper classified commands the way the hooks do.
| Agent | How it could be captured | Status | Source |
|---|---|---|---|
| OpenClaw | Plugin hooks. before_tool_call can block or require approval. after_tool_call observes. |
possible, not built | Plugin hooks, reference |
| Hermes Agent (Nous Research) | Shell and plugin hooks. pre_tool_call can block, or escalate to Hermes's approval gate. Outbound webhooks. Also an stdio MCP client. |
possible, not built | Event hooks |
| Agent Zero | Extension points tool_execute_before and tool_execute_after. Whether the first can block: unverified. |
possible, not built | Extensions reference |
| OpenHands, local CLI and GUI | Claude-compatible .openhands/hooks.json. PreToolUse blocks with exit code 2. Tool names differ (terminal, not Bash). |
possible, not built | Hooks |
| Open Interpreter | Runs code on the local machine with a confirmation prompt. No hook or structured action log was found in current docs. Unverified. | unverified | Project |
Integration paths, for later issues. Not built, and not support claims:
- OpenClaw. An in-process plugin on
before_tool_callandafter_tool_callthat posts to ingest.HOOK.mdhandlers are session lifecycle, not the tool boundary. - Hermes. A shell
pre_tool_call/post_tool_callentry is the closest thing to an IDE hook installer.{"action":"block"}is a real deny. - Agent Zero. An extension at those two points.
- OpenHands. A hook installer and a mapper. OpenHands Cloud loads the same hooks in the cloud, which is category G.
Agents that drive a browser or a desktop on your machine. A click, a keystroke and a page load are not tool calls a hook sees unless the agent routes them through a tool. Detections apply: partly. untrusted-input-then-risky-action is written for agents that read external content, but the shell and credential rules see nothing of a browser session.
| Agent | How it could be captured | Status | Source |
|---|---|---|---|
| Playwright MCP | An stdio MCP server (npx @playwright/mcp). Wrap it and every browser tool call is recorded. |
proxy as above | Repository |
| Browser Use | on_step_start and on_step_end hooks on agent.run(). The hook gets the agent and its browser session. They observe a step; they are not documented as a deny. |
possible, not built | Hooks |
| Claude computer use, in your own loop | The API returns the action and your code performs it, so your loop is the place to record. Same as category E. | possible, not built | Computer use tool |
| Claude Desktop computer use | Built-in tools, not stdio MCP. The proxy does not see them. | not covered | See category D |
| Stagehand, Skyvern (self-hosted) | Libraries and services that run a browser where you deploy them. Hook points not checked. | unverified |
Any app that launches stdio MCP servers can be recorded by wrapping each one:
agentmetry mcp-proxy -- <server command>The proxy is supported and tested (agentmetry/hooks/mcp_proxy.py, tests/test_mcp_audit_proxy.py). It logs every stdio tools/call and fingerprints tools/list. HTTP, SSE and streamable HTTP are not proxied. Tools the app runs itself are invisible to it. agentmetry mcp inventories Claude, Cursor, Windsurf and VS Code configs; inventory is not capture. Detections apply: partly, depending on the servers. A filesystem or shell server maps; a calendar server does not.
| Client | How it could be captured | Status | Source |
|---|---|---|---|
| Any stdio MCP client | Wrap each server command. | supported and tested (the proxy) | agentmetry/hooks/mcp_proxy.py |
| Claude Desktop | Same wrap. Cowork and Chat also load plugin hooks, which this repo does not install. | proxy as above. Hook installer possible, not built | Plugins and hooks |
| VS Code | Same wrap. mcp.json is already inventoried. |
proxy as above | MCP servers |
| LM Studio | Host since 0.3.17. mcp.json in Cursor's notation, launched locally. Not in the inventory reader. |
proxy as above | MCP in LM Studio |
| Jan | STDIO, HTTP and SSE transports. Jan Agent reads the same mcp_config.json. |
proxy as above (STDIO only) | MCP servers |
| ChatGPT desktop app | Custom MCP connectors are remote HTTPS servers (Developer Mode). Local stdio servers are not run. From secondary sources; unverified against OpenAI's docs. | not traceable locally | See category G |
Wrapping a server and also installing a host hook records the same MCP call twice if both fire.
The process runs where you deploy it, so capture is an adapter in that process that posts to the ingest API. Detections apply: partly for the two shipped adapters (server-side ATT&CK mapping only, no traits), and the same for any new one unless it classifies commands too.
| Framework | Hook point | Can it block a tool? | Status | Source |
|---|---|---|---|---|
| CrewAI | Event bus: ToolUsageStartedEvent, ToolUsageFinishedEvent, ToolUsageErrorEvent. |
Adapter records only | supported and tested | Event listeners |
| OpenSRE | Agent(..., on_runtime_event=...). |
Adapter records only | supported and tested | core/events.py |
| LangChain / LangGraph | BaseCallbackHandler.on_tool_start / on_tool_end on the runnable config. |
Not established | possible, not built | callbacks/base.py |
| OpenAI Agents SDK | RunHooks / AgentHooks on_tool_start and on_tool_end, or a custom TracingProcessor. |
Not established | possible, not built | Lifecycle |
| Microsoft Agent Framework | Function middleware around every tool call. | Yes: MiddlewareTermination, or not calling call_next() |
possible, not built | Middleware |
| Semantic Kernel | Function invocation filter around every KernelFunction. |
Yes: a filter that does not call next stops the function |
possible, not built | Filters |
| AutoGen | Reported to be in maintenance mode, with Microsoft Agent Framework as the successor. From secondary sources; unverified. | see Agent Framework | Repository | |
| Google ADK | before_tool_callback and after_tool_callback. |
Yes: returning a dict from before_tool_callback skips the tool (per Google Cloud's copy of the ADK reference) |
possible, not built | Callback types |
| Pydantic AI | before_tool_execute, tool_execute (wrap), after_tool_execute, tool_execute_error. |
Yes: SkipToolExecution; ApprovalRequired defers to a human |
possible, not built | Hooks |
| smolagents (Hugging Face) | step_callbacks, run at the end of each step, after the action executed. |
No: it runs after the action | possible, not built | Agents reference |
| LlamaIndex | AgentWorkflow streams ToolCall and ToolCallResult events. The instrumentation dispatcher takes event handlers. |
Not established | possible, not built | Streaming |
| Agno | tool_hooks (middleware around each call) and pre_hook / post_hook on @tool. |
Yes: a tool hook can raise or return its own result instead of calling the tool | possible, not built | Tool hooks |
| Mastra | onStepFinish exposes tool calls and results per step. Tracing records tool spans. A per-call hook was not found. |
Not established | possible, not built | Tracing |
| Vercel AI SDK | A tool's execute is your function, so a wrapper can record and refuse. AI SDK 6 added needsApproval. From secondary sources; unverified against ai-sdk.dev. |
Yes, in your own wrapper | possible, not built | AI SDK |
Notes:
- Blocking is not a promise. "Yes" means the framework documents a way for code at that point to stop the tool. Agentmetry's framework adapters are recorders. A blocking adapter would be new work, and a deny that the framework then ignores would repeat the Codex failure.
- Microsoft Agent Governance Toolkit files are a separate, shipped path:
agentmetry import-agtreads aFileAuditSinkJSONL file after the file's own chain verifies, tested intest_agt_adapter.py. It imports a file some other runtime wrote. It does not make Semantic Kernel, Agent Framework, LangGraph or CrewAI supported on their own. - Where the framework runs matters. A LangGraph graph on your server is this category. The same graph on a vendor's hosted platform is category G.
Platforms where you build an agent in a visual editor and run it on your own servers. Capture would be a receiver that maps the platform's events into ingest. Detections apply: record only, mostly. Their tools are usually SaaS API calls (mail, chat, CRM), not endpoint actions.
| Platform | How it could be captured | Status | Source |
|---|---|---|---|
| n8n | Log streaming to a webhook or syslog. Event types include AI node events, among them a tool-called event. Enterprise licence. Whether events carry arguments: unverified. | possible, not built | Log streaming |
| Dify | OpenTelemetry export on self-hosted (ENABLE_OTEL and an OTLP endpoint). Whether each tool call is its own span: unverified. |
possible, not built | Dify |
| Langflow | Tracing through Langfuse, Opik and others. A native tool-call hook was not found. | unverified | Langfuse integration |
| Flowise | Analytics through Langfuse and others. A native tool-call hook was not found. | unverified | Analytics |
agentmetry otel is an OTLP receiver for Claude Code's event shape only. Several platforms here and in category G export OpenTelemetry, so a general OTLP mapping would open several rows at once. That is a design question, not a claim.
A local recorder cannot trace these. Where the vendor keeps its own log, that is the customer's record, not an Agentmetry trail. The last column says whether that log holds tool-level actions or only administrative events, as far as was checked.
| Agent | Vendor's own logs |
|---|---|
| Grok app (grok.com, iOS, Android) | Management API audit logs are administrative. Custom MCP must be a public URL; localhost is rejected. A tool-call log was not found. |
| @bot on X, Grok Bot cloud computer | Work runs on the Bot's cloud computer. Enterprise Action Recording is off by default and exported over OpenTelemetry. Audit logs on that page are control-plane events. Optional local execution has no documented hook. |
| @grok on X | An action log was not found. Unverified. |
| ChatGPT, including ChatGPT agent | Enterprise and Edu: the Compliance Logs Platform. OpenAI's agent article says agent conversations appear in Compliance API logs, but individual actions (virtual computer use, app requests) do not. A consumer export was not found. |
| Claude.ai | Enterprise: the Compliance API returns conversation content and activity events (sign-ins, admin and configuration changes, MCP server configuration). A tool-call log was not found. |
| Gemini app, Perplexity, Manus | Not checked. |
| Agent | Vendor's own logs |
|---|---|
| Microsoft Copilot Studio agents | Microsoft Purview audit: admin activity plus maker and user interactions with agents, also through the Office 365 Management API. Some channels are not logged. Tool-level event names: unverified. |
| Salesforce Agentforce | Session Tracing Data Model in Data 360. The Session Trace OTel API (beta) returns turns, LLM calls and actions per session: one session per request, last 72 hours. |
| Gemini Enterprise | Cloud Audit Logs plus usage audit logs, which identify the agent that handled a request. Tool-level detail: unverified. |
| ServiceNow AI agents | Not checked. |
| Agent | Vendor's own logs |
|---|---|
| Cursor Cloud Agents | Compliance and monitoring: audit logs do not include cloud agent runs. OpenTelemetry Export can deliver cloud agent logs. |
| Codex cloud tasks | Codex policy changes are in the workspace audit log. A tool-call trace was not established. |
| GitHub Copilot cloud agent | Hooks run inside the job's sandbox (reference). Org audit log coverage of those calls: unverified. |
| Devin | Enterprise audit log API (v3 examples). Which session actions it records: unverified. |
| OpenHands Cloud | Hooks load in cloud sessions and run where the session runs, so a recorder on a laptop does not see them. |
Agentmetry records the tool calls agents report through their hooks. Malicious code in a package or an extension usually runs outside any tool call, so most of these attacks are invisible to it. Each row below is written from the incident's primary report and pinned by a synthetic test in apps/orchestrator/tests/test_supply_chain_boundaries.py. None of it has been run against a real compromise.
| Incident | What ran | What Agentmetry would record | What it would not |
|---|---|---|---|
| Nx s1ngularity | An npm postinstall script scanned the machine, attempted to use local AI tools, and uploaded results with the GitHub CLI |
Tool calls of any agent session whose hooks fired. A credential read followed by gh repo create in one session raises dotfile-read-then-git-push |
The install script, its upload, and anything linking a spawned agent to it. Rules run per session, and gh api or gh gist uploads do not match |
| Trojanized Claude Code extension in Cursor | Code ran when the extension module loaded, with no model or tool call | Nothing | All of it. covered in the heartbeat means a hook is configured |
| LiteLLM 1.107.0 | .pth and sitecustomize.py files ran at every Python start |
The python or pip tool call, if an agent made one |
The startup code, its file reads and its network traffic |
| Cline 2.3.0 | A postinstall installed a legitimate, unrelated package |
The npm install call, hashed, so the package name is not stored by default |
The child install. A custom tool policy can deny the call, which is a policy result, not a malware verdict |
The shipped block_agent_cli_weaponization policy matches a tool call that starts an agent CLI. It runs in log mode by default, and an install script's own spawn is not a tool call, so it would not see the Nx case.
- Codex deny failed open. Fixed by #246, shipped in 0.9.5.
- Gemini CLI read as Antigravity. A
~/.geminidirectory made coverage report Antigravity as installed. Fixed: presence is now~/.gemini/antigravityor one of our hook files (Surface.presenceincore/diagnostics/hook_coverage.py). - Unknown agents were labelled
cursor. Anysource_appoutsideKNOWN_EXTERNAL_APPSwas stored ascursor, so an event from a new integration was attributed to the wrong agent. Fixed: it is recorded asunknown, and the claimed name is kept insource.claimed_app(_resolve_source_appincore/audit/external.py). A missingsource_appstill means Cursor, for hooks that predate the field. - Two stale docs.
adapters/trae/README.mdanddocs/integrations/chinese-agents.mdsaid Trae ships no lifecycle hooks, anddocs/agentmetry-external-ingest.mdsaid Codex hooks may miss unified exec and some MCP. Both corrected against the vendors' pages on 2026-10-13.