paircode 0.11.3__tar.gz → 0.11.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. {paircode-0.11.3 → paircode-0.11.5}/PKG-INFO +5 -5
  2. {paircode-0.11.3 → paircode-0.11.5}/README.md +3 -3
  3. {paircode-0.11.3 → paircode-0.11.5}/pyproject.toml +2 -2
  4. {paircode-0.11.3 → paircode-0.11.5}/src/paircode/__init__.py +1 -1
  5. {paircode-0.11.3 → paircode-0.11.5}/src/paircode/runner.py +7 -1
  6. {paircode-0.11.3 → paircode-0.11.5}/src/paircode/state.py +13 -13
  7. {paircode-0.11.3 → paircode-0.11.5}/src/paircode/templates/claude/commands/paircode.md +31 -30
  8. {paircode-0.11.3 → paircode-0.11.5}/src/paircode/templates/codex/commands/paircode.md +3 -3
  9. {paircode-0.11.3 → paircode-0.11.5}/src/paircode/templates/gemini/commands/paircode.toml +3 -3
  10. {paircode-0.11.3 → paircode-0.11.5}/src/paircode/templates/peers.yaml +1 -1
  11. {paircode-0.11.3 → paircode-0.11.5}/tests/test_state.py +8 -8
  12. {paircode-0.11.3 → paircode-0.11.5}/.gitignore +0 -0
  13. {paircode-0.11.3 → paircode-0.11.5}/LICENSE +0 -0
  14. {paircode-0.11.3 → paircode-0.11.5}/diary/001-step-a-architecture.md +0 -0
  15. {paircode-0.11.3 → paircode-0.11.5}/diary/002-v0.10-release-pipeline.md +0 -0
  16. {paircode-0.11.3 → paircode-0.11.5}/diary/003-arch-b-pivot-grappling.md +0 -0
  17. {paircode-0.11.3 → paircode-0.11.5}/src/paircode/__main__.py +0 -0
  18. {paircode-0.11.3 → paircode-0.11.5}/src/paircode/cli.py +0 -0
  19. {paircode-0.11.3 → paircode-0.11.5}/src/paircode/converge.py +0 -0
  20. {paircode-0.11.3 → paircode-0.11.5}/src/paircode/detect.py +0 -0
  21. {paircode-0.11.3 → paircode-0.11.5}/src/paircode/handshake.py +0 -0
  22. {paircode-0.11.3 → paircode-0.11.5}/src/paircode/installer.py +0 -0
  23. {paircode-0.11.3 → paircode-0.11.5}/src/paircode/templates/FOCUS.md +0 -0
  24. {paircode-0.11.3 → paircode-0.11.5}/src/paircode/templates/JOURNEY.md +0 -0
  25. {paircode-0.11.3 → paircode-0.11.5}/src/paircode/util.py +0 -0
  26. {paircode-0.11.3 → paircode-0.11.5}/tests/__init__.py +0 -0
  27. {paircode-0.11.3 → paircode-0.11.5}/tests/test_cli_smoke.py +0 -0
  28. {paircode-0.11.3 → paircode-0.11.5}/tests/test_converge.py +0 -0
  29. {paircode-0.11.3 → paircode-0.11.5}/tests/test_smoke.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: paircode
3
- Version: 0.11.3
3
+ Version: 0.11.5
4
4
  Summary: Adversarial journey framework — orchestrate multiple LLM peers through research, plan, and execute stages with file-trace peer review.
5
5
  Project-URL: Homepage, https://github.com/starshipagentic/paircode
6
6
  Project-URL: Repository, https://github.com/starshipagentic/paircode
@@ -21,7 +21,7 @@ Classifier: Programming Language :: Python :: 3.13
21
21
  Classifier: Topic :: Software Development
22
22
  Requires-Python: >=3.10
23
23
  Requires-Dist: click>=8.1
24
- Requires-Dist: cliworker>=0.8.1
24
+ Requires-Dist: cliworker>=0.8.3
25
25
  Requires-Dist: pyyaml>=6.0
26
26
  Requires-Dist: rich>=13.0
27
27
  Description-Content-Type: text/markdown
@@ -76,9 +76,9 @@ your-project/
76
76
  .paircode/
77
77
  JOURNEY.md # fleet log
78
78
  peers.yaml # roster: who's on the team
79
- peers/
79
+ sandbox/
80
80
  peer-a-codex/ # codex's persistent sandbox (code goes here)
