Chapter 8: jevhooks-events/src, thirty-three events and three roles

Claude Code 2.1.287 raises thirty-three kinds of settings-hook event, and HookEvent in lib.rs names every one, spelled exactly as the hooks are (PreToolUse, Stop, UserPromptSubmit, ...). The plugin's claim is "every Claude Code hook event backed by Jev", and this is where that is made concrete: every event has a role, and the function that gives it one, HookEvent::role, has no default case.

RoleEventsWhat happens
DecidePreToolUse, StopSent to the daemon and waited on: the answer changes what happens.
ObserveUserPromptSubmit, PostToolUse, PostToolUseFailure, PermissionDenied, SessionEndSent to the daemon without waiting: the daemon needs them to decide (the prompt a turn's end is judged against, what became of a command it judged, a session to forget).
Ignorethe other twenty-sixNot sent. Nothing is judged on them, or needed for a judgment, yet.

Aside: why "no default case" matters. In Rust a match must cover every variant, or the program does not compile. role lists all thirty-three by name, with no _ => catch-all. So the day Claude Code adds a thirty-fourth event and someone adds it to HookEvent, the build stops until they say what is done with it. An event cannot slip in as "ignored" because nobody thought about it.

Then two more types for the answer:

  • Verdict: Allow (run it without asking), Ask (ask the user first, or, for a Stop, do not stop yet), Pass (no opinion: whatever would have happened without the plugin happens). Lowercase on the wire.
  • Decision: the daemon's whole answer to a deciding event: the verdict, a line for the user (what Jev said and how sure it was, or why nothing was asked), ms (the daemon's time, Jev included) and session_usd (what this session's questions have cost so far).

Try it. cargo test -p jevhooks-events. every_event_is_listed_once walks HookEvent::ALL and checks for thirty-three distinct events; names_are_the_hook_names checks that PreToolUse travels as "PreToolUse" and that "Stop" reads back as Stop.

For the people who maintain it

Roles are not the whole routing. The mod narrows them per call (chapter 10): a tool event for anything but Bash, or for a plainly read-only Bash command, is ignored whatever its role says.

In this folder

PathWhat
lib.rsHookEvent and HookEvent::ALL, HookEvent::role, Role, Verdict, Decision, and the two tests.

← Previous: Chapter 7, jevhooks-events/ · Up: jevhooks-events · Next: Chapter 9, jevhooks-mod/ →