Claude Code hook comparison
AlphaCRO’s plugin system was designed alongside a Claude Code compatibility
layer (@alphacro/agent-claude-code-compat) that loads .claude-plugin/
directories and maps their hooks into AlphaCRO’s typed hook framework.
This page compares both hook surfaces side-by-side so you can understand which hooks port directly, which are AlphaCRO-only additions, and which Claude Code events have no current equivalent.
Architecture difference
Section titled “Architecture difference”Claude Code hooks are configured via JSON (hooks.json or
settings.json). Each hook is a shell command, HTTP endpoint, MCP tool
call, LLM prompt, or agent that receives JSON on stdin and optionally
returns a JSON decision on stdout. Hooks are file-based and external to
the process.
AlphaCRO hooks are TypeScript functions registered via defineHook()
inside a Plugin. They run in-process, receive typed inputs, and return
typed decisions. The compatibility adapter bridges the two: it discovers
Claude Code plugin hooks on disk, wraps each shell/HTTP/MCP handler in a
typed AlphaCRO hook, and registers them through the standard plugin
composition pipeline.
Hook mapping table
Section titled “Hook mapping table”The table below shows every hook event from both systems. The “Mapping”
column shows how the compatibility adapter (CLAUDE_HOOK_EVENT_TO_ALPHACRO
in packages/agent-claude-code-compat/src/hooks.ts) bridges them.
Shared hooks (direct 1:1 mapping)
Section titled “Shared hooks (direct 1:1 mapping)”These hooks exist in both systems and map directly through the compat adapter.
| Claude Code event | AlphaCRO hook | Fires when |
|---|---|---|
SessionStart | SessionStart | Session begins or resumes |
SessionEnd | SessionEnd | Session terminates |
UserPromptSubmit | UserPromptSubmit | User sends a message, before processing |
PreToolUse | PreToolUse | Before a tool call executes (can block) |
PostToolUse | PostToolUse | After a tool call succeeds |
SubagentStart | SubagentStart | Sub-agent spawned |
SubagentStop | SubagentStop | Sub-agent finished |
Notification | Notification | Notification emitted |
PreCompact | PreCompact | Before context compaction |
Stop | Stop | Agent finishes responding |
StopFailure | Stop | Turn ends due to API error (mapped to Stop) |
AlphaCRO-only hooks
Section titled “AlphaCRO-only hooks”These hooks have no Claude Code equivalent. They exist because AlphaCRO’s plugin system runs in-process and can intercept the model pipeline at points that external shell hooks cannot reach.
| AlphaCRO hook | Category | Purpose |
|---|---|---|
BeforeTurn | Lifecycle | Fires before each model step in the agentic loop. Lets plugins prepare state or inject context per-iteration. |
DecorateToolSchema | Registry | Transforms the tool schema array before the model sees it. Used by planning to inject task_ids into every non-planning tool’s input schema. |
DecorateSystemPrompt | Registry | Appends SystemPromptFragment[] to the system prompt per-turn. Used by planning to surface the active task list. |
DecoratePromptMessages | Prompt | Rewrites the fully-assembled LanguageModelV3Prompt after buildPrompt and before model.doStream. Used by skills to redact superseded load_skill bodies. |
PostToolUseFailure | Per-tool | Fires after a tool call fails (distinct from PostToolUse which fires on success). |
PostToolBatch | Per-tool | Fires after a full batch of parallel tool calls resolves, before the next model call. |
OnEvent | Misc | Fires on every event appended to the domain event log. General-purpose telemetry/audit hook. |
Claude Code-only events (no AlphaCRO equivalent)
Section titled “Claude Code-only events (no AlphaCRO equivalent)”These Claude Code events are parsed by the compatibility adapter but
surfaced on the unmapped list rather than being forwarded to an
AlphaCRO hook. Hosts can implement bespoke listeners for them or warn
the user that they’re unsupported.
| Claude Code event | Category | Purpose |
|---|---|---|
Setup | Lifecycle | Fires with --init-only or --init/--maintenance in -p mode. One-time CI/script preparation. |
UserPromptExpansion | Prompt | When a user-typed command expands into a prompt. Can block the expansion. |
PermissionRequest | Permission | When a permission dialog appears. |
PermissionDenied | Permission | When a tool call is denied by the auto-mode classifier. Can request retry. |
MessageDisplay | Display | While assistant message text is displayed. |
TaskCreated | Tasks | When a task is created via TaskCreate. |
TaskCompleted | Tasks | When a task is marked as completed. |
TeammateIdle | Multi-agent | When an agent team teammate is about to go idle. |
InstructionsLoaded | Config | When a CLAUDE.md or .claude/rules/*.md file is loaded into context. |
ConfigChange | Config | When a configuration file changes during a session. |
CwdChanged | Filesystem | When the working directory changes (e.g. cd command). |
FileChanged | Filesystem | When a watched file changes on disk. |
WorktreeCreate | Git | When a git worktree is being created. |
WorktreeRemove | Git | When a git worktree is being removed. |
PostCompact | Lifecycle | After context compaction completes. |
Elicitation | MCP | When an MCP server requests user input during a tool call. |
ElicitationResult | MCP | After a user responds to an MCP elicitation. |
Key design differences
Section titled “Key design differences”Hook handler types
Section titled “Hook handler types”| Claude Code | AlphaCRO | |
|---|---|---|
| Shell command | Primary mechanism (type: "command") | Via compat adapter only |
| HTTP endpoint | Supported (type: "http") | Via compat adapter only |
| MCP tool | Supported (type: "mcp_tool") | Via compat adapter only |
| LLM prompt | Supported (type: "prompt") | Via compat adapter only |
| Agent | Supported (type: "agent") | Via compat adapter only |
| In-process function | Not available | Primary mechanism (defineHook()) |
Hook matching and filtering
Section titled “Hook matching and filtering”Claude Code uses a matcher string (exact match, regex, or *) and
an optional if condition (tool subcommand pattern) to filter when hooks
fire. Matchers are evaluated per-event-type against different fields
(tool name, notification type, file path, etc.).
AlphaCRO uses the matcher field on defineHook() which accepts a
RegExp or exact string matched against tool names. Priority-based
ordering (priority number) controls execution order across plugins,
with higher values running first.
Hook decisions
Section titled “Hook decisions”Both systems support hooks that return decisions (allow/deny/block), but the mechanism differs:
Claude Code: hooks return JSON on stdout with a hookSpecificOutput
object containing event-specific fields like permissionDecision,
updatedInput, additionalContext, etc. Exit code 2 blocks the action.
AlphaCRO: hooks return typed decision objects directly from the
handler function. For example, PreToolUse returns
{ decision: "allow" | "deny" | "ask" | "defer", updatedInput?, reason? }.
Permission model
Section titled “Permission model”Claude Code has dedicated PermissionRequest and PermissionDenied
events, plus a permissionDecision field on PreToolUse. The permission
flow is: classifier → PermissionRequest hook → user dialog.
AlphaCRO folds permissions into the Plugin.permissions() contribution
and the PreToolUse hook. The evaluation order is:
disallowedTools → allowedTools → canUseTool() → permissionMode default.
There is no separate permission dialog event — the decision is made
entirely within the hook pipeline.
Prompt decoration
Section titled “Prompt decoration”This is where AlphaCRO’s in-process model diverges most from Claude Code:
DecorateToolSchemacan add, remove, or transform tool input schemas before the model sees them (e.g. injectingtask_idsfields).DecorateSystemPromptcan append structured fragments to the system prompt per-turn.DecoratePromptMessagescan rewrite the entire assembled prompt (e.g. redacting superseded skill bodies to save context).
Claude Code has no equivalent — external hooks cannot intercept the
prompt assembly pipeline. The closest mechanism is SessionStart with a
compact matcher to re-inject context after compaction, but this is
coarser-grained and cannot transform existing content.
Compat adapter: how Claude Code plugins load in AlphaCRO
Section titled “Compat adapter: how Claude Code plugins load in AlphaCRO”The @alphacro/agent-claude-code-compat package bridges the two systems:
-
Discovery —
discoverPluginAt()walks a plugin directory and parsesplugin.json,hooks/hooks.json,skills/*/SKILL.md,commands/*.md,agents/*.md,.mcp.json, and.lsp.json. -
Loading —
loadClaudeCodePlugin()converts the discovered plugin into an AlphaCROPluginobject:- Each
commands/*.mdandskills/*/SKILL.mdbecomes aSlashCommandDefinition. - Each
agents/*.mdbecomes aSubagentDefinition. - Each hook group in
hooks.jsonis mapped throughCLAUDE_HOOK_EVENT_TO_ALPHACROand wrapped in adefineHook()call that executes the original shell command/HTTP/MCP handler. - MCP and LSP configs are surfaced on the
discoveredmetadata but not auto-launched.
- Each
-
Composition — the resulting
Pluginis passed tocomposePlugins()alongside native AlphaCRO plugins. Hook ordering, tool registry merging, and conflict detection work identically.
import { loadClaudeCodePluginsFrom } from "@alphacro/agent-claude-code-compat";
const ccPlugins = await loadClaudeCodePluginsFrom(pluginDirs, { runHookCommand, handleCommand,});
composePlugins({ plugins: [...nativePlugins, ...ccPlugins],});See the Claude Code compatibility reference for the full adapter API.