81
- peer-b-gemini/ # gemini's persistent sandbox
81
+ peer-b-gemini/ # gemini's persistent sandbox
82
82
  focus-01-<slug>/
83
83
  FOCUS.md # this focus's prompt + metadata
84
84
  research/
@@ -97,7 +97,7 @@ your-project/
97
97
 
98
98
  **Code vs. reports.** Files inside `focus-*/` are markdown *reports* (opinions, plans, critiques, summaries of work). Actual code lives elsewhere:
99
99
 
100
- - **Peers** code in their sandboxed workspaces at `.paircode/peers/<peer-id>/` — persistent across focuses.
100
+ - **Peers** code in their sandboxed workspaces at `.paircode/sandbox/<peer-id>/` — persistent across focuses.
101
101
  - **Alpha** codes directly in the project root (the real repo) — alpha *is* the project.
102
102
 
103
103
  ## Stages
@@ -48,9 +48,9 @@ your-project/
48
48
  .paircode/
49
49
  JOURNEY.md # fleet log
50
50
  peers.yaml # roster: who's on the team
51
- peers/
51
+ sandbox/
52
52
  peer-a-codex/ # codex's persistent sandbox (code goes here)
53
- peer-b-gemini/ # gemini's persistent sandbox
53
+ peer-b-gemini/ # gemini's persistent sandbox
54
54
  focus-01-<slug>/
55
55
  FOCUS.md # this focus's prompt + metadata
56
56
  research/
@@ -69,7 +69,7 @@ your-project/
69
69
 
70
70
  **Code vs. reports.** Files inside `focus-*/` are markdown *reports* (opinions, plans, critiques, summaries of work). Actual code lives elsewhere:
71
71
 
72
- - **Peers** code in their sandboxed workspaces at `.paircode/peers/<peer-id>/` — persistent across focuses.
72
+ - **Peers** code in their sandboxed workspaces at `.paircode/sandbox/<peer-id>/` — persistent across focuses.
73
73
  - **Alpha** codes directly in the project root (the real repo) — alpha *is* the project.
74
74
 
75
75
  ## Stages
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "paircode"
7
- version = "0.11.3"
7
+ version = "0.11.5"
8
8
  description = "Adversarial journey framework — orchestrate multiple LLM peers through research, plan, and execute stages with file-trace peer review."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -39,7 +39,7 @@ dependencies = [
39
39
  "click>=8.1",
40
40
  "pyyaml>=6.0",
41
41
  "rich>=13.0",
42
- "cliworker>=0.8.1",
42
+ "cliworker>=0.8.3",
43
43
  ]
44
44
 
45
45
  [project.urls]
@@ -2,4 +2,4 @@
2
2
 
3
3
  See README.md and diary/001-step-a-architecture.md for the full design.
4
4
  """
5
- __version__ = "0.11.2"
5
+ __version__ = "0.11.4"
@@ -107,8 +107,14 @@ def run_peer(
107
107
  f"<!-- cli: {cli} -->\n"
108
108
  f"<!-- model: {model or '(default)'} -->\n"
109
109
  f"<!-- duration_s: {cli_result.duration_s:.1f} -->\n"
110
- f"<!-- ok: {cli_result.ok} -->\n\n"
110
+ f"<!-- ok: {cli_result.ok} -->\n"
111
111
  )
112
+ # Surface the cliworker watchdog's reason on failure so downstream tools
113
+ # can tell startup-idle hangs apart from hard timeouts apart from real errors.
114
+ timeout_kind = getattr(cli_result, "timeout_kind", None)
115
+ if timeout_kind:
116
+ header += f"<!-- timeout_kind: {timeout_kind} -->\n"
117
+ header += "\n"
112
118
  if cli_result.ok:
113
119
  body = cli_result.stdout
114
120
  else:
@@ -4,9 +4,9 @@ The .paircode/ layout (from diary/001-step-a-architecture.md):
4
4
 
5
5
  .paircode/
6
6
  JOURNEY.md ← fleet log, focus transitions
7
- peers.yaml ← roster
8
- peers/
9
- peer-a-{cli}/ ← per-peer working dir (+profile.md, +code if full-fork)
7
+ peers.yaml ← roster (who's on the team)
8
+ sandbox/
9
+ peer-a-{cli}/ ← per-peer persistent sandbox (code/scripts/prototypes)
10
10
  focus-01-{slug}/
11
11
  FOCUS.md
12
12
  research/
@@ -53,7 +53,7 @@ class PaircodeState:
53
53
  root: Path # path to .paircode/ dir itself
54
54
  journey_path: Path
55
55
  peers_path: Path
56
- peers_dir: Path
56
+ sandbox_dir: Path
57
57
  focus_dirs: list[Path] # sorted by name
58
58
 
59
59
  @property
@@ -90,7 +90,7 @@ def load_state(root: Path) -> PaircodeState:
90
90
  root=root,
91
91
  journey_path=root / JOURNEY_FILE,
92
92
  peers_path=root / PEERS_FILE,
93
- peers_dir=root / "peers",
93
+ sandbox_dir=root / "sandbox",
94
94
  focus_dirs=focus_dirs,
95
95
  )
96
96
 
@@ -109,19 +109,19 @@ def _peer_id(entry) -> str | None:
109
109
 
110
110
 
111
111
  def ensure_peer_dirs(state: PaircodeState, proposed: Iterable) -> list[Path]:
112
- """Create .paircode/peers/{peer.id}/ for each entry. Idempotent.
112
+ """Create .paircode/sandbox/{peer.id}/ for each entry. Idempotent.
113
113
 
114
114
  Accepts iterables of ProposedPeer dataclasses OR plain dicts (anything
115
115
  with an `id` attribute / key). Silently skips entries without a usable id.
116
- Returns the list of peer-dir paths that now exist (created or pre-existing).
116
+ Returns the list of sandbox-dir paths that now exist (created or pre-existing).
117
117
  """
