Skip to content

Phase agents are worktree-isolated but plan state lives in the main checkout #26

Description

@nonameffh

Summary

cf-phase-runner and cf-phase-compiler are declared with isolation = true, which the generator translates to isolation: worktree for Claude Code. But a plan's authoritative state lives under {cf-studio-path}/.plans/{task-slug}/ (designed to be gitignored), and target SDLC artifacts are meant to be written in the main working tree. Worktree isolation is therefore structurally mismatched with plan execution/compilation: every meaningful write is a sandbox escape, and gitignored plan state is not even present inside the worktree.

Root cause

Worktree isolation assumes the agent's working set lives inside the worktree. For phase execution/compilation that assumption is false:

Both agents are isolation = true:

The generator unconditionally emits isolation: worktree when agent.isolation is true (agents.py#L1284, #L4588, #L5241).

Net effect: writes to the canonical (main-tree) plan dir + SDLC outputs escape the worktree sandbox, triggering per-write permission prompts; gitignored plan state is absent from the worktree entirely.

Note that the generator is already configurable per agent — isolation is a manifest field (default false, manifest.py#L82), and most write-capable agents (cf-generate-author-*, cf-generate-coder-*, the migrate-* set) are explicitly isolation = false and operate in-place. The phase agents are the remaining write-capable agents still set to isolation = true.

Proposed fixes (pick one or combine)

  1. Default these agents to non-worktree isolation (recommended). Set isolation = false for cf-phase-runner and cf-phase-compiler in skills/studio/agents.toml so they operate on the gitignored plan state in the main tree. Keep worktree only where parallel code mutation is the goal (cf-codegen). Update the agents' rationale comments (currently "write access is bounded by host isolation").
  2. Make plan state visible in the worktree — mount/symlink {cf-studio-path}/.plans/<task-slug>/ into the worktree, or stage plan artifacts under a non-gitignored, worktree-tracked location.
  3. Pre-approve known plan paths for writing inside the worktree sandbox — treat the canonical plan dir plus the plan's declared outputs as pre-approved, so no per-write prompts occur.
  4. Document a recommended permission allowlist for the recurring read-only commands (e.g. validate, validate --artifact, list-ids, where-used/where-defined) and for writes under the plan dir + module docs.

How fix 1 behaves

isolation is a per-dispatch property, not a session-wide mode: the orchestrator never runs in a worktree, and only a dispatched sub-agent whose frontmatter carries isolation: worktree gets its own worktree for that one run. Sub-agents with isolation = false write directly to the main tree.

After fix 1, the only write-capable agent left in a worktree is cf-codegen — which is the legitimate use (isolated code generation from a complete spec; it never touches plan state). cf-brainstorm-expert and cf-brainstorm-panel stay isolation = true but are read-only, so the write-escape problem does not apply.

This is also not "the only way code gets written": cf-codegen is only the first-match path when a task is fully specified with no clarification (coding.md#L135); otherwise code/artifacts are written in-place by cf-generate-coder-*, cf-generate-author-*, cf-pdsl-*, cf-migrate-migrator, etc. (all already isolation = false). Fix 1 simply moves the two phase agents onto that same in-place model.

Workaround

Run plan phases/compilation without worktree isolation (in the main checkout) — inline or via a non-isolated subagent — so all writes stay inside the working tree and no sandbox-escape prompts occur.

Note on regeneration

isolation: worktree is emitted by the agents generator, so any manual edit to the generated .claude/agents/*.md (or other tool targets) is overwritten on regenerate/update. The fix must change what the generator emits — i.e. the isolation value in skills/studio/agents.toml — not the generated files.

Affected tests (for whoever picks this up)

  • tests/test_subagent_registration.py
  • tests/test_agents_coverage.py
  • tests/test_agents_existing_snapshot.py

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions