fix: prevent global hooks from firing inside SDK-spawned Claude subprocesses
Discovered during Memoria Phase 4 first compile run: when compile.py
invokes claude_agent_sdk.query(), the spawned `claude` subprocess
inherits the global ~/.claude/settings.json hook config. Its
SessionEnd hook then fires when the subprocess wraps up, triggering
flush.py against today's daily log — polluting the log with compile
metadata and creating a soft recursion (every compile call also
generates a flush call).
flush.py already had this guard (CLAUDE_INVOKED_BY=memory_flush set
at module top before any SDK import). compile.py / query.py / lint.py
did not.
Add the same guard to the other three SDK call sites with
script-specific sentinel values:
- compile.py → memoria_compile
- query.py → memoria_query
- lint.py → memoria_lint
The sentinel value doesn't matter — both session-end.py and
pre-compact.py check `if os.environ.get("CLAUDE_INVOKED_BY"): exit(0)`,
so any non-empty value short-circuits. Using distinct sentinels makes
diagnostics clearer if a hook trace ever shows it.
Verified: imports clean, all 29 acceptance tests still pass.
This commit is contained in:
parent
86c7dc9ded
commit
b57ce15fff
3 changed files with 23 additions and 3 deletions
|
|
@ -13,9 +13,17 @@ Usage:
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Recursion guard — must be set BEFORE claude_agent_sdk imports anything that
|
||||||
|
# spawns a Claude subprocess. Inner SessionEnd / PreCompact hooks check
|
||||||
|
# CLAUDE_INVOKED_BY at startup and exit if set, preventing the global hooks
|
||||||
|
# from triggering flush.py against this process's daily log (which would
|
||||||
|
# pollute the log with compile metadata and could create a recursion loop).
|
||||||
|
os.environ["CLAUDE_INVOKED_BY"] = "memoria_compile"
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,15 @@ Usage:
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Recursion guard — set before any SDK import so global SessionEnd/PreCompact
|
||||||
|
# hooks see CLAUDE_INVOKED_BY in the nested Claude subprocess's env and exit
|
||||||
|
# cleanly. See compile.py for full rationale.
|
||||||
|
os.environ["CLAUDE_INVOKED_BY"] = "memoria_lint"
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from config import KNOWLEDGE_DIR, REPORTS_DIR, now_iso, today_iso
|
from config import KNOWLEDGE_DIR, REPORTS_DIR, now_iso, today_iso
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,15 @@ Usage:
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Recursion guard — see compile.py for rationale. Set before any SDK import
|
||||||
|
# so the global SessionEnd/PreCompact hooks see CLAUDE_INVOKED_BY in the
|
||||||
|
# nested Claude subprocess's env and exit cleanly.
|
||||||
|
os.environ["CLAUDE_INVOKED_BY"] = "memoria_query"
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from config import KNOWLEDGE_DIR, QA_DIR, now_iso
|
from config import KNOWLEDGE_DIR, QA_DIR, now_iso
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue