paircode 0.10.1__tar.gz → 0.11.3__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 (42) hide show
  1. {paircode-0.10.1 → paircode-0.11.3}/.gitignore +3 -0
  2. paircode-0.11.3/PKG-INFO +154 -0
  3. paircode-0.11.3/README.md +126 -0
  4. paircode-0.11.3/diary/002-v0.10-release-pipeline.md +126 -0
  5. paircode-0.11.3/diary/003-arch-b-pivot-grappling.md +133 -0
  6. {paircode-0.10.1 → paircode-0.11.3}/pyproject.toml +1 -1
  7. {paircode-0.10.1 → paircode-0.11.3}/src/paircode/__init__.py +1 -1
  8. paircode-0.11.3/src/paircode/cli.py +354 -0
  9. paircode-0.10.1/src/paircode/seal.py → paircode-0.11.3/src/paircode/converge.py +8 -4
  10. {paircode-0.10.1 → paircode-0.11.3}/src/paircode/handshake.py +6 -8
  11. {paircode-0.10.1 → paircode-0.11.3}/src/paircode/installer.py +37 -21
  12. {paircode-0.10.1 → paircode-0.11.3}/src/paircode/state.py +56 -10
  13. paircode-0.11.3/src/paircode/templates/claude/commands/paircode.md +169 -0
  14. paircode-0.11.3/src/paircode/templates/codex/commands/paircode.md +161 -0
  15. paircode-0.11.3/src/paircode/templates/gemini/commands/paircode.toml +152 -0
  16. {paircode-0.10.1 → paircode-0.11.3}/src/paircode/templates/peers.yaml +0 -1
  17. paircode-0.11.3/src/paircode/util.py +18 -0
  18. paircode-0.11.3/tests/test_cli_smoke.py +668 -0
  19. paircode-0.10.1/tests/test_seal.py → paircode-0.11.3/tests/test_converge.py +2 -2
  20. {paircode-0.10.1 → paircode-0.11.3}/tests/test_smoke.py +4 -18
  21. {paircode-0.10.1 → paircode-0.11.3}/tests/test_state.py +40 -1
  22. paircode-0.10.1/PKG-INFO +0 -160
  23. paircode-0.10.1/README.md +0 -132
  24. paircode-0.10.1/src/paircode/cli.py +0 -419
  25. paircode-0.10.1/src/paircode/drive.py +0 -385
  26. paircode-0.10.1/src/paircode/gates.py +0 -62
  27. paircode-0.10.1/src/paircode/journey.py +0 -63
  28. paircode-0.10.1/src/paircode/templates/claude_slash_command.md +0 -23
  29. paircode-0.10.1/src/paircode/templates/codex_rules.md +0 -13
  30. paircode-0.10.1/src/paircode/templates/codex_slash_command.md +0 -24
  31. paircode-0.10.1/src/paircode/templates/gemini_slash_command.toml +0 -25
  32. paircode-0.10.1/tests/test_cli_smoke.py +0 -377
  33. paircode-0.10.1/tests/test_drive.py +0 -146
  34. paircode-0.10.1/tests/test_gates.py +0 -49
  35. {paircode-0.10.1 → paircode-0.11.3}/LICENSE +0 -0
  36. {paircode-0.10.1 → paircode-0.11.3}/diary/001-step-a-architecture.md +0 -0
  37. {paircode-0.10.1 → paircode-0.11.3}/src/paircode/__main__.py +0 -0
  38. {paircode-0.10.1 → paircode-0.11.3}/src/paircode/detect.py +0 -0
  39. {paircode-0.10.1 → paircode-0.11.3}/src/paircode/runner.py +0 -0
  40. {paircode-0.10.1 → paircode-0.11.3}/src/paircode/templates/FOCUS.md +0 -0
  41. {paircode-0.10.1 → paircode-0.11.3}/src/paircode/templates/JOURNEY.md +0 -0
  42. {paircode-0.10.1 → paircode-0.11.3}/tests/__init__.py +0 -0
@@ -35,3 +35,6 @@ ENV/
35
35
  /tmp/
36
36
  scratch/
37
37
  dist/
