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.
- {paircode-0.10.1 → paircode-0.11.3}/.gitignore +3 -0
- paircode-0.11.3/PKG-INFO +154 -0
- paircode-0.11.3/README.md +126 -0
- paircode-0.11.3/diary/002-v0.10-release-pipeline.md +126 -0
- paircode-0.11.3/diary/003-arch-b-pivot-grappling.md +133 -0
- {paircode-0.10.1 → paircode-0.11.3}/pyproject.toml +1 -1
- {paircode-0.10.1 → paircode-0.11.3}/src/paircode/__init__.py +1 -1
- paircode-0.11.3/src/paircode/cli.py +354 -0
- paircode-0.10.1/src/paircode/seal.py → paircode-0.11.3/src/paircode/converge.py +8 -4
- {paircode-0.10.1 → paircode-0.11.3}/src/paircode/handshake.py +6 -8
- {paircode-0.10.1 → paircode-0.11.3}/src/paircode/installer.py +37 -21
- {paircode-0.10.1 → paircode-0.11.3}/src/paircode/state.py +56 -10
- paircode-0.11.3/src/paircode/templates/claude/commands/paircode.md +169 -0
- paircode-0.11.3/src/paircode/templates/codex/commands/paircode.md +161 -0
- paircode-0.11.3/src/paircode/templates/gemini/commands/paircode.toml +152 -0
- {paircode-0.10.1 → paircode-0.11.3}/src/paircode/templates/peers.yaml +0 -1
- paircode-0.11.3/src/paircode/util.py +18 -0
- paircode-0.11.3/tests/test_cli_smoke.py +668 -0
- paircode-0.10.1/tests/test_seal.py → paircode-0.11.3/tests/test_converge.py +2 -2
- {paircode-0.10.1 → paircode-0.11.3}/tests/test_smoke.py +4 -18
- {paircode-0.10.1 → paircode-0.11.3}/tests/test_state.py +40 -1
- paircode-0.10.1/PKG-INFO +0 -160
- paircode-0.10.1/README.md +0 -132
- paircode-0.10.1/src/paircode/cli.py +0 -419
- paircode-0.10.1/src/paircode/drive.py +0 -385
- paircode-0.10.1/src/paircode/gates.py +0 -62
- paircode-0.10.1/src/paircode/journey.py +0 -63
- paircode-0.10.1/src/paircode/templates/claude_slash_command.md +0 -23
- paircode-0.10.1/src/paircode/templates/codex_rules.md +0 -13
- paircode-0.10.1/src/paircode/templates/codex_slash_command.md +0 -24
- paircode-0.10.1/src/paircode/templates/gemini_slash_command.toml +0 -25
- paircode-0.10.1/tests/test_cli_smoke.py +0 -377
- paircode-0.10.1/tests/test_drive.py +0 -146
- paircode-0.10.1/tests/test_gates.py +0 -49
- {paircode-0.10.1 → paircode-0.11.3}/LICENSE +0 -0
- {paircode-0.10.1 → paircode-0.11.3}/diary/001-step-a-architecture.md +0 -0
- {paircode-0.10.1 → paircode-0.11.3}/src/paircode/__main__.py +0 -0
- {paircode-0.10.1 → paircode-0.11.3}/src/paircode/detect.py +0 -0
- {paircode-0.10.1 → paircode-0.11.3}/src/paircode/runner.py +0 -0
- {paircode-0.10.1 → paircode-0.11.3}/src/paircode/templates/FOCUS.md +0 -0
- {paircode-0.10.1 → paircode-0.11.3}/src/paircode/templates/JOURNEY.md +0 -0
- {paircode-0.10.1 → paircode-0.11.3}/tests/__init__.py +0 -0
paircode-0.11.3/PKG-INFO
ADDED
|
@@ -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.
|
|
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" }
|