Capability Map
The source of truth for feature and hook support across every adapter.
packages/soubi/src/core/capabilities.ts records what each harness can represent. Adapters consult this data through core emission helpers, so fallback policy stays declarative instead of being hidden in target-specific branches.
How a feature resolves
Each portable feature is resolved independently for each requested harness:
Feature tier
Declares whether a feature is native, translated, dropped, or a hard requirement.
Hook mapping
Adds native event names, flow control, and supported handler types.
Author override
Lets a plugin make a specific unsupported feature stricter or softer.
Feature capabilities
Every portable feature × harness pair has one fallback tier:
const CLAUDE: HarnessCapabilities = {
features: {
agent: { tier: "support" },
asset: { tier: "support" },
command: { tier: "support" },
hook: { tier: "support" },
instructions: { tier: "support" },
mcp: { note: "Emitted into .mcp.json.", tier: "support" },
skill: { tier: "support" },
tool: {
note: "Generated MCP stdio server in .mcp.json.",
tier: "support",
},
},
harness: "claude",
hooks: {},
};Portable feature kinds are instructions, skill, command, agent, hook, tool, mcp, and asset.
Hook capabilities
Hooks need finer granularity. A hook entry records the harness event name, whether it can block work, and which handler types execute:
PreToolUse: {
flow: "blocking",
handlerTypes: ["command"],
nativeName: "BeforeTool",
tier: "support",
}Observe-only events
Some events run but ignore flow-control fields such as continue and decision. Gemini CLI's pre-compaction and post-stream-chunk hooks can observe work but cannot block it:
PreCompact: {
flow: "observe-only",
handlerTypes: ["command"],
nativeName: "BeforeCompaction",
note: "Observability-only: continue/decision are ignored.",
tier: "degrade",
}Handler-type granularity
Event support is not the same as handler support. Codex CLI runs command handlers but skips prompt and agent handlers. resolveHookTier() degrades the result when the event exists but the selected handler type cannot execute.
Inspect the resolved matrix
capabilityMatrix() returns one row per feature and harness. soubi check uses the same capability data and author overrides when it reports the exact result for a plugin:
npx soubi check . --harness claude,codex,opencodeCheck hook behavior before relying on it
Harness hook APIs change more often than their file formats. Run soubi check
for the exact plugin and targets you plan to ship.