1# Chapter 6: crates, three Rust packages and why there are three 2 3Everything the plugin does that is not plumbing is Rust, in three crates (a 4crate is Rust's package: one `Cargo.toml`, the way an npm package has one 5`package.json`). Each exists because of where it has to run. 6 7- **jevhooks-events** runs everywhere. It is the vocabulary: the hook 8 events, what is done with each, the verdict and the decision. It does no 9 I/O at all, so it compiles both into the mod and into the daemon. 10- **jevhooks-mod** runs inside Claude Code. It is compiled to WebAssembly 11 and then to JavaScript, and decides in well under a millisecond what to 12 do with each event. 13- **jevhooks-daemon** runs as its own process. It is the `jevhooks` binary: 14 the daemon that asks Jev, the per-session MCP server, and the 15 command-line tools that read them. 16 17```mermaid 18flowchart BT 19 events["jevhooks-events<br/>the vocabulary, no I/O"] 20 modc["jevhooks-mod<br/>routing, as JavaScript"] 21 daemon["jevhooks-daemon<br/>the jevhooks binary"] 22 jevcrates["jev-http, jev-protocol<br/>(third-party/jevcrates)"] 23 rmcp["rmcp<br/>(the deizel/rust-sdk fork)"] 24 modc --> events 25 daemon --> events 26 daemon --> jevcrates 27 daemon --> rmcp 28``` 29 30(An arrow means "depends on".) 31 32The point of the split is the line down the middle. The mod and the daemon 33live in different processes and speak JSON over a socket; the only way to 34be sure they agree on what `"PreToolUse"` or `"ask"` means is for both to be 35compiled from the same Rust enum. That enum is in `jevhooks-events`, and 36it is the only thing the two sides share. 37 38> **Aside: the fork everyone trips over.** The root `Cargo.toml` asks for 39> rmcp 3.5.0, the Rust MCP library, and then patches it with a commit on 40> `deizel/rust-sdk`, a private fork. rmcp 3.5.0 refuses every request 41> after the way Claude Code 2.1.287 opens a stdio server (`server/discover`, 42> then `initialize`), so without the patch the MCP server connects and 43> offers no tools. The fork carries one fix on top of the `rmcp-v3.5.0` tag. 44> It is fetched over SSH and is not public yet, and Cargo resolves the 45> whole workspace before building any part of it: without access, even 46> `cargo test -p jevhooks-events`, which does not use rmcp, stops at 47> fetching it. 48 49> **Try it.** With access to the fork, `cargo test` from the repository 50> root runs every crate's tests. None of them needs the network, a Jev 51> key or a daemon: the verdicts are tested on made-up probabilities, and 52> the routing on made-up events. 53 54The chapters that follow take them in the order an event meets them: the 55vocabulary (7 and 8), the routing in the mod (9 and 10), the daemon (11 and 5612). 57 58## For the people who maintain it 59 60All three are version `0.1.0`, edition 2024, `publish = false`, and take 61every dependency's version from the root `Cargo.toml`'s 62`[workspace.dependencies]`. The release profile there (`opt-level = "s"`, 63`lto`, `panic = "abort"`, one codegen unit) applies to the wasm build and 64to the daemon alike. 65 66### In this folder 67 68| Crate | What | 69| --- | --- | 70| [jevhooks-events/](jevhooks-events/) | Chapters 7 and 8: every hook event, its role, the verdict and the decision. Depends on `serde` only. | 71| [jevhooks-mod/](jevhooks-mod/) | Chapters 9 and 10: the routing and the read-only filter, built as a `cdylib` for wasm32 and an `rlib` for native tests. | 72| [jevhooks-daemon/](jevhooks-daemon/) | Chapters 11 and 12: the `jevhooks` binary. | 73 74← Previous: [Chapter 5, tests/](../plugin/tests/) · Up: [jevhooks](../) · Next: [Chapter 7, jevhooks-events/](jevhooks-events/) →