fix: run Claude summarization tool-less so it can't hijack an active session#108
Open
minyek wants to merge 1 commit into
Open
fix: run Claude summarization tool-less so it can't hijack an active session#108minyek wants to merge 1 commit into
minyek wants to merge 1 commit into
Conversation
…k an active session Background summarization resumes a Claude session and asks it for a <summary>, but buildSummarizerQueryOptions() set no tool restriction, so the resumed session ran with full default tool access. When the session was still mid-task, the model kept EXECUTING the original task instead of summarizing — running mvn/git, editing files, committing work-in-progress, and dropping scratch files into the working tree. It recurred every sync cycle. Restrict the query to be tool-less with tools: [], which per the Agent SDK Options docs disables every built-in tool, so a resumed session has no tool to invoke and can only emit text — the Claude-side equivalent of the read-only sandbox the Codex summarizer path already uses. permissionMode: 'plan' is deliberately avoided because it makes the model emit a plan, polluting the <summary>. Also make test/show.test.ts's timestamp assertion locale/timezone-independent — it now computes the expected string via toLocaleString() the same way show.ts does, instead of a hardcoded US/ISO regex that failed under non-US locales.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Background summarization could hijack an active Claude session and run commands in the user's working tree. To summarize a recent conversation the plugin resumes that Claude session and asks it for a
<summary>— but it did so with full default tool access. When the resumed session was still mid-task, the model inherited the task's momentum and the ability to execute tools, so it kept executing the original task instead of summarizing.Process fingerprint — a second
claudeparented undersync-cli.js, resuming a live session with full permissions:Observed during an active worktree session: the spawned agent committed a work-in-progress refactor on the user's branch with a model-generated message, along with various other tool uses. It recurred every sync cycle (~2–2.5h) and had to be killed each time.
Root cause
buildSummarizerQueryOptions()insrc/summarizer.tsset no tool, permission, or sandbox restriction, so the resumed Claude ran under--permission-mode default(full tool access). Summarization is text-only work, but nothing stopped the model from invokingBash/Edit/Write/Task. This is asymmetric with the Codex summarizer path in the same file, which already forks read-only (sandbox: 'read-only',approvalPolicy: 'never'). The#87reentrancy guard is orthogonal — it stops the recursive sync→summarize→sync cascade but does not restrict tool execution.Fix
Restrict the Claude summarization query to be tool-less — the Claude-side equivalent of the Codex
sandbox: 'read-only'— viatools: []inbuildSummarizerQueryOptions(). Per the Agent SDKOptionsdocs,toolsis the documented way to restrict which tools are available, and[]disables every built-in, so a resumed mid-task session has no tool to invoke and can only emit text.(
allowedToolsis only an auto-approve list, not a restriction, and adisallowedToolsdenylist would be a strict subset of whattools: []already removes — so neither adds protection overtools: [].)Testing
New assertions in
test/summarizer-options.test.tspin the restriction so a future refactor can't silently drop it:tools: []verified on both the resume and fresh-session paths.Also includes a fix to
test/show.test.ts: its timestamp assertion used a hardcoded US/ISO regex and failed under non-US locales; it now computes the expected string viatoLocaleString()the same wayshow.tsdoes, making it locale/timezone-independent.Verification
npx vitest run test/summarizer-options.test.ts test/show.test.ts→ 44 passed.dist/rebuilt fromsrc/and committed alongside it.Scope
This PR implements the must-have tool restriction. A separate, related issue — a session summarized mid-flight has its summary frozen at the partial state and never re-summarized as it grows — is tracked and fixed in a follow-up PR (#109) . The tool restriction alone defangs the runaway; the follow-up closes the frozen-partial gap.