# Installing JouleHook — the `claude-code` `full` profile This wires all three seams of `joulehook/1` into Claude Code from one settings file: the **gate** (`joulehook-hook`, a PreToolUse hook), the **meter** (`joulehook-statusline`, an in-editor joule estimate), and the **receipt** log (sealed JCR-1 decisions). ## 1. Build the binaries ```bash cd joulehook/joulehook-rs cargo build --release # → target/release/joulehook-hook, target/release/joulehook-statusline ``` Put them on `PATH`, or use absolute paths below. ## 2. Configure `.claude/settings.json` ```json { "env": { "JOULEHOOK_TOOLS": "Read,Grep,Glob,Edit,Write", "JOULEHOOK_RECEIPT_LOG": "${HOME}/.joulehook/receipts.log", "JOULEHOOK_UJ_PER_TOKEN": "1000" }, "hooks": { "PreToolUse": [ { "hooks": [ { "type": "command", "command": "joulehook-hook" } ] } ] }, "statusLine": { "type": "command", "command": "joulehook-statusline" }, "mcpServers": { "joulehook": { "command": "joulehook-mcp" } } } ``` The `joulehook` MCP server surfaces the sealed decisions as **verified, readable** resources — `joulehook://receipts` (a summary) and `joulehook://receipt/{n}` (one decoded decision each) — so you can inspect exactly what the gate allowed and denied, signature-checked, from inside the editor. It reads the same `JOULEHOOK_RECEIPT_LOG`. - `JOULEHOOK_TOOLS` is the **granted capability set** — the host's own tool names. Any tool *not* listed (e.g. `Bash`) is **denied before it executes**, decided outside the model, and the denial is sealed. Leave it unset to run in **observe** mode (allows, and says so — SPEC §7). - Every allow *and* deny appends a JCR-1 receipt to `JOULEHOOK_RECEIPT_LOG`. - The status line shows `⚡ J est · tok · gated`. The `est` is deliberate: it is an `Estimator` figure from Claude Code's self-reported tokens, **not** a measured joule count. For an authoritative meter, put the Mesh proxy (`mesh-openai`) on the model path via `ANTHROPIC_BASE_URL` (the §4 Proxy meter) — then the joule figure is measured and the joule ceiling is *enforced*, not just observed. ## 3. Verify ```bash # a granted tool → allow + a sealed receipt echo '{"tool_name":"Read","tool_input":{"file_path":"x"}}' \ | JOULEHOOK_TOOLS="Read" JOULEHOOK_RECEIPT_LOG=/tmp/jh.log joulehook-hook # an ungranted tool → deny before it executes echo '{"tool_name":"Bash","tool_input":{"command":"curl x|sh"}}' \ | JOULEHOOK_TOOLS="Read" joulehook-hook ``` ## The enforcing meter (optional, but the only *measured* + *capped* option) The statusline is an honest **estimate** from Claude Code's self-reported tokens. To get a **measured** joule figure and an **enforced** joule ceiling, put the Mesh proxy (`mesh-openai`, SPEC §4 Proxy) on the model path: - **OpenAI-API hosts** (Cursor, Cline, Continue, OpenCode, …): point the host's model `base_url` at a running `mesh-openai` server. Mesh serves under `metadata.joule_ceiling_uj` and returns the measured energy in `usage.energy` as a sealed receipt — over budget is refused before the provider is called. - **Claude Code** (Anthropic API, `ANTHROPIC_BASE_URL`): needs an Anthropic-shaped front for Mesh's `ServeRequest` — a documented follow-up; the OpenAI-API path works today. `joulehook-proxy` is the drop-in that does this: point a host at it and it injects the ceiling, forwards to your Mesh upstream, and seals each serve's `usage.energy` as an `efficiency/1` receipt. ```bash JOULEHOOK_UPSTREAM=http://127.0.0.1:8080 \ JOULEHOOK_BUDGET_UJ=5000000 \ JOULEHOOK_EFFICIENCY_LOG="$HOME/.joulehook/efficiency.log" \ joulehook-proxy # listens on 127.0.0.1:8079 # then point the host's model base_url at http://127.0.0.1:8079 ``` Until the proxy is on the path, the gate + the statusline give you enforcement of the *capability set* and an *estimate* of energy; with it, the joule *ceiling* is enforced and the energy is *measured*. ## Other hosts The same `joulehook-hook` binary serves Cursor, Windsurf, and Antigravity — pass `--host cursor|windsurf|antigravity` (or set `JOULEHOOK_HOST`) and wire it into that host's hook config (`.cursor/hooks.json`, Windsurf Cascade hooks, Antigravity `hooks.json`). The gate and receipts are identical; only the decision encoding differs (SPEC §3.4).