Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c35eaa6
Add Codex CLI driver for OpenAI's codex agent
moodmosaic Apr 11, 2026
09b13aa
Fix activity filter using real Codex JSONL output
moodmosaic Apr 11, 2026
64d2dc8
Add comprehensive OpenAI pricing to Codex test configs
moodmosaic Apr 11, 2026
747fba6
Add codex-cli to dashboard short_driver() display mapping
moodmosaic Apr 11, 2026
c3b8ccb
Fall back to wall-clock timing when driver reports no duration
moodmosaic Apr 11, 2026
beb6318
Expand codex-mixed config with gpt-5.3-codex and gpt-5.2 agents
moodmosaic Apr 11, 2026
e42af16
Add ChatGPT subscription auth support for Codex CLI driver
moodmosaic Apr 11, 2026
5c74bf2
Add test configs and assertions for Codex ChatGPT auth modes
moodmosaic Apr 11, 2026
733c6d5
Fix Codex container auth: config path, dir ownership, false fatal
moodmosaic Apr 11, 2026
1c5ff1a
Widen dashboard Auth column to fit 'chatgpt' label
moodmosaic Apr 11, 2026
1cbd3b4
Use --mount instead of -v for auth.json bind mount
moodmosaic Apr 11, 2026
cde4ce1
Add missing OpenAI model pricing (pro, codex, 5.1 variants)
moodmosaic Apr 11, 2026
5f01bf8
Add Codex reasoning effort support and test coverage
moodmosaic Apr 11, 2026
a9b8a0f
Warn when auth.json is a corrupted directory
moodmosaic Apr 11, 2026
211e21c
Print failed test names in summary for CI visibility
moodmosaic Apr 11, 2026
261cc8f
Fix jq 1.8 trailing-zero formatting in pricing test
moodmosaic Apr 11, 2026
90ec07f
Fix context stripping surviving git pull and make usage limits retriable
moodmosaic Apr 12, 2026
e11dd79
Fix Codex CLI version in provenance trailers
moodmosaic Apr 12, 2026
0a4aa92
Fix duplicate activity lines and stale rebase blocking push
moodmosaic Apr 13, 2026
7636782
Inline system prompt into Codex exec prompt text
moodmosaic Apr 13, 2026
27866fb
Fix Codex cost double-counting cached tokens
moodmosaic Apr 13, 2026
00ff2d7
Document per-driver effort values in USAGE.md
moodmosaic Apr 13, 2026
3bbd5a1
Bridge .claude/CLAUDE.md and skills to Codex CLI conventions
moodmosaic Apr 13, 2026
561d91e
Bump version to 0.19.0 for Codex CLI driver
moodmosaic Apr 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,40 @@
# Changelog

## 0.19.0 — 2026-04-13

- **Codex CLI driver.** New `codex-cli` driver
(`lib/drivers/codex-cli.sh`) implements the full interface for
OpenAI's Codex CLI: headless mode with `codex exec --json`,
JSONL stats extraction (with cached-token deduplication for
accurate cost), activity parsing, fatal/retriable error
detection, and reasoning effort support.
- **ChatGPT subscription auth.** Codex agents can authenticate
via `"auth": "chatgpt"` (mounts `~/.codex/auth.json`) or
`"auth": "apikey"` (uses `OPENAI_API_KEY`). Auto-detection
when both are present. Usage-limit errors from ChatGPT
subscriptions are retriable.
- **Bridge .claude/ conventions to Codex.** When `AGENTS.md` is
absent, copies `.claude/CLAUDE.md` (or root `CLAUDE.md`) so
Codex picks up project instructions. When `.agents/skills/`
is absent, symlinks `.claude/skills/` so Codex discovers
existing skills. Both are git-excluded to avoid committing
bridged files.
- **Context stripping hooks.** Git hooks (`post-merge`,
`post-checkout`, `post-rewrite`) re-strip `.claude/` after
`git pull --rebase`, preventing agents from seeing files
removed by `context: slim` or `context: none`.
- **Stale rebase cleanup.** Push safety net cleans up stale
`.git/rebase-merge` and `.git/rebase-apply` before retries,
preventing repeated `git pull --rebase` failures.
- **Inline system prompt for Codex.** System instructions are
prepended directly to the prompt text rather than relying on
project-level instruction files, ensuring rules are always
applied under `--skip-git-repo-check`.
- **Document per-driver effort values.** USAGE.md now lists
valid effort values for each driver (Claude Code:
low/medium/high/max; Codex CLI: none/low/medium/high/xhigh).
Gemini CLI ignores the field.

## 0.18.4 — 2026-04-11

- **Tag and driver in setup wizard.** `setup.sh` now prompts for
Expand Down
19 changes: 15 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,24 @@ RUN if echo ",$SWARM_AGENTS," | grep -q ",claude-code,"; then \
fi
ENV PATH="/home/agent/.local/bin:${PATH}"

