@lovenyberg/ove 0.1.1 → 0.2.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/CLAUDE.md +4 -3
- package/README.md +38 -6
- package/bin/ove.ts +21 -2
- package/config.example.json +3 -0
- package/docs/examples.md +65 -3
- package/docs/favicon.ico +0 -0
- package/docs/index.html +25 -8
- package/docs/plans/2026-02-21-codex-runner-design.md +51 -0
- package/docs/plans/2026-02-21-codex-runner-plan.md +475 -0
- package/package.json +1 -1
- package/src/config.test.ts +52 -2
- package/src/config.ts +39 -1
- package/src/index.ts +76 -12
- package/src/router.test.ts +25 -0
- package/src/router.ts +11 -0
- package/src/runner.ts +1 -0
- package/src/runners/codex.test.ts +85 -0
- package/src/runners/codex.ts +137 -0
- package/src/setup.test.ts +87 -20
- package/src/setup.ts +180 -54
- package/docs/CNAME +0 -1
package/CLAUDE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Ove
|
|
2
2
|
|
|
3
|
-
Your grumpy but meticulous dev companion — routes chat messages to Claude Code CLI in isolated worktrees.
|
|
3
|
+
Your grumpy but meticulous dev companion — routes chat messages to AI coding agents (Claude Code CLI or OpenAI Codex CLI) in isolated worktrees.
|
|
4
4
|
|
|
5
5
|
## Stack
|
|
6
6
|
- Bun + TypeScript
|
|
@@ -11,12 +11,13 @@ Your grumpy but meticulous dev companion — routes chat messages to Claude Code
|
|
|
11
11
|
- Bun.serve for HTTP API + Web UI
|
|
12
12
|
- gh CLI for GitHub polling
|
|
13
13
|
- bun:sqlite for task queue
|
|
14
|
-
- claude -p CLI for code tasks
|
|
14
|
+
- claude -p CLI for code tasks (default runner)
|
|
15
|
+
- codex exec CLI for code tasks (alternative runner)
|
|
15
16
|
|
|
16
17
|
## Structure
|
|
17
18
|
- src/adapters/ — chat platform adapters (Slack, WhatsApp, Telegram, Discord, CLI) and event adapters (GitHub, HTTP API)
|
|
18
19
|
- src/queue.ts — SQLite task queue
|
|
19
|
-
- src/runners/ — agent runner implementations (Claude,
|
|
20
|
+
- src/runners/ — agent runner implementations (Claude, Codex)
|
|
20
21
|
- src/repos.ts — git clone/pull/worktree management
|
|
21
22
|
- src/router.ts — message → task mapping
|
|
22
23
|
- src/config.ts — repo/user configuration
|
package/README.md
CHANGED
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
|
|
14
14
|
Talk to Ove from Slack, WhatsApp, Telegram, Discord, GitHub issues, a Web UI, or the terminal — he'll grumble about it, but he'll review your PRs, fix your issues, run your tests, brainstorm ideas, and scaffold new projects. Properly.
|
|
15
15
|
|
|
16
|
+
**Just chat.** You don't need to memorize commands. Talk to Ove like you'd talk to a colleague — ask questions, describe what you need, paste error messages, think out loud. He understands natural language. The commands below are shortcuts, not requirements.
|
|
17
|
+
|
|
16
18
|
## Quick Start
|
|
17
19
|
|
|
18
20
|
```bash
|
|
@@ -23,11 +25,23 @@ ove start
|
|
|
23
25
|
|
|
24
26
|
## Prerequisites
|
|
25
27
|
|
|
26
|
-
- [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) installed and authenticated
|
|
28
|
+
- [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) installed and authenticated (default runner)
|
|
29
|
+
- Or [OpenAI Codex CLI](https://github.com/openai/codex) installed and authenticated (alternative runner)
|
|
27
30
|
- [GitHub CLI](https://cli.github.com) (`gh`) installed and authenticated
|
|
28
31
|
- SSH access to your git repos
|
|
29
32
|
|
|
30
|
-
##
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
Talk to Ove the way you'd talk to a teammate. These all work:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
"can you check what's failing in the auth tests on my-app?"
|
|
39
|
+
"the login page is broken, users get a 500 after submitting"
|
|
40
|
+
"how does the payment webhook work in my-app?"
|
|
41
|
+
"refactor the user service, it's getting messy"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Ove figures out the intent, picks the right repo, and gets to work. For common tasks, there are also shorthand commands:
|
|
31
45
|
|
|
32
46
|
```
|
|
33
47
|
review PR #N on <repo> Code review with inline comments
|
|
@@ -60,7 +74,7 @@ ove init
|
|
|
60
74
|
ove start
|
|
61
75
|
```
|
|
62
76
|
|
|
63
|
-
Requires [Bun](https://bun.sh), Claude Code CLI, and GitHub CLI on your machine.
|
|
77
|
+
Requires [Bun](https://bun.sh), Claude Code CLI (or Codex CLI), and GitHub CLI on your machine.
|
|
64
78
|
|
|
65
79
|
### Docker
|
|
66
80
|
|
|
@@ -70,11 +84,11 @@ docker compose up -d # start container
|
|
|
70
84
|
docker compose logs -f # watch logs
|
|
71
85
|
```
|
|
72
86
|
|
|
73
|
-
The image includes Bun, git, and Claude CLI. Mounts `config.json`, `.env`, `repos/`, and SSH keys from the host.
|
|
87
|
+
The image includes Bun, git, and Claude CLI (install Codex CLI separately if needed). Mounts `config.json`, `.env`, `repos/`, and SSH keys from the host.
|
|
74
88
|
|
|
75
89
|
### VM
|
|
76
90
|
|
|
77
|
-
Ove runs well on a small VM (2 CPU, 4 GB RAM). Install Bun, Claude Code, and GitHub CLI, then run as a systemd service:
|
|
91
|
+
Ove runs well on a small VM (2 CPU, 4 GB RAM). Install Bun, Claude Code (or Codex CLI), and GitHub CLI, then run as a systemd service:
|
|
78
92
|
|
|
79
93
|
```bash
|
|
80
94
|
git clone git@github.com:jacksoncage/ove.git && cd ove
|
|
@@ -146,6 +160,7 @@ sudo systemctl enable --now ove
|
|
|
146
160
|
"cli:local": { "name": "alice", "repos": ["my-app"] }
|
|
147
161
|
},
|
|
148
162
|
"claude": { "maxTurns": 10 },
|
|
163
|
+
"runner": { "name": "claude" },
|
|
149
164
|
"cron": [
|
|
150
165
|
{
|
|
151
166
|
"schedule": "0 9 * * 1-5",
|
|
@@ -157,6 +172,23 @@ sudo systemctl enable --now ove
|
|
|
157
172
|
}
|
|
158
173
|
```
|
|
159
174
|
|
|
175
|
+
### Runner Selection
|
|
176
|
+
|
|
177
|
+
By default Ove uses Claude Code CLI. To use OpenAI Codex instead, set the `runner` field globally or per-repo:
|
|
178
|
+
|
|
179
|
+
```json
|
|
180
|
+
{
|
|
181
|
+
"runner": { "name": "codex", "model": "o3" },
|
|
182
|
+
"repos": {
|
|
183
|
+
"my-app": {
|
|
184
|
+
"runner": { "name": "claude" }
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Per-repo `runner` overrides the global default. Supported runners: `"claude"` (default), `"codex"`.
|
|
191
|
+
|
|
160
192
|
Static cron jobs go in `config.json`. Users can also create schedules via chat — these are stored in SQLite and managed with `list schedules` / `remove schedule #N`.
|
|
161
193
|
|
|
162
194
|
## Testing
|
|
@@ -172,7 +204,7 @@ bun test # 150 tests
|
|
|
172
204
|
3. Router parses intent and extracts repo/args
|
|
173
205
|
4. Task gets queued in SQLite (one per repo at a time)
|
|
174
206
|
5. Worker creates an isolated git worktree
|
|
175
|
-
6. Runs `claude -p` with streaming
|
|
207
|
+
6. Runs the configured agent runner (`claude -p` or `codex exec`) with streaming JSON output
|
|
176
208
|
7. Status updates stream back (chat: edits a message, HTTP: SSE, GitHub: single comment)
|
|
177
209
|
8. Result sent back, worktree cleaned up
|
|
178
210
|
|
package/bin/ove.ts
CHANGED
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
-
import { existsSync } from "node:fs";
|
|
3
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { createInterface } from "node:readline/promises";
|
|
6
6
|
import { validateConfig, runSetup } from "../src/setup";
|
|
7
7
|
|
|
8
|
+
async function checkForUpdate(): Promise<void> {
|
|
9
|
+
try {
|
|
10
|
+
const pkgPath = join(import.meta.dir, "..", "package.json");
|
|
11
|
+
const { name, version: current } = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
12
|
+
const res = await fetch(`https://registry.npmjs.org/${name}/latest`, {
|
|
13
|
+
signal: AbortSignal.timeout(3000),
|
|
14
|
+
});
|
|
15
|
+
if (!res.ok) return;
|
|
16
|
+
const { version: latest } = await res.json() as { version: string };
|
|
17
|
+
if (latest && latest !== current) {
|
|
18
|
+
process.stdout.write(`\n Update available: ${current} → ${latest}\n`);
|
|
19
|
+
process.stdout.write(` Run: npm install -g ${name}\n\n`);
|
|
20
|
+
}
|
|
21
|
+
} catch {
|
|
22
|
+
// Silent fail — don't block startup for update checks
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
8
26
|
const args = process.argv.slice(2);
|
|
9
27
|
const command = args[0];
|
|
10
28
|
|
|
@@ -23,7 +41,8 @@ if (command === "init") {
|
|
|
23
41
|
}
|
|
24
42
|
|
|
25
43
|
if (command === "start" || !command) {
|
|
26
|
-
|
|
44
|
+
await checkForUpdate();
|
|
45
|
+
process.stdout.write(" Checking config...\n");
|
|
27
46
|
const { valid, issues } = validateConfig();
|
|
28
47
|
|
|
29
48
|
if (!valid) {
|
package/config.example.json
CHANGED
package/docs/examples.md
CHANGED
|
@@ -1,8 +1,56 @@
|
|
|
1
1
|
# Example Interactions
|
|
2
2
|
|
|
3
|
-
Examples showing Ove across different transports
|
|
3
|
+
Examples showing Ove across different transports. You can use shorthand commands or just chat naturally — Ove understands both.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Natural Conversation
|
|
6
|
+
|
|
7
|
+
You don't need commands. Just describe what you need, like you'd tell a colleague.
|
|
8
|
+
|
|
9
|
+
**Slack DM:**
|
|
10
|
+
```
|
|
11
|
+
alice: the login page is broken, users get a 500 after submitting the form
|
|
12
|
+
ove: Task queued (aaa11111). Working on it...
|
|
13
|
+
> Grep: "login" in src/
|
|
14
|
+
> Read: src/routes/auth.ts
|
|
15
|
+
> Read: src/middleware/session.ts
|
|
16
|
+
ove: Found the issue — the session middleware wasn't awaiting the
|
|
17
|
+
database call on line 34 of src/middleware/session.ts. Created
|
|
18
|
+
PR #47 with the fix and added a test:
|
|
19
|
+
https://github.com/org/my-app/pull/47
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Telegram:**
|
|
23
|
+
```
|
|
24
|
+
alice: can you add input validation to the user registration endpoint in my-app?
|
|
25
|
+
ove: Task queued (bbb22222). Working on it...
|
|
26
|
+
> Read: src/routes/users.ts
|
|
27
|
+
> Edit: src/routes/users.ts
|
|
28
|
+
> Write: src/routes/users.test.ts
|
|
29
|
+
> Bash: bun test
|
|
30
|
+
ove: Done. Added zod validation for email, password length, and
|
|
31
|
+
username format. All 48 tests pass. PR #48:
|
|
32
|
+
https://github.com/org/my-app/pull/48
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Discord:**
|
|
36
|
+
```
|
|
37
|
+
alice: how does the caching layer work in my-app? I need to understand
|
|
38
|
+
it before I make changes
|
|
39
|
+
ove: Looking into it...
|
|
40
|
+
> Glob: **/*cache*
|
|
41
|
+
> Read: src/cache/redis.ts
|
|
42
|
+
> Read: src/cache/keys.ts
|
|
43
|
+
> Read: src/middleware/cache.ts
|
|
44
|
+
ove: The caching layer has 3 parts:
|
|
45
|
+
1. src/cache/redis.ts — Redis client wrapper with connection pooling
|
|
46
|
+
2. src/cache/keys.ts — key generation with TTL per resource type
|
|
47
|
+
3. src/middleware/cache.ts — Express middleware that caches GET
|
|
48
|
+
responses by URL + user role
|
|
49
|
+
Cache invalidation happens on POST/PUT/DELETE via the afterWrite
|
|
50
|
+
hook in the base repository class.
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## PR Review (shorthand)
|
|
6
54
|
|
|
7
55
|
**Slack DM:**
|
|
8
56
|
```
|
|
@@ -128,7 +176,9 @@ alice: remove schedule #1
|
|
|
128
176
|
ove: Schedule #1 removed.
|
|
129
177
|
```
|
|
130
178
|
|
|
131
|
-
## Free-form
|
|
179
|
+
## More Free-form Examples
|
|
180
|
+
|
|
181
|
+
Anything you type works. Ove parses intent from natural language.
|
|
132
182
|
|
|
133
183
|
```
|
|
134
184
|
alice: what does the auth middleware do in my-app
|
|
@@ -143,6 +193,18 @@ ove: The auth middleware in my-app:
|
|
|
143
193
|
Located in src/middleware/auth.ts (42 lines).
|
|
144
194
|
```
|
|
145
195
|
|
|
196
|
+
```
|
|
197
|
+
alice: the CI is red on main, can you check what's going on?
|
|
198
|
+
ove: Task queued (ggg77777). Working on it...
|
|
199
|
+
> Bash: gh run list --limit 5
|
|
200
|
+
> Bash: gh run view 12345 --log-failed
|
|
201
|
+
> Read: src/api.test.ts
|
|
202
|
+
ove: The test "should return 404 for unknown routes" is failing
|
|
203
|
+
because the new /health endpoint was added without updating
|
|
204
|
+
the route count assertion. Line 89 in src/api.test.ts expects
|
|
205
|
+
12 routes but there are now 13. Want me to fix it?
|
|
206
|
+
```
|
|
207
|
+
|
|
146
208
|
## HTTP API
|
|
147
209
|
|
|
148
210
|
**Send a task via curl:**
|
package/docs/favicon.ico
ADDED
|
Binary file
|
package/docs/index.html
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<link rel="icon" href="favicon.ico">
|
|
6
7
|
<title>Ove — Your Grumpy Dev Companion</title>
|
|
7
8
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
8
9
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
@@ -593,8 +594,8 @@
|
|
|
593
594
|
<h1>Ove</h1>
|
|
594
595
|
<div class="hero-subtitle">Dev companion</div>
|
|
595
596
|
<p class="hero-quote">
|
|
596
|
-
"
|
|
597
|
-
<span>— Ove, on every
|
|
597
|
+
"Just tell me what's wrong. I'll figure it out."
|
|
598
|
+
<span>— Ove, on every conversation</span>
|
|
598
599
|
</p>
|
|
599
600
|
<div class="hero-actions">
|
|
600
601
|
<a class="btn" href="#getting-started">Get started</a>
|
|
@@ -620,6 +621,15 @@
|
|
|
620
621
|
<h2>What Ove Does</h2>
|
|
621
622
|
<p class="section-note">He grumbles, but he gets it done. Properly.</p>
|
|
622
623
|
|
|
624
|
+
<p>Talk to Ove like you'd talk to a colleague. Ask questions, describe problems, paste error logs, think out loud — he understands natural language. No need to memorize commands. Just chat.</p>
|
|
625
|
+
|
|
626
|
+
<pre data-label="just chat">"the login page throws a 500 after submitting"
|
|
627
|
+
"can you check what's breaking the auth tests on my-app?"
|
|
628
|
+
"how does the payment webhook work?"
|
|
629
|
+
"refactor the user service, it's getting messy"</pre>
|
|
630
|
+
|
|
631
|
+
<p>Ove figures out the intent, picks the right repo, and gets to work. For common tasks, there are also shorthand commands — but they're shortcuts, not requirements.</p>
|
|
632
|
+
|
|
623
633
|
<div class="features">
|
|
624
634
|
<div class="feature">
|
|
625
635
|
<div class="feature-label">01 — Review</div>
|
|
@@ -671,7 +681,8 @@
|
|
|
671
681
|
|
|
672
682
|
<h3>Prerequisites</h3>
|
|
673
683
|
<ol class="steps">
|
|
674
|
-
<li><a href="https://docs.anthropic.com/en/docs/claude-code">Claude Code CLI</a> installed and authenticated</li>
|
|
684
|
+
<li><a href="https://docs.anthropic.com/en/docs/claude-code">Claude Code CLI</a> installed and authenticated (default runner)</li>
|
|
685
|
+
<li>Or <a href="https://github.com/openai/codex">OpenAI Codex CLI</a> installed and authenticated (alternative runner)</li>
|
|
675
686
|
<li><a href="https://cli.github.com">GitHub CLI</a> (<code>gh</code>) installed and authenticated</li>
|
|
676
687
|
<li>SSH access to your Git repos</li>
|
|
677
688
|
</ol>
|
|
@@ -721,6 +732,7 @@ sudo systemctl enable --now ove</pre>
|
|
|
721
732
|
"cli:local": { "name": "alice", "repos": ["my-app"] }
|
|
722
733
|
},
|
|
723
734
|
"claude": { "maxTurns": 10 },
|
|
735
|
+
"runner": { "name": "claude" },
|
|
724
736
|
"cron": [
|
|
725
737
|
{
|
|
726
738
|
"schedule": "0 9 * * 1-5",
|
|
@@ -731,6 +743,8 @@ sudo systemctl enable --now ove</pre>
|
|
|
731
743
|
]
|
|
732
744
|
}</pre>
|
|
733
745
|
|
|
746
|
+
<p>Set <code>"runner"</code> globally to <code>{"name": "codex"}</code> to use OpenAI Codex, or override per-repo with a <code>"runner"</code> field inside the repo config. Supported runners: <code>claude</code> (default), <code>codex</code>.</p>
|
|
747
|
+
|
|
734
748
|
<p>Static cron jobs go in <code>config.json</code>. Users can also create schedules from chat — just say something like <code>lint and check every day at 9</code>. These are stored in SQLite and managed with <code>list schedules</code> / <code>remove schedule #N</code>.</p>
|
|
735
749
|
|
|
736
750
|
<div class="ove-says">
|
|
@@ -741,7 +755,7 @@ sudo systemctl enable --now ove</pre>
|
|
|
741
755
|
|
|
742
756
|
<section class="section">
|
|
743
757
|
<h2>Commands</h2>
|
|
744
|
-
<p class="section-note">
|
|
758
|
+
<p class="section-note">Shortcuts for common tasks. You can also just type what you need in plain language.</p>
|
|
745
759
|
|
|
746
760
|
<dl class="cmd-grid">
|
|
747
761
|
<dt>review PR #N on <repo></dt>
|
|
@@ -782,7 +796,7 @@ sudo systemctl enable --now ove</pre>
|
|
|
782
796
|
<li><span class="step-n">2</span><span class="step-arrow">›</span> Router parses intent and extracts repo/args</li>
|
|
783
797
|
<li><span class="step-n">3</span><span class="step-arrow">›</span> Task gets queued in SQLite — one per repo at a time</li>
|
|
784
798
|
<li><span class="step-n">4</span><span class="step-arrow">›</span> Worker creates an isolated git worktree</li>
|
|
785
|
-
<li><span class="step-n">5</span><span class="step-arrow">›</span> Runs <code>claude -p</code> with streaming
|
|
799
|
+
<li><span class="step-n">5</span><span class="step-arrow">›</span> Runs the configured runner (<code>claude -p</code> or <code>codex exec</code>) with streaming JSON output</li>
|
|
786
800
|
<li><span class="step-n">6</span><span class="step-arrow">›</span> Status updates stream back — chat edits, SSE, or GitHub comment</li>
|
|
787
801
|
<li><span class="step-n">7</span><span class="step-arrow">›</span> Result sent back, worktree cleaned up</li>
|
|
788
802
|
</ol>
|
|
@@ -846,7 +860,7 @@ sudo systemctl enable --now ove</pre>
|
|
|
846
860
|
<p class="section-note">Pick your method. They all work. Ove doesn't care.</p>
|
|
847
861
|
|
|
848
862
|
<h3>Docker</h3>
|
|
849
|
-
<p>The Dockerfile builds an image with Bun, git, openssh-client, and Claude CLI baked in. Just mount your config and go.</p>
|
|
863
|
+
<p>The Dockerfile builds an image with Bun, git, openssh-client, and Claude CLI baked in. Install Codex CLI separately if needed. Just mount your config and go.</p>
|
|
850
864
|
<pre data-label="docker-compose.yml">services:
|
|
851
865
|
ove:
|
|
852
866
|
build: .
|
|
@@ -868,9 +882,12 @@ sudo systemctl enable --now ove</pre>
|
|
|
868
882
|
<pre data-label="shell"># Bun
|
|
869
883
|
curl -fsSL https://bun.sh/install | bash
|
|
870
884
|
|
|
871
|
-
# Claude Code
|
|
885
|
+
# Claude Code (default runner)
|
|
872
886
|
npm install -g @anthropic-ai/claude-code
|
|
873
887
|
|
|
888
|
+
# Or Codex CLI (alternative runner)
|
|
889
|
+
# npm install -g @openai/codex
|
|
890
|
+
|
|
874
891
|
# GitHub CLI
|
|
875
892
|
sudo apt install gh
|
|
876
893
|
gh auth login
|
|
@@ -915,7 +932,7 @@ journalctl -u ove -f</pre>
|
|
|
915
932
|
</div>
|
|
916
933
|
|
|
917
934
|
<footer>
|
|
918
|
-
Built by <a href="https://www.jacksoncage.se/">Love Billingskog Nyberg</a> · Powered by <a href="https://docs.anthropic.com/en/docs/claude-code">Claude Code</a>
|
|
935
|
+
Built by <a href="https://www.jacksoncage.se/">Love Billingskog Nyberg</a> · Powered by <a href="https://docs.anthropic.com/en/docs/claude-code">Claude Code</a> & <a href="https://github.com/openai/codex">Codex</a>
|
|
919
936
|
</footer>
|
|
920
937
|
|
|
921
938
|
</body>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Codex Runner Design
|
|
2
|
+
|
|
3
|
+
Add OpenAI Codex CLI as a second agent runner alongside Claude Code CLI.
|
|
4
|
+
|
|
5
|
+
## Config
|
|
6
|
+
|
|
7
|
+
Global default runner + per-repo override:
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"runner": { "name": "claude" },
|
|
12
|
+
"repos": {
|
|
13
|
+
"my-app": {
|
|
14
|
+
"url": "git@github.com:user/my-app.git",
|
|
15
|
+
"defaultBranch": "main",
|
|
16
|
+
"runner": { "name": "codex", "model": "o3" }
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`RunnerConfig`: `{ name: "claude" | "codex"; model?: string }`. Defaults to `"claude"` if omitted.
|
|
23
|
+
|
|
24
|
+
## New Types
|
|
25
|
+
|
|
26
|
+
`RunnerConfig` added to `config.ts` on both `Config` (global) and `RepoConfig` (per-repo). `RunOptions` gets optional `model` field.
|
|
27
|
+
|
|
28
|
+
## CodexRunner (`src/runners/codex.ts`)
|
|
29
|
+
|
|
30
|
+
Implements `AgentRunner`. Spawns `codex exec --json --yolo --skip-git-repo-check --ephemeral -C <workDir> "prompt"`.
|
|
31
|
+
|
|
32
|
+
Key differences from ClaudeRunner:
|
|
33
|
+
- No `--max-turns` (exec mode runs one turn, unlimited tool calls)
|
|
34
|
+
- No `--mcp-config` flag (Codex reads MCP from `~/.codex/config.toml`)
|
|
35
|
+
- JSONL output format (one JSON object per line) instead of Claude's stream-json
|
|
36
|
+
- Uses `CODEX_API_KEY` / `OPENAI_API_KEY` env vars
|
|
37
|
+
|
|
38
|
+
JSONL event mapping to `StatusEvent`:
|
|
39
|
+
- `item.completed` + `agent_message` -> `{ kind: "text" }` + final output
|
|
40
|
+
- `item.started` + `command_execution` -> `{ kind: "tool", tool: "shell" }`
|
|
41
|
+
- `item.started` + `file_change` -> `{ kind: "tool", tool: "file_change" }`
|
|
42
|
+
- `item.started` + `mcp_tool_call` -> `{ kind: "tool", tool: <name> }`
|
|
43
|
+
- `turn.failed` -> error output
|
|
44
|
+
|
|
45
|
+
## Runner Selection (`index.ts`)
|
|
46
|
+
|
|
47
|
+
Factory function creates runners by name. Per-task resolution: repo config -> global default -> "claude". Runners cached by name.
|
|
48
|
+
|
|
49
|
+
## Unchanged
|
|
50
|
+
|
|
51
|
+
`AgentRunner` interface, `RunResult`, `StatusEvent`, queue, router, adapters — all untouched.
|