Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/fix-1014-parallel-spawn-warning.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@bradygaster/squad-cli": patch
"@bradygaster/squad-sdk": patch
---

Coordinator template now warns before launching 2+ parallel background agents in a shared worktree: global-scope git operations (stash/clean/restore) from one agent can silently delete another agent's untracked files. Warn-only — worktree mode remains opt-in. The worktree reference no longer claims shared-worktree concurrency is safe when agents touch different files.
11 changes: 11 additions & 0 deletions .github/agents/squad.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,17 @@ When the user gives any task, the Coordinator MUST:
```
5. **Chain follow-ups.** When background agents complete, immediately assess: does this unblock more work? Launch it without waiting for the user to ask.

**Shared-worktree guard.** Before spawning 2+ background agents in one turn, check whether worktree mode is active (see Pre-Spawn: Worktree Setup). If it is NOT, show the user this warning before launching:

```
⚠️ Launching {N} parallel background agents in a shared worktree.
Global-scope git operations (stash, clean, restore) from one agent can
silently delete another agent's untracked files. Enable worktree mode
for per-stream isolation, or accept the risk for this wave.
```

Warn once per session, then proceed — this is a caution, not a gate.

**Example — "Team, build the login page":**
- Turn 1: Spawn {Lead} (architecture), {Frontend} (UI), {Backend} (API), {Tester} (test cases from spec) — ALL background, ALL in one tool call
- Collect results. Scribe merges decisions.
Expand Down
11 changes: 11 additions & 0 deletions .squad-templates/squad.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,17 @@ When the user gives any task, the Coordinator MUST:
```
5. **Chain follow-ups.** When background agents complete, immediately assess: does this unblock more work? Launch it without waiting for the user to ask.

**Shared-worktree guard.** Before spawning 2+ background agents in one turn, check whether worktree mode is active (see Pre-Spawn: Worktree Setup). If it is NOT, show the user this warning before launching:

```
⚠️ Launching {N} parallel background agents in a shared worktree.
Global-scope git operations (stash, clean, restore) from one agent can
silently delete another agent's untracked files. Enable worktree mode
for per-stream isolation, or accept the risk for this wave.
```

Warn once per session, then proceed — this is a caution, not a gate.

**Example — "Team, build the login page":**
- Turn 1: Spawn {Lead} (architecture), {Frontend} (UI), {Backend} (API), {Tester} (test cases from spec) — ALL background, ALL in one tool call
- Collect results. Scribe merges decisions.
Expand Down
2 changes: 1 addition & 1 deletion .squad-templates/worktree-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ When worktree mode is enabled, the coordinator creates dedicated worktrees for i
- Before creating a new worktree, check if one exists for the same issue
- `git worktree list` shows all active worktrees
- If found, reuse it (cd to the path, verify branch is correct, `git pull` to sync)
- Multiple agents can work in the same worktree concurrently if they modify different files
- Multiple agents can work in the same worktree concurrently if they modify different files. Untracked files are still at risk: a global `git stash` / `git clean` from one agent can delete another agent's not-yet-committed files — prefer per-issue worktrees for parallel background work

**Cleanup:**
- After a PR is merged, the worktree should be removed
Expand Down
11 changes: 11 additions & 0 deletions packages/squad-cli/templates/squad.agent.md.template
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,17 @@ When the user gives any task, the Coordinator MUST:
```
5. **Chain follow-ups.** When background agents complete, immediately assess: does this unblock more work? Launch it without waiting for the user to ask.

**Shared-worktree guard.** Before spawning 2+ background agents in one turn, check whether worktree mode is active (see Pre-Spawn: Worktree Setup). If it is NOT, show the user this warning before launching:

```
⚠️ Launching {N} parallel background agents in a shared worktree.
Global-scope git operations (stash, clean, restore) from one agent can
silently delete another agent's untracked files. Enable worktree mode
for per-stream isolation, or accept the risk for this wave.
```

Warn once per session, then proceed — this is a caution, not a gate.

**Example — "Team, build the login page":**
- Turn 1: Spawn {Lead} (architecture), {Frontend} (UI), {Backend} (API), {Tester} (test cases from spec) — ALL background, ALL in one tool call
- Collect results. Scribe merges decisions.
Expand Down
2 changes: 1 addition & 1 deletion packages/squad-cli/templates/worktree-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ When worktree mode is enabled, the coordinator creates dedicated worktrees for i
- Before creating a new worktree, check if one exists for the same issue
- `git worktree list` shows all active worktrees
- If found, reuse it (cd to the path, verify branch is correct, `git pull` to sync)
- Multiple agents can work in the same worktree concurrently if they modify different files
- Multiple agents can work in the same worktree concurrently if they modify different files. Untracked files are still at risk: a global `git stash` / `git clean` from one agent can delete another agent's not-yet-committed files — prefer per-issue worktrees for parallel background work

**Cleanup:**
- After a PR is merged, the worktree should be removed
Expand Down
11 changes: 11 additions & 0 deletions packages/squad-sdk/templates/squad.agent.md.template
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,17 @@ When the user gives any task, the Coordinator MUST:
```
5. **Chain follow-ups.** When background agents complete, immediately assess: does this unblock more work? Launch it without waiting for the user to ask.

**Shared-worktree guard.** Before spawning 2+ background agents in one turn, check whether worktree mode is active (see Pre-Spawn: Worktree Setup). If it is NOT, show the user this warning before launching:

```
⚠️ Launching {N} parallel background agents in a shared worktree.
Global-scope git operations (stash, clean, restore) from one agent can
silently delete another agent's untracked files. Enable worktree mode
for per-stream isolation, or accept the risk for this wave.
```

Warn once per session, then proceed — this is a caution, not a gate.

**Example — "Team, build the login page":**
- Turn 1: Spawn {Lead} (architecture), {Frontend} (UI), {Backend} (API), {Tester} (test cases from spec) — ALL background, ALL in one tool call
- Collect results. Scribe merges decisions.
Expand Down
2 changes: 1 addition & 1 deletion packages/squad-sdk/templates/worktree-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ When worktree mode is enabled, the coordinator creates dedicated worktrees for i
- Before creating a new worktree, check if one exists for the same issue
- `git worktree list` shows all active worktrees
- If found, reuse it (cd to the path, verify branch is correct, `git pull` to sync)
- Multiple agents can work in the same worktree concurrently if they modify different files
- Multiple agents can work in the same worktree concurrently if they modify different files. Untracked files are still at risk: a global `git stash` / `git clean` from one agent can delete another agent's not-yet-committed files — prefer per-issue worktrees for parallel background work

**Cleanup:**
- After a PR is merged, the worktree should be removed
Expand Down
11 changes: 11 additions & 0 deletions templates/squad.agent.md.template
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,17 @@ When the user gives any task, the Coordinator MUST:
```
5. **Chain follow-ups.** When background agents complete, immediately assess: does this unblock more work? Launch it without waiting for the user to ask.

**Shared-worktree guard.** Before spawning 2+ background agents in one turn, check whether worktree mode is active (see Pre-Spawn: Worktree Setup). If it is NOT, show the user this warning before launching:

```
⚠️ Launching {N} parallel background agents in a shared worktree.
Global-scope git operations (stash, clean, restore) from one agent can
silently delete another agent's untracked files. Enable worktree mode
for per-stream isolation, or accept the risk for this wave.
```

Warn once per session, then proceed — this is a caution, not a gate.

**Example — "Team, build the login page":**
- Turn 1: Spawn {Lead} (architecture), {Frontend} (UI), {Backend} (API), {Tester} (test cases from spec) — ALL background, ALL in one tool call
- Collect results. Scribe merges decisions.
Expand Down
2 changes: 1 addition & 1 deletion templates/worktree-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ When worktree mode is enabled, the coordinator creates dedicated worktrees for i
- Before creating a new worktree, check if one exists for the same issue
- `git worktree list` shows all active worktrees
- If found, reuse it (cd to the path, verify branch is correct, `git pull` to sync)
- Multiple agents can work in the same worktree concurrently if they modify different files
- Multiple agents can work in the same worktree concurrently if they modify different files. Untracked files are still at risk: a global `git stash` / `git clean` from one agent can delete another agent's not-yet-committed files — prefer per-issue worktrees for parallel background work

**Cleanup:**
- After a PR is merged, the worktree should be removed
Expand Down
64 changes: 64 additions & 0 deletions test/ci/parallel-spawn-warning.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* CI tests for the shared-worktree spawn warning (#1014).
*
* A real incident showed that parallel background agents on a shared
* worktree can silently lose untracked files to another stream's global
* git operations (stash/clean/restore). The coordinator template must
* warn before launching 2+ background agents without worktree isolation,
* and the worktree reference must not claim shared-worktree concurrency
* is safe for untracked files.
*
* Canonical source: .squad-templates/
*/

import { describe, it, expect } from 'vitest';
import { readFileSync } from 'node:fs';
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';

const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = resolve(__dirname, '../..');

function readTemplate(relPath: string): string {
return readFileSync(resolve(ROOT, relPath), 'utf-8');
}

describe('shared-worktree spawn warning contract (#1014)', () => {
const squadTemplate = readTemplate('.squad-templates/squad.agent.md');
const worktreeReference = readTemplate('.squad-templates/worktree-reference.md');

it('keeps the shared-worktree guard inside the Parallel Fan-Out section', () => {
const fanOut = squadTemplate.slice(
squadTemplate.indexOf('### Parallel Fan-Out'),
squadTemplate.indexOf('### Shared File Architecture'),
);

expect(fanOut).toContain('**Shared-worktree guard.**');
expect(fanOut).toContain('2+ background agents');
expect(fanOut).toContain('Pre-Spawn: Worktree Setup');
expect(fanOut).toContain('untracked files');
expect(fanOut).toContain('a caution, not a gate');
});

it('warns about stash/clean/restore specifically', () => {
expect(squadTemplate).toContain('stash, clean, restore');
});

it('worktree reference no longer claims shared-worktree concurrency is safe for untracked files', () => {
expect(worktreeReference).toContain('Untracked files are still at risk');
});

it('all governed copies of the coordinator template carry the guard', () => {
const copies = [
'.github/agents/squad.agent.md',
'templates/squad.agent.md.template',
'packages/squad-cli/templates/squad.agent.md.template',
'packages/squad-sdk/templates/squad.agent.md.template',
];
for (const copy of copies) {
expect(readTemplate(copy), `${copy} is missing the shared-worktree guard`).toContain(
'**Shared-worktree guard.**',
);
}
});
});