github / github/spec-kit

[Feature]: Multi-agent isolation protocol — process-level feature context without shared-state races

未关闭
#4,128 2 条评论 2 个 reaction 已指派 0 人 在 GitHub 查看
主要语言
Python
星标
137k
派生
12.3k
平均合并
2 天 12 小时
30 天内合并 PR
159

描述

## 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.json` file as their feature context pointer. This creates a **write-write race condition**:

```
Timeline:
t0 Agent-A: SPECIFY_FEATURE_DIRECTORY="specs/003-auth" → setup-plan.sh
→ get_feature_paths() persists "specs/003-auth" to feature.json ✓
t1 Agent-B: SPECIFY_FEATURE_DIRECTORY="specs/004-perf" → setup-tasks.sh
→ get_feature_paths() persists "specs/004-perf" to feature.json ← overwrites A's value
t2 Agent-A: (new process, no env var) → check-prerequisites.sh
→ reads feature.json → resolves "specs/004-perf" ← WRONG FEATURE
```

The root issue: `get_feature_paths()` in `common.sh` (L191-192) **always persists** `SPECIFY_FEATURE_DIRECTORY` back to `feature.json` unless the caller explicitly passes `--no-persist`. Since most scripts (`setup-plan.sh`, `setup-tasks.sh`) call `get_feature_paths` without `--no-persist`, every agent invocation silently overwrites the shared singleton.

### Impact

- **Silent cross-contamination**: Agent B's plan/tasks get written into Agent A's feature directory (or vice versa) without any error signal.
- **Non-reproducible failures**: The behavior depends on timing — sometimes it works, sometimes it doesn't, making debugging extremely difficult.
- **Blocks multi-agent orchestration**: Features like `/speckit-implement-waves` (#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](https://github.com/wittkung/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_DIRECTORY` correctly in their own processes, but the persist-on-read side effect in `get_feature_paths` caused each agent to clobber the other's `feature.json` entry on every script call.

---

## Root Cause Analysis

The feature resolution chain in `common.sh` `get_feature_paths()` (L163-231) has a correct **read** priority:

```
1. SPECIFY_FEATURE_DIRECTORY env var (explicit override)
2. .specify/feature.json (persisted fallback)
3. Error (no context)
```

But it has an **unconditional write side effect** on the env-var branch (L191-192):

```bash
if [[ "$no_persist" != true ]]; then
_persist_feature_json "$repo_root" "$SPECIFY_FEATURE_DIRECTORY"
fi
```

The `--no-persist` guard (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` (like `setup-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**:

| Mechanism | Status | Issue |
|:----------|:-------|:------|
| `SPECIFY_FEATURE_DIRECTORY` env var priority | ✅ Working | — |
| `--no-persist` read-only resolution | ✅ Working | #3025 |
| `CURRENT_BRANCH` fallback from feature dir basename | ✅ Working | #3026 |
| `SPECIFY_INIT_DIR` for monorepo project scoping | ✅ Working | — |
| Parser fallback chain (jq → python3 → grep/sed) | ✅ Working | #3304 |

What's **missing** is the guidance layer: documentation, agent skill instructions, and an environment-level `no-persist` toggle.

---

## Proposed Solution

### 1. Official multi-agent documentation (`docs/multi-agent.md`)

A new document covering:
- The race condition scenario (as above)
- The **Multi-Agent Isolation Protocol**: always inject `SPECIFY_FEATURE_DIRECTORY` per-process, never rely on `feature.json` for read
- Integration-specific examples (Antigravity subagents, Claude Code sub-agents, Cursor multi-tab, CI matrix)
- FAQ: "Do I need git worktrees?" → No, env-var isolation is sufficient for same-checkout concurrency

### 2. Update agent skill templates to stop instructing direct `feature.json` writes

Currently, the `specify` command template (the upstream equivalent of `speckit-specify/SKILL.md`) instructs agents to:

> *Persist the resolved path to `.specify/feature.json`: `{"feature_directory": ""}`*

This instruction should be replaced with:

> *Pass the resolved feature directory to downstream commands via `SPECIFY_FEATURE_DIRECTORY` environment variable prefix. Example: `SPECIFY_FEATURE_DIRECTORY="specs/003-auth" .specify/scripts/bash/setup-plan.sh --json`*

The `feature.json` persistence should remain as an **automatic side effect** of `get_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_PERSIST` environment variable

Add an environment-level equivalent of the `--no-persist` function parameter:

```bash
# In get_feature_paths(), after the --no-persist argument check (L167-171):
if [[ "${SPECIFY_NO_PERSIST:-}" == "1" || "${SPECIFY_NO_PERSIST:-}" == "true" ]]; then
no_persist=true
fi
```

This allows CI pipelines and agent orchestrators to set `SPECIFY_NO_PERSIST=1` globally, ensuring that no script invocation can accidentally write `feature.json` — even scripts that don't pass `--no-persist` internally.

---

## Backward Compatibility

This proposal is **fully backward compatible**:

| Scenario | Before | After |
|:---------|:-------|:------|
| Single agent, no env var | Reads `feature.json` | Identical behavior |
| Single agent, with env var | Reads env var, persists to `feature.json` | Identical behavior |
| Multi-agent, each sets env var | Race on `feature.json` (bug) | Each agent's reads are short-circuited by env var; persistence is harmless |
| Multi-agent + `SPECIFY_NO_PERSIST=1` | N/A | No `feature.json` writes at all |
| `specify integration upgrade` | Overwrites managed files | `docs/multi-agent.md` is not in manifest; protocol rules live in user-space |

No 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_PERSIST` is strictly additive.

---

## Reference Implementation

We've been running this protocol in production at [TTZip](https://github.com/wittkung/TTZip) with Antigravity (Google DeepMind's agentic coding tool) subagents. Our implementation consists of:

1. **Project-level rule file** ([`.agents/rules/speckit-multiagent.md`](https://github.com/wittkung/TTZip/blob/main/.agents/rules/speckit-multiagent.md)): Instructs all agents to inject `SPECIFY_FEATURE_DIRECTORY` per-process and never read/write `feature.json` directly.
2. **Global user rule**: Gates (hard state machine gating) that prevent any agent from writing production code before spec/plan/tasks artifacts exist under the declared feature directory.
3. **Concurrent verification**: Validated that two agents operating on `specs/003-sorting-fix/` and `specs/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_PERSIST` env var is a small, additive improvement to `common.sh`.

---

## Related Issues

- #3507 — `/speckit-implement-waves`: Needs this isolation protocol as a prerequisite for safe parallel phase execution
- #1476 — Git worktree isolation: Our approach is complementary (env-var isolation within a single checkout vs. filesystem isolation across worktrees)
- #3025 — `--no-persist` for read-only resolution: Foundation we build on
- #3026 — `CURRENT_BRANCH` fallback: Foundation we build on
- #752 — Claude Code subagent feature execution: Would benefit from this protocol

## Component

Core scripts (`common.sh`), Documentation, Agent skill templates

贡献指南

打开贡献指南

调研方向

从 common.sh 中的 get_feature_paths 开始,然后检查 specify skill 模板和现有的文档布局。在 docs/multi-agent.md 中定义多代理协议,更新模板指南,并评估 SPECIFY_NO_PERSIST 的可选行为。当文档化的工作流和模板避免直接写入 feature.json,同时保留所述的向后兼容情形时,即表示完成。

由索引模型根据 Issue 内容生成。

评估

技术栈
shell
领域
documentation, tooling
Issue 类型
功能
难度
4/5
预计耗时
3-5 天
活跃度
冷清
描述清晰度
基本清楚
新手友好度
55/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。