Hooks
Hooks are the secret sauce: they let PLUR run without the agent ever calling a tool. The agent walks into a conversation with relevant engrams already in context; it walks out with new engrams already captured. No prompt nudging, no manual saves.
Different runtimes have different hook surfaces. Here’s what PLUR uses in each.
Claude Code
Section titled “Claude Code”Installed by npx @plur-ai/mcp init or plur init. Writes to ~/.claude/settings.json (global) or .claude/settings.json (project).
| Claude Code event | PLUR action |
|---|---|
SessionStart | Call plur_session_start with task description. Inject top-N engrams into the system prompt. |
UserPromptSubmit | Scan the user message for correction patterns. Stage candidate engrams. |
Stop | Call plur_session_end. Write the episode, promote stable candidates. |
The hook binary itself is ~/.plur/bin/plur-claude-hook, installed by plur init. To inspect what’s in settings.json:
cat ~/.claude/settings.json | jq '.hooks'Expected shape:
{ "hooks": { "SessionStart": [{ "type": "command", "command": "~/.plur/bin/plur-claude-hook session-start" }], "UserPromptSubmit": [{ "type": "command", "command": "~/.plur/bin/plur-claude-hook prompt" }], "Stop": [{ "type": "command", "command": "~/.plur/bin/plur-claude-hook session-end" }] }}Project-level scoping
Section titled “Project-level scoping”When .plur.yaml is present in the project root, hooks read it on session start and tag every engram captured during that session with the configured scope and domain. Without .plur.yaml, engrams default to scope: global.
Disabling a hook
Section titled “Disabling a hook”Remove the line from settings.json. To re-enable later, re-run plur init. The hook is idempotent — it won’t duplicate entries.
Cursor (v0.13.0, experimental)
Section titled “Cursor (v0.13.0, experimental)”Installed by plur init --cursor (auto-detected when a .cursor/ directory exists in the project). Writes .cursor/mcp.json (with the reduced PLUR_TOOL_PROFILE=cursor tool profile), .cursor/hooks.json, and a static .cursor/rules/plur-memory.mdc rule.
| Cursor event | Handler | PLUR action |
|---|---|---|
sessionStart | plur hook-cursor-session-start | Inject recalled engrams for the new conversation (BM25-only, deliberately — the hook must beat a cold-start embedder load). Writes the session sentinel. |
preToolUse | plur hook-cursor-guard | Session guard — deny tool calls until plur_session_start has run. Mainly covers background/cloud agents, where sessionStart never fires. |
postToolUse | plur hook-cursor-post-tool | Mark the sentinel when plur_session_start was called; on a 10-minute cadence, write a plur_learn reminder. |
stop | plur hook-cursor-stop | Every 3rd completed stop, auto-submit a follow-up nudge to record learnings via plur_learn. |
All four hooks are registered with failClosed: false — a hook failure never blocks Cursor.
One Cursor-specific quirk: Cursor’s hook-output additional_context field is dropped by a confirmed race condition (acknowledged by Cursor’s team, no fix ETA), so PLUR delivers recalled memory and reminders through dynamically rewritten rules files (.cursor/rules/plur-context.mdc, .cursor/rules/plur-reminder.mdc) instead of hook output. plur init --cursor gitignores both, since they can contain recalled engram content. plur doctor diagnoses the Cursor wiring, including whether the workspace is loading the reduced tool profile.
OpenClaw
Section titled “OpenClaw”@plur-ai/claw implements seven hooks via OpenClaw’s ContextEngine plugin slot:
| Hook | PLUR action |
|---|---|
bootstrap | Open the local engram store; warm the index. |
ingest | Scan incoming content for correction patterns; stage candidates. |
assemble (required) | Inject relevant engrams into the assembled system prompt. |
compact (required) | Prioritise pinned/locked engrams when context fills; spill the rest. |
afterTurn | Capture the turn as an episode; check for learnings. |
prepareSubagentSpawn | Hand the subagent a scoped engram bundle so it inherits memory. |
onSubagentEnded | Merge subagent learnings back into the parent store. |
Most ContextEngine plugins implement only assemble and compact and miss the loop. PLUR’s claw plugin implements all seven — that’s what makes the integration “deep”. See OpenClaw adapter.
Hermes (Python)
Section titled “Hermes (Python)”Three lifecycle hooks pick up automatically once plur-hermes is installed:
| Hermes hook | PLUR action |
|---|---|
pre_llm_call | Inject relevant memories into the upcoming LLM call. |
post_llm_call | Extract corrections, preferences, and insights from the response. |
on_session_end | Write the episode timeline. Promote stable candidates. |
These mirror the OpenClaw triad of assemble / afterTurn / lifecycle-end. See Hermes adapter.
What “automatic capture” actually does
Section titled “What “automatic capture” actually does”The capture step (UserPromptSubmit / ingest / post_llm_call) scans for these patterns by default:
- “no, actually …”
- “from now on …”
- “the way we do X here is …”
- “don’t … instead …”
- “always …” / “never …”
- “correction:” / “clarification:”
Pattern matches stage candidate engrams — not active ones. Candidates need to recur (default 3 times) or be explicitly promoted before they enter the injection pool. This avoids polluting recall with one-off frustrations.
You can customise patterns in ~/.plur/config.yaml:
capture: correction_patterns: - default - "(?i)never\\s+do\\s+" - "(?i)always\\s+prefer\\s+" auto_promote_after: 3What “automatic injection” actually does
Section titled “What “automatic injection” actually does”On session start (or assemble / pre_llm_call), the hook calls plur_inject with:
- The task description (if available — Claude Code passes the first user message).
- The current scope (read from
.plur.yamlor session config). - A budget (default: 12 engrams, ~2 KB of system prompt).
The returned engrams are prepended to the system prompt as a structured block:
## DIRECTIVES[ENG-2026-0325-021] ...
## CONSTRAINTS[ENG-2026-0503-061] ...
## ALSO CONSIDER[ENG-2026-0101-019] ...This is the format every PLUR-aware agent recognises. The same pattern works in Claude Code, OpenClaw, Hermes, and custom adapters.
Debugging hook failures
Section titled “Debugging hook failures”If hooks aren’t firing:
plur doctor # full diagnostictail -f ~/.plur/episodes.yaml # watch for eventsls -la ~/.plur/bin/ # confirm hook binary presentcat ~/.claude/settings.json | jq '.hooks' # confirm registrationIf injection is running but engrams aren’t appearing in context, check the embedder:
plur doctorbge-small-en-v1.5 is the default embedder (~50 MB, 384-dim); the first hybrid call downloads it. Without it, hybrid recall falls back to BM25-only.