1# Chapter 8: jevhooks-events/src, thirty-three events and three roles 2 3Claude Code 2.1.287 raises thirty-three kinds of settings-hook event, and 4`HookEvent` in [lib.rs](lib.rs) names every one, spelled exactly as the 5hooks are (`PreToolUse`, `Stop`, `UserPromptSubmit`, ...). The plugin's 6claim is "every Claude Code hook event backed by Jev", and this is where 7that is made concrete: every event has a **role**, and the function that 8gives it one, `HookEvent::role`, has no default case. 9 10| Role | Events | What happens | 11| --- | --- | --- | 12| `Decide` | `PreToolUse`, `Stop` | Sent to the daemon and waited on: the answer changes what happens. | 13| `Observe` | `UserPromptSubmit`, `PostToolUse`, `PostToolUseFailure`, `PermissionDenied`, `SessionEnd` | Sent 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). | 14| `Ignore` | the other twenty-six | Not sent. Nothing is judged on them, or needed for a judgment, yet. | 15 16> **Aside: why "no default case" matters.** In Rust a `match` must cover 17> every variant, or the program does not compile. `role` lists all 18> thirty-three by name, with no `_ =>` catch-all. So the day Claude Code 19> adds a thirty-fourth event and someone adds it to `HookEvent`, the build 20> stops until they say what is done with it. An event cannot slip in as 21> "ignored" because nobody thought about it. 22 23Then two more types for the answer: 24 25- **`Verdict`**: `Allow` (run it without asking), `Ask` (ask the user 26 first, or, for a `Stop`, do not stop yet), `Pass` (no opinion: whatever 27 would have happened without the plugin happens), and `Hold` (not yet: 28 the machine has no room for this command, ask me again; chapter 12 has 29 the waiting room). Lowercase on the wire. 30- **`Decision`**: the daemon's whole answer to a deciding event: the 31 `verdict`, a `line` for the user (what Jev said and how sure it was, or 32 why nothing was asked), `ms` (the daemon's time, Jev included) and 33 `session_usd` (what this session's questions have cost so far). 34 35And two for the other thing the daemon can be asked, which model a prompt 36goes to: 37 38- **`Tier`**: `Haiku`, `Sonnet`, `Opus`, `Fable`, in that order, smallest 39 first. The order is the point: `Tier` is `Ord`, so "the next model up" 40 is a comparison and not a lookup table somebody has to keep. 41- **`ModelChoice`**: the daemon's answer to a submitted prompt: the 42 `tier` Jev chose, the `model` id that tier means on this machine (both 43 absent when the session's own model stands), and the same `line`, `ms` 44 and `session_usd` a `Decision` has. 45 46> **Try it.** `cargo test -p jevhooks-events`. `every_event_is_listed_once` 47> walks `HookEvent::ALL` and checks for thirty-three distinct events; 48> `names_are_the_hook_names` checks that `PreToolUse` travels as 49> `"PreToolUse"` and that `"Stop"` reads back as `Stop`. 50 51## For the people who maintain it 52 53Roles are not the whole routing. The mod narrows them per call (chapter 5410): a tool event for anything but Bash, or for a plainly read-only Bash 55command, is ignored whatever its role says. 56 57### In this folder 58 59| Path | What | 60| --- | --- | 61| [lib.rs](lib.rs) | `HookEvent` and `HookEvent::ALL`, `HookEvent::role`, `Role`, `Verdict`, `Decision`, `Tier`, `ModelChoice`, `socket_path`, and their tests. | 62 63← Previous: [Chapter 7, jevhooks-events/](../) · Up: [jevhooks-events](../) · Next: [Chapter 9, jevhooks-mod/](../../jevhooks-mod/) →