Repository navigation
[Feature]: Multi-agent isolation protocol — process-level feature context without shared-state races #4128
Description
Activity
Addendum: Why this matters beyond any single platform — universal multi-agent safety through the process environment
I want to highlight a design property of this proposal that I think deserves explicit attention: the isolation boundary is the UNIX/Win32 process environment — the most universal, zero-cost primitive available, and this makes the protocol work across all 30+ Spec Kit integrations without any platform-specific support.
The landscape of multi-agent isolation approaches
Approach Isolation boundary Requires platform support? Cost Portability Git worktrees (#1476) Filesystem (separate directory trees) Yes — agent must know how to create/manage worktrees High — full directory duplication, node_modules/venvbloat, disk I/OGit-specific Remote VMs / Codespaces OS-level (separate machines) Yes — platform must provision and manage VMs Very high — network latency, cold start, infrastructure cost Platform-locked (Cursor Cloud, Codespaces) Platform-native sub-agents Thread/session (platform-managed context) Yes — requires platform's sub-agent API Medium — depends on platform Platform-locked (Claude Code sub-agents, Copilot agents, Antigravity subagents) SPECIFY_FEATURE_DIRECTORYenv var (this proposal)Process environment No — works on any shell, any OS, any agent Zero — one env var prefix per command Universal — bash, zsh, PowerShell, cmd, CI runners The key insight: every AI coding agent, regardless of platform, eventually executes a shell command. Whether it's Claude Code running
bash, Cursor invoking a terminal, Copilot Workspace executing a script, or Antigravity callingrun_command— they all spawn a process. And every process has an environment.What this means in practice
A project maintainer can write one rule file (like our
.agents/rules/speckit-multiagent.md) that says:"Prefix all Spec Kit script calls with
SPECIFY_FEATURE_DIRECTORY=<your-feature-dir>"And this single instruction works identically across:
- Antigravity (Google) — subagents with
invoke_subagent - Claude Code — sub-agents with
/speckit.implementin parallel terminals - Cursor — multiple Composer tabs or background agents
- Copilot Workspace — parallel task execution
- Windsurf / Cline / Roo Code — concurrent sessions
- CI/CD (GitHub Actions matrix) — parallel jobs in the same checkout (with
SPECIFY_NO_PERSIST=1)
No platform needs to add any multi-agent primitives. No worktree management. No VM provisioning. The protocol is non-invasive — it rides on infrastructure that already exists everywhere.
Contrast with branch-based approaches
Many multi-agent systems default to "one branch per agent" for isolation. This introduces significant complexity:
- Branch conflicts: Two agents touching the same file on different branches create merge conflicts that require human resolution
- Branch management overhead: Creating, switching, merging, and cleaning up branches adds ceremony that dwarfs the actual work
- Platform coupling: Branch-based isolation requires the platform to implement branch lifecycle management — not all do
- Spec Kit's design already decoupled from branches: The
SPECIFY_FEATURE_DIRECTORY→feature.json→ error resolution chain ([Bug]: get_feature_paths persists .specify/feature.json during read-only path resolution (check-prerequisites.sh --paths-only) #3025, [Bug]: get_feature_paths emits empty CURRENT_BRANCH when SPECIFY_FEATURE unset, despite feature context via SPECIFY_FEATURE_DIRECTORY/feature.json #3026) was explicitly designed to work without git branch context. Our proposal simply documents this capability and makes agents aware of it.
The elegance of the env-var approach is that multiple agents can work on different features within the same branch (e.g.,
main), because the isolation is at the feature-directory level, not the branch level. Each agent writes to its ownspecs/<NNN-feature>/directory tree. There's no merge conflict because there's no branch divergence.Summary
This proposal turns an implicit capability of Spec Kit's existing architecture into an explicit, documented, cross-platform protocol. The upstream cost is near-zero (docs + template wording change + optional 3-line env var). The downstream value is that every Spec Kit user, on any platform, gets multi-agent safety without waiting for their specific platform to ship isolation features.
Reacted by WittKung- Antigravity (Google) — subagents with
I can support a SPECIFY_FEATURE_NO_PERSIST for this use case
- added a commit that references this issue
on Sep 23, 2026
Problem Statement
When multiple AI agents run Spec Kit pipelines concurrently within the same repository checkout (e.g., Antigravity subagents, Claude Code sub-agents, or parallel Cursor Composer tabs), they share a single
.specify/feature.jsonfile as their feature context pointer. This creates a write-write race condition:The root issue:
get_feature_paths()incommon.sh(L191-192) always persistsSPECIFY_FEATURE_DIRECTORYback tofeature.jsonunless the caller explicitly passes--no-persist. Since most scripts (setup-plan.sh,setup-tasks.sh) callget_feature_pathswithout--no-persist, every agent invocation silently overwrites the shared singleton.Impact
/speckit-implement-waves([Feature]: /speckit-implement-waves => run each phase in a subagent to prevent context rot #3507), which propose running phases in parallel subagents, cannot work safely without solving this shared-state problem first.Real-world reproduction
We encountered this in TTZip (a macOS archive utility, 525+ tests, 28 design patterns) while running Antigravity subagents to parallelize a sorting-bugfix TDD suite alongside a 7z compression optimization. Both agents used
SPECIFY_FEATURE_DIRECTORYcorrectly in their own processes, but the persist-on-read side effect inget_feature_pathscaused each agent to clobber the other'sfeature.jsonentry on every script call.Root Cause Analysis
The feature resolution chain in
common.shget_feature_paths()(L163-231) has a correct read priority:But it has an unconditional write side effect on the env-var branch (L191-192):
The
--no-persistguard (added in #3025) is a function-level parameter, not an environment-level control. Scripts that are "just resolving paths" but don't know they should pass--no-persist(likesetup-plan.sh,setup-tasks.sh) trigger the persist unconditionally.What already works
Credit to the maintainers — the infrastructure for multi-agent isolation is already in place:
SPECIFY_FEATURE_DIRECTORYenv var priority--no-persistread-only resolutionCURRENT_BRANCHfallback from feature dir basenameSPECIFY_INIT_DIRfor monorepo project scopingWhat's missing is the guidance layer: documentation, agent skill instructions, and an environment-level
no-persisttoggle.Proposed Solution
1. Official multi-agent documentation (
docs/multi-agent.md)A new document covering:
SPECIFY_FEATURE_DIRECTORYper-process, never rely onfeature.jsonfor read2. Update agent skill templates to stop instructing direct
feature.jsonwritesCurrently, the
specifycommand template (the upstream equivalent ofspeckit-specify/SKILL.md) instructs agents to:This instruction should be replaced with:
The
feature.jsonpersistence should remain as an automatic side effect ofget_feature_paths()for single-agent backward compatibility, but agents should not be told to write it directly (which bypasses the script's own idempotency guards in_persist_feature_json).3. (Optional)
SPECIFY_NO_PERSISTenvironment variableAdd an environment-level equivalent of the
--no-persistfunction parameter:This allows CI pipelines and agent orchestrators to set
SPECIFY_NO_PERSIST=1globally, ensuring that no script invocation can accidentally writefeature.json— even scripts that don't pass--no-persistinternally.Backward Compatibility
This proposal is fully backward compatible:
feature.jsonfeature.jsonfeature.json(bug)SPECIFY_NO_PERSIST=1feature.jsonwrites at allspecify integration upgradedocs/multi-agent.mdis not in manifest; protocol rules live in user-spaceNo existing scripts, templates, or workflows change behavior. The persist side effect is still there (it's a "last writer wins" overwrite that's harmless when every reader uses env vars).
SPECIFY_NO_PERSISTis strictly additive.Reference Implementation
We've been running this protocol in production at TTZip with Antigravity (Google DeepMind's agentic coding tool) subagents. Our implementation consists of:
.agents/rules/speckit-multiagent.md): Instructs all agents to injectSPECIFY_FEATURE_DIRECTORYper-process and never read/writefeature.jsondirectly.specs/003-sorting-fix/andspecs/006-7z-conquest/simultaneously produce zero cross-contamination.The protocol adds zero overhead to single-agent workflows and requires no upstream code changes to function — it's purely a documentation and guidance contribution. The optional
SPECIFY_NO_PERSISTenv var is a small, additive improvement tocommon.sh.Related Issues
/speckit-implement-waves: Needs this isolation protocol as a prerequisite for safe parallel phase executiongit worktreeSupport for Concurrent/Parallel Agent Execution #1476 — Git worktree isolation: Our approach is complementary (env-var isolation within a single checkout vs. filesystem isolation across worktrees)--no-persistfor read-only resolution: Foundation we build onCURRENT_BRANCHfallback: Foundation we build onComponent
Core scripts (
common.sh), Documentation, Agent skill templates