duet-cli 0.1.0__tar.gz → 0.2.1__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.
- duet_cli-0.2.1/PKG-INFO +164 -0
- duet_cli-0.2.1/README.md +143 -0
- {duet_cli-0.1.0 → duet_cli-0.2.1}/duet.py +435 -71
- duet_cli-0.2.1/duet_cli.egg-info/PKG-INFO +164 -0
- {duet_cli-0.1.0 → duet_cli-0.2.1}/pyproject.toml +1 -1
- {duet_cli-0.1.0 → duet_cli-0.2.1}/tests/test_duet.py +233 -5
- duet_cli-0.1.0/PKG-INFO +0 -360
- duet_cli-0.1.0/README.md +0 -339
- duet_cli-0.1.0/duet_cli.egg-info/PKG-INFO +0 -360
- {duet_cli-0.1.0 → duet_cli-0.2.1}/LICENSE +0 -0
- {duet_cli-0.1.0 → duet_cli-0.2.1}/duet_cli.egg-info/SOURCES.txt +0 -0
- {duet_cli-0.1.0 → duet_cli-0.2.1}/duet_cli.egg-info/dependency_links.txt +0 -0
- {duet_cli-0.1.0 → duet_cli-0.2.1}/duet_cli.egg-info/entry_points.txt +0 -0
- {duet_cli-0.1.0 → duet_cli-0.2.1}/duet_cli.egg-info/requires.txt +0 -0
- {duet_cli-0.1.0 → duet_cli-0.2.1}/duet_cli.egg-info/top_level.txt +0 -0
- {duet_cli-0.1.0 → duet_cli-0.2.1}/setup.cfg +0 -0
duet_cli-0.2.1/PKG-INFO
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: duet-cli
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Two CLI agents in conversation. One Python file. Stdlib only.
|
|
5
|
+
Author: Volkan Altan
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/volkan/duet
|
|
8
|
+
Project-URL: Repository, https://github.com/volkan/duet
|
|
9
|
+
Keywords: agents,cli,claude,codex,llm,orchestration,pair-programming
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Topic :: Software Development
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Provides-Extra: yaml
|
|
19
|
+
Requires-Dist: pyyaml; extra == "yaml"
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# duet
|
|
23
|
+
|
|
24
|
+
**Two CLI agents in conversation. One Python file. Stdlib only.**
|
|
25
|
+
|
|
26
|
+
`duet` runs two command-line coding agents in alternating turns until they
|
|
27
|
+
agree. By default that is Claude and Codex; Gemini and Copilot are also
|
|
28
|
+
supported, and you can pair two agents from the same backend. One agent plans
|
|
29
|
+
or reviews while the other implements; each keeps its own session memory across
|
|
30
|
+
turns, and every run leaves a transcript you can inspect.
|
|
31
|
+
|
|
32
|
+
## Use it three ways
|
|
33
|
+
|
|
34
|
+
### 1. Inside Claude Code — `/duet`
|
|
35
|
+
|
|
36
|
+
The fastest path if you already live in Claude Code.
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
/plugin marketplace add volkan/duet
|
|
40
|
+
/plugin install duet@volkan-duet
|
|
41
|
+
/duet
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Plain `/duet` runs Claude Code's real `/review`, then loops Codex and Claude in
|
|
45
|
+
a worktree until they converge. Pass any upstream command as the kickoff:
|
|
46
|
+
`/duet 'npm test 2>&1' --turns 4`. The plugin shells out to the `duet` CLI, so
|
|
47
|
+
install that first (see below) and make sure `command -v duet` passes in Claude
|
|
48
|
+
Code's shell. Full guide:
|
|
49
|
+
[docs/CLAUDE_CODE_PLUGIN.md](https://github.com/volkan/duet/blob/main/docs/CLAUDE_CODE_PLUGIN.md).
|
|
50
|
+
|
|
51
|
+
### 2. Inside Codex — `$duet`
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
codex plugin marketplace add volkan/duet
|
|
55
|
+
codex plugin add duet@volkan-duet
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Start a new Codex thread and invoke `$duet`, or just ask Codex to use duet in
|
|
59
|
+
plain language. Like the Claude Code plugin, the skill shells out to the `duet`
|
|
60
|
+
CLI, so install that first (see below) and make sure `command -v duet` passes in
|
|
61
|
+
Codex's shell. Full guide:
|
|
62
|
+
[docs/CODEX_PLUGIN.md](https://github.com/volkan/duet/blob/main/docs/CODEX_PLUGIN.md).
|
|
63
|
+
|
|
64
|
+
### 3. From the terminal — `duet`
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pipx install duet-cli # the command it installs is `duet`
|
|
68
|
+
duet --task "Fix the failing test" --cwd ~/code/myrepo
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The PyPI package is `duet-cli` (bare `duet` on PyPI is Google's async library),
|
|
72
|
+
so `pipx`/`uvx` isolation is recommended. Add `'duet-cli[yaml]'` if you want
|
|
73
|
+
`--config foo.yaml`. One-shot, no install:
|
|
74
|
+
`uvx --from duet-cli duet --task "..."` — note this is ephemeral and does not put
|
|
75
|
+
`duet` on PATH, so the `/duet` and `$duet` plugins need a persistent install
|
|
76
|
+
(`pipx install duet-cli` or `make install`) instead.
|
|
77
|
+
|
|
78
|
+
## Examples
|
|
79
|
+
|
|
80
|
+
Each command teaches one capability. The partner agent speaks first.
|
|
81
|
+
|
|
82
|
+
**Review loop** — Codex reviews at max effort, Claude applies only the fixes
|
|
83
|
+
Codex asks for, in an isolated worktree:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
duet --task "Review the latest commit; fix only what the reviewer requests." \
|
|
87
|
+
--lead claude:coder --partner codex:reviewer \
|
|
88
|
+
--reasoning max --worktree --worktree-for lead --turns 6
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Seed from another tool's output** — drive the loop from Claude Code's real
|
|
92
|
+
`/review`, a test run, or any command:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
duet --task-from-cmd 'claude -p /review' \
|
|
96
|
+
--lead claude:reviewer --partner codex:coder \
|
|
97
|
+
--worktree --recap --cwd ~/workspace/project --turns 6
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Deep planner, fast coder** — Claude plans at high effort while Codex coder
|
|
101
|
+
turns drop to low for latency:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
duet --reasoning high --codex-fast \
|
|
105
|
+
--task "Fix the issue" --cwd ~/workspace/project
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Verify gate** — a convergence proposal only counts if `make test` exits 0;
|
|
109
|
+
any failure feeds back into the next turn:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
duet --task "Fix the issue" \
|
|
113
|
+
--lead claude:coder --partner codex:reviewer \
|
|
114
|
+
--verify-cmd 'make test' --worktree --worktree-for lead
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Resume a plan** — plan with Codex in its own session, then hand the session
|
|
118
|
+
id to duet; Codex implements with the plan in context while Claude reviews
|
|
119
|
+
(`--resume-claude <id>` does the inverse):
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
duet --resume-codex <codex-session-id> --worktree --reasoning max \
|
|
123
|
+
--task "Implement the plan from your Codex planning session."
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Reusable configs ship under `examples/` — `pr-review.yaml` (deep review of
|
|
127
|
+
`HEAD`) and `codex-test-fix.yaml` (Codex planner diagnoses failing checks, Codex
|
|
128
|
+
coder fixes them). Run one with `duet --config examples/pr-review.yaml`.
|
|
129
|
+
|
|
130
|
+
## How it works
|
|
131
|
+
|
|
132
|
+
Each agent keeps its own conversation memory across turns (Claude via
|
|
133
|
+
`--resume`, Codex via `codex exec resume`, Gemini and Copilot via their JSON
|
|
134
|
+
session ids). On each turn duet sends one agent's latest reply to the other.
|
|
135
|
+
|
|
136
|
+
To converge, an agent must include an `LGTM rationale:` explaining why the work
|
|
137
|
+
is done, followed by the sentinel `<<<LGTM>>>` on its own line — a bare
|
|
138
|
+
sentinel is ignored, and **both** agents must agree in back-to-back turns. The
|
|
139
|
+
loop also stops on `--turns`, a per-turn timeout, or Ctrl-C. After a normal
|
|
140
|
+
stop, duet opens a `force>` prompt so you can push another round.
|
|
141
|
+
|
|
142
|
+
Every run writes a directory with `transcript.md`, `state.json`, per-turn
|
|
143
|
+
stderr logs, and the `wt/` worktree when `--worktree` is on. Inspect a run with
|
|
144
|
+
`duet --status <run-id>`, list runs with `duet --list`, and start a fresh run
|
|
145
|
+
from saved state with `duet --continue <run> --task "next thing"`.
|
|
146
|
+
|
|
147
|
+
- **Backends:** `claude`, `codex`, `gemini`, `copilot`
|
|
148
|
+
- **Roles:** `planner`, `coder`, `reviewer`, `triage-reviewer`, or a custom one
|
|
149
|
+
- **Reasoning:** `--reasoning minimal|low|medium|high|xhigh|max`
|
|
150
|
+
|
|
151
|
+
## Documentation
|
|
152
|
+
|
|
153
|
+
[docs/USAGE.md](https://github.com/volkan/duet/blob/main/docs/USAGE.md) is the
|
|
154
|
+
full reference: every flag, reasoning levels, session memory, output layout,
|
|
155
|
+
`--status` / `--continue`, the force prompt, Codex sandbox and network rules,
|
|
156
|
+
and worktree mode.
|
|
157
|
+
|
|
158
|
+
## Contributing
|
|
159
|
+
|
|
160
|
+
Contributor guidance is in
|
|
161
|
+
[CLAUDE.md](https://github.com/volkan/duet/blob/main/CLAUDE.md); Codex entry
|
|
162
|
+
notes are in [AGENTS.md](https://github.com/volkan/duet/blob/main/AGENTS.md).
|
|
163
|
+
CI runs on every PR and is advisory until marked required — see
|
|
164
|
+
[.github/BRANCH_PROTECTION.md](https://github.com/volkan/duet/blob/main/.github/BRANCH_PROTECTION.md).
|
duet_cli-0.2.1/README.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# duet
|
|
2
|
+
|
|
3
|
+
**Two CLI agents in conversation. One Python file. Stdlib only.**
|
|
4
|
+
|
|
5
|
+
`duet` runs two command-line coding agents in alternating turns until they
|
|
6
|
+
agree. By default that is Claude and Codex; Gemini and Copilot are also
|
|
7
|
+
supported, and you can pair two agents from the same backend. One agent plans
|
|
8
|
+
or reviews while the other implements; each keeps its own session memory across
|
|
9
|
+
turns, and every run leaves a transcript you can inspect.
|
|
10
|
+
|
|
11
|
+
## Use it three ways
|
|
12
|
+
|
|
13
|
+
### 1. Inside Claude Code — `/duet`
|
|
14
|
+
|
|
15
|
+
The fastest path if you already live in Claude Code.
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
/plugin marketplace add volkan/duet
|
|
19
|
+
/plugin install duet@volkan-duet
|
|
20
|
+
/duet
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Plain `/duet` runs Claude Code's real `/review`, then loops Codex and Claude in
|
|
24
|
+
a worktree until they converge. Pass any upstream command as the kickoff:
|
|
25
|
+
`/duet 'npm test 2>&1' --turns 4`. The plugin shells out to the `duet` CLI, so
|
|
26
|
+
install that first (see below) and make sure `command -v duet` passes in Claude
|
|
27
|
+
Code's shell. Full guide:
|
|
28
|
+
[docs/CLAUDE_CODE_PLUGIN.md](https://github.com/volkan/duet/blob/main/docs/CLAUDE_CODE_PLUGIN.md).
|
|
29
|
+
|
|
30
|
+
### 2. Inside Codex — `$duet`
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
codex plugin marketplace add volkan/duet
|
|
34
|
+
codex plugin add duet@volkan-duet
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Start a new Codex thread and invoke `$duet`, or just ask Codex to use duet in
|
|
38
|
+
plain language. Like the Claude Code plugin, the skill shells out to the `duet`
|
|
39
|
+
CLI, so install that first (see below) and make sure `command -v duet` passes in
|
|
40
|
+
Codex's shell. Full guide:
|
|
41
|
+
[docs/CODEX_PLUGIN.md](https://github.com/volkan/duet/blob/main/docs/CODEX_PLUGIN.md).
|
|
42
|
+
|
|
43
|
+
### 3. From the terminal — `duet`
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pipx install duet-cli # the command it installs is `duet`
|
|
47
|
+
duet --task "Fix the failing test" --cwd ~/code/myrepo
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The PyPI package is `duet-cli` (bare `duet` on PyPI is Google's async library),
|
|
51
|
+
so `pipx`/`uvx` isolation is recommended. Add `'duet-cli[yaml]'` if you want
|
|
52
|
+
`--config foo.yaml`. One-shot, no install:
|
|
53
|
+
`uvx --from duet-cli duet --task "..."` — note this is ephemeral and does not put
|
|
54
|
+
`duet` on PATH, so the `/duet` and `$duet` plugins need a persistent install
|
|
55
|
+
(`pipx install duet-cli` or `make install`) instead.
|
|
56
|
+
|
|
57
|
+
## Examples
|
|
58
|
+
|
|
59
|
+
Each command teaches one capability. The partner agent speaks first.
|
|
60
|
+
|
|
61
|
+
**Review loop** — Codex reviews at max effort, Claude applies only the fixes
|
|
62
|
+
Codex asks for, in an isolated worktree:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
duet --task "Review the latest commit; fix only what the reviewer requests." \
|
|
66
|
+
--lead claude:coder --partner codex:reviewer \
|
|
67
|
+
--reasoning max --worktree --worktree-for lead --turns 6
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Seed from another tool's output** — drive the loop from Claude Code's real
|
|
71
|
+
`/review`, a test run, or any command:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
duet --task-from-cmd 'claude -p /review' \
|
|
75
|
+
--lead claude:reviewer --partner codex:coder \
|
|
76
|
+
--worktree --recap --cwd ~/workspace/project --turns 6
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Deep planner, fast coder** — Claude plans at high effort while Codex coder
|
|
80
|
+
turns drop to low for latency:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
duet --reasoning high --codex-fast \
|
|
84
|
+
--task "Fix the issue" --cwd ~/workspace/project
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Verify gate** — a convergence proposal only counts if `make test` exits 0;
|
|
88
|
+
any failure feeds back into the next turn:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
duet --task "Fix the issue" \
|
|
92
|
+
--lead claude:coder --partner codex:reviewer \
|
|
93
|
+
--verify-cmd 'make test' --worktree --worktree-for lead
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**Resume a plan** — plan with Codex in its own session, then hand the session
|
|
97
|
+
id to duet; Codex implements with the plan in context while Claude reviews
|
|
98
|
+
(`--resume-claude <id>` does the inverse):
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
duet --resume-codex <codex-session-id> --worktree --reasoning max \
|
|
102
|
+
--task "Implement the plan from your Codex planning session."
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Reusable configs ship under `examples/` — `pr-review.yaml` (deep review of
|
|
106
|
+
`HEAD`) and `codex-test-fix.yaml` (Codex planner diagnoses failing checks, Codex
|
|
107
|
+
coder fixes them). Run one with `duet --config examples/pr-review.yaml`.
|
|
108
|
+
|
|
109
|
+
## How it works
|
|
110
|
+
|
|
111
|
+
Each agent keeps its own conversation memory across turns (Claude via
|
|
112
|
+
`--resume`, Codex via `codex exec resume`, Gemini and Copilot via their JSON
|
|
113
|
+
session ids). On each turn duet sends one agent's latest reply to the other.
|
|
114
|
+
|
|
115
|
+
To converge, an agent must include an `LGTM rationale:` explaining why the work
|
|
116
|
+
is done, followed by the sentinel `<<<LGTM>>>` on its own line — a bare
|
|
117
|
+
sentinel is ignored, and **both** agents must agree in back-to-back turns. The
|
|
118
|
+
loop also stops on `--turns`, a per-turn timeout, or Ctrl-C. After a normal
|
|
119
|
+
stop, duet opens a `force>` prompt so you can push another round.
|
|
120
|
+
|
|
121
|
+
Every run writes a directory with `transcript.md`, `state.json`, per-turn
|
|
122
|
+
stderr logs, and the `wt/` worktree when `--worktree` is on. Inspect a run with
|
|
123
|
+
`duet --status <run-id>`, list runs with `duet --list`, and start a fresh run
|
|
124
|
+
from saved state with `duet --continue <run> --task "next thing"`.
|
|
125
|
+
|
|
126
|
+
- **Backends:** `claude`, `codex`, `gemini`, `copilot`
|
|
127
|
+
- **Roles:** `planner`, `coder`, `reviewer`, `triage-reviewer`, or a custom one
|
|
128
|
+
- **Reasoning:** `--reasoning minimal|low|medium|high|xhigh|max`
|
|
129
|
+
|
|
130
|
+
## Documentation
|
|
131
|
+
|
|
132
|
+
[docs/USAGE.md](https://github.com/volkan/duet/blob/main/docs/USAGE.md) is the
|
|
133
|
+
full reference: every flag, reasoning levels, session memory, output layout,
|
|
134
|
+
`--status` / `--continue`, the force prompt, Codex sandbox and network rules,
|
|
135
|
+
and worktree mode.
|
|
136
|
+
|
|
137
|
+
## Contributing
|
|
138
|
+
|
|
139
|
+
Contributor guidance is in
|
|
140
|
+
[CLAUDE.md](https://github.com/volkan/duet/blob/main/CLAUDE.md); Codex entry
|
|
141
|
+
notes are in [AGENTS.md](https://github.com/volkan/duet/blob/main/AGENTS.md).
|
|
142
|
+
CI runs on every PR and is advisory until marked required — see
|
|
143
|
+
[.github/BRANCH_PROTECTION.md](https://github.com/volkan/duet/blob/main/.github/BRANCH_PROTECTION.md).
|