.agents/memory/2026-02-25-recursive-extraction-loop-prevention-implementatio.md

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:

  1. CLI Hook Guard (packages/cli/src/cli.ts): Added a preAction hook on the hookCmd that exits silently (exit code 0) when the sentinel is set, preventing all hook subcommands from firing in spawned contexts.

  2. Scheduler Spawn (packages/daemon/src/scheduler/spawn.ts): Injects SIGNET_NO_HOOKS: "1" into the child process environment when spawning agents, ensuring spawned processes inherit the sentinel.

  3. Pipeline Provider (packages/daemon/src/pipeline/provider.ts): Adds SIGNET_NO_HOOKS: "1" to the ClaudeCodeProvider's child environment alongside existing CLAUDECODE stripping as belt-and-suspenders defense.

  4. Daemon HTTP Guard (packages/daemon/src/daemon.ts): Added an isInternalCall() helper that checks for x-signet-no-hooks: 1 header, 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.