118
- state.peers_dir.mkdir(exist_ok=True)
118
+ state.sandbox_dir.mkdir(exist_ok=True)
119
119
  created: list[Path] = []
120
120
  for entry in proposed:
121
121
  pid = _peer_id(entry)
122
122
  if not pid:
123
123
  continue
124
- peer_dir = state.peers_dir / pid
124
+ peer_dir = state.sandbox_dir / pid
125
125
  peer_dir.mkdir(exist_ok=True)
126
126
  created.append(peer_dir)
127
127
  return created
@@ -130,7 +130,7 @@ def ensure_peer_dirs(state: PaircodeState, proposed: Iterable) -> list[Path]:
130
130
  def init_paircode(project_root: Path | None = None, force: bool = False) -> PaircodeState:
131
131
  """Bootstrap .paircode/ in `project_root` (or cwd). Returns the new state.
132
132
 
133
- Also pre-creates a subdir per auto-detected peer under .paircode/peers/.
133
+ Also pre-creates a subdir per auto-detected peer under .paircode/sandbox/.
134
134
  If no peers are detected, the parent dir exists but stays empty.
135
135
  """
136
136
  if project_root is None:
@@ -142,7 +142,7 @@ def init_paircode(project_root: Path | None = None, force: bool = False) -> Pair
142
142
  f"{root} already exists. Use --force to overwrite, or `paircode status` to inspect."
143
143
  )
144
144
  root.mkdir(parents=True, exist_ok=True)
145
- (root / "peers").mkdir(exist_ok=True)
145
+ (root / "sandbox").mkdir(exist_ok=True)
146
146
 
147
147
  journey = _render(
148
148
  _read_template("JOURNEY.md"),
@@ -162,8 +162,8 @@ def init_paircode(project_root: Path | None = None, force: bool = False) -> Pair
162
162
 
163
163
  ensure_peer_dirs(state, propose_roster())
164
164
  except Exception:
165
- # Scaffolding peers is best-effort; a detect failure shouldn't
166
- # block bootstrap. The peers/ parent dir is already there.
165
+ # Scaffolding sandboxes is best-effort; a detect failure shouldn't
166
+ # block bootstrap. The sandbox/ parent dir is already there.
167
167
  pass
168
168
 
169
169
  return state
@@ -18,12 +18,11 @@ Inside every `$FOCUS/{stage}/`:
18
18
 
19
19
  `N` in `vN` is the current round number, starting at 1. Only write v1 in the first round; bump to v2, v3, … if you do review rounds.
20
20
 
21
- **Code vs. reports.** Every file inside `$FOCUS/{stage}/` is a **markdown report** (opinion, critique, plan, or summary of work). Actual code lives elsewhere:
21
+ **Reports vs. code — the three rules.** Files inside `$FOCUS/{stage}/` are always **markdown reports** (opinions, plans, critiques, summaries). Actual code lives elsewhere, and sandboxes are **always available, never required**:
22
22
 
23
- - **Peers** code in their sandboxed workspace at `.paircode/peers/{peer-id}/` — persistent across focuses, each peer builds there.
24
- - **Alpha** codes directly in the project root (the user's repo) alpha IS the project, no sandbox.
25
-
26
- The `$FOCUS/execute/*-v1.md` files describe what was done; the `$FOCUS/execute/` dir is never where code is written.
23
+ 1. **Always available.** Peers can use their persistent sandbox at `.paircode/sandbox/{peer-id}/` at **any stage** not just execute. Verifying a bug in `ask`, grounding research in real data, prototyping a tricky plan section — all fine. Alpha (this Claude session) works directly in the project root (the user's repo). **Code only when it makes your answer materially better** — a 5-line verification script is cheap insurance; a 500-line prototype during an `ask` is over-engineering.
24
+ 2. **Separation.** Markdown is the deliverable; the sandbox is the laboratory. Scripts, prototypes, dumps, evidence files live in `.paircode/sandbox/{peer-id}/`. The `$FOCUS/{stage}/*-v1.md` file summarizes what you did + what it proved. The `$FOCUS/` tree is never where code is written.
25
+ 3. **Isolation.** Peers never touch files outside their own sandbox. Alpha never touches other peers' sandboxes. The project root is alpha's.
27
26
 
28
27
  ## Step 1 — Bootstrap
29
28
 
@@ -44,34 +43,41 @@ PEERS=$(paircode roster --alpha claude <user's --peer/--peers flags if any>)
44
43
 
45
44
  `paircode roster` always returns a usable list. Trust it.
46
45
 
47
- ## Step 2 — Pick the stage
46
+ ## Step 2 — Pick the flow (not just a stage)
47
+
48
+ Read the user's quoted prompt and pick the **whole flow** you're committing to. Store it as `{flow}`. Each flow is an ordered list of stages; you run them in order.
48
49
 
49
- Read the user's quoted prompt and decide which stage best fits. Store your pick as `{stage}`:
50
+ | Flow | Deliverable | Trigger phrases |
51
+ |---|---|---|
52
+ | `ask` | Opinion on existing work | "what do you think", "review X", "critique", "second opinion" |
53
+ | `research` | Investigation report | "figure out", "explore", "find the right", "how should we" |
54
+ | `research → plan` | Concrete plan | "plan the X", "design the Y", "lay out the approach" |
55
+ | `research → plan → execute` | **Shipped code / action done** | "build", "fix", "implement", "write code for", "ship", "do", and most imperative tasks |
56
+ | `execute` | Just do it (plan already exists) | "execute the plan at focus-NN", "run the migration from focus-05" |
50
57
 
51
- - **research** explore new ground, figure something out. ("build a KISS PHQ-9 depression engine", "find the right TTS library", "how should we approach X")
52
- - **plan** — produce a concrete implementation plan, usually building on prior research. ("plan the refactor based on focus-02's research")
53
- - **execute** — do the work from an existing plan. ("execute the plan at focus-02")
54
- - **ask** — get opinions on existing work. ("what does codex think of this PR", "review my approach at <path>")
58
+ **Default when ambiguous: `research plan execute`.** It's safer to over-deliver than to stop at research for a prompt that meant "build this." The only prompts that aren't build-shaped are explicit opinion/review requests.
55
59
 
56
- When unsure, pick `research` it's the safe cold-investigation default. All four stage subdirs already exist under `$FOCUS` no mkdir needed.
60
+ Write `{flow}` into `$FOCUS/FOCUS.md` (append a line like `flow: research plan execute`) so later steps can see your commitment.
61
+
62
+ The stage for **this iteration** is the first stage in `{flow}`. Store that as `{stage}`. All four stage subdirs already exist under `$FOCUS`.
57
63
 
58
64
  ## Step 3 — Fire peers in parallel
59
65
 
60
66
  For each peer id in `$PEERS`, spawn one subagent using the **Agent tool** with `subagent_type=general-purpose` and `run_in_background=true`. Send them all in a single message so they run truly concurrently.
61
67
 
62
- Construct a stage-appropriate peer prompt. The general shape for each `{stage}`:
68
+ Construct a stage-appropriate peer prompt. Every prompt reminds the peer its sandbox is available; the deliverable is always the markdown report. General shape for each `{stage}`:
63
69
 
64
- - **research**: "Read $FOCUS/FOCUS.md. Give an honest, skeptical, specific **cold take** on the prompt. Clean markdown, no preamble."
65
- - **plan**: "Read $FOCUS/FOCUS.md and any `../research/*-FINAL.md` if present. Write a **concrete step-by-step plan** for this prompt: goal, scope, numbered steps, risks, success criteria. Be KISS. Clean markdown."
66
- - **execute**: "Read $FOCUS/FOCUS.md and the plan at `$FOCUS/plan/*-FINAL.md`. **Execute the plan IN YOUR PEER WORKSPACE at `.paircode/peers/{peer-id}/`** that is your persistent sandbox. Write code there, run commands there. Do NOT touch files outside that workspace. Then write a markdown report to your output file summarizing: what you built, files touched (paths relative to your peer workspace), tests/verification status, what's open. The output file holds the *report*; the *code* lives in your peer workspace."
67
- - **ask**: "Read $FOCUS/FOCUS.md and the artifact it points to. Give your **honest critique** of that artifact what's wrong, what's right, severity-ranked findings with file:line citations where possible. Clean markdown, no preamble."
70
+ - **research**: "Read $FOCUS/FOCUS.md. Give an honest, skeptical, specific **cold take** on the prompt. Use your sandbox at `.paircode/sandbox/{peer-id}/` to write quick scripts grounding your claims in real data (not README marketing) if it would sharpen your take. Clean markdown report, no preamble."
71
+ - **plan**: "Read $FOCUS/FOCUS.md and any `../research/*-FINAL.md` if present. Write a **concrete step-by-step plan**: goal, scope, numbered steps, risks, success criteria. Be KISS. Use your sandbox at `.paircode/sandbox/{peer-id}/` to prototype tricky sections and verify feasibility. Clean markdown."
72
+ - **execute**: "Read $FOCUS/FOCUS.md and the plan at `$FOCUS/plan/*-FINAL.md`. **Carry out the plan and produce working artifacts.** For code-shipping plans: work in your peer workspace at `.paircode/sandbox/{peer-id}/`, write code there, run commands there, run tests there. For action plans (run a migration, make an API call, file a ticket): do the action and report results. Do NOT touch files outside your workspace. Your output is a markdown report summarizing what you built/ran, files touched, verification status, what's open."
73
+ - **ask**: "Read $FOCUS/FOCUS.md and the artifact it points to. Give your **honest critique** — severity-ranked findings with file:line citations where possible. If reproducing a claim by running a quick script in your sandbox (`.paircode/sandbox/{peer-id}/`) would make your critique sharper, do it. Your output is still a critique report, not a prototype. Clean markdown, no preamble."
68
74
 
69
75
  Each subagent's prompt:
70
76
 
71
77
  ```
72
78
  You are the {peer-id} peer in a paircode {stage} cycle.
73
79
 
74
- Your persistent workspace: .paircode/peers/{peer-id}/
80
+ Your persistent workspace: .paircode/sandbox/{peer-id}/
75
81
  The focus we're on: $FOCUS
76
82
  The prompt from the user: "<the quoted prompt>"
77
83
  The stage: {stage}
@@ -93,7 +99,7 @@ Do not try to "fix" the peer's output. We want the raw file-trace on disk.
93
99
 
94
100
  While the peer subagents run, you (the team lead) write your own v1 at `$FOCUS/{stage}/alpha-v1.md`. Use the Write tool. Same stage-appropriate rules as above — and your advantage over the peers is you have this session's full context (memory, recent work, the maintainer's voice).
95
101
 
96
- **Execute-stage asymmetry:** when `{stage}` is `execute`, peers code inside their sandboxed peer workspaces (`.paircode/peers/{peer-id}/`). You, alpha, code directly in the project root — you're working on the user's actual repo. Your `alpha-v1.md` is a report summarizing what landed in the real project files; the code itself lives in the repo, not in `$FOCUS/execute/`.
102
+ **Execute-stage asymmetry:** when `{stage}` is `execute`, peers code inside their sandboxed peer workspaces (`.paircode/sandbox/{peer-id}/`). You, alpha, code directly in the project root — you're working on the user's actual repo. Your `alpha-v1.md` is a report summarizing what landed in the real project files; the code itself lives in the repo, not in `$FOCUS/execute/`.
97
103
 
98
104
  ## Step 5 — Wait and read
99
105
 
@@ -136,20 +142,13 @@ Then read every `*-FINAL.md` and write `$FOCUS/{stage}/consensus.md` via the Wri
136
142
 
137
143
  Adversarial-but-honest. No pile-on. No rubber-stamping either.
138
144
 
139
- ## Step 8 — Next stage or done?
140
-
141
- After a stage converges, decide whether to transition to another stage or wrap up:
145
+ ## Step 8 — Advance the flow (mechanical)
142
146
 
143
- - **Done** the user's prompt is now served. Go to Step 9.
144
- - **Next stage** — move to whichever stage follows naturally from what you just finished. Pick the new `{stage}`, then jump back to **Step 3** (Fire peers). Skip Step 1 — focus is still open. Skip Step 2 — you already picked. The previous stage's `*-FINAL.md` files are input for the next stage's peer prompts.
147
+ Look at the `{flow}` you committed to in Step 2. Set `{stage}` to the **next** stage in that flow and jump back to **Step 3** (Fire peers). Skip Step 1 (focus is still open) and Step 2 (flow already chosen). The previous stage's `*-FINAL.md` files are input for the next stage's peer prompts.
145
148
 
146
- Typical chains:
147
- - `ask → done`
148
- - `research → done` (if research itself was the deliverable)
149
- - `research → plan → execute → done` (most common full-build chain)
150
- - `research → plan → done` (when the plan is the deliverable and the maintainer will execute manually)
149
+ **If the last stage just finished, go to Step 9.**
151
150
 
152
- Back-to-Step-3 recursion is how paircode moves through multiple stages in one invocation. No round cap, no stage cap team lead's call when to stop.
151
+ This step is mechanical. Do not re-deliberate. Do not ask the user whether to continue. The user's prompt in `$ARGUMENTS` was implicit go-ahead for the whole flow; stopping early is an exception that only happens if **something blocked you** (a peer hard-errored and the blocker is critical, the consensus explicitly said "do not proceed", or the user interrupted). If you do stop early, say so explicitly in the final report with the reason.
153
152
 
154
153
  ## Step 9 — Final report
155
154
 
@@ -166,4 +165,6 @@ Keep it under 200 words. Brief, honest, actionable.
166
165
  - **Never skip Step 1.** The focus and roster helpers do the work Python is better at.
167
166
  - **Never invent peer commands.** Always route through `paircode invoke <id> "..." --out <path>` — that's how cliworker's speed flags, MCP strip, and output tracing work.
168
167
  - **Never pass the interactive Claude session as a peer by mistake.** `paircode roster --alpha claude` handles that for you.
168
+ - **Peer sandboxes are always available, never required.** Use them when it materially sharpens your answer, not by default.
169
+ - **The user's prompt is implicit go-ahead for the whole `{flow}`.** Do not pause for permission between stages. If you must stop early, say so explicitly in the final report with the reason.
169
170
  - **No AI attribution** in any artifact you write (consensus.md, alpha-*.md). See the maintainer's CLAUDE.md.
@@ -21,7 +21,7 @@ Inside every `$FOCUS/{stage}/`:
21
21
 
22
22
  **Code vs. reports.** Every file inside `$FOCUS/{stage}/` is a **markdown report** (opinion, critique, plan, or summary of work). Actual code lives elsewhere:
23
23
 
24
- - **Peers** code in their sandboxed workspace at `.paircode/peers/{peer-id}/` — persistent across focuses.
24
+ - **Peers** code in their sandboxed workspace at `.paircode/sandbox/{peer-id}/` — persistent across focuses.
25
25
  - **Alpha** codes directly in the project root (the user's repo) — alpha IS the project, no sandbox.
26
26
 
27
27
  The `$FOCUS/execute/*-v1.md` files describe what was done; the `$FOCUS/execute/` dir is never where code is written.
@@ -77,14 +77,14 @@ Construct one per stage — keep it reusable across peers:
77
77
 
78
78
  - **research**: "Read $FOCUS/FOCUS.md. Give an honest, skeptical, specific **cold take** on the prompt. Clean markdown, no preamble."
79
79
  - **plan**: "Read $FOCUS/FOCUS.md and any `../research/*-FINAL.md` if present. Write a **concrete step-by-step plan** for this prompt: goal, scope, numbered steps, risks, success criteria. Be KISS. Clean markdown."
80
- - **execute**: "Read $FOCUS/FOCUS.md and the plan at `$FOCUS/plan/*-FINAL.md`. **Execute the plan IN YOUR PEER WORKSPACE at `.paircode/peers/{peer-id}/`** — that is your persistent sandbox. Write code there, run commands there. Do NOT touch files outside that workspace. Then write a markdown report to your output file summarizing: what you built, files touched (paths relative to your peer workspace), tests/verification status, what's open. The output file holds the *report*; the *code* lives in your peer workspace."
80
+ - **execute**: "Read $FOCUS/FOCUS.md and the plan at `$FOCUS/plan/*-FINAL.md`. **Execute the plan IN YOUR PEER WORKSPACE at `.paircode/sandbox/{peer-id}/`** — that is your persistent sandbox. Write code there, run commands there. Do NOT touch files outside that workspace. Then write a markdown report to your output file summarizing: what you built, files touched (paths relative to your peer workspace), tests/verification status, what's open. The output file holds the *report*; the *code* lives in your peer workspace."
81
81
  - **ask**: "Read $FOCUS/FOCUS.md and the artifact it points to. Give your **honest critique** — severity-ranked findings with file:line citations where possible. Clean markdown, no preamble."
82
82
 
83
83
  ## Step 4 — Team lead's own take
84
84
 
85
85
  After the serial peer loop completes (or right after you kick it off if your tools allow), write your own v1 at `$FOCUS/{stage}/alpha-v1.md` using the shell tool (e.g. `cat > ... <<'EOF'`). Same stage-appropriate rules as above — your advantage over the peers is session context (memory, recent work, the maintainer's voice).
86
86
 
87
- **Execute-stage asymmetry:** when `{stage}` is `execute`, peers code inside their sandboxed peer workspaces (`.paircode/peers/{peer-id}/`). You, alpha, code directly in the project root — the user's actual repo. Your `alpha-v1.md` is a report summarizing what landed in the real project files; the code itself lives in the repo, not in `$FOCUS/execute/`.
87
+ **Execute-stage asymmetry:** when `{stage}` is `execute`, peers code inside their sandboxed peer workspaces (`.paircode/sandbox/{peer-id}/`). You, alpha, code directly in the project root — the user's actual repo. Your `alpha-v1.md` is a report summarizing what landed in the real project files; the code itself lives in the repo, not in `$FOCUS/execute/`.
88
88
 
89
89
  ## Step 5 — Wait and read
90
90
 
@@ -21,7 +21,7 @@ N in vN is the current round number, starting at 1. Only write v1 in the first r
21
21
 
22
22
  **Code vs. reports.** Every file inside $FOCUS/{stage}/ is a markdown report (opinion, critique, plan, or summary of work). Actual code lives elsewhere:
23
23
 
24
- - Peers code in their sandboxed workspace at .paircode/peers/{peer-id}/ — persistent across focuses.
24
+ - Peers code in their sandboxed workspace at .paircode/sandbox/{peer-id}/ — persistent across focuses.
25
25
  - Alpha codes directly in the project root (the user's repo) — alpha IS the project, no sandbox.
26
26
 
27
27
  The $FOCUS/execute/*-v1.md files describe what was done; the $FOCUS/execute/ dir is never where code is written.
@@ -71,14 +71,14 @@ Construct one per stage — keep it reusable across peers:
71
71
 
72
72
  - research: "Read $FOCUS/FOCUS.md. Give an honest, skeptical, specific cold take on the prompt. Clean markdown, no preamble."
73
73
  - plan: "Read $FOCUS/FOCUS.md and any ../research/*-FINAL.md if present. Write a concrete step-by-step plan for this prompt: goal, scope, numbered steps, risks, success criteria. Be KISS. Clean markdown."
74
- - execute: "Read $FOCUS/FOCUS.md and the plan at $FOCUS/plan/*-FINAL.md. Execute the plan IN YOUR PEER WORKSPACE at .paircode/peers/{peer-id}/ — that is your persistent sandbox. Write code there, run commands there. Do NOT touch files outside that workspace. Then write a markdown report to your output file summarizing: what you built, files touched (paths relative to your peer workspace), tests/verification status, what's open. The output file holds the report; the code lives in your peer workspace."
74
+ - execute: "Read $FOCUS/FOCUS.md and the plan at $FOCUS/plan/*-FINAL.md. Execute the plan IN YOUR PEER WORKSPACE at .paircode/sandbox/{peer-id}/ — that is your persistent sandbox. Write code there, run commands there. Do NOT touch files outside that workspace. Then write a markdown report to your output file summarizing: what you built, files touched (paths relative to your peer workspace), tests/verification status, what's open. The output file holds the report; the code lives in your peer workspace."
75
75
  - ask: "Read $FOCUS/FOCUS.md and the artifact it points to. Give your honest critique — severity-ranked findings with file:line citations where possible. Clean markdown, no preamble."
76
76
 
77
77
  ## Step 4 — Team lead's own take
78
78
 
79
79
  After the serial peer loop completes, write your own v1 to $FOCUS/{stage}/alpha-v1.md via run_shell_command (cat > ... <<'EOF' or equivalent). Same stage-appropriate rules — your advantage over the peers is session context.
80
80
 
81
- **Execute-stage asymmetry:** when {stage} is execute, peers code inside their sandboxed peer workspaces (.paircode/peers/{peer-id}/). You, alpha, code directly in the project root — the user's actual repo. Your alpha-v1.md is a report summarizing what landed in the real project files; the code itself lives in the repo, not in $FOCUS/execute/.
81
+ **Execute-stage asymmetry:** when {stage} is execute, peers code inside their sandboxed peer workspaces (.paircode/sandbox/{peer-id}/). You, alpha, code directly in the project root — the user's actual repo. Your alpha-v1.md is a report summarizing what landed in the real project files; the code itself lives in the repo, not in $FOCUS/execute/.
82
82
 
83
83
  ## Step 5 — Wait and read
84
84
 
@@ -5,7 +5,7 @@
5
5
  # project root.
6
6
  #
7
7
  # Every other LLM that participates is a peer. Each peer gets an entry
8
- # below AND a folder at .paircode/peers/peer-N-{cli}/.
8
+ # below AND a folder at .paircode/sandbox/peer-N-{cli}/.
9
9
  #
10
10
  # Fields:
11
11
  # id — peer-a, peer-b, peer-c, ... (unique, immutable)
@@ -22,13 +22,13 @@ def test_init_creates_paircode_structure(tmp_path: Path):
22
22
  assert state.root.is_dir()
23
23
  assert state.journey_path.exists()
24
24
  assert state.peers_path.exists()
25
- assert state.peers_dir.is_dir()
25
+ assert state.sandbox_dir.is_dir()
26
26
  assert state.focus_count == 0
27
27
  assert state.active_focus is None
28
28
 
29
29
 
30
30
  def test_init_scaffolds_peer_dirs_from_detected_clis(tmp_path: Path, monkeypatch):
31
- """init_paircode should create .paircode/peers/{id}/ for each detected peer."""
31
+ """init_paircode should create .paircode/sandbox/{id}/ for each detected peer."""
32
32
  fake_proposed = [
33
33
  ProposedPeer(id="peer-a-codex", cli="codex", priority="high", notes=""),
34
34
  ProposedPeer(id="peer-b-gemini", cli="gemini", priority="low", notes=""),
@@ -36,15 +36,15 @@ def test_init_scaffolds_peer_dirs_from_detected_clis(tmp_path: Path, monkeypatch
36
36
  monkeypatch.setattr("paircode.handshake.propose_roster", lambda: fake_proposed)
37
37
 
38
38
  state = init_paircode(tmp_path)
39
- assert (state.peers_dir / "peer-a-codex").is_dir()
40
- assert (state.peers_dir / "peer-b-gemini").is_dir()
39
+ assert (state.sandbox_dir / "peer-a-codex").is_dir()
40
+ assert (state.sandbox_dir / "peer-b-gemini").is_dir()
41
41
 
42
42
 
43
- def test_init_with_no_detected_peers_leaves_peers_dir_empty(tmp_path: Path, monkeypatch):
43
+ def test_init_with_no_detected_peers_leaves_sandbox_dir_empty(tmp_path: Path, monkeypatch):
44
44
  monkeypatch.setattr("paircode.handshake.propose_roster", lambda: [])
45
45
  state = init_paircode(tmp_path)
46
- assert state.peers_dir.is_dir()
47
- assert list(state.peers_dir.iterdir()) == []
46
+ assert state.sandbox_dir.is_dir()
47
+ assert list(state.sandbox_dir.iterdir()) == []
48
48
 
49
49
 
50
50
  def test_ensure_peer_dirs_accepts_dicts_and_is_idempotent(tmp_path: Path, monkeypatch):
@@ -54,7 +54,7 @@ def test_ensure_peer_dirs_accepts_dicts_and_is_idempotent(tmp_path: Path, monkey
54
54
  dicts = [{"id": "peer-a-codex", "cli": "codex"}, {"id": "peer-c-ollama"}]
55
55
  created = ensure_peer_dirs(state, dicts)
56
56
  assert len(created) == 2
57
- assert (state.peers_dir / "peer-a-codex").is_dir()
57
+ assert (state.sandbox_dir / "peer-a-codex").is_dir()
58
58
  # Running again is a no-op (idempotent)
59
59
  created_again = ensure_peer_dirs(state, dicts)
60
60
  assert len(created_again) == 2
File without changes
File without changes
File without changes
File without changes
File without changes