@arnilo/prism-hooks
v0.12.1
Published
Out-of-process hooks.json adapter for Prism: Claude/Codex-compatible declarative hooks compiled onto public extension, middleware, guardrail, instruction, and stop-hook seams.
Maintainers
Readme
@arnilo/prism-hooks
Run a Claude Code / Codex-compatible hooks.json against Prism. The package parses
the declarative config, validates it loudly, and compiles each event onto a public
Prism seam — no Prism internals, no new runtime dependency, @arnilo/prism as the
only peer.
bun add @arnilo/prism @arnilo/prism-hooksimport { activateKernel, createAgent, createExtensionKernel } from "@arnilo/prism";
import { createHooksExtension, hookCommandHash, parseHooksConfig } from "@arnilo/prism-hooks";
const config = parseHooksConfig(await readFile("hooks.json", "utf8"));
const handler = { type: "command", command: "node audit-tool.js" } as const;
const hooks = createHooksExtension(config, {
trusted: { [handler.command]: hookCommandHash(handler) },
});
const kernel = createExtensionKernel();
await kernel.load([hooks]);
const activated = activateKernel(kernel);
const agent = createAgent({
model,
provider,
guardrails: hooks.guardrails, // required for UserPromptSubmit / PreToolUse / PostToolUse
instructionInjectors: activated.instructionInjectors,
stopHooks: activated.stopHooks,
middleware: activated.middleware,
});Event → seam map
| hooks.json event | Prism seam |
| --- | --- |
| SessionStart | session_start middleware → instruction-injector context queue |
| UserPromptSubmit | input guardrail (block) → instruction-injector context queue |
| PreToolUse | tool_call middleware (updatedInput) + tool_input guardrail (deny) |
| PostToolUse | tool_result middleware (context) + tool_output guardrail (deny) |
| Stop | registered stop hook, bounded by RunLimits.maxStopContinuations |
Guardrails and stop hooks are returned/registered as inert contributions: the host
activates them through AgentConfig (or RunOptions), exactly like every other
kernel contribution.
Semantics
commandhandlers spawn with an argv array — the command string is tokenized locally (quotes/escapes only) and never run through a shell;"shell": trueis rejected at parse time.- Exit codes follow Claude/Codex:
0success (JSON stdout parsed),2block with stderr as the reason, anything else a non-blocking error reported ashooks:warning. There is no exit code64in either reference. timeoutis in seconds (default 600); expiry warns and never blocks.- Matchers: literal tokens (with
|/,alternatives) select exactly; anything with metacharacters is an unanchored regex. No$1capture substitution. additionalContextLimitis a token threshold (default 2500,0= unlimited); oversized context spills to<tmpdir>/hook_outputs/and a pointer is injected.async: truehandlers run detached; their context lands at the next assembly.- Trust:
options.trustedmaps a command string to a digest fromhookCommandHash()(SHA-256 over the effective argv). Unlisted or mismatched handlers are skipped with a warning;trusted: "all"is the logged escape hatch.
Full documentation: docs/hooks.md
and docs/middleware-hooks.md.