# --- Gemini CLI (requires Node.js) ---
# --- Node.js (shared by Gemini CLI and Codex CLI) ---
USER root
RUN if echo ",$SWARM_AGENTS," | grep -q ",gemini-cli,"; then \
RUN if echo ",$SWARM_AGENTS," | grep -qE ",(gemini-cli|codex-cli),"; then \
curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/* \
&& npm install -g @google/gemini-cli; \
&& rm -rf /var/lib/apt/lists/*; \
fi

# --- Gemini CLI ---
RUN if echo ",$SWARM_AGENTS," | grep -q ",gemini-cli,"; then \
npm install -g @google/gemini-cli; \
fi

# --- Codex CLI ---
RUN if echo ",$SWARM_AGENTS," | grep -q ",codex-cli,"; then \
npm install -g @openai/codex \
&& mkdir -p /home/agent/.codex \
&& chown agent:agent /home/agent/.codex; \
fi
USER agent

Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,5 +130,6 @@ Each driver implements a fixed role interface:
| `agent_activity_jq` | jq filter for activity display |

Built-in drivers: `claude-code` (default), `gemini-cli`,
`fake` (test double). See [USAGE.md](USAGE.md#writing-a-new-driver)
for the full interface and guide to writing a new driver.
`codex-cli`, `fake` (test double). See
[USAGE.md](USAGE.md#writing-a-new-driver) for the full interface
and guide to writing a new driver.
64 changes: 52 additions & 12 deletions USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ Credentials stay as env vars (not in shell history).
|----------|---------|-------------|
| `ANTHROPIC_API_KEY` | | API key (or use `CLAUDE_CODE_OAUTH_TOKEN`). |
| `CLAUDE_CODE_OAUTH_TOKEN` | | OAuth token via `claude setup-token`. |
| `OPENAI_API_KEY` | | OpenAI API key (for Codex CLI driver). |
| `CODEX_AUTH_JSON` | `~/.codex/auth.json` | Path to Codex auth file (ChatGPT subscription). |
| `GEMINI_API_KEY` | | Google API key (for Gemini CLI driver). |
| `SWARM_CONFIG` | | Path to swarmfile (or place `swarm.json` in repo root). |
| `SWARM_TITLE` | | Dashboard title override. |
| `SWARM_SKIP_DEP_CHECK` | | Set to `1` to silence dependency version warnings. |
Expand All @@ -48,16 +51,22 @@ Per-group fields in `swarm.json` `agents` array:
|-------|--------|-------|
| `model` | model name | Required. |
| `count` | integer | Number of agents in this group. |
| `effort` | `low`, `medium`, `high` | Adaptive reasoning depth. |
| `effort` | string | Reasoning depth (see below). |
| `context` | `full`, `slim`, `none` | How much of `.claude/` to keep (default: `full`). |
| `prompt` | file path | Per-group prompt override (default: top-level). |
| `auth` | `apikey`, `oauth`, omit | Which host credential to inject (see [Auth modes](#auth-modes)). |
| `auth` | `apikey`, `oauth`, `chatgpt`, omit | Which host credential to inject (see [Auth modes](#auth-modes)). |
| `api_key` | key or `$VAR` | Per-group API key for third-party endpoints. |
| `auth_token` | key or `$VAR` | Per-group Bearer token (OpenRouter-style). |
| `base_url` | URL | Per-group API endpoint. |
| `tag` | string or `$VAR` | Label for grouping runs (default: top-level). |
| `driver` | driver name | Agent driver override (default: top-level or `claude-code`). |

**Effort values** are driver-dependent:

- Claude Code: `low`, `medium`, `high`, `max` (Opus only).
- Codex CLI: `none`, `minimal`, `low`, `medium`, `high`, `xhigh`.
- Gemini CLI: ignored.

Top-level fields: `prompt`, `setup`, `max_idle` (default: `3`),
`max_retry_wait`, `driver`, `inject_git_rules`,
`git_user` (`name`, `email`), `claude_code_version`, `title`,
Expand Down Expand Up @@ -271,12 +280,9 @@ agent runs a different prompt to validate and normalize findings.

Three credential mechanisms serve different purposes:

- **`auth`** — Controls which host credential
(`ANTHROPIC_API_KEY` vs `CLAUDE_CODE_OAUTH_TOKEN`) is
forwarded to the container. Use when both credentials are
set on the host and you want per-group billing control
(e.g. some agents on API, others on subscription).
Values: `apikey`, `oauth`, or omit (pass both).
- **`auth`** — Controls which host credential is forwarded to
the container. Values: `apikey`, `oauth`, `chatgpt`, or
omit (auto-detect).

- **`api_key`** — Per-group API key for third-party endpoints
(MiniMax, etc.). Passed as `ANTHROPIC_API_KEY` inside the
Expand All @@ -287,17 +293,49 @@ Three credential mechanisms serve different purposes:
`ANTHROPIC_API_KEY` so Claude Code enters third-party mode.
Supports `$VAR` references.

### Claude Code

| `auth` value | Credential injected |
|---|---|
| `apikey` | `ANTHROPIC_API_KEY` only |
| `oauth` | `CLAUDE_CODE_OAUTH_TOKEN` only |
| omit | Both (CLI decides) |

For subscription auth (Pro/Max/Teams/Enterprise), generate
an OAuth token with `claude setup-token` and export
`CLAUDE_CODE_OAUTH_TOKEN`.

### Codex CLI

| `auth` value | Credential injected |
|---|---|
| `apikey` | `OPENAI_API_KEY` only |
| `chatgpt` | Mounts `~/.codex/auth.json` (ChatGPT subscription) |
| omit | API key if set + auth.json if found |

For ChatGPT subscription auth (Plus/Pro/Team/Enterprise),
run `codex login` on the host to create `~/.codex/auth.json`,
then set `"auth": "chatgpt"` in your swarm config:

```json
{
"driver": "codex-cli",
"agents": [{ "model": "gpt-5.4", "auth": "chatgpt" }]
}
```

The auth file is bind-mounted read-only into containers.
Override the path with `CODEX_AUTH_JSON=/path/to/auth.json`.

### General rules

Groups with `api_key` or `auth_token` ignore the `auth`
field; their custom credential is always used. When neither
is set, `auth` determines which host credential to inject.

The dashboard **Auth** column reflects the actual credential
source: `key`, `oauth`, `token`, or `auto` (see Dashboard
columns).
source: `key`, `oauth`, `chatgpt`, `token`, or `auto` (see
Dashboard columns).

## Git coordination

Expand All @@ -320,8 +358,9 @@ Stats collected per session inside each container
Dashboard columns:

- **Auth** — credential source: `key` (API key), `oauth`
(subscription token), `token` (Bearer / OpenRouter-style),
`auto` (both key + OAuth present, CLI decides).
(Claude subscription token), `chatgpt` (ChatGPT subscription),
`token` (Bearer / OpenRouter-style),
`auto` (multiple credentials present, CLI decides).
- **Ctx** — context mode: `bare` (no `.claude/`), `slim`
(only `CLAUDE.md`), or blank for full context.
- **Cost** — cumulative API cost in USD.
Expand All @@ -348,6 +387,7 @@ Built-in drivers:
|--------|-----|---------|
| `claude-code` | `claude` | Yes |
| `gemini-cli` | `gemini` | |
| `codex-cli` | `codex` | |
| `fake` | (none) | Test double for unit testing |

Set the driver globally in `swarm.json`:
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.18.4
0.19.0
7 changes: 4 additions & 3 deletions dashboard.sh
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ short_driver() {
case "${1:-}" in
claude-code) printf 'claude' ;;
gemini-cli) printf 'gemini' ;;
codex-cli) printf 'codex' ;;
*) printf '%s' "${1:-}" ;;
esac
}
Expand Down Expand Up @@ -293,7 +294,7 @@ emit_row() {

printf " ${open}%-3s %-${MODEL_COL_W}s" "$id_str" "$model_str"
if $SHOW_DRIVER; then printf " %-${DRV_COL_W}s" "$driver_str"; fi
if $SHOW_AUTH; then printf " %-6s" "$auth_str"; fi
if $SHOW_AUTH; then printf " %-7s" "$auth_str"; fi
printf " %b%-14s%b %7s" "$status_color" "$status_str" "$RESET" "$cost_str"
if $SHOW_INOUT; then printf " %13s" "$inout_str"; fi
if $SHOW_CACHE; then printf " %7s" "$cache_str"; fi
Expand All @@ -307,7 +308,7 @@ emit_row() {
emit_header() {
printf " ${BOLD}%-3s %-${MODEL_COL_W}s" "#" "Model"
if $SHOW_DRIVER; then printf " %-${DRV_COL_W}s" "Driver"; fi
if $SHOW_AUTH; then printf " %-6s" "Auth"; fi
if $SHOW_AUTH; then printf " %-7s" "Auth"; fi
printf " %-14s %7s" "Status" "Cost"
if $SHOW_INOUT; then printf " %13s" "In/Out"; fi
if $SHOW_CACHE; then printf " %7s" "Cache"; fi
Expand Down Expand Up @@ -361,7 +362,7 @@ draw() {
local avail=$((TERM_COLS - base_w))
if $HAS_MULTI_DRIVERS && [ "$avail" -ge $((DRV_COL_W + 1)) ]; then SHOW_DRIVER=true; avail=$((avail - DRV_COL_W - 1)); fi
if [ "$avail" -ge 14 ]; then SHOW_INOUT=true; avail=$((avail - 14)); fi
if [ "$avail" -ge 7 ]; then SHOW_AUTH=true; avail=$((avail - 7)); fi
if [ "$avail" -ge 9 ]; then SHOW_AUTH=true; avail=$((avail - 9)); fi
if [ "$avail" -ge 7 ]; then SHOW_TURNS=true; avail=$((avail - 7)); fi
if [ "$avail" -ge 7 ]; then SHOW_TPS=true; avail=$((avail - 7)); fi
if [ "$avail" -ge 8 ]; then SHOW_CACHE=true; avail=$((avail - 8)); fi
Expand Down
Loading
Loading