@rivus/agent-kit/harness/events
readHookEvent, builtinHookDialects, LifecycleEvent — anywhere, no imports
Functions
readHookEvent()
function readHookEvent(
agent: string,
payload: unknown,
env: Readonly<Record<string, string | undefined>>,
options?: ReadHookEventOptions
): LifecycleEvent;Translates one hook payload, synchronously and without IO, so a hook process can load nothing else. The payload
is whatever the agent sent (parsed JSON on stdin, or the event object a plugin forwards), and env is the hook
process's environment. The payload is parsed into a view at this boundary, and every path the dialects read is a
chain of zod schemas, so an unexpected type reads as absent. Host markers choose the source before the
dialect reads the event. An unknown payload shape or event reads as phase
unknown with the event name it carried; it never throws.
Naming an agent without a dialect is a programming error: it throws an AgentKitError with code
capability-unsupported, whatever the payload.
Parameters
agent
string
payload
unknown
env
Readonly<Record<string, string | undefined>>
options?
Returns
Interfaces
HookDialect
One agent's hook facts: the only place they are kept. Hook installation generates registrations from it (event
names, timeout unit, what an observer prints), and readHookEvent reads payloads with it.
Properties
agent
readonly agent: string;delivery
readonly delivery: "command" | "plugin";command: the agent runs a command with the payload as JSON on stdin and reads its exit code and stdout.
plugin: the agent calls an in-process plugin, which forwards each event's object as the payload.
events
readonly events: Readonly<Record<string, HookEventSpec>>;Native event name → its meaning. Events missing here read as phase unknown.
fields
readonly fields: PayloadFields;hostMarkers?
readonly hostMarkers?: HostMarkers;output?
readonly output?: HookOutput;How command hooks' exit codes and stdout are read, unless an event overrides it.
runsHooksOf?
readonly runsHooksOf?: readonly ForeignHooks[];specificationVersion
readonly specificationVersion: "harness-v1";timeout?
readonly timeout?: HookTimeout;Absent for plugin delivery, which has no hook timeout.
trust?
readonly trust?: object;content-hash: each new or changed hook definition waits for the user's review, so a command that embeds a
version asks again after every upgrade. workspace: hooks run once their folder is trusted, with no per-hook
review.
review
readonly review: "content-hash" | "workspace";unverified?
readonly unverified?: string;HookEventSpec
Properties
aliases?
readonly aliases?: readonly string[];Other spellings of this event in payloads, such as Grok's snake_case wire names.
fields?
readonly fields?: Omit<PayloadFields, "event">;Sources that replace the dialect's fields of the same name for this event, for a path that holds the value only
on some events. The event name itself always comes from the dialect's fields.event.
gate?
readonly gate?: true;A permission gate: the hook's response decides whether the operation proceeds.
lifecycle
readonly lifecycle: LifecycleMapping | LifecycleSwitch;Phase unknown only on a gate kept for its response rules, such as Cursor's tab-completion file read.
output?
readonly output?: HookOutput;How this event reads exit codes and stdout, when that differs from the dialect's output.
subagent?
readonly subagent?: true;The event is a subagent's own start or stop.
unverified?
readonly unverified?: string;HookOutput
What the agent does with a command hook's exit code and stdout. block stops the operation the event announces
(a tool call, a prompt, a stop; on an event that cannot block, exit code 2 only reports stderr); proceed lets it
continue; hook-failed lets it continue and records the hook run as failed.
Properties
emptyStdout
readonly emptyStdout: "proceed" | "block" | "undocumented";Exit code 0 with nothing on stdout.
exitCode2
readonly exitCode2: "proceed" | "block" | "undocumented";fields?
readonly fields?: readonly string[];Top-level JSON fields the event accepts on stdout.
invalidStdout
readonly invalidStdout: "proceed" | "block" | "undocumented" | "hook-failed";Exit code 0 with stdout that is not JSON, or JSON the event does not accept.
otherExitCodes
readonly otherExitCodes: "proceed" | "block" | "undocumented" | "hook-failed";passThrough
readonly passThrough: string;What a hook that only observes prints, on every path, so that the operation proceeds unchanged.
plainStdout?
readonly plainStdout?: "context" | "shown";Exit code 0 with plain text on stdout, where the text does more than invalidStdout says: context adds it to
the model's context and shown shows it to the user. An observer must print nothing, or JSON, there.
unverified?
readonly unverified?: string;What the agent's documentation does not confirm: it is silent, or the agent's source behaves differently.
LifecycleEvent
One hook payload translated into orthogonal fields. A field the payload does not carry is absent. subagent is
set when the event describes a subagent, which does not change the main session's state.
Properties
agent
readonly agent: string;The real source after sniffing: Grok and Cursor also run Claude Code's hooks.
blocker?
readonly blocker?: LifecycleBlocker;cwd?
readonly cwd?: string;nativeEvent
readonly nativeEvent: string;The event name as the agent sent it; empty when the payload names none.
outcome?
readonly outcome?: LifecycleOutcome;Only on the end of a turn.
phase
readonly phase: LifecyclePhase;scope?
readonly scope?: LifecycleScope;sessionId?
readonly sessionId?: string;subagent?
readonly subagent?: object;id?
readonly id?: string;type?
readonly type?: string;terminal?
readonly terminal?: TerminalIdentity;tool?
readonly tool?: object;The tool's name and call id, never its arguments.
callId?
readonly callId?: string;name
readonly name: string;transcriptPath?
readonly transcriptPath?: string;turnId?
readonly turnId?: string;Orders events across turns, so late events of an older turn can be dropped.
PayloadFields
Where a payload of this agent carries each value a LifecycleEvent needs.
Properties
cwd?
readonly cwd?: FieldSource;event
readonly event: FieldSource;sessionId?
readonly sessionId?: FieldSource;subagentId?
readonly subagentId?: FieldSource;subagentMarker?
readonly subagentMarker?: FieldSource;A value here marks an event as coming from inside a subagent, not only a subagent's own start and stop.
Defaults to subagentId; a type alone is not enough where the main session can carry one too.
subagentType?
readonly subagentType?: FieldSource;toolCallId?
readonly toolCallId?: FieldSource;toolName?
readonly toolName?: FieldSource;transcriptPath?
readonly transcriptPath?: FieldSource;turnId?
readonly turnId?: FieldSource;ReadHookEventOptions
Properties
providers?
readonly providers?: readonly Provider[];Type Aliases
FieldPath
type FieldPath = readonly string[];Keys from the payload root, such as ["properties", "info", "id"]; an array index is a key too ("0").
Variables
builtinHookDialects
const builtinHookDialects: object;Type Declaration
claude-code
readonly "claude-code": typeof claudeCodeHookDialect;codex
readonly codex: typeof codexHookDialect;cursor
readonly cursor: typeof cursorHookDialect;gemini-cli
readonly "gemini-cli": typeof geminiCliHookDialect;grok
readonly grok: typeof grokHookDialect;opencode
readonly opencode: typeof opencodeHookDialect;pi
readonly pi: typeof piHookDialect;zcode
readonly zcode: typeof zcodeHookDialect;