38
+
39
+ # paircode runtime state (focuses, peer workspaces, etc.)
40
+ .paircode/
@@ -0,0 +1,154 @@
1
+ Metadata-Version: 2.4
2
+ Name: paircode
3
+ Version: 0.11.3
4
+ Summary: Adversarial journey framework — orchestrate multiple LLM peers through research, plan, and execute stages with file-trace peer review.
5
+ Project-URL: Homepage, https://github.com/starshipagentic/paircode
6
+ Project-URL: Repository, https://github.com/starshipagentic/paircode
7
+ Project-URL: Issues, https://github.com/starshipagentic/paircode/issues
8
+ Author-email: Travis Somerville <travis.somerville@gmail.com>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: agents,claude,codex,gemini,llm,multi-agent,ollama,orchestration,peer-review
12
+ Classifier: Development Status :: 2 - Pre-Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Software Development
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: click>=8.1
24
+ Requires-Dist: cliworker>=0.8.1
25
+ Requires-Dist: pyyaml>=6.0
26
+ Requires-Dist: rich>=13.0
27
+ Description-Content-Type: text/markdown
28
+
29
+ # paircode
30
+
31
+ **Multi-LLM peer review for your code, with file-traces on disk.** One primary LLM (alpha, usually Claude Code) + any number of peer LLMs (Codex, Gemini, Ollama, …) running research / plan / execute / ask cycles with structured cross-review rounds stored entirely as Markdown on disk.
32
+
33
+ > Born from 31 iterations of dual-LLM silent-agreement hunting on a real ML project. See `diary/001-step-a-architecture.md` for the origin story and `diary/003-arch-b-pivot-grappling.md` for the current (v0.11) team-lead architecture.
34
+
35
+ ## Install
36
+
37
+ ```bash
38
+ pipx install paircode # or: pip install --user paircode
39
+ paircode install # registers /paircode in every detected LLM CLI
40
+ ```
41
+
42
+ `paircode install` deploys `/paircode` into each LLM CLI it finds on your PATH:
43
+
44
+ | CLI | How it's installed | What you get |
45
+ |---|---|---|
46
+ | Claude Code | file-drop `~/.claude/commands/paircode.md` | `/paircode` slash command |
47
+ | Codex CLI | `codex marketplace add starshipagentic/paircode-codex` | `/paircode` slash command |
48
+ | Gemini CLI | `gemini extensions install github.com/starshipagentic/paircode-gemini --consent` | `/paircode` slash command |
49
+
50
+ In Gemini you may need `/commands reload` the first time. In Codex the marketplace fetches on first use.
51
+
52
+ paircode delegates LLM subprocess invocation to [`cliworker`](https://pypi.org/project/cliworker/) — that's where speed flags, MCP strip tricks, skip-cache, and subscription-first fallback live. paircode adds the peer-review orchestration on top (file-traces, stages, rosters, convergence).
53
+
54
+ ## Use it
55
+
56
+ Inside any LLM CLI that has `/paircode` installed, just type:
57
+
58
+ ```
59
+ /paircode "build a KISS PHQ-9 depression risk engine"
60
+ ```
61
+
62
+ or
63
+
64
+ ```
65
+ /paircode "review my auth middleware approach at src/auth/"
66
+ /paircode "plan the refactor" --peers codex,gemini
67
+ /paircode "get a second opinion on this PR" --peer gemini
68
+ ```
69
+
70
+ The slash command's team-lead prompt (the LLM you're inside) reads your prompt, picks a stage (`research | plan | execute | ask`), fires peers, collects their markdown, iterates through review rounds until convergence, and writes `consensus.md` at the end. Everything lands under `.paircode/` in your current project.
71
+
72
+ ## What ends up on disk
73
+
74
+ ```
75
+ your-project/
76
+ .paircode/
77
+ JOURNEY.md # fleet log
78
+ peers.yaml # roster: who's on the team
79
+ peers/
80
+ peer-a-codex/ # codex's persistent sandbox (code goes here)
81
+ peer-b-gemini/ # gemini's persistent sandbox
82
+ focus-01-<slug>/
83
+ FOCUS.md # this focus's prompt + metadata
84
+ research/
85
+ alpha-v1.md ... alpha-vN.md
86
+ peer-a-codex-v1.md ...
87
+ reviews/round-01-peer-a-codex-critiques-alpha.md
88
+ alpha-FINAL.md
89
+ peer-a-codex-FINAL.md
90
+ consensus.md # team-lead synthesis (last thing written)
91
+ plan/ (same shape)
92
+ execute/ (same shape)
93
+ ask/ (same shape)
94
+ focus-02-<slug>/
95
+ ...
96
+ ```
97
+
98
+ **Code vs. reports.** Files inside `focus-*/` are markdown *reports* (opinions, plans, critiques, summaries of work). Actual code lives elsewhere:
99
+
100
+ - **Peers** code in their sandboxed workspaces at `.paircode/peers/<peer-id>/` — persistent across focuses.
101
+ - **Alpha** codes directly in the project root (the real repo) — alpha *is* the project.
102
+
103
+ ## Stages
104
+
105
+ Stage is picked by the team-lead LLM based on the prompt:
106
+
107
+ | Stage | When | Typical prompt |
108
+ |---|---|---|
109
+ | `research` | Explore new ground | "build X", "find the right Y", "how should we approach Z" |
110
+ | `plan` | Concrete implementation plan from prior research | "plan the refactor based on focus-02" |
111
+ | `execute` | Do the work from an existing plan | "execute the plan at focus-02" |
112
+ | `ask` | Get opinions on existing work | "what does codex think of this PR", "review my approach at <path>" |
113
+
114
+ The team lead can chain stages in one invocation: `research → plan → execute → done`. No hard round cap — the team lead converges when peers stop surfacing new signal.
115
+
116
+ ## Commands (the helper CLI)
117
+
118
+ Most users will only ever type `paircode install` and then use `/paircode` inside their LLM CLI. The binary's other commands are helpers the team-lead slash command calls on your behalf:
119
+
120
+ ```
121
+ paircode print current .paircode/ state
122
+ paircode install register /paircode in every detected LLM CLI
123
+ paircode uninstall remove /paircode from LLM CLIs (idempotent)
124
+ paircode ensure-scaffold idempotent .paircode/ init + handshake (silent)
125
+ paircode focus new <slug> create a new focus dir, print its path
126
+ paircode focus active print the active focus path
127
+ paircode roster [--alpha <cli>] [--peer <id>] [--peers <id,id>]
128
+ print peer ids, best-effort, never errors
129
+ paircode invoke <peer-id> "<prompt>" --out <path>
130
+ fire one peer, write file-trace to --out
131
+ paircode converge <stage> copy each participant's latest vN to *-FINAL.md
132
+ ```
133
+
134
+ ## Model compatibility
135
+
136
+ | CLI | `/paircode` slash command | Peer invocation | Parallel peers? | Status |
137
+ |---|---|---|---|---|
138
+ | Claude Code (`claude`) | ✓ file-drop at `~/.claude/commands/paircode.md` | ✓ `claude -p <prompt>` | ✓ via Agent tool + `run_in_background=true` | stable |
139
+ | Codex (`codex`) | ✓ via `codex marketplace add` | ✓ `codex exec <prompt>` | ✗ serial-only (codex constraint) | stable |
140
+ | Gemini (`gemini`) | ✓ via `gemini extensions install` | ✓ `gemini -p <prompt>` | ✗ serial-only (gemini constraint) | stable |
141
+ | Ollama (`ollama`) | — (local models, no slash-cmd host) | ✓ `ollama run <model> <prompt>` | n/a | peer-only |
142
+ | Aider / others | — | best-effort, PRs welcome | — | planned |
143
+
144
+ Peer roster is auto-detected at first install via `paircode handshake` (silent, called by `ensure-scaffold`). Edit `.paircode/peers.yaml` to customize.
145
+
146
+ ## Why this exists
147
+
148
+ See [`diary/001-step-a-architecture.md`](diary/001-step-a-architecture.md). Short version: running two LLMs adversarially surfaces silent-agreement bug classes that neither engine alone catches — cross-engine agreement is not the same as correctness when both engines share a blind spot.
149
+
150
+ See [`diary/003-arch-b-pivot-grappling.md`](diary/003-arch-b-pivot-grappling.md) for why v0.11 moved orchestration out of a Python driver and into the slash-command's team-lead LLM.
151
+
152
+ ## License
153
+
154
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,126 @@
1
+ # paircode
2
+
3
+ **Multi-LLM peer review for your code, with file-traces on disk.** One primary LLM (alpha, usually Claude Code) + any number of peer LLMs (Codex, Gemini, Ollama, …) running research / plan / execute / ask cycles with structured cross-review rounds stored entirely as Markdown on disk.
4
+
5
+ > Born from 31 iterations of dual-LLM silent-agreement hunting on a real ML project. See `diary/001-step-a-architecture.md` for the origin story and `diary/003-arch-b-pivot-grappling.md` for the current (v0.11) team-lead architecture.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pipx install paircode # or: pip install --user paircode
11
+ paircode install # registers /paircode in every detected LLM CLI
12
+ ```
13
+
14
+ `paircode install` deploys `/paircode` into each LLM CLI it finds on your PATH:
15
+
16
+ | CLI | How it's installed | What you get |
17
+ |---|---|---|
18
+ | Claude Code | file-drop `~/.claude/commands/paircode.md` | `/paircode` slash command |
19
+ | Codex CLI | `codex marketplace add starshipagentic/paircode-codex` | `/paircode` slash command |
20
+ | Gemini CLI | `gemini extensions install github.com/starshipagentic/paircode-gemini --consent` | `/paircode` slash command |
21
+
22
+ In Gemini you may need `/commands reload` the first time. In Codex the marketplace fetches on first use.
23
+
24
+ paircode delegates LLM subprocess invocation to [`cliworker`](https://pypi.org/project/cliworker/) — that's where speed flags, MCP strip tricks, skip-cache, and subscription-first fallback live. paircode adds the peer-review orchestration on top (file-traces, stages, rosters, convergence).
25
+
26
+ ## Use it
27
+
28
+ Inside any LLM CLI that has `/paircode` installed, just type:
29
+
30
+ ```
31
+ /paircode "build a KISS PHQ-9 depression risk engine"
32
+ ```
33
+
34
+ or
35
+
36
+ ```
37
+ /paircode "review my auth middleware approach at src/auth/"
38
+ /paircode "plan the refactor" --peers codex,gemini
39
+ /paircode "get a second opinion on this PR" --peer gemini
40
+ ```
41
+
42
+ The slash command's team-lead prompt (the LLM you're inside) reads your prompt, picks a stage (`research | plan | execute | ask`), fires peers, collects their markdown, iterates through review rounds until convergence, and writes `consensus.md` at the end. Everything lands under `.paircode/` in your current project.
43
+
44
+ ## What ends up on disk
45
+
46
+ ```
47
+ your-project/
48
+ .paircode/
49
+ JOURNEY.md # fleet log
50
+ peers.yaml # roster: who's on the team
51
+ peers/
52
+ peer-a-codex/ # codex's persistent sandbox (code goes here)
53
+ peer-b-gemini/ # gemini's persistent sandbox
54
+ focus-01-<slug>/
55
+ FOCUS.md # this focus's prompt + metadata
56
+ research/
57
+ alpha-v1.md ... alpha-vN.md
58
+ peer-a-codex-v1.md ...
59
+ reviews/round-01-peer-a-codex-critiques-alpha.md
60
+ alpha-FINAL.md
61
+ peer-a-codex-FINAL.md
62
+ consensus.md # team-lead synthesis (last thing written)
63
+ plan/ (same shape)
64
+ execute/ (same shape)
65
+ ask/ (same shape)
66
+ focus-02-<slug>/
67
+ ...
68
+ ```
69
+
70
+ **Code vs. reports.** Files inside `focus-*/` are markdown *reports* (opinions, plans, critiques, summaries of work). Actual code lives elsewhere:
71
+
72
+ - **Peers** code in their sandboxed workspaces at `.paircode/peers/<peer-id>/` — persistent across focuses.
73
+ - **Alpha** codes directly in the project root (the real repo) — alpha *is* the project.
74
+
75
+ ## Stages
76
+
77
+ Stage is picked by the team-lead LLM based on the prompt:
78
+
79
+ | Stage | When | Typical prompt |
80
+ |---|---|---|
81
+ | `research` | Explore new ground | "build X", "find the right Y", "how should we approach Z" |
82
+ | `plan` | Concrete implementation plan from prior research | "plan the refactor based on focus-02" |
83
+ | `execute` | Do the work from an existing plan | "execute the plan at focus-02" |
84
+ | `ask` | Get opinions on existing work | "what does codex think of this PR", "review my approach at <path>" |
85
+
86
+ The team lead can chain stages in one invocation: `research → plan → execute → done`. No hard round cap — the team lead converges when peers stop surfacing new signal.
87
+
88
+ ## Commands (the helper CLI)
89
+
90
+ Most users will only ever type `paircode install` and then use `/paircode` inside their LLM CLI. The binary's other commands are helpers the team-lead slash command calls on your behalf:
91
+
92
+ ```
93
+ paircode print current .paircode/ state
94
+ paircode install register /paircode in every detected LLM CLI
95
+ paircode uninstall remove /paircode from LLM CLIs (idempotent)
96
+ paircode ensure-scaffold idempotent .paircode/ init + handshake (silent)
97
+ paircode focus new <slug> create a new focus dir, print its path
98
+ paircode focus active print the active focus path
99
+ paircode roster [--alpha <cli>] [--peer <id>] [--peers <id,id>]
100
+ print peer ids, best-effort, never errors
101
+ paircode invoke <peer-id> "<prompt>" --out <path>
102
+ fire one peer, write file-trace to --out
103
+ paircode converge <stage> copy each participant's latest vN to *-FINAL.md
104
+ ```
105
+
106
+ ## Model compatibility
107
+
108
+ | CLI | `/paircode` slash command | Peer invocation | Parallel peers? | Status |
109
+ |---|---|---|---|---|
110
+ | Claude Code (`claude`) | ✓ file-drop at `~/.claude/commands/paircode.md` | ✓ `claude -p <prompt>` | ✓ via Agent tool + `run_in_background=true` | stable |
111
+ | Codex (`codex`) | ✓ via `codex marketplace add` | ✓ `codex exec <prompt>` | ✗ serial-only (codex constraint) | stable |
112
+ | Gemini (`gemini`) | ✓ via `gemini extensions install` | ✓ `gemini -p <prompt>` | ✗ serial-only (gemini constraint) | stable |
113
+ | Ollama (`ollama`) | — (local models, no slash-cmd host) | ✓ `ollama run <model> <prompt>` | n/a | peer-only |
114
+ | Aider / others | — | best-effort, PRs welcome | — | planned |
115
+
116
+ Peer roster is auto-detected at first install via `paircode handshake` (silent, called by `ensure-scaffold`). Edit `.paircode/peers.yaml` to customize.
117
+
118
+ ## Why this exists
119
+
120
+ See [`diary/001-step-a-architecture.md`](diary/001-step-a-architecture.md). Short version: running two LLMs adversarially surfaces silent-agreement bug classes that neither engine alone catches — cross-engine agreement is not the same as correctness when both engines share a blind spot.
121
+
122
+ See [`diary/003-arch-b-pivot-grappling.md`](diary/003-arch-b-pivot-grappling.md) for why v0.11 moved orchestration out of a Python driver and into the slash-command's team-lead LLM.
123
+
124
+ ## License
125
+
126
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,126 @@
1
+ # Diary 002 — v0.10 release pipeline + cliworker split + satellite repos
2
+
3
+ **Stardate:** 2026-04-18
4
+ **From:** v0.9.1 (file-drop install for all 3 CLIs)
5
+ **To:** v0.10.1 (native register via satellite repos, driven by `cliworker.invoke()`)
6
+
7
+ ---
8
+
9
+ ## Context — what v0.10 cracked open
10
+
11
+ Between v0.1 and v0.9 paircode's installer evolved through four bad implementations (broken codex rules file, per-CLI no-ops, file-drop, correct file-drop) before landing on the right answer in v0.10: use each vendor's own registration command, not file-drop.
12
+
13
+ Research (2026-04-18) confirmed both Codex and Gemini now have user-level slash-command registration:
14
+ - Codex 0.121.0 → `codex marketplace add <owner/repo>` (git-clones a marketplace repo)
15
+ - Gemini 0.35.3 → `gemini extensions install <url> --consent` (git-clones an extension repo)
16
+
17
+ Neither is deprecated (Codex has both `marketplace` and a now-deprecated `prompts/` file-drop). Industry pattern for tools installing their own slash commands → **native register when available**. So paircode joins that pattern.
18
+
19
+ ## The three-repo architecture
20
+
21
+ ```
22
+ ~/dev/paircode Python package (main repo, pypi)
23
+ ├── src/paircode/templates/
24
+ │ ├── claude_slash_command.md source of truth
25
+ │ ├── codex_slash_command.md ↓
26
+ │ └── gemini_slash_command.toml ↓
27
+ └── scripts/release.py auto-syncs to satellites
28
+
29
+ ~/dev/paircode-codex Codex marketplace satellite (GitHub only)
30
+ ├── .agents/plugins/marketplace.json
31
+ ├── plugins/paircode/
32
+ │ ├── .codex-plugin/plugin.json
33
+ │ └── commands/paircode.md copied from paircode's template
34
+ └── README + LICENSE
35
+
36
+ ~/dev/paircode-gemini Gemini extension satellite (GitHub only)
37
+ ├── gemini-extension.json
38
+ ├── commands/paircode.toml copied from paircode's template
39
+ └── README + LICENSE
40
+ ```
41
+
42
+ **Zero Python in the satellites.** The Python `paircode` CLI lives once, on pypi. Satellites hold only the slash-command manifest each vendor expects. `/paircode` triggers a markdown/TOML prompt telling the host CLI to shell out to the `paircode` binary — which the user already installed via `pipx install paircode`.
43
+
44
+ ## Install flow after v0.10
45
+
46
+ ```bash
47
+ pipx install paircode # Python binary, once
48
+ paircode install # registers /paircode in every detected LLM CLI
49
+ ```
50
+
51
+ `paircode install` does per CLI:
52
+ - **claude** — file-drop `~/.claude/commands/paircode.md` (unchanged, it's the native pattern)
53
+ - **codex** — `cliworker.invoke("codex", "marketplace", "add", "starshipagentic/paircode-codex")`
54
+ - **gemini** — `cliworker.invoke("gemini", "extensions", "install", "https://github.com/starshipagentic/paircode-gemini", "--consent")`
55
+
56
+ All three idempotent:
57
+ - claude overwrites file (harmless)
58
+ - codex greps `~/.codex/config.toml` for `[marketplaces.paircode]` before invoking
59
+ - gemini greps `gemini extensions list` for `paircode` before invoking
60
+
61
+ All three graceful on failure:
62
+ - If the `invoke()` call returns ok=False, installer prints the exact command for copy-paste + captured stderr
63
+ - Never silently succeeds with a non-working state
64
+
65
+ ## Why `cliworker.invoke()` exists
66
+
67
+ cliworker already had `run(prompt, *clis, ...)` for LLM invocation. Admin commands like `codex marketplace add` aren't LLM invocations — no prompt, no API-key stripping, no CLAUDE_FAST, no fallback chain. But they DO want cliworker's subprocess plumbing: timeout, FileNotFoundError handling, `CLIResult` dataclass, skip-cache opt-in.
68
+
69
+ v0.8 of cliworker added `invoke(cli, *args, ...)` — same subprocess guts, no LLM semantics. Default `stdin=DEVNULL` so any unexpected interactive prompt fails fast instead of hanging (critical: Gemini's `extensions install` has a fallback "install via git clone?" prompt if the GitHub release is missing).
70
+
71
+ Paircode uses it. Navcom can use it later. Any tool that wants "run a CLI, get a CLIResult back" gets it for free.
72
+
73
+ ## The release pipeline
74
+
75
+ `scripts/release.py` is the only command needed to cut a paircode release:
76
+
77
+ ```bash
78
+ cd ~/dev/paircode
79
+ ./scripts/release.py 0.11.0 # explicit version
80
+ ./scripts/release.py patch # auto-bump patch segment
81
+ ./scripts/release.py minor
82
+ ./scripts/release.py --dry-run 0.11.0 # preview, write nothing
83
+ ```
84
+
85
+ What it does in order:
86
+ 1. Preflight — working trees clean, tests pass, required tools present (git, starforge, gh)
87
+ 2. Bump paircode version in `pyproject.toml` + `src/paircode/__init__.py`
88
+ 3. Commit + tag + push paircode to GitHub
89
+ 4. `starforge beam --pypi` → publishes to pypi (with user's auto-approved yes pipe)
90
+ 5. For each satellite:
91
+ - Copy latest template from paircode's `src/paircode/templates/`
92
+ - Bump version in the satellite's manifest
93
+ - Commit + tag + push
94
+ - `starforge beam` (no --pypi, just GitHub)
95
+ - `gh release create` — **critical** for Gemini, which falls back to an interactive prompt when the release is missing
96
+ 6. Print summary with every URL
97
+
98
+ One command = pypi, main GitHub repo, both satellite GitHub repos, both satellite GitHub releases, all version-locked.
99
+
100
+ ## Open paper cuts (not shipping blockers)
101
+
102
+ - **`__version__` string drift** — starforge auto-bumps `pyproject.toml` version on publish (e.g., 0.10.0 → 0.10.1) but leaves `__init__.py` alone. Every release needs a manual follow-up commit to sync. The release.py script could detect starforge's bump and sync automatically; not implemented yet.
103
+ - **Codex has no uninstall CLI** — paircode's `uninstall` for codex edits `~/.codex/config.toml` directly (strips the `[marketplaces.paircode]` section). Fragile. If OpenAI adds `codex marketplace remove <name>`, migrate to that.
104
+ - **Gemini keychain warning** — on macOS Homebrew install, gemini prints `Keychain initialization encountered an error: Cannot find module '../build/Release/keytar.node'` before every command. It falls back to FileKeychain so everything still works. Not a paircode bug; noisy stderr captured in some idempotency checks. Could be suppressed.
105
+
106
+ ## Key files — where to look when something changes
107
+
108
+ | Change this template | Edit this file | Satellites auto-sync on next release |
109
+ |---|---|---|
110
+ | Claude slash command | `src/paircode/templates/claude_slash_command.md` | (only Claude; no satellite) |
111
+ | Codex slash command | `src/paircode/templates/codex_slash_command.md` | `paircode-codex/plugins/paircode/commands/paircode.md` |
112
+ | Gemini slash command | `src/paircode/templates/gemini_slash_command.toml` | `paircode-gemini/commands/paircode.toml` |
113
+ | Runner (subprocess → LLM) | `src/paircode/runner.py` (delegates to `cliworker.run`/`run_fast`) | — |
114
+ | Installer behavior | `src/paircode/installer.py` (delegates to `cliworker.invoke`) | — |
115
+ | Release steps | `scripts/release.py` | — |
116
+
117
+ ## Verified live (2026-04-18)
118
+
119
+ - `cliworker` 0.8.1 on pypi with `invoke()`
120
+ - `paircode` 0.10.1 on pypi, depends on `cliworker>=0.8.1`
121
+ - `starshipagentic/paircode-codex` at tag v0.10.0, GitHub release live
122
+ - `starshipagentic/paircode-gemini` at tag v0.10.0, GitHub release live
123
+ - End-to-end `paircode uninstall && paircode install` on dev machine: all three CLIs cleanly register/deregister, `/paircode` appears in each tool's slash menu
124
+ - 52 pytest green in paircode, 88 pytest green in cliworker
125
+
126
+ *End of diary 002. Next milestone targets: real-data validation, cross-project orchestration.*
@@ -0,0 +1,133 @@
1
+ # Diary 003 — Arch-B pivot: cold-use failure exposed Python-driven orchestrator as a regression
2
+
3
+ **Stardate:** 2026-04-20
4
+ **From:** v0.10.1 — Python-driven orchestrator (drive.py with ThreadPoolExecutor spawning fresh `claude -p` / `gemini -p` / `codex exec` subprocesses in parallel)
5
+ **Toward:** Arch B — interactive Claude session IS the team lead; Python shrinks to filesystem scaffolding + template rendering
6
+
7
+ **This diary is a preservation record, not a migration log.** No code has changed on `main` beyond this file. A companion branch `path-python-controls-stages` pins the current Python-driven state so we can return if Arch B underdelivers.
8
+
9
+ ---
10
+
11
+ ## What triggered this pivot
12
+
13
+ The maintainer ran `/paircode` cold in Claude Code after weeks away, trying to get a second opinion on an unrelated engineering question. He typed:
14
+
15
+ ```
16
+ /paircode use gemini for reserach only to 'i mean go look at their actual releases...'
17
+ ```
18
+
19
+ Four concrete failures in one invocation:
20
+
21
+ 1. **Slash command pass-through failed.** `~/.claude/commands/paircode.md` instructs the LLM to pass args literally to the CLI. `paircode use gemini for research only to '...'` → `Error: No such command 'use'`. The slash command's own literal-pass-through instruction is the failing case.
22
+ 2. **Fallback picked the wrong flag.** The previous session fell back to `paircode drive "<topic>" --alpha-cli gemini --research-only`. Wrong: `--alpha-cli` swaps the driver — it replaces Claude with Gemini as alpha. The maintainer wanted Claude (this session) to keep driving and Gemini to be added as a peer. Inverted alpha/peer.
23
+ 3. **No primitive for "just get an opinion".** The architecture has `research → plan → execute`. "What does Gemini think of X" isn't any of those — it's review-of-existing. No native primitive. The previous session hacked it with `--research-only`, which is semantically wrong.
24
+ 4. **Flag soup.** `--alpha-cli`, `--alpha-model`, `--timeout`, `--research-rounds`, `--plan-rounds`, `--execute-rounds`, `--research-only`. User has to pre-classify their task into flag combinations before typing the quoted prompt.
25
+
26
+ The redesign brief written mid-session (see conversation transcript 2026-04-20) names these as Gap 1–4.
27
+
28
+ ## What the maintainer wants
29
+
30
+ Single verb CLI:
31
+
32
+ ```
33
+ paircode "<whatever you want>" # ~95% of invocations
34
+ paircode "<whatever>" --peer gemini # filter roster to one peer
35
+ paircode "<whatever>" --peers gemini,codex # subset
36
+ ```
37
+
38
+ The LLM reads the quoted prompt and picks the right stages itself. Stages (research / plan / execute / ask-or-review) become invisible templates the LLMs consult, not CLI verbs the user types.
39
+
40
+ Plus the philosophy, stated verbatim in the session: *"my philosophy is auto fucking install bro!"* — setup work like `init`, `handshake` happens silently inside the main verb. Saved as a feedback memory under `/Users/t/.claude/projects/-Users-t-dev-paircode/memory/feedback_auto_install.md`.
41
+
42
+ ## The architectural fork — Arch A vs Arch B
43
+
44
+ The real discovery of this session is that today's `drive.py` architecture is **the opposite of what worked in the maintainer's original mlmodel repo.** Comparing the two:
45
+
46
+ | | Arch A — current paircode | Arch B — mlmodel pattern |
47
+ |---|---|---|
48
+ | Alpha identity | Fresh `claude -p` subprocess spawned by Python | Interactive Claude session where `/paircode` was typed |
49
+ | Alpha's context | None (headless, no memory, no session) | Full (session + user memory + project state) |
50
+ | Orchestrator | Python `ThreadPoolExecutor` in drive.py | The interactive Claude session itself, via its Bash + Agent tools |
51
+ | Claude peers | Fresh `claude -p` subprocess | In-process Agent tool subagents (background) |
52
+ | Codex/Gemini peers | `cliworker.run()` → shell subprocess | Bash subprocess |
53
+ | Runs after user closes Claude? | Yes (headless loop) | No (dies with session) |
54
+ | Python code surface | Large — drive.py, gates.py, ThreadPoolExecutor | Small — scaffold + template render |
55
+
56
+ **Evidence for Arch B being what the maintainer originally built:**
57
+
58
+ - `/Users/t/clients/syra/mlmodel/.claude/commands/peerkickoff.md` — team lead is the interactive Claude, spawns two Agent-tool subagents in parallel with `run_in_background=true`, then synthesizes.
59
+ - `/Users/t/clients/syra/mlmodel/.claude/commands/audit-me.md` — interactive Claude spawns one subagent that shells out to codex CLI for peer review.
60
+ - `/Users/t/clients/syra/mlmodel/.claude/commands/audit-codex.md` — interactive Claude does PART 1 (review) itself with full context, then spawns a subagent to fire codex for self-heal.
61
+ - **Zero Python orchestrator binary in mlmodel.** Slash command markdown + Bash + Agent tool handles everything.
62
+
63
+ The maintainer confirmed this was his "worked fucking great" baseline. Today's paircode drive.py is a regression introduced during vibe-coding that built a Python thread pool which spawns the very `claude -p` subprocess that strips alpha of its session context.
64
+
65
+ ## Decisions made in this session
66
+
67
+ **CLI surface (user-facing):**
68
+ - `paircode "<prompt>"` — the one verb.
69
+ - `paircode` bare — prints current state (eats what `status` used to do).
70
+ - `paircode install` / `paircode uninstall` — stay. One-time setup that writes to `~/.claude`, `~/.codex`, `~/.gemini`. Maintainer explicitly said this is fine because users self-selected into it by installing paircode.
71
+ - **Dies as user verbs:** `init`, `handshake`, `status`, `focus`, `stage`, `seal`, `drive`.
72
+
73
+ **Auto-silent preconditions inside the main verb:**
74
+ - If `.paircode/` missing → `init_paircode()` runs silently.
75
+ - If `peers.yaml` empty / stale → handshake runs silently.
76
+ - Focus creation is procedural (`open_focus()` in state.py), always-new-per-invocation by default, escape hatch `--continue` to reuse the most recent unsealed focus when the previous team lead flaked.
77
+
78
+ **Semantic decisions vs mechanical decisions:**
79
+ - LLMs decide: is this a new topic? is this round converged? which focus to continue? who gets which stage?
80
+ - Python decides: where files go on disk, how directories are scaffolded, template rendering, roster persistence.
81
+
82
+ **Sealing + consensus (the maintainer's design):**
83
+ - Team lead (interactive Claude) runs multiple rounds from the one `/paircode` invocation.
84
+ - When the team lead has heard enough, it tells each peer to write their `{peer}-FINAL.md`.
85
+ - Team lead then writes its own `alpha-FINAL.md`.
86
+ - Team lead reads all FINALs and writes a **new artifact: `consensus.md`** — the very last thing before closing out the focus.
87
+ - **Current prompts in drive.py do NOT describe any of this.** The maintainer had believed sealing logic was already in the prompts; verification showed it is not. This is a real prompt authoring task, not a memory of existing work.
88
+
89
+ **Capability syntax rejected:**
90
+ - Brief proposed `--peer gemini:opine` / `--peer codex:work` for inline capability override.
91
+ - Maintainer explicitly dislikes this. Capability stays in `.paircode/peers.yaml` only; edit the file if you want to change it. No per-invocation override flag.
92
+
93
+ ## Open tensions we are grappling with
94
+
95
+ 1. **Headless execution.** Arch A can run for an hour unattended after the user closes Claude. Arch B dies with the session. mlmodel worked fine without headless, but this is a genuine capability loss. Does it matter for the paircode use cases? Unresolved. Preservation branch exists partly because of this.
96
+ 2. **Claude-reviewing-Claude support.** mlmodel used Agent tool subagents for claude-on-claude peer review. paircode's current thesis is cross-vendor adversarial (different engines surface different blind spots). Do we keep Claude-on-Claude as an option or cut it for simplicity? Leaning toward cut, not decided.
97
+ 3. **Consensus.md prompt authoring.** The final-round team-lead prompt needs to instruct: seal each peer, write your own FINAL, read all FINALs, write `consensus.md`, report. Not drafted yet.
98
+ 4. **Codex + Gemini as team lead.** Slash commands are installed via satellites for all three CLIs. If `/paircode` is invoked inside Codex or Gemini (not Claude), can those hosts run the Arch B orchestration? Codex has subagent primitives; Gemini's are different. Cross-host parity for Arch B is an open question. Without parity, paircode is effectively Claude-first with Codex/Gemini as peers only.
99
+ 5. **`cliworker` dependency.** If the slash command does all subprocess work via its host CLI's Bash tool, `cliworker.run()` leaves the runtime path. cliworker still matters for `paircode install` (marketplace add, extensions install via `invoke()`). The LLM-call speed-flag logic currently in cliworker.run becomes dead code from paircode's perspective.
100
+ 6. **Testability.** Today's drive.py has unit tests (`tests/test_drive.py`). Arch B moves orchestration into slash command markdown, which is untestable by pytest. Smoke tests would have to shell out through a real LLM CLI — slow, flaky, costly. Mitigation: keep the procedural Python helpers (`init_paircode`, `open_focus`, template render, seal_stage) testable in isolation, and accept that the orchestration loop itself becomes an integration-test concern.
101
+
102
+ ## Why we're preserving now
103
+
104
+ Arch B is a bet. It matches the maintainer's philosophy, it matches the pattern that worked in mlmodel, it dissolves Gap 1–4 cleanly. But it trades away:
105
+
106
+ - Headless execution
107
+ - A testable orchestration loop
108
+ - Cross-host parity guarantees (Codex/Gemini may not support the team-lead pattern as cleanly)
109
+
110
+ If any of those turn out to matter more than they look like they do today, we come back to this branch. The Python-driven orchestrator at v0.10.1 is a working, shipped system with 52 green tests. Killing it without preservation would be a mistake.
111
+
112
+ ## Preservation details
113
+
114
+ - Branch `path-python-controls-stages` cut from `main` immediately after this diary commits.
115
+ - `main` continues toward the Arch B rewrite.
116
+ - The `drive` command, `run_stage`, `run_stage_cold`, `run_review_round`, `run_alpha_revision`, and the ThreadPoolExecutor orchestration in `drive.py` are expected to be deleted from `main` during the rewrite. They remain intact on the preservation branch.
117
+ - `state.py` (procedural scaffolding) stays on `main` unchanged — Arch B still uses it.
118
+ - `runner.py` / `cliworker` integration: fate undecided. See tension #5.
119
+
120
+ ## Key files as of this diary
121
+
122
+ | Concern | File | Fate in Arch B |
123
+ |---|---|---|
124
+ | `/paircode` slash command (Claude) | `src/paircode/templates/claude_slash_command.md` | **Rewritten** — becomes the orchestrator |
125
+ | `/paircode` slash command (Codex) | `src/paircode/templates/codex_slash_command.md` | Rewritten; parity with Claude version tbd |
126
+ | `/paircode` slash command (Gemini) | `src/paircode/templates/gemini_slash_command.toml` | Rewritten; parity tbd |
127
+ | Python CLI | `src/paircode/cli.py` | Reduced to `paircode "<prompt>"`, `install`, `uninstall`, bare-state |
128
+ | Drive loop | `src/paircode/drive.py` | **Deleted** on main, preserved on branch |
129
+ | State scaffolding | `src/paircode/state.py` | Kept |
130
+ | Runner | `src/paircode/runner.py` | Undecided |
131
+ | Seal | `src/paircode/seal.py` | Kept as a helper the slash command can call silently |
132
+
133
+ *End of diary 003. Next session: draft the rewritten slash command template + the trimmed Python CLI.*
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "paircode"
7
- version = "0.10.1"
7
+ version = "0.11.3"
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" }
@@ -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.10.0"
5
+ __version__ = "0.11.2"