Soubi

Hooks

Run or translate lifecycle behavior across harness event systems.

A hook attaches behavior to a harness lifecycle event. Event names, blocking behavior, and executable handler types vary by target, so Soubi resolves hooks through the capability map before emission.

Define a hook

Add a TypeScript or JavaScript module under hooks/:

hooks/pre-tool-use.ts
import { defineHook } from "soubi";

export default defineHook({
  event: "PreToolUse",
  matcher: "Edit|Write",
  description: "Protect generated and security-sensitive files.",
  handler: {
    type: "command",
    command: "node ./scripts/guard-files.mjs",
  },
});

Hook modules may use .ts, .tsx, .mts, .js, or .mjs.

Choose a handler

Soubi models four handler types:

TypeBehavior
commandRun a shell command
promptAsk the harness model to evaluate instructions
agentDelegate the event to an agent
functionCall generated runtime code where supported

An event can exist on a harness without supporting every handler type. soubi check reports that distinction.

Use portable command paths

Provide platform-specific commands when a hook must run on both Unix and PowerShell:

handler: {
  type: "command",
  command: {
    unix: "./scripts/check.sh",
    powershell: "./scripts/check.ps1",
  },
  async: true,
}

async remains non-blocking only on harnesses with a compatible native feature.

Remap one target

Use a harness override when a target names an equivalent event differently:

harness: {
  codex: { event: "SessionEnd" },
}

Read Capability Map for event-level support and Fallback Tiers for the effect of onUnsupported.

On this page