Soubi

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

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

On this page