claude-codex-pair 0.4.0 → 0.5.1

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.
package/DESIGN.md CHANGED
@@ -7,7 +7,7 @@ and they talk through a shared directory that works like a chat channel.
7
7
 
8
8
  | Topic | Choice |
9
9
  |---|---|
10
- | Topology | Two live sessions. No headless spawning. |
10
+ | Topology | Manual mode uses two live sessions. Opt-in `pair start --as <author>` owns an interactive author and starts a headless reviewer for each round. |
11
11
  | Roles | Symmetric. Either agent can author or review. |
12
12
  | Interface | One `pair` CLI (Node/TS). The agents learn it from a thin prompt: a Claude skill and an AGENTS.md section for Codex. |
13
13
  | Waiting | `pair wait` checks the files every second and returns as soon as a message arrives. By default it gives up after 540s, printing `no message … yet` and exiting 0 (agent UIs show any non-zero exit as a failure), which keeps a foreground run under Claude Code's 10-minute Bash cap. Interactive Claude Code sessions run `pair wait --timeout 3600` as a background command and spend no model turns until it exits. Codex can't do the same, because a finished background command doesn't resume it. Instead, pair's MCP server queues a fixed note into the Codex session when a message is pending (see Notifications), so an idle Codex makes no model calls. Codex never polls, because each check of a running command is a model call: without the MCP server it checks once and the user asks it to check again. Headless runs wait in the foreground. |
@@ -86,7 +86,9 @@ at most once a day, cache the answer under the state directory, and stay quiet o
86
86
  to stderr after the command's own output, so `pair wait`'s first line is still the delivery or
87
87
  timeout line agents read. `pair upgrade` installs with npm, then runs the `init` of the package it
88
88
  just installed (found with `npm root --global`), not the first `pair` on PATH, because both this
89
- process and an older copy on PATH would write the old templates.
89
+ process and an older copy on PATH would write the old templates. It asks `npm view` first, so it uses
90
+ the same registry as the install. Already on the latest version, it only runs the in-process
91
+ refresh. If the check fails, it goes ahead with the install, which reports the actual npm error.
90
92
 
91
93
  Channel operations report `EACCES` and `EPERM` with the affected path and the sandbox
92
94
  configuration printed by `init`. Either ordinary permissions or sandbox restrictions can
@@ -144,6 +146,76 @@ A note already accepted by the daemon still runs either way, so the prompt tells
144
146
  note that arrives after the user said stop. A repeated note costs one short
145
147
  turn: `pair wait --timeout 5` prints `no message` and Codex ends its turn.
146
148
 
149
+ ## Auto sessions
150
+
151
+ `pair start` runs in the user's terminal outside agent sandboxes. It resolves both CLI executables
152
+ once, binds a private Unix control socket for this worktree/channel/state-directory combination,
153
+ and forks an IPC guardian. A second launcher cannot bind that socket. `pair status` and `pair stop`
154
+ contact the live owner; persisted PIDs are diagnostic only. State and rotating reviewer logs are
155
+ kept beside the existing listener state. The short socket path is under a private
156
+ `/tmp/pair-auto-<uid>/` directory (or `PAIR_AUTO_SOCKET_DIR`) because macOS limits Unix socket path
157
+ length. The path is canonicalized, and a Claude author receives an exact, per-session
158
+ `sandbox.network.allowUnixSockets` entry through `--settings`. No global settings file is edited.
159
+
160
+ The guardian owns the interactive author and each bounded reviewer in separate Unix process groups.
161
+ The author inherits the terminal streams; the guardian forwards resize signals. Since `setsid`
162
+ removes its controlling terminal, `/dev/tty` consumers and Ctrl+Z job control are unsupported.
163
+ The launcher saves tty state and restores it during cleanup, and the guardian does so if the
164
+ launcher dies. Reviewers stream
165
+ JSON events into the launcher, which records their session IDs. Each request/response from the auto
166
+ author asks the owner to run one review round and waits for its result over the control socket.
167
+ The owner validates that the message is pending in its author's lane. Duplicate requests for the
168
+ same running message share the job. A saved session is resumed only within the same review thread;
169
+ no `--last` session lookup is used.
170
+
171
+ Optional `--reviewer-model` and `--reviewer-effort` overrides are applied on every reviewer launch,
172
+ including resume. Codex receives `--model` and `--config model_reasoning_effort="LEVEL"`; Claude
173
+ receives `--model` and `--effort`. Overrides never enter the interactive author's arguments or
174
+ persist to either CLI's config. The live state reports these requested overrides and labels
175
+ omitted values as `CLI default`, since the launcher does not resolve inherited provider settings.
176
+ Known effort names are checked for the reviewer backend before startup; each CLI/model validates
177
+ whether it supports the selected combination.
178
+
179
+ The reviewer receives instructions to read one message, send one verdict, and exit. Its CLI role
180
+ and expected message are also checked by `pair send`/`wait`, avoiding an unrelated pending author
181
+ duty in the opposite lane. Reviewer exits are checked against the on-disk verdict, not just the
182
+ process exit code. Successful verdicts are returned through the author's original `send`, using
183
+ the existing message formatting and archive behavior. This replaces idle model waits and MCP
184
+ notifications in auto mode. An explicit author `wait` retries a failed pending round. Interactive
185
+ Claude runs these blocking review commands as background Bash tasks and reads their completion
186
+ output, avoiding the foreground tool timeout. Its author instructions are appended to the system
187
+ prompt; generated instructions also tell agents to check their role after clear/compaction.
188
+
189
+ Every termination path stops accepting jobs, terminates owned groups, escalates to SIGKILL after
190
+ the configured grace period, and observes the CLI exit and stream closure. Even a successful CLI
191
+ exit triggers cleanup of remaining group members. A private IPC disconnect cleans up if the
192
+ launcher dies; a monotonic heartbeat deadline covers a hung launcher without counting wall-clock
193
+ jumps or suspended wall-clock time. The guardian itself exits after its
194
+ jobs are collected. The launcher also tracks live child identities for emergency cleanup if the
195
+ guardian fails. No cleanup loads a PID from disk and signals it, and no command kills by agent name.
196
+
197
+ This is process-group supervision on macOS/Linux, not OS containment: descendants that create their
198
+ own sessions/groups can escape it, and killing both supervisors can leave a stale control socket.
199
+ Stale sockets are reported for manual inspection, never silently replaced. Windows auto mode is
200
+ not yet supported. Manual mode and its notification lifecycle remain unchanged.
201
+
202
+ ## Manual reset
203
+
204
+ `pair reset` moves whole pending lanes into `resets/<reset-id>/` in the current channel, leaving
205
+ source files, archived history, and session registrations untouched. `--as` selects the lane's
206
+ author; omitting it resets both, independent of `PAIR_AGENT`. Moving whole lanes also handles
207
+ legacy flat files, malformed messages, partial writes, and older thread directories without
208
+ requiring successful protocol parsing. A small `reset.json` records the time, worktree and planned
209
+ lanes. Reset backups are deliberately outside archive retention and `pair history`.
210
+ Both preview and reset output show best-effort lane states. Unread closed threads still in their
211
+ lanes are included in the backup; only already-archived history is left in `pair history`.
212
+
213
+ Each lane rename is atomic. If a later rename fails, the command reports which lanes moved and
214
+ where their backup is; it never deletes or rolls back over new data. Manual agents must be stopped
215
+ before reset. On macOS/Linux, reset exclusively binds the auto-mode control socket until it finishes,
216
+ so it refuses live or stale ownership and serializes with `pair start`. `--dry-run` only inspects
217
+ the pending lanes and creates neither backups nor an ownership socket, even while auto mode runs.
218
+
147
219
  ## Usage
148
220
 
149
221
  ```
@@ -161,6 +233,7 @@ pair wait --as <agent> [--timeout s]
161
233
  pair status
162
234
  pair history [thread-id]
163
235
  pair clean --keep N
236
+ pair reset [--as <agent>] [--dry-run]
164
237
  pair init
165
238
  pair uninit
166
239
  pair register | unregister
@@ -169,7 +242,7 @@ pair mcp
169
242
 
170
243
  ## Known limits
171
244
 
172
- - A lane still in the old flat layout (before 1c588ed) isn't migrated. Commands fail with a hint to move its files into a subdirectory, and the messages are left untouched.
245
+ - A lane still in the old flat layout (before 1c588ed) isn't migrated. Commands fail with a recovery hint; `pair reset` can back up and clear it without parsing the old files.
173
246
  - Polling, not fs events. A 1s delay is fine for chat between agents.
174
247
  - Archiving is safe against concurrent readers and stale `wait`s. A thread disappearing mid-read counts as closed. A stale archive can only target its own, already-archived directory, so it never touches a newer thread.
175
248
  - Notifications are verified end to end with Codex CLI 0.162.1 on the shared app-server daemon. A registered session that had ended its turn was woken about 1s after Claude's request, then reviewed and replied in one turn. Other cases also verified:
package/README.md CHANGED
@@ -18,6 +18,9 @@ terminal A: claude terminal B: codex ("be my reviewer")
18
18
 
19
19
  Roles are symmetric: Codex can ask Claude for a review the same way.
20
20
 
21
+ Pair also has an opt-in auto mode: open one interactive agent, and pair starts its partner for
22
+ each review round. The existing two-terminal workflow remains available.
23
+
21
24
  ## Install
22
25
 
23
26
  ```sh
@@ -114,11 +117,138 @@ pending. The note never contains message text. Codex reads the message itself wi
114
117
 
115
118
  ### Start the agents
116
119
 
120
+ For auto mode, see below. For the manual workflow, start both agents yourself:
121
+
117
122
  After setup, start Claude Code and Codex in separate terminals in the same worktree of this repo. Each
118
123
  worktree has its own channel, so an agent started in another checkout won't see the messages
119
124
  (see [Worktrees](#worktrees)). Restart any sessions that were already open so they load the new
120
125
  instructions and sandbox settings.
121
126
 
127
+ ### Auto mode (macOS and Linux)
128
+
129
+ Install and sign in to both Claude Code and Codex first. After `pair init`, run either command in
130
+ your own terminal, outside an agent session:
131
+
132
+ ```sh
133
+ pair start --as claude # interactive Claude, automatic Codex reviewer
134
+ pair start --as codex # interactive Codex, automatic Claude reviewer
135
+ ```
136
+
137
+ Give the interactive agent a task as usual. When it sends a review request, pair starts the partner
138
+ in non-interactive mode in the same worktree. Each reviewer handles one round and exits. Follow-up
139
+ rounds resume that reviewer's saved session; new threads start fresh sessions. Requests and responses
140
+ return the review inline, so auto mode does not require pair's Codex MCP notification server or a
141
+ second terminal. The author still verifies findings and fixes or rejects them. The existing round
142
+ cap and escalation rules apply.
143
+
144
+ Auto mode uses a CLI wrapper belonging to this run. Agents receive its absolute path as `PAIR_BIN`,
145
+ so a login shell cannot accidentally use an older pair installation. The launcher passes the role
146
+ instructions at startup; the generated instructions from `pair init` also describe auto mode.
147
+ Claude receives them through `--append-system-prompt` so they survive a clear. Interactive Claude
148
+ runs managed `send` and retry commands in the Bash tool's background mode, then reads their output
149
+ on completion; a review can take longer than the foreground tool timeout.
150
+
151
+ For a Claude author, the launcher passes `sandbox.network.allowUnixSockets` through `--settings`,
152
+ allowing only this worktree's exact control socket for that session. It prints the path at startup,
153
+ uses the canonical `/private/tmp` path on macOS, and leaves your settings files unchanged. Existing
154
+ allowlist entries merge with this one. If managed policy still denies the connection, the failed
155
+ request names the required setting and stays on disk. See [Claude's sandbox documentation](https://code.claude.com/docs/en/sandboxing).
156
+
157
+ Use another terminal in this worktree to inspect or stop the session:
158
+
159
+ ```sh
160
+ pair status
161
+ pair ps -v
162
+ pair stop # stops the author and all managed reviewers/tools
163
+ ```
164
+
165
+ Exiting the author also stops its managed workers. Pair uses separate process groups, a guardian
166
+ with a private parent connection and heartbeat, and termination followed by forced termination
167
+ after a grace period. The guardian cleans up if the launcher is force-killed. Cleanup covers
168
+ ordinary descendants that remain in their process group; deliberately detached descendants or
169
+ simultaneously killing both the launcher and guardian require OS-level supervision for stronger
170
+ guarantees. Pair never signals a process based on a saved PID or its executable name.
171
+ The heartbeat uses monotonic time so clock corrections and suspended wall-clock time do not expire
172
+ the session. Pair saves and restores terminal settings on exit, including after forced author
173
+ termination. Process-group isolation gives the author inherited terminal streams but no controlling
174
+ terminal: programs that require `/dev/tty` (such as some password prompts) and Ctrl+Z job control are
175
+ not supported in this mode. Run those operations from your own terminal.
176
+
177
+ Only one auto launcher can own a worktree at a time. Stop a manual reviewer before switching to
178
+ auto mode; an existing Codex registration blocks automatic Codex reviewer startup until you run
179
+ `pair unregister`. If all supervising processes are forcibly killed, a stale socket may remain.
180
+ `pair status` names it; inspect it before removing it and restarting. Pair does not automatically
181
+ take over stale sockets or kill the PIDs in old state files.
182
+
183
+ Reviewers use saved CLI authentication. Codex runs with its workspace-write sandbox and explicit
184
+ channel access. Its worktree is writable, for example for test artifacts; source edits are prohibited
185
+ by its instructions rather than an OS read-only boundary. Claude runs with `dontAsk`, its configured tool permissions, and additional allow
186
+ rules for reading/searching and the pair CLI; commands requiring other permission approval are
187
+ denied. Auto mode does not enable either CLI's permission-bypass flags. Keep the sandbox paths from
188
+ `pair init` configured for the author. A failed launch, missing verdict, or timeout preserves the
189
+ request. The author can run `pair wait --as <author>` inside the same auto session to retry that
190
+ round. `pair status` reports the last failure and the bounded log location.
191
+
192
+ Optional launch settings:
193
+
194
+ ```sh
195
+ pair start --as claude --reviewer-model CODEX_MODEL_ID --reviewer-effort high
196
+ pair start --as codex --reviewer-model opus --reviewer-effort high
197
+ pair start --as claude --timeout 900 --grace 2
198
+ pair start --as codex --claude /absolute/path/to/claude --codex /absolute/path/to/codex
199
+ ```
200
+
201
+ `--timeout` limits each reviewer round (default 900 seconds, maximum 86400); `--grace` is the wait
202
+ between termination and forced termination (default 2 seconds, maximum 30). Executables are
203
+ resolved once at startup. The interactive author is not subject to the reviewer timeout.
204
+
205
+ `--reviewer-model` accepts the partner CLI's model ID or alias. `--reviewer-effort` sets the
206
+ reviewer's reasoning effort. These overrides apply to every review round, including resumed
207
+ sessions, and leave the interactive author's settings alone. Either flag can be omitted; each
208
+ omitted setting inherits the reviewer CLI's normal defaults. No CLI configuration files are edited.
209
+
210
+ For Codex, effort is passed as `--config model_reasoning_effort="LEVEL"`; recognized levels are
211
+ `none`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`, and `ultra`. For Claude, it is passed as
212
+ `--effort LEVEL`; recognized levels are `low`, `medium`, `high`, `xhigh`, `max`, and `ultracode`.
213
+ The installed CLI and selected model must support the requested combination; an unsupported
214
+ combination fails the review round and keeps the request available for recovery.
215
+
216
+ `pair status` and `pair ps` display the requested model and effort overrides. An omitted override
217
+ is shown as `CLI default`; pair does not claim to resolve the provider's inherited settings.
218
+
219
+ ## Reset stale requests
220
+
221
+ Run `pair reset` manually from the affected worktree to clear outdated pending requests:
222
+
223
+ ```sh
224
+ pair reset --dry-run # preview the affected lanes without changing files
225
+ pair reset # reset both directions in this worktree
226
+ pair reset --as claude # only requests authored by Claude (claude-to-codex)
227
+ pair reset --as codex # only requests authored by Codex (codex-to-claude)
228
+ ```
229
+
230
+ `--dry-run` is only supported by `reset`; other commands reject it before making changes.
231
+
232
+ Stop manual author/reviewer sessions first. If an auto session owns the worktree, reset refuses
233
+ to change it; run `pair stop` before resetting. Preview remains available while auto mode runs.
234
+ Reset also holds the auto-mode ownership socket while moving requests, so another auto launcher
235
+ cannot start during the operation. If a stale socket is left after all supervising processes were
236
+ killed, inspect the path reported by `pair status` before removing that socket and retrying.
237
+
238
+ Reset moves each selected lane into `~/.pair/<repo>-<hash>/resets/<reset-id>/` (under `PAIR_HOME`
239
+ when configured) and prints the backup path. It preserves every file, including malformed requests,
240
+ legacy layouts, older threads, and partial writes. New requests start with fresh lanes. Source
241
+ files, finished history in `archive/`, and Codex notification registrations are unchanged.
242
+ `--as` selects the request's author; without it both lanes are reset, regardless of `PAIR_AGENT`.
243
+ Unread approvals and escalations still in a lane are backed up too, so their verdicts will no
244
+ longer be delivered. Preview and reset output show each lane's state, including `closed`, or
245
+ `unparseable` if the requests cannot be read by the protocol.
246
+
247
+ Backups include `reset.json` with the worktree, time, and selected lanes. They are separate from
248
+ finished review history, so `pair history`, automatic archive retention, and `pair clean` leave
249
+ them alone. Delete a backup manually when you no longer need it. A reset that fails partway names
250
+ the backup holding already-moved requests; the remaining lane is left available for a retry.
251
+
122
252
  ## Upgrading from 0.1.x
123
253
 
124
254
  Codex no longer keeps a long `pair wait` running. To keep automatic pickup after upgrading, install
@@ -162,16 +292,20 @@ The agents run `send` and `wait` themselves. You'll mostly use `init`, `status`,
162
292
 
163
293
  ```
164
294
  pair send <request|review|response> --as <claude|codex> [--verdict approve|changes] <file|->
295
+ pair start --as <claude|codex> [--reviewer-model MODEL] [--reviewer-effort LEVEL]
296
+ [--claude /path] [--codex /path] [--timeout seconds] [--grace seconds]
297
+ pair stop # stop this worktree's auto launcher and its managed agents
165
298
  pair wait --as <claude|codex> [--timeout seconds] # prints "no message … yet" on timeout
166
299
  pair status
167
300
  pair history [thread-id] # list finished threads (latest first), or print one (any unique part of its id)
168
301
  pair clean --keep N # delete all but the N newest finished threads
302
+ pair reset [--as <claude|codex>] [--dry-run] # back up stale pending lanes (default: both)
169
303
  pair init
170
304
  pair upgrade # install the latest pair from npm, then refresh this worktree's instructions
171
305
  pair uninit # undo pair init in this worktree (keeps history; see "Uninstall")
172
306
  pair register | unregister # run by Codex in its shell: let pair_listen notify this session
173
307
  pair mcp # stdio MCP server for Codex (see "Let pair wake Codex")
174
- pair ps [-v] # running pair mcp and pair wait processes by worktree, with each worktree's Codex registration (-v: full commands)
308
+ pair ps [-v] # pair processes by worktree, including auto launchers/guardians (-v: full commands)
175
309
  ```
176
310
 
177
311
  `pair status` shows the channel, worktree root, installed package version, and each lane's turn.
@@ -203,8 +337,10 @@ offline or sandboxed.
203
337
  ## Upgrading
204
338
 
205
339
  Run `pair upgrade` in your own terminal, not through an agent: agent sandboxes block the network and
206
- global installs. It runs `npm install -g claude-codex-pair@latest`, then the new `pair init` in the
207
- current worktree if pair is set up there. Other worktrees refresh their instructions on the next
340
+ global installs. If npm has a newer version, it runs `npm install -g claude-codex-pair@latest`, then
341
+ the new `pair init` in the current worktree if pair is set up there, and prints only the files that
342
+ `init` wrote or kept. Already on the latest version, it installs nothing and only refreshes this
343
+ worktree's stale instructions. Other worktrees refresh their instructions on the next
208
344
  `pair send`, `wait`, `history` or `clean`. pair owns these files, so edits inside them are
209
345
  overwritten. pair, including `pair init`, never rewrites instructions that a newer pair wrote, so
210
346
  worktrees shared by different versions don't flip back and forth. To downgrade, delete them first. Restart Claude Code and Codex afterwards. Running
@@ -223,6 +359,7 @@ so a cleanup problem doesn't prevent delivering a review or starting the next th
223
359
  | `PAIR_MAX_ROUNDS` | `3` | Number of review rounds before escalation |
224
360
  | `PAIR_KEEP` | `100` | Finished threads to keep, by finish time. Older ones are deleted whenever a thread finishes. `all` keeps everything, `0` keeps none |
225
361
  | `PAIR_NO_UPDATE_CHECK` | (none) | Any value turns off the daily npm version check |
362
+ | `PAIR_AUTO_SOCKET_DIR` | `/tmp/pair-auto-<uid>` | Optional absolute private directory for auto-mode sockets; keep it short for Unix socket path limits |
226
363
 
227
364
  ## Uninstall
228
365