diff --git a/plugins/project-setup-jj/scripts/jj-workspace-create.sh b/plugins/project-setup-jj/scripts/jj-workspace-create.sh index 45d71a6..54f2085 100755 --- a/plugins/project-setup-jj/scripts/jj-workspace-create.sh +++ b/plugins/project-setup-jj/scripts/jj-workspace-create.sh @@ -9,7 +9,10 @@ input=$(cat) name=$(echo "$input" | jq -r '.name') cwd=$(echo "$input" | jq -r '.cwd') -DIR="$cwd/.claude/workspaces/$name" +# Create workspace OUTSIDE the repo to prevent jj's auto-snapshotting in the +# default workspace from attributing workspace file edits to @. +# Using /tmp ensures the workspace directory is not under the repo root. +DIR="/tmp/jj-workspaces/$(basename "$cwd")/$name" mkdir -p "$(dirname "$DIR")" # Pin workspace to the current working copy's parents (not the working copy itself). diff --git a/plugins/workspace-jj/README.md b/plugins/workspace-jj/README.md index 5eedf10..2427f66 100644 --- a/plugins/workspace-jj/README.md +++ b/plugins/workspace-jj/README.md @@ -8,7 +8,7 @@ Provides the **fan-flames** skill — a parallel task orchestrator that dispatch ## How It Works -- **WorktreeCreate**: Runs `jj workspace add --revision @-` to create an isolated workspace at `.claude/workspaces//`, pinned to the parent revision for independent branching +- **WorktreeCreate**: Runs `jj workspace add --revision @-` to create an isolated workspace at `/tmp/jj-workspaces///`, pinned to the parent revision for independent branching. Workspaces are created outside the repo to prevent jj's auto-snapshotting from attributing workspace edits to the default workspace's `@`. - **WorktreeRemove**: Runs `jj workspace forget` and removes the directory on cleanup Workspaces share the same repository store (lightweight, fast to create) but each gets an independent working copy pinned to the same parent revision. diff --git a/plugins/workspace-jj/commands/fan-flames.md b/plugins/workspace-jj/commands/fan-flames.md index 0941df8..64b07fd 100644 --- a/plugins/workspace-jj/commands/fan-flames.md +++ b/plugins/workspace-jj/commands/fan-flames.md @@ -91,6 +91,22 @@ Wave assignment: **Overlaps detected:** Present wave plan, wait for user confirmation. +### Parallelism Threshold + +After computing waves, calculate the parallelism ratio: tasks in the largest wave / total tasks. If less than 40% of tasks can run in parallel (e.g., 2 of 9 tasks in the largest wave), warn the user: + +``` +⚠️ Low parallelism: only N/M tasks can run in parallel (largest wave: W tasks). +File overlaps make most tasks sequential. The overhead of workspace setup, +spec review, and squash ceremony may exceed the time saved. + +Options: + a) Proceed with fan-flames anyway + b) Switch to single-agent sequential execution (superpowers:executing-plans) +``` + +Wait for user decision. + 5. **Recommend** 3-5 concurrent workspaces per wave. ## Phase 2: FAN OUT 🪭 — Dispatch @@ -156,6 +172,23 @@ Agent tool: **Workspaces remain alive** through the REVIEW phase so fix subagents can be dispatched if spec review fails. +### Workspace Integrity Check + +After collecting results, verify each subagent's changes actually landed in its workspace, not in the default workspace's `@`: + +```bash +# Check if default workspace @ has unexpected changes +jj diff -r @ --stat +``` + +If the default workspace's `@` shows changes that belong to a subagent task, workspace isolation failed (**Pattern C**). Handle by: +1. Report the issue: "Workspace isolation failure — Task N's edits landed in the default workspace instead of its workspace." +2. Skip squash for that task (changes are already in `@`) +3. Verify the content is correct by diffing against the task spec +4. Continue with remaining tasks normally + +This is a known edge case — the WorktreeCreate hook creates the jj workspace, but the agent may resolve file paths to the main repo instead of the workspace copy. + ### Recovery: Missing Change IDs ```bash @@ -166,7 +199,17 @@ jj log -r 'description("Task N: ")' --no-graph -T 'change_id' **Skip this phase if `--skip-spec-review` is set.** Clean up workspaces and proceed to FAN IN. -For each DONE/DONE_WITH_CONCERNS task, dispatch a spec reviewer subagent (read-only, no isolation needed). All reviewers run in parallel. +### Tiered Review + +Not all tasks need a full reviewer agent. Before dispatching, assess each task's complexity: + +**Trivial tasks** (< 10 lines changed, no logic/control flow changes — e.g., visibility modifiers, import reordering, renaming): Verify inline by reading the diff yourself. Report: "Task N: trivial change (N lines), verified inline — PASS." No reviewer agent needed. + +**Non-trivial tasks** (logic changes, new functions, structural modifications): Dispatch a spec reviewer subagent as below. + +### Spec Reviewer Dispatch + +For each non-trivial DONE/DONE_WITH_CONCERNS task, dispatch a spec reviewer subagent (read-only, no isolation needed). All reviewers run in parallel. Read the spec reviewer template at: `plugins/workspace-jj/skills/fan-flames-spec-reviewer.md` @@ -204,7 +247,7 @@ jj log -r 'ancestors(@) & ( | )' --no-graph -T 'change ### Pattern B: Independent branches — squash each into @, smallest diff first: ```bash -jj squash --from --into @ +JJ_EDITOR=true jj squash --from --into @ jj resolve --list # check for conflicts ``` diff --git a/plugins/workspace-jj/scripts/jj-workspace-create.sh b/plugins/workspace-jj/scripts/jj-workspace-create.sh index 45d71a6..54f2085 100755 --- a/plugins/workspace-jj/scripts/jj-workspace-create.sh +++ b/plugins/workspace-jj/scripts/jj-workspace-create.sh @@ -9,7 +9,10 @@ input=$(cat) name=$(echo "$input" | jq -r '.name') cwd=$(echo "$input" | jq -r '.cwd') -DIR="$cwd/.claude/workspaces/$name" +# Create workspace OUTSIDE the repo to prevent jj's auto-snapshotting in the +# default workspace from attributing workspace file edits to @. +# Using /tmp ensures the workspace directory is not under the repo root. +DIR="/tmp/jj-workspaces/$(basename "$cwd")/$name" mkdir -p "$(dirname "$DIR")" # Pin workspace to the current working copy's parents (not the working copy itself). diff --git a/plugins/workspace-jj/skills/fan-flames.md b/plugins/workspace-jj/skills/fan-flames.md index dde0a80..501339e 100644 --- a/plugins/workspace-jj/skills/fan-flames.md +++ b/plugins/workspace-jj/skills/fan-flames.md @@ -126,6 +126,22 @@ Proceed with this wave plan? (or restructure) Wait for user confirmation before proceeding. +### Parallelism Threshold + +After computing waves, calculate the parallelism ratio: tasks in the largest wave / total tasks. If less than 40% of tasks can run in parallel (e.g., 2 of 9 tasks in the largest wave), warn the user: + +``` +⚠️ Low parallelism: only N/M tasks can run in parallel (largest wave: W tasks). +File overlaps make most tasks sequential. The overhead of workspace setup, +spec review, and squash ceremony may exceed the time saved. + +Options: + a) Proceed with fan-flames anyway + b) Switch to single-agent sequential execution (superpowers:executing-plans) +``` + +Wait for user decision. + 5. **Recommend** 3-5 concurrent workspaces per wave for most tasks. Note the recommendation but do not block dispatch if more are requested. ## Phase 2: FAN OUT 🪭 — Create Workspaces and Dispatch @@ -215,6 +231,23 @@ As subagents return, classify each result: Track which tasks succeeded and which failed. **Capture the change ID and workspace directory name from each subagent's report** — change IDs are needed for fan-in squash, workspace names for cleanup. +### Workspace Integrity Check + +After collecting results, verify each subagent's changes actually landed in its workspace, not in the default workspace's `@`: + +```bash +# Check if default workspace @ has unexpected changes +jj diff -r @ --stat +``` + +If the default workspace's `@` shows changes that belong to a subagent task, workspace isolation failed (**Pattern C**). Handle by: +1. Report the issue: "Workspace isolation failure — Task N's edits landed in the default workspace instead of its workspace." +2. Skip squash for that task (changes are already in `@`) +3. Verify the content is correct by diffing against the task spec +4. Continue with remaining tasks normally + +This is a known edge case — the WorktreeCreate hook creates the jj workspace, but the agent may resolve file paths to the main repo instead of the workspace copy. + ### Recovery: Missing Change IDs If a subagent crashes or times out before reporting its change ID, the change still exists in jj's DAG — it's just not referenced. Recover it by searching for the task description: @@ -233,9 +266,17 @@ In v1, workspaces survived COLLECT and were cleaned up during FAN IN (after each Runs once per wave, after COLLECT and before FAN IN. +### Tiered Review + +Not all tasks need a full reviewer agent. Before dispatching, assess each task's complexity: + +**Trivial tasks** (< 10 lines changed, no logic/control flow changes — e.g., visibility modifiers, import reordering, renaming): Verify inline by reading the diff yourself. Report: "Task N: trivial change (N lines), verified inline — PASS." No reviewer agent needed. + +**Non-trivial tasks** (logic changes, new functions, structural modifications): Dispatch a spec reviewer subagent as below. + ### Spec Reviewer Dispatch -For each DONE or DONE_WITH_CONCERNS task, dispatch a spec reviewer subagent. Spec reviewers run in the orchestrator's context (no `isolation: "worktree"`) — they are read-only, using `jj diff -r` and `jj file show -r` to inspect changes by change ID. All reviewers for the wave run in parallel and cannot conflict. +For each non-trivial DONE or DONE_WITH_CONCERNS task, dispatch a spec reviewer subagent. Spec reviewers run in the orchestrator's context (no `isolation: "worktree"`) — they are read-only, using `jj diff -r` and `jj file show -r` to inspect changes by change ID. All reviewers for the wave run in parallel and cannot conflict. Use the template at `./fan-flames-spec-reviewer.md` to construct each reviewer prompt. Fill in: - `[FULL TEXT of task requirements from plan]` — the complete task text @@ -253,7 +294,7 @@ Use the template at `./fan-flames-spec-reviewer.md` to construct each reviewer p When a spec reviewer returns FAIL: -1. Dispatch fix subagent **without** `isolation: "worktree"` (the workspace already exists — `isolation` would create a new one). Tell the subagent to work in the existing workspace directory path (e.g., `.claude/workspaces//`) and provide the reviewer's specific findings +1. Dispatch fix subagent **without** `isolation: "worktree"` (the workspace already exists — `isolation` would create a new one). Tell the subagent to work in the existing workspace directory path (e.g., `/tmp/jj-workspaces///`) and provide the reviewer's specific findings 2. Fix subagent uses the same implementer protocol (DONE / BLOCKED / NEEDS_CONTEXT) 3. Re-dispatch spec reviewer for that task only (same template, updated implementer report) 4. Repeat until PASS @@ -341,7 +382,7 @@ jj workspace list # default workspace should be marked 1. **Squash into the default workspace:** ```bash -jj squash --from --into @ +JJ_EDITOR=true jj squash --from --into @ ``` 2. **Check for conflicts:**