Platform capability matrix
This page states exactly what AgentBoot can and cannot do on each platform, because a governance claim that's true on one platform and assumed on the others isn't a governance claim.
Officially supported (enforcement-grade): the CLI surfaces of Claude Code, OpenAI Codex CLI, and GitHub Copilot CLI. On these three, AgentBoot emits blocking compliance hooks from one canonical set of portable hook scripts, kept in lock-step.
Officially supported output (advisory-enforcement): the universal AGENTS.md
standard β the industry-standard cross-tool instruction file. AgentBoot generates and
maintains it as a first-class, officially supported output. Support tier is not
enforcement tier: AGENTS.md is advisory by nature (the standard has no hook
mechanism), so it never carries blocking enforcement β that remains a Claude Code /
Codex / Copilot capability.
Community tier (advisory): Cursor, Windsurf, Gemini, JetBrains, and
agentskills.io SKILL.md output. AgentBoot emits native
instruction files for these, and drift detection still covers the files β but
AgentBoot does not emit enforcement hooks for them, so nothing enforces the
content. (Several of these tools β Cursor, Windsurf, Gemini β do have hook surfaces
of their own; AgentBoot just doesn't bind them today.) Guidance an agent can ignore
is not a control.
The matrixβ
| Capability | Claude Code | OpenAI Codex CLI | GitHub Copilot CLI | Community tier |
|---|---|---|---|---|
| Compiled instructions (personas, traits, gotchas β native config) | β
CLAUDE.md, skills, settings.json | β
AGENTS.md, .agents/skills/ | β
copilot-instructions.md, path-scoped .instructions.md, agents | β
Native files emitted (Cursor rules, Gemini, JetBrains, SKILL.md) β advisory only. The universal AGENTS.md file is an officially supported output (not community tier), but its enforcement class is the same: advisory |
| Blocking pre-tool-use / lifecycle hooks | β
Full hook lifecycle (PreToolUse, PostToolUse, Stop, β¦), blocking on exit code 2, via .claude/settings.json | β
Blocking on exit code 2, via .codex/hooks.json β hooks require a trust review unless deployed as managed; tool coverage is partial (shell/patch/MCP, not WebSearch); SessionEnd unsupported | β οΈ Blocking on exit code 2, via .github/hooks/agentboot.json β lower ceiling: fewer hook types; command-hook timeouts fail open (a slow hook does not block); exit-2 blocking is documented but not yet empirically verified for GA | β AgentBoot emits no enforcement here β instructions only. (Cursor/Windsurf/Gemini have hook surfaces of their own; AgentBoot does not bind them today.) |
| Drift detection | β Content-hash manifest comparison flags any managed file that's been modified | β Same mechanism | β Same mechanism | β Same mechanism β the files are still drift-checked, but nothing enforces their content |
| Managed settings (non-overridable) | β
managed-settings.json β MDM-deployable; overrides user and project settings | β No native non-overridable settings layer. HARD guardrails are protected at build time (a lower scope cannot silently disable one) and ride in the emitted hooks/config | β Same as Codex | β Not available |
| MCP | β
.mcp.json compiled and synced, with an approved-server allowlist filter | β
.codex/config.toml emitted with the AgentBoot MCP server entry ([mcp_servers.agentboot]) automatically | β οΈ No MCP config emitted for Copilot β point it at the AgentBoot MCP server manually | β οΈ Varies by tool; manual setup |
Enforcement classificationβ
Every security-relevant control above falls into exactly one of these classes per platform β when evaluating AgentBoot as a control, use the class, not the feature name:
| Class | Meaning | Where it applies |
|---|---|---|
| Hard-enforced | The platform mechanically blocks the action; a developer cannot override it locally | Claude Code managed settings via MDM; Claude Code blocking hooks |
| Enforced, known bypasses | Blocks in the normal path, but a documented gap exists | Codex hooks (partial tool coverage, trust-review requirement); Copilot exit-2 blocking (not yet empirically GA-verified) |
| Fail-open | Enforces when healthy; a failure/timeout allows the action | Copilot command-hook timeouts; any hook if its runtime dependency (node) is missing |
| Advisory | The agent receives the policy as instructions; nothing enforces it | Entire community tier; the officially supported AGENTS.md output; output-scan in default (warn) mode |
| Unsupported | The control does not exist on the platform | Managed settings outside Claude Code; MCP allowlisting outside compiled configs |
Prompt instructions are not a security boundary. An instruction saying "never do
X" is behavior shaping; prompt injection or simple non-compliance can bypass it. Hard
controls live outside the prompt: hooks, managed settings, platform permissions, and
your organization's own perimeter (network egress, DLP, branch protection).
agentboot doctor prints an Enforcement section that applies this classification
to your actual config: if you have hard org policy configured and an output platform
can only receive it as advisory instructions, doctor says so.
Reading the matrix honestlyβ
- Drift detection detects; it does not prevent. A content-hash mismatch tells
you a synced repo has modified managed files β visibly, in
/abstatus andlist_repos. It does not stop the modification from happening. What AgentBoot gives you is drift you can see, not drift that cannot occur. - Copilot's ceiling is real and stated on purpose. Its hooks block on exit code 2 like the other two, but it exposes fewer hook types, its command-hook timeouts fail open (a slow hook does not block), and exit-2 blocking is documented but not yet empirically verified for GA. If your control depends on a specific lifecycle event, verify it exists on your target platform before you rely on it.
- Codex hooks aren't zero-config. They require a trust review unless deployed as managed, and cover shell/patch/MCP calls (not WebSearch) β confirm the tool call you want to gate is in scope.
- Support is scoped to the CLI surface β for now. Official support covers each tool's command-line surface. The IDE and editor extensions of these same tools, and additional platforms, are on the roadmap β not shipped today. If your team lives primarily in an IDE extension, plan around the CLI surface for the enforcement levels above.
- Enforcement lives on the agent surface, not around it. Blocking hooks bind the three official CLI surfaces. They do not constrain a developer who uninstalls the tooling or works outside it β pair them with your normal repo-level controls (branch protections, CI, review).
- Sync PRs touch only agent-config files, so they're safe to auto-merge β under your own branch protections. AgentBoot never asks you to weaken them.
If a cell says advisory, treat it as advisory.
Tested, not just documented:
agentboot conformanceexecutes the compiled hook scripts per platform and writesdist/<platform>/enforcement-manifest.jsonrecording declared level vs observed behavior. The classification in this matrix is the same single source of truth the harness tests anddoctorreports.
Capability Γ platform β which platforms EMIT a capability at allβ
The table above is about enforcement strength. This one is about a prior and different question: does the platform receive a mechanism for the capability at all? A capability nobody emits is not weakly enforced β it is absent.
The source of truth is CAPABILITY_SUPPORT in scripts/lib/conformance.ts. Every row
was verified by building a hub with the capability configured and inspecting dist/,
and each carries a warrant (file:line of the emitter) so a reviewer can check the
row against the code. The build fails when a configured capability's platform set does
not intersect personas.outputFormats.
| Capability | claude | codex | copilot | plugin | cursor | gemini | windsurf | jetbrains | agents | skill |
|---|---|---|---|---|---|---|---|---|---|---|
claude.hooks (org-authored) | β | β | β | β | β | β | β | β | β | β |
claude.permissions (allow + deny) | β | β | β | β | β | β | β | β | β | β |
claude.mcpServers | β | β | β | β | β | β | β | β | β | β |
claude.settings pass-through | β | β | β | β | β | β | β | β | β | β |
mcp.enforceApproved filtering | β | β | β | β | β | β | β | β | β | β |
ab.modelOverrides | β | β | β | β | β | β | β | β | β | β |
managed.guardrails.disableBypassPermissions | β | β | β | β | β | β | β | β | β | β |
compliance.inputScan.scannerCommand | β | β | β | β | β | β | β | β | β | β |
compliance.outputScan.blocking | β | β | β | β | β | β | β | β | β | β |
managed.guardrails.denyTools | β | β | β | β | β | β | β | β | β | β |
managed.guardrails.requireAuditLog | β | β | β | β | β | β | β | β | β | β |
managed.guardrails.forcePlugins | β | β | β | β | β | β | β | β | β | β |
instructions[].applyTo (narrowing) | β | β | β | β | β | β | β | β | β | β |
gotchas[].paths | β | β | β | β | β | β | β | β | β | β |
managed.guardrails.forcePlugins has an empty row on purpose. It is typed,
documented, accepted β and read by no code path on any platform. Setting it fails the
build, because that is the only honest thing a governance product can do with a knob
wired to nothing.
plugin carries the generated compliance hooks, not claude.hooks. Both were
verified by building and grepping dist/; the distinction matters and is easy to
assume wrongly.
Instruction path scoping (applyTo) β native, translated, or unsupportedβ
applyTo is a third axis: not "how strongly is it enforced" and not "is it emitted at
all", but "did the target receive the scope the operator actually wrote".
| Platform | Support | Mechanism |
|---|---|---|
| copilot | native | applyTo: is a first-class Copilot instruction key |
| cursor | translated | globs: + alwaysApply: false in the .mdc frontmatter |
| windsurf | translated | trigger: glob + globs: in .windsurf/rules/ |
| jetbrains | translated | globs: in .aiassistant/rules/ |
| claude | unsupported | rules/ files are @-imported unconditionally from CLAUDE.md |
| skill | unsupported | SKILL.md instruction files have no scoping key |
| plugin | unsupported | plugin rules/ load with the plugin, unscoped |
| agents Β· codex | unsupported | text is inlined into AGENTS.md, which is always-on |
| gemini | unsupported | text is inlined into GEMINI.md, which is always-on |
On the unsupported tier a narrow rule is necessarily delivered always-on β which is the
opposite of what the operator wrote, not merely a weaker version of it. That inversion
fails the build unless the artifact carries scope-unsupported: acknowledged, and an
acknowledged artifact ships with a Scope: preamble in its body so the agent is told which
paths the rule is for. A universal applyTo: "**" is always-on by definition and never
triggers anything.
The translated tier produces no diagnostic at all: nothing was lost, so there is nothing to say.