1.8 KiB
2026-02-25 Session Notes
Recursive Extraction Loop Prevention Implementation
Nicholai implemented a multi-layer guard mechanism to prevent infinite recursive extraction loops in the Signet daemon scheduler. The scheduler spawns full Claude Code/OpenCode agent sessions that inherit the environment, which fire Signet's session-start/end hooks, triggering summary jobs and memory extraction—creating a potentially infinite, expensive loop.
The solution uses a SIGNET_NO_HOOKS=1 sentinel environment variable checked at four distinct layers:
-
CLI Hook Guard (
packages/cli/src/cli.ts): Added apreActionhook on thehookCmdthat exits silently (exit code 0) when the sentinel is set, preventing all hook subcommands from firing in spawned contexts. -
Scheduler Spawn (
packages/daemon/src/scheduler/spawn.ts): InjectsSIGNET_NO_HOOKS: "1"into the child process environment when spawning agents, ensuring spawned processes inherit the sentinel. -
Pipeline Provider (
packages/daemon/src/pipeline/provider.ts): AddsSIGNET_NO_HOOKS: "1"to the ClaudeCodeProvider's child environment alongside existingCLAUDECODEstripping as belt-and-suspenders defense. -
Daemon HTTP Guard (
packages/daemon/src/daemon.ts): Added anisInternalCall()helper that checks forx-signet-no-hooks: 1header, with early returns on hook routes (/api/hooks/session-start,/api/hooks/user-prompt-submit,/api/hooks/session-end) to guard against direct HTTP API calls bypassing the CLI.
The implementation is non-breaking: normal user sessions are unaffected (env var not set), existing safe code paths remain unchanged, and no schema/API changes are introduced. Verification includes build/typecheck/test validation plus manual testing of the hook suppression behavior and daemon logging.