Skip to content

fix(daemon): isolate the curator's SDK session (setting_sources=[])#18

Merged
nickroci merged 1 commit into
mainfrom
fix/curator-sdk-isolation
May 29, 2026
Merged

fix(daemon): isolate the curator's SDK session (setting_sources=[])#18
nickroci merged 1 commit into
mainfrom
fix/curator-sdk-isolation

Conversation

@nickroci

Copy link
Copy Markdown
Owner

The finding

You asked me to check whether the curator could be running your tasks rather than just curating. Short answer: no — its output schema is memory-verbs-only (no "run command"/"edit file" action), it runs with cwd=~/.agent-mem/knowledge, and empirically it only writes memory entries.

But the check surfaced a real isolation gap: run_typed never set setting_sources, which defaults to None → the SDK loads ~/.claude/settings.json + project + local settings. So the Librarian/Scholar inherited the user's permissions (tool auto-approvals), hooks, and enableAllProjectMcpServers — none of which a background curator should have. It stayed on-task only because its prompt + memory-only output kept it there; nothing enforced the sandbox.

The fix

Set setting_sources=[] (SDK isolation mode) in run_typed. Because both roles funnel through run_typed, this isolates the Librarian and the Scholar in one place — they now get only the read-only research tools + submit_result we pass explicitly, regardless of your global config.

Bonus: a second layer against the recursion loop fixed in #16 — the user's event-appending hooks aren't even loaded into the curator's own session now.

Verification

  • Regression test asserts run_typed builds ClaudeAgentOptions(setting_sources=[]).
  • ruff clean, pyright strict 0 errors, 585 daemon tests / 90.50%.
  • Fails safe: if isolation ever broke the SDK call, the run raises TypedAgentError → batch dropped (visible in the log), never a loop or a paid-API fallback.

Independent of #17 (opus-4-8 config) — disjoint files (typed_agent.py only), merges in any order.

Recommend a quick live check after merge: confirm the first real curator batch still logs parsed_ok=True (i.e. the isolated session still drives the research + submit tools). Happy to run an isolated smoke test against a throwaway library first if you'd prefer.

🤖 Generated with Claude Code

run_typed left setting_sources unset, which defaults to None — and the SDK then
loads the user's ~/.claude + project + local settings.json. So the curator
inherited the user's permissions (tool auto-approvals), hooks, and
enableAllProjectMcpServers — none of which a background memory curator should
have. It only stayed on-task because its prompt + memory-only output schema kept
it there; isolation was not enforced.

Set setting_sources=[] (SDK isolation mode) in run_typed. Both roles funnel
through run_typed, so this isolates the Librarian AND the Scholar in one place:
they now get ONLY the read-only research tools + submit_result passed explicitly
here, regardless of the user's global config. Bonus: a second layer against the
recursion loop — the user's event-appending hooks aren't loaded into the
curator's own session at all.

Regression test asserts run_typed builds options with setting_sources=[].

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@nickroci nickroci merged commit f884f92 into main May 29, 2026
4 checks passed
@nickroci nickroci deleted the fix/curator-sdk-isolation branch May 29, 2026 16:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant