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/) →