CLAUDE.md · diff
git:20260902.2801461 to git:20260904.2eb2ea6
4 added, 2 removed. Audit A to A.
<!-- GENERATED by `vodou-core rules render` from templates/rules/ (adapter: hosts/claude-code.md). Edit the source, not this file — `vodou-core rules render --check` fails CI on drift. Target: CLAUDE.md -->
# Vodou - Claude Code Integration
See **`AGENTS.md`** for the full Vodou operating manual: subsystem map (Vodou-Console, Vodou-Board, Vodou-channels, Vodou-Recall, Vodou-Enhanced-Thinking, etc.), Layer 1/2/3 architecture, memory model, scheduler, work logging format, security defaults, and boundaries. It is **not** inlined into your session context (44 KB against a 24 KB budget — it never was, and the bootstrap now says so); read it with your file tool when you need it. This file covers **Claude Code-specific integration and the shared project policy**.
## Scope of this file
**This file applies to Claude Code** — the developer CLI running in a user's terminal/IDE alongside their code. It does **not** apply to the Claude CLI subprocess that the gateway spawns to answer web-chat messages. That subprocess follows `AGENTS.md` §6.5 (mid-turn shell-outs allowed, 3 per turn cap, supervised path). If you are the gateway-chat LLM, read this file as context but defer to AGENTS.md §6.5 for tool-execution behavior.
## Tool Priority — Vodou Always Wins
**STRICT ORDER. Never deviate.**
1. **Vodou Skills** (Layer 1) — if a skill is returned, follow it completely
2. **Vodou intent_mappings** — before touching ANY other tool, check if Vodou has it:
```bash
sqlite3 vodou-core.db "SELECT keyword, server_name, tool_name FROM intent_mappings WHERE keyword LIKE '%X%' LIMIT 5;"
```
If a match exists → `./vodou-core call <server> <tool> '<args>'`. Done.
3. **Vodou MCP servers directly** — `./vodou-core call <server> <tool>` for known servers (gmail, zapier, slack, etc.)
4. **Cloud connector tools** (`mcp__claude_ai_*` and the like) — **LAST RESORT ONLY.** Only when Vodou has zero coverage. Vodou ALWAYS has priority.
If the prompt hook surfaces a `### Vodou Intent Match` block, **use that route immediately** — no deliberation needed.
**Exception:** a hint ending `(matched inside prose, not auto-run)` means a registered keyword happened to appear in a sentence — e.g. "screenshot" in *"tell me what to do for each screenshot"*. That is **not** a request to call the tool. Hints marked `(side-effecting: not auto-run)` are the same judgement with higher stakes. The daemon's own router may still fire the tool independently; the hint only says *this hook* did not.
**No double-fire rule:** when `active_context` already contains `### Vodou Tool Results (auto-routed)` with a completed result, **do NOT call the tool again**. Present what is there. Re-executing causes duplicate side effects (double emails, duplicate records).
## Skills Are Layer 1 — They Always Come First
When Vodou routes a query to a skill, the skill takes absolute priority. You are its **executor**, not a substitute. Canonical rules and the full stopping-point checklist live in `AGENTS.md` under "Skills Are Layer 1". Short version:
- If a skill is returned, **follow it** — don't answer the question yourself.
- If skill output contains `STOPPING POINT`, `Reply with the number`, `Reply with 1-`, or `Display to user`: display the intro + full numbered menu verbatim, then **STOP**. Wait for the user's choice. Never assume.
- If a skill calls MCP tools, **use those tool calls** — don't substitute your own knowledge.
- Execute steps in order, never skip or combine.
## Agent Instructions & AGENT_ACTIONS
Skills can embed executable tool sequences as `<!-- AGENT_ACTIONS_N: {...} -->` HTML comments. Full spec (template variables, `loop`, `capture`, `stream_progress`) lives in `AGENTS.md` §6. Short form:
1. **Vodou-Console web chat**: the gateway's workflow driver handles execution automatically — you just format results.
2. **Any coding agent (this file)**: parse the AGENT_ACTIONS JSON and execute each step via `./vodou-core call <server> <tool> '<args>'`.
If Vodou output contains `## Agent instructions` (human-readable) or `AGENT_ACTIONS:` (inline JSON), execute those steps before replying. If `.vodou/workspace/agent_next_steps.json` exists at turn start, run those actions, then respond.
### MCP Tool Calls Are Mandatory — Never Fake Data
When AGENT_ACTIONS or a skill says to call MCP tools, you MUST execute ALL of them via `./vodou-core call <server> <tool>` BEFORE responding. Never substitute LLM knowledge for live data. Users need real numbers, not approximations.
## Running Vodou from a coding agent
**The right primitive is `./vodou-core call <server> <tool> '<json-args>'`** — deterministic, single-spawn, no subprocess tree, returns clean JSON. Use this for every tool execution you would otherwise reach for brain/do.
`./do "<text>"`, `./oi`, `./vodou` and `./vodou-core brain "..."` DO work headlessly (no TTY gate triggers in current code, verified 2026-05-15), but **they spawn the full BrainLoader subprocess tree**, and in rapid loops have historically built up to 100s of orphan processes requiring a reboot (the 425-process incident). So:
- ✅ One-shot brain/do calls are fine.
- ❌ Don't loop them, don't poll them, don't use them inside retry logic.
- ❌ Don't run `--version` to check the binary — read `Cargo.toml` `[package].version` instead.
- ❌ Don't poke the worker from here — ask the user to run it interactively.
- For a question *about* a command (not a request to run it): just answer.
If the user types `do "<text>"` expecting the launcher: for a known tool, `./vodou-core call` — same effect, no spawn hazard; for an ambiguous query needing BrainLoader routing, one `./do` is fine. Three or more in a turn: stop and use targeted `vodou-core call`.
(The `AGENTS.md` §6.5 mid-turn shell-out guidance with its 3-call cap is for the LLM running *inside the gateway chat* — a different, supervised process. Same shape of rule, applied here in spirit.)
## Helper scripts you should know about
- `./do "<query>"` — primary entry point for any task.
- `./vodou-core call <server> <tool> '<json-args>'` — direct MCP tool call, headless.
- `./vodou-core mem search "<query>" [--top-k N] [--json]` — hybrid FTS5+vector search over `memory.db` via the daemon socket (same pipeline BrainLoader uses). Use this instead of raw `sqlite3 memory.db "... MATCH ..."` — raw FTS5 skips the reranker and scope boost. Distinct from Vodou-Recall (which searches chat turns).
- `./vodou-core builds` — which build is which: engine binary, console dist, every extension folder, plus what the daemon and worker are actually running. Run it when a fix "didn't work" before assuming the code is wrong.
- `./vodou-core flows` — is the product still telling itself the truth? Four flows graded from LIVE evidence. `--json` for CI, exit 2 on a red row. A grader with no evidence answers **`unknown`, never `ok`**.
- `./vodou-core hosts` — which host adapters have real evidence of working, graded from `gateway.db` rows (not a rotating log — that was the bug).
- `scripts/broken-lab.sh` — break Vodou on purpose in an isolated instance and see what every surface says. Use it before claiming what a user "would see" in a failure.
- `./vodou-core intent-signal "<prompt>"` — what the keyword router would do with a prompt, and why. `--file <path>` for a distribution.
- `./vodou-core mem hygiene [--examples]` — do stored facts stand alone for a stranger? A ranking number, not a tidiness one.
- `./vodou-core rules render [--check]` — regenerate this file and its siblings from `templates/rules/`. **This file is generated; edit the source.**
- `./open-gateway.sh` — re-open the web UI without restarting services.
- `./start-vodou-services.sh` / `./stop-vodou-services.sh` — boot / tear down daemon + worker + console. `VODOU_NO_OPEN_BROWSER=1` suppresses the browser.
## Committing from parallel sessions
Multiple agent sessions work in this ONE worktree concurrently. Two incidents on 2026-07-04: a commit swept another session's edited `src/main.rs` (with a `mod` pointing at a not-yet-committed file — HEAD didn't compile from a fresh checkout), and a hot file was rewritten under a session mid-edit. Rules:
1. **Stage explicit paths only.** Never `git add -A`, `git add -u`, or `git add .` — you WILL sweep another session's in-flight work.
2. **Before staging a shared hot file** (`src/main.rs`, `src/daemon.rs`, `MCP-servers/Vodou-Console/src/llm.ts`, `MCP-servers/Vodou-Console/src/index.ts`, `vodou-hook/src/main.rs`), run `git diff <file>` and look for hunks you didn't author. If you find any, stage only your hunks, and say so in the commit message.
3. **If the prompt context shows `### Live peers on your files`**, another session is editing the same files right now. That block is computed from real session state, not guessed — treat it as the reason rule 2 exists.
4. **A `pre-commit` guard blocks self-inconsistent commits** (staged `mod foo;` / relative TS import whose target file isn't in the index). Source: `scripts/commit-guard.py`; bypass only for genuine emergencies with `VODOU_SKIP_COMMIT_GUARD=1`.
5. **A `secret-guard` blocks staging a credential VALUE** (`scripts/secret-guard.py`). It scans `git diff --cached` added lines against `.build/release-pii-patterns.txt`. Bypass `VODOU_SKIP_SECRET_GUARD=1`, but prefer fixing the string: if it is a test fixture, make it not key-shaped; if it was ever real, revoke it.
6. **A `date-guard` blocks staged lines that violate the time canon** (`scripts/date-guard.py`; canon: `PLANS/PLAN-TIME-CANON.md`). SQLite instants are naive UTC `YYYY-MM-DD HH:MM:SS`; day identity is the LOCAL day; display parses naive-as-UTC, renders local. Bypass a true false-positive with `VODOU_SKIP_DATE_GUARD=1`.
7. **A `coherence-guard` blocks the seam-audit's enforceable rules** (`scripts/coherence-guard.py`): a raw `scope`/enum reaching `textContent`/`innerHTML` (translate via `scopeLabel()`); a displayed `*_count` nothing writes; an iframe of our own surface with no declared min-width. When deliberate, say so in the diff — `// COHERENCE-INTENTIONAL: <why>`.
8. **New module + its declaration commit together.** If you add `mod x;` or an import of a new file, that file goes in the SAME commit.
9. **A `rules-guard` blocks a generated rules file that is out of step with its source** (`scripts/rules-guard.py`). `CLAUDE.md`, `.cursorrules` and `.cursor/rules/vodou-policy.mdc` are generated from `templates/rules/` by `./vodou-core rules render`; edit the source, render, stage both. Bypass `VODOU_SKIP_RULES_GUARD=1`.
10. **An `entrypoint-guard` blocks an executable script that starts a long-lived process and belongs to no stack** (`scripts/entrypoint-guard.py`; registry: `stacks.toml`, PLAN-SEAMS P4 / lane canon rule 3). It is deliberately **not** a grep for `nohup` — four of the thirteen occurrences in this tree are prose (an echo, a docstring, two comments), and a guard that fires on documentation is one people learn to bypass. Module code inside an already-declared process is governed by `processes.toml` instead. `scripts/entrypoint-guard.py --audit` grades the whole tree; `scripts/test-entrypoint-guard.sh` proves it fires in both directions. Bypass `VODOU_SKIP_ENTRYPOINT_GUARD=1`, but prefer adding the file to a stack's `entrypoints`.
- If `.git/hooks/pre-commit` is ever missing, reinstall ALL SIX guards — `.git/hooks/` is not versioned, so a fresh clone has none, and reinstalling only the first silently drops the others:
+ 11. **An `env-example-guard` blocks a generated `.env.example` that disagrees with its manifest** (`scripts/env-example-guard.py`). `.env.example` is generated from `scripts/env.example.manifest.json` by `scripts/sync-env-example.mjs`, the same generated-from-source shape `rules-guard` covers for `CLAUDE.md` — and it had drifted on every value anyone checked: re-running the generator would have uncommented `WEB_PORT` (defeating auto-port-assignment), commented out `ORT_DYLIB_PATH` (turning semantic memory off for everyone AND breaking the packer's three per-platform `sed`s, which anchor on `^ORT_DYLIB_PATH=`), and re-enabled the compact schedule PLAN-DYNAMIC-MEMORY-MD deliberately turned off. Compares key STATE (active-vs-commented and value), not rendered prose, so reflowing a description cannot fail a commit. Bypass `VODOU_SKIP_ENV_EXAMPLE_GUARD=1`; prefer fixing whichever side is wrong — usually the manifest, because `.env.example` is what ships and gets fixed by hand.
+
+ If `.git/hooks/pre-commit` is ever missing, reinstall ALL SEVEN guards — `.git/hooks/` is not versioned, so a fresh clone has none, and reinstalling only the first silently drops the others:
```sh
- printf '#!/bin/sh\nROOT="$(git rev-parse --show-toplevel)"\npython3 "$ROOT/scripts/commit-guard.py" && python3 "$ROOT/scripts/secret-guard.py" && python3 "$ROOT/scripts/date-guard.py" && python3 "$ROOT/scripts/coherence-guard.py" && python3 "$ROOT/scripts/rules-guard.py" && python3 "$ROOT/scripts/entrypoint-guard.py"\n' > .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit
+ printf '#!/bin/sh\nROOT="$(git rev-parse --show-toplevel)"\npython3 "$ROOT/scripts/commit-guard.py" && python3 "$ROOT/scripts/secret-guard.py" && python3 "$ROOT/scripts/date-guard.py" && python3 "$ROOT/scripts/coherence-guard.py" && python3 "$ROOT/scripts/rules-guard.py" && python3 "$ROOT/scripts/entrypoint-guard.py" && python3 "$ROOT/scripts/env-example-guard.py"\n' > .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit
```
## MCP server dependencies — never npm-install by package name
Servers under `MCP-servers/` ship prebuilt `node_modules/`. Some deps are **vendored, not on npm**: `@vodou/*` packages (e.g. `@vodou/channel-sdk`) are `file:` links into a `packages/` dir inside the same server — a registry 404 for them is expected, not evidence they're lost. Never run `npm install <package-name>` inside an `MCP-servers/*` dir; naming a package forces a registry lookup and npm can prune the vendored link while failing. To repair `ERR_MODULE_NOT_FOUND`: a **plain** `npm install` (no name) in that server's directory. Full rules: `AGENTS.md` §Troubleshooting.
## Lane canon (parallel processes, ports, injectors)
Two plans found the same disease in different organs — five-then-seven context injectors nobody counted, and a second web process nobody restarted for seven weeks. The rule, once:
1. **Two lanes → one identity + one arbiter, never deletion.** A second lane that was locally correct stays. What gets added is a shared identity and one place that decides who pays. Deleting the lane amputates the surface that needed it.
2. **Precedence is one rule, everywhere: process env > `.env` > gateway setting.** A script that reads `.env` after the environment (so `FLAG=0 ./script` cannot override an `.env` line) is a bug, not a convention.
3. **No new port, process, or prompt-injection site without a registry entry.** Start, stop and the updater must all know a process; an injection site declares a lane name, a budget and a trust label.
4. **Cross-store identity is resolved through the owner, not by opening its DB.** memory.db has ids; gateway.db has names and settings; vodou-core.db has turn receipts. Ask the owner; don't open a second handle and cache the answer.
5. **Ephemeral output is not a fact.** Tool measurements (`[RUN]` notes, CPU numbers) may be logged and shown, but are not extracted as facts, not fed to the contradiction detector, and not injected as memory on a later turn.
## Work Logging
Log at end of every coding session. Full format, categories, and metadata keys: `AGENTS.md` §"Enhanced Work Logging".
```bash
./do "log: category: description | key: value"
```
## Auto-memory
Four memory types: **user** (preferences, role), **feedback** (rules with Why + How to apply), **project** (in-flight work), **reference** (external system pointers). Daily incremental logs: `memory/YYYY-MM-DD.md`. Extraction runs every prompt via the prompt hook.
**Don't save** code patterns, git history, ephemeral task state, or anything already in `AGENTS.md`. `MEMORY.md` is **rendered from memory.db** each session — edits to the rendered file are overwritten; pin a memory instead (`vodou-core mem pin`).
## Claude Code Hooks
Hooks use `vodou-hook-bin` — a zero-thread, ~400KB binary that talks to the daemon via Unix socket; never opens the DB directly.
- **SessionStart**: `./vodou-hook-bin startup` (TTY) or `./vodou-hook-bin cursor-session` (JSON `{"additional_context":"…"}` for IDE hooks). Returns the workspace bootstrap, ending with a `### context budget` line that names anything evicted.
- **UserPromptSubmit**: `./vodou-hook-bin sock prompt` — sends prompt to daemon for memory search, falls back to buffering if daemon is down.
- **SessionEnd**: `./vodou-hook-bin sock flush` — triggers full session memory extraction via daemon.
## Claude Code Memory (auto-memory)
Project-local memory path: `.claude/projects/<project-hash>/memory/MEMORY.md`. MEMORY.md is dual-injected: once via Vodou workspace bootstrap (AGENTS.md context), once via Claude Code's own auto-memory system — that's intentional. See the system prompt's `# auto memory` block for the full rules.