Skip to content

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.

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.

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.

These hooks exist in both systems and map directly through the compat adapter.

Claude Code eventAlphaCRO hookFires when
SessionStartSessionStartSession begins or resumes
SessionEndSessionEndSession terminates
UserPromptSubmitUserPromptSubmitUser sends a message, before processing
PreToolUsePreToolUseBefore a tool call executes (can block)
PostToolUsePostToolUseAfter a tool call succeeds
SubagentStartSubagentStartSub-agent spawned
SubagentStopSubagentStopSub-agent finished
NotificationNotificationNotification emitted
PreCompactPreCompactBefore context compaction
StopStopAgent finishes responding
StopFailureStopTurn ends due to API error (mapped to Stop)

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 hookCategoryPurpose
BeforeTurnLifecycleFires before each model step in the agentic loop. Lets plugins prepare state or inject context per-iteration.
DecorateToolSchemaRegistryTransforms the tool schema array before the model sees it. Used by planning to inject task_ids into every non-planning tool’s input schema.
DecorateSystemPromptRegistryAppends SystemPromptFragment[] to the system prompt per-turn. Used by planning to surface the active task list.
DecoratePromptMessagesPromptRewrites the fully-assembled LanguageModelV3Prompt after buildPrompt and before model.doStream. Used by skills to redact superseded load_skill bodies.
PostToolUseFailurePer-toolFires after a tool call fails (distinct from PostToolUse which fires on success).
PostToolBatchPer-toolFires after a full batch of parallel tool calls resolves, before the next model call.
OnEventMiscFires 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 eventCategoryPurpose
SetupLifecycleFires with --init-only or --init/--maintenance in -p mode. One-time CI/script preparation.
UserPromptExpansionPromptWhen a user-typed command expands into a prompt. Can block the expansion.
PermissionRequestPermissionWhen a permission dialog appears.
PermissionDeniedPermissionWhen a tool call is denied by the auto-mode classifier. Can request retry.
MessageDisplayDisplayWhile assistant message text is displayed.
TaskCreatedTasksWhen a task is created via TaskCreate.
TaskCompletedTasksWhen a task is marked as completed.
TeammateIdleMulti-agentWhen an agent team teammate is about to go idle.
InstructionsLoadedConfigWhen a CLAUDE.md or .claude/rules/*.md file is loaded into context.
ConfigChangeConfigWhen a configuration file changes during a session.
CwdChangedFilesystemWhen the working directory changes (e.g. cd command).
FileChangedFilesystemWhen a watched file changes on disk.
WorktreeCreateGitWhen a git worktree is being created.
WorktreeRemoveGitWhen a git worktree is being removed.
PostCompactLifecycleAfter context compaction completes.
ElicitationMCPWhen an MCP server requests user input during a tool call.
ElicitationResultMCPAfter a user responds to an MCP elicitation.
Claude CodeAlphaCRO
Shell commandPrimary mechanism (type: "command")Via compat adapter only
HTTP endpointSupported (type: "http")Via compat adapter only
MCP toolSupported (type: "mcp_tool")Via compat adapter only
LLM promptSupported (type: "prompt")Via compat adapter only
AgentSupported (type: "agent")Via compat adapter only
In-process functionNot availablePrimary mechanism (defineHook())

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.

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? }.

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: disallowedToolsallowedToolscanUseTool()permissionMode default. There is no separate permission dialog event — the decision is made entirely within the hook pipeline.

This is where AlphaCRO’s in-process model diverges most from Claude Code:

  • DecorateToolSchema can add, remove, or transform tool input schemas before the model sees them (e.g. injecting task_ids fields).
  • DecorateSystemPrompt can append structured fragments to the system prompt per-turn.
  • DecoratePromptMessages can 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:

  1. DiscoverydiscoverPluginAt() walks a plugin directory and parses plugin.json, hooks/hooks.json, skills/*/SKILL.md, commands/*.md, agents/*.md, .mcp.json, and .lsp.json.

  2. LoadingloadClaudeCodePlugin() converts the discovered plugin into an AlphaCRO Plugin object:

    • Each commands/*.md and skills/*/SKILL.md becomes a SlashCommandDefinition.
    • Each agents/*.md becomes a SubagentDefinition.
    • Each hook group in hooks.json is mapped through CLAUDE_HOOK_EVENT_TO_ALPHACRO and wrapped in a defineHook() call that executes the original shell command/HTTP/MCP handler.
    • MCP and LSP configs are surfaced on the discovered metadata but not auto-launched.
  3. Composition — the resulting Plugin is passed to composePlugins() 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.