Under the hood
Hooks
How voodoo knows what Claude Code is doing without reading its screen, and without writing anything into your project.
Working out what an agent is doing by reading English text off its screen misreads. Claude Code runs a hook at each turn of its work, so voodoo asks it instead.
How it is wired
The daemon starts Claude Code with --settings, pointing at one settings file it keeps in its own home. In that file every hook is a curl to a receiver on the loopback interface. Those reports drive a small state machine, and nothing polls.
- Nothing is written into your project. No
.claude/settings.local.jsonto merge into, nothing to clean up, nothing forgit statusto notice. - A hook runs inside the agent’s turn, so it gives the daemon three seconds and then gives up. It never fails, and it is inert outside a session voodoo started.
- The receiver’s replies are always empty, because Claude Code reads whatever a prompt hook prints into the model’s context.
What the hooks don’t say
- Granting a permission fires no hook. The tool it was for finishing is the first sign you said yes.
- Cancelling a turn fires no stop. The agent reporting itself idle is the only sign the turn is over.
- A stop is held while subagents are still reported running, with ninety seconds’ grace so one that never reports back can’t hold a turn open forever.
Inside a session
| Variable | What it is |
|---|---|
| LU_SESSION_ID | Which session the process is. Set inside every session. |
| LU_HOOK_URL | Where an agent’s hooks report to. A port the system picks, new on every start of the daemon. |
| LU_HOOK_TOKEN | What the hooks prove themselves with. New on every start of the daemon. |
More on the receiver under security.