Skip to content

Commit f884f92

Browse files
authored
Merge pull request #18 from nickroci/fix/curator-sdk-isolation
fix(daemon): isolate the curator's SDK session (setting_sources=[])
2 parents a6ba413 + 26c5da4 commit f884f92

2 files changed

Lines changed: 37 additions & 0 deletions

File tree

daemon/agent_mem_daemon/typed_agent.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,15 @@ async def run_typed(
278278
max_turns=max_turns,
279279
cwd=str(cwd) if cwd is not None else None,
280280
env=env or {},
281+
# SDK isolation mode: load NO filesystem settings. Without this the SDK
282+
# defaults to loading ~/.claude + project + local settings.json, so the
283+
# curator would inherit the user's permissions, hooks, and project MCP
284+
# servers — none of which a background memory curator should have. With
285+
# ``[]`` it gets ONLY the read-only research tools + submit_result we
286+
# pass explicitly here. Applies to both roles (both go through run_typed).
287+
# Also a second layer against the recursion loop: the user's event-
288+
# appending hooks aren't even loaded into the curator's own session.
289+
setting_sources=[],
281290
)
282291

283292
run = _query or query

daemon/tests/test_typed_agent.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,34 @@ async def fake_query(*, prompt: object, options: object): # noqa: ARG001
144144
assert res.attempts == 1
145145

146146

147+
async def test_run_typed_runs_in_sdk_isolation_mode() -> None:
148+
"""The curator must NOT inherit the user's filesystem settings (permissions,
149+
hooks, project MCP servers). run_typed must pass setting_sources=[] so both
150+
roles get only the research + submit tools handed to them — regression guard
151+
for the isolation property."""
152+
shared: _RunState[Decision] = _RunState()
153+
captured: dict[str, object] = {}
154+
155+
async def fake_query(*, prompt: object, options: object): # noqa: ARG001
156+
captured["options"] = options
157+
evaluate_submission({"n": 1, "label": "x"}, Decision, None, [], shared, 4)
158+
yield _assistant_calling_submit()
159+
yield _result(0.0)
160+
161+
await run_typed(
162+
"p",
163+
Decision,
164+
deps=None,
165+
system_prompt="s",
166+
model="m",
167+
mcp_servers={},
168+
allowed_tools=[],
169+
_query=fake_query,
170+
_state=shared,
171+
)
172+
assert captured["options"].setting_sources == [] # type: ignore[attr-defined]
173+
174+
147175
async def test_run_typed_never_submitted_raises_typed_agent_error() -> None:
148176
shared: _RunState[Decision] = _RunState()
149177

0 commit comments

Comments
 (0)