fix: add permissionMode: acceptEdits to worktree agents (#1334)

Worktree agents (gsd-executor, gsd-debugger) prompt for edit permissions
on every new directory they touch, even when the user has "accept edits"
enabled. This is caused by Claude Code's directory-scoped permission
model not propagating to worktree paths.

Setting permissionMode: acceptEdits in the agent frontmatter tells Claude
Code to auto-approve file edits for these agents, bypassing the per-
directory prompts. This is safe because these agents are already granted
Write/Edit in their tools list and are spawned in isolated worktrees.

- Add permissionMode: acceptEdits to gsd-executor.md frontmatter
- Add permissionMode: acceptEdits to gsd-debugger.md frontmatter
- Add regression tests verifying worktree agents have the field
- Add test ensuring all isolation="worktree" spawns are covered

Upstream: anthropics/claude-code#29110, anthropics/claude-code#28041

Fixes #1334

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-03-23 13:47:28 -04:00
parent aaaa8e96fe
commit a6939f135f
4 changed files with 57 additions and 5 deletions

View File

@@ -2,6 +2,7 @@
name: gsd-debugger
description: Investigates bugs using scientific method, manages debug sessions, handles checkpoints. Spawned by /gsd:debug orchestrator.
tools: Read, Write, Edit, Bash, Grep, Glob, WebSearch
permissionMode: acceptEdits
color: orange
# hooks:
# PostToolUse:

View File

@@ -2,6 +2,7 @@
name: gsd-executor
description: Executes GSD plans with atomic commits, deviation handling, checkpoint protocols, and state management. Spawned by execute-phase orchestrator or execute-plan command.
tools: Read, Write, Edit, Bash, Grep, Glob
permissionMode: acceptEdits
color: yellow
# hooks:
# PostToolUse:

View File

@@ -85,10 +85,7 @@ Continue to spawn_agents.
<step name="detect_runtime_capabilities">
Before spawning agents, detect whether the current runtime supports the `Task` tool for subagent delegation.
**Runtimes with Task tool:** Claude Code, Cursor, OpenCode (native subagent support via `Task` or `task`)
**Runtimes WITHOUT Task tool:** Antigravity, Gemini CLI, Codex, and others
**How to detect:** Check if you have access to a `Task` or `task` tool (either casing counts). If you do NOT have a Task/task tool (or only have tools like `browser_subagent` which is for web browsing, NOT code analysis):
**How to detect:** Check if you have access to a `Task` tool (may be capitalized as `Task` or lowercase as `task` depending on runtime). If you do NOT have a `Task`/`task` tool (or only have tools like `browser_subagent` which is for web browsing, NOT code analysis):
→ **Skip `spawn_agents` and `collect_confirmations`** — go directly to `sequential_mapping` instead.
@@ -218,7 +215,7 @@ If any agent failed, note the failure and continue with successful documents.
Continue to verify_output.
</step>
<step name="sequential_mapping" condition="Task/task tool is NOT available (e.g. Antigravity, Gemini CLI, Codex)">
<step name="sequential_mapping" condition="Task tool is NOT available (e.g. Antigravity, Gemini CLI, Codex)">
When the `Task` tool is unavailable, perform codebase mapping sequentially in the current context. This replaces `spawn_agents` and `collect_confirmations`.
**IMPORTANT:** Do NOT use `browser_subagent`, `Explore`, or any browser-based tool. Use only file system tools (Read, Bash, Write, Grep, Glob, list_dir, view_file, grep_search, or equivalent tools available in your runtime).

View File

@@ -339,3 +339,56 @@ describe('DISCUSS: discussion log generation', () => {
);
});
});
// ─── Worktree Permission Mode (#1334) ───────────────────────────────────────
describe('PERM: worktree agents have permissionMode: acceptEdits', () => {
// Agents spawned with isolation="worktree" need permissionMode: acceptEdits
// to avoid per-directory edit permission prompts in the worktree path.
// See: anthropics/claude-code#29110, anthropics/claude-code#28041
const WORKTREE_AGENTS = ['gsd-executor', 'gsd-debugger'];
for (const agent of WORKTREE_AGENTS) {
test(`${agent} has permissionMode: acceptEdits`, () => {
const content = fs.readFileSync(path.join(AGENTS_DIR, agent + '.md'), 'utf-8');
const frontmatter = content.split('---')[1] || '';
assert.ok(
frontmatter.includes('permissionMode: acceptEdits'),
`${agent} must have permissionMode: acceptEdits — worktree agents need this to avoid ` +
`per-directory edit permission prompts (see #1334)`
);
});
}
test('worktree-spawned agents are covered', () => {
// Verify that agents referenced with isolation="worktree" in workflows
// are included in the WORKTREE_AGENTS list above
const dirs = [WORKFLOWS_DIR, COMMANDS_DIR];
const worktreeAgentTypes = new Set();
for (const dir of dirs) {
if (!fs.existsSync(dir)) continue;
const files = fs.readdirSync(dir).filter(f => f.endsWith('.md'));
for (const file of files) {
const content = fs.readFileSync(path.join(dir, file), 'utf-8');
// Find patterns like: subagent_type="gsd-executor" ... isolation="worktree"
// These can span multiple lines in Task() calls
const taskBlocks = content.match(/Task\([^)]*isolation="worktree"[^)]*\)/gs) || [];
for (const block of taskBlocks) {
const typeMatch = block.match(/subagent_type="([^"]+)"/);
if (typeMatch) {
worktreeAgentTypes.add(typeMatch[1]);
}
}
}
}
for (const agentType of worktreeAgentTypes) {
assert.ok(
WORKTREE_AGENTS.includes(agentType),
`${agentType} is spawned with isolation="worktree" but not in WORKTREE_AGENTS list — ` +
`add permissionMode: acceptEdits to its frontmatter and update this test`
);
}
});
});