hooklane
v0.1.0
Published
Composable hook pipelines for coding agents
Maintainers
Readme
Hooklane
Hooklane is a small JavaScript runtime for composing deterministic hook pipelines for coding agents.
The host decides the event and matcher. A Hooklane entry only describes execution:
native hook -> Hooklane entry -> series / parallel -> one native resultStatus
This repository is a tested prototype. It currently provides:
entry(),series(), andparallel()- ordinary async functions as pipeline steps
- sequential context propagation
- parallel snapshot isolation and deterministic result joining
- explicit conflicts when parallel branches rewrite the same input field
- short-circuiting on
deny,block, orcontinue: false - Codex and Claude Code input/output adapters
- a
hooklane runcommand
It intentionally does not install or edit host configuration yet.
Requirements
- Node.js 20 or newer
The runtime has no production dependencies.
Installation
npm install --global hooklaneFor library usage inside a project:
npm install hooklaneEntry DSL
import { entry, parallel, series } from "hooklane";
import validate from "./validate.mjs";
import audit from "./audit.mjs";
import metrics from "./metrics.mjs";
import finalize from "./finalize.mjs";
export default entry(
series(
validate,
parallel(audit, metrics),
finalize,
),
);An entry does not declare an event or matcher. Those come from the native hook configuration that launches it.
Step functions
A step is an ordinary async function:
export default async function validate(context) {
const command = context.current.toolInput.command;
if (/\brm\s+-rf\b/.test(command)) {
return {
decision: "deny",
reason: "Destructive command detected.",
};
}
return {
updatedInput: {
...context.current.toolInput,
command: command.trim(),
},
};
}Step names come from named JavaScript functions. A later step can read earlier results:
export default async function finalize(context) {
const audit = context.results.audit;
const metrics = context.results.metrics;
return {
additionalContext: [
`Audit: ${audit.status}`,
`Metrics: ${metrics.status}`,
],
};
}Context behavior
In series(a, b, c), each step observes the current state produced by all previous steps.
In parallel(b, c), both branches receive the same snapshot. They cannot see each other's in-flight changes. After both finish, their results are joined and made available to the next step.
If two parallel branches return different values for the same updatedInput field, execution fails instead of choosing one nondeterministically.
Canonical result
Steps return a platform-neutral partial result:
{
decision: "allow" | "ask" | "block" | "deny",
reason: "...",
updatedInput: {},
additionalContext: "..." | ["..."],
systemMessage: "...",
continue: true | false,
stopReason: "...",
data: {}
}data is stored in context.results.<step>.data for later steps but is never sent to the host.
The selected host adapter converts the merged canonical result into the event-specific native result.
Codex
Configure one command hook in .codex/hooks.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "hooklane run --host codex ./hooks/security.entry.mjs",
"timeout": 30
}
]
}
]
}
}Codex launches the command and writes the event JSON to stdin. Hooklane runs the entry and writes one native result JSON to stdout.
Claude Code
The equivalent command is:
{
"type": "command",
"command": "hooklane run --host claude-code ./hooks/security.entry.mjs"
}Place it under the desired event and matcher in the relevant Claude Code hook configuration.
CLI
hooklane run --host <codex|claude-code> <entry.mjs>--host is explicit because Codex and Claude Code event payloads are intentionally similar and should not be guessed.
All diagnostic messages go to stderr. Stdout is reserved for the single native JSON result.
Run the example
npm run example:codex
npm run example:claudeTest
npm testThe test suite covers context propagation, parallel joining, input conflicts, short-circuiting, adapter encoding, and full CLI stdin/stdout execution.
Next implementation steps
- host configuration installer and uninstaller
- timeout and error policies for individual steps
- command and HTTP step helpers
- native output escape hatch
- additional event codecs and compatibility fixtures
- prompt, agent, and MCP-backed steps
