Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
c62a985
codex: add signal file + Monitor/PushNotification callback for backgr…
dragonali May 20, 2026
48ea163
codex: add --worktree isolation mode and honor user sandbox_mode config
dragonali May 20, 2026
7ca8130
codex: add thread exclusivity warning to rescue command
dragonali May 20, 2026
82af00d
test: add worktree-b test file
dragonali May 20, 2026
19b55fb
test: add worktree-a test file
dragonali May 20, 2026
6f79d96
Merge worktree-b: add worktree-test-b.test.mjs
dragonali May 20, 2026
8da7ac3
docs: add --worktree docs, thread exclusivity warning, and Chinese RE…
dragonali May 20, 2026
05df69a
chore: remove temporary worktree test files
dragonali May 20, 2026
f8c8092
feat: add live observer for Codex tasks with ANSI color support
dragonali May 21, 2026
964f96a
chore: bump version to 1.1.0 in package.json
dragonali May 21, 2026
3c77304
docs: add /codex:observe command documentation to README
dragonali May 21, 2026
be0c0bf
docs: add CHANGELOG.md with 1.1.0 and 1.0.4 release notes
dragonali May 21, 2026
0afb94d
fix: update command list test to include observe.md
dragonali May 21, 2026
12c13a8
chore: ignore local tool state directories (.claude, .claude-plugin, …
dragonali May 21, 2026
17b8a1d
fix: prevent broker process leaks with default killProcess and idle t…
dragonali May 21, 2026
b5332f4
chore: add pre-push hook for CHANGELOG, version, and README checks
dragonali May 21, 2026
daf533f
fix: restore marketplace.json tracking and sync version to 1.1.0
dragonali May 21, 2026
f9d5075
chore: bump version to 1.2.0
dragonali May 21, 2026
af88f38
refactor: flatten plugin structure from plugins/codex/ to repo root
dragonali May 21, 2026
20f1985
chore: bump version to 1.2.1
dragonali May 21, 2026
cf2917c
fix: add missing source field in marketplace.json
dragonali May 21, 2026
cce49f5
fix: restore plugins/codex/ subdirectory layout for marketplace insta…
dragonali May 21, 2026
e6ef383
chore: rename marketplace openai-codex → dragon-cc-codex
dragonali May 21, 2026
7188e2c
fix: remove inline !exec from /codex:observe slash command (1.2.4)
dragonali May 22, 2026
bc3563d
fix: look up codex jobs across workspaces for observe/status/result/c…
dragonali May 22, 2026
4e654f1
chore: bump version to 1.2.5
dragonali May 22, 2026
d2ace4f
fix: scan multiple state roots so cross-session lookup actually works…
dragonali May 22, 2026
c9e00c9
docs: document /codex:status --all and the multi-root state layout
dragonali May 22, 2026
d91ed08
feat: auto-spawn observer in tmux split when /codex:observe runs (1.3.0)
dragonali May 24, 2026
d51b40e
docs: openspec proposal for osascript spawn backends
dragonali May 24, 2026
c6eb73c
docs: tighten osascript spec per adversarial review
dragonali May 24, 2026
746b3a1
docs: close round-2 spec ambiguities
dragonali May 24, 2026
2e3ffcd
docs: align design Decision 1 and scope guards to osascript only
dragonali May 24, 2026
4d772f1
feat: add ghostty + iterm2 osascript spawn backends (1.4.0)
dragonali May 24, 2026
da67712
fix: correct ghostty/iterm2 applescript object model after adversaria…
dragonali May 24, 2026
cd23640
docs: changelog + readme entries for 1.3.0 + 1.4.0
dragonali May 24, 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
6 changes: 3 additions & 3 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
{
"name": "openai-codex",
"name": "dragon-cc-codex",
"owner": {
"name": "OpenAI"
},
"metadata": {
"description": "Codex plugins to use in Claude Code for delegation and code review.",
"version": "1.0.4"
"version": "1.4.0"
},
"plugins": [
{
"name": "codex",
"description": "Use Codex from Claude Code to review code or delegate tasks.",
"version": "1.0.4",
"version": "1.4.0",
"author": {
"name": "OpenAI"
},
Expand Down
14 changes: 14 additions & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
#
# Git pre-push hook
# Validates CHANGELOG, version bump, and README consistency before pushing.
#
# Installed via: npm run setup-hooks
# Bypass with: git push --no-verify

set -e

HOOK_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$HOOK_DIR/.." && pwd)"

exec node "$REPO_ROOT/scripts/pre-push-check.mjs"
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,11 @@ vite.config.ts.timestamp-*

output/
plugins/codex/.generated/

# Local tool state (Claude Code, Codex plugin runtime)
.claude/
.codex/

# Local Claude Code plugin state (but track marketplace.json manifest)
.claude-plugin/*
!.claude-plugin/marketplace.json
162 changes: 162 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

70 changes: 70 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

This is `@openai/codex-plugin-cc` — a Claude Code plugin that wraps the [Codex app server](https://developers.openai.com/codex/app-server) and Codex CLI, exposing slash commands (`/codex:review`, `/codex:adversarial-review`, `/codex:rescue`, `/codex:status`, `/codex:result`, `/codex:cancel`, `/codex:setup`) and a `codex:codex-rescue` subagent. The plugin lives in `plugins/codex/`.

## Commands

```bash
# Generate app-server TypeScript types (requires `codex` binary on PATH)
npm run prebuild

# Type-check (no emit, checkJs over .mjs sources)
npm run build

# Run all tests (Node.js built-in test runner, no framework)
npm test

# Run a single test file
node --test tests/<file>.test.mjs

# Version bump
node scripts/bump-version.mjs [--check]
```

There is no bundler, no runtime transpiler, and no lint step. Tests run the `.mjs` sources directly with `node --test`.

## Architecture

The runtime is a single CLI entry point, `plugins/codex/scripts/codex-companion.mjs`, dispatched by subcommand (`setup`, `review`, `adversarial-review`, `task`, `status`, `result`, `cancel`). Slash commands in `plugins/codex/commands/*.md` shell out to this script via `node "${CLAUDE_PLUGIN_ROOT}/scripts/codex-companion.mjs" <subcommand> "$ARGUMENTS"`.

Key modules under `plugins/codex/scripts/lib/`:

- `codex.mjs` — high-level Codex operations: auth/availability checks, `runAppServerTurn`, `runAppServerReview`, structured output parsing, session runtime status
- `app-server.mjs` — low-level Codex app server stdio protocol client
- `app-server-protocol.d.ts` + `.generated/app-server-types/` — generated types consumed by the build
- `broker-endpoint.mjs` / `broker-lifecycle.mjs` — manage a persistent app-server broker process shared across commands
- `job-control.mjs` / `tracked-jobs.mjs` — background job records, progress updates, cancellation
- `state.mjs` — per-workspace state dir (hashed slug under `CLAUDE_PLUGIN_DATA` or `$TMPDIR/codex-companion`), `state.json` + `jobs/` directory, capped at 50 jobs
- `git.mjs` — review target resolution (`auto` / `working-tree` / `branch`), context collection
- `render.mjs` — all user-facing output formatting
- `args.mjs` — argument parsing; flags like `--wait`, `--background`, `--resume-last`, `--model`, `--effort` are routing controls stripped before the task text is forwarded
- `prompts.mjs` — loads templates from `plugins/codex/prompts/` and interpolates them
- `codex-config.mjs` — reads `sandbox_mode` from user's Codex config (`~/.codex/config.toml` / `.codex/config.toml`)
- `process.mjs` — process tree termination, binary availability checks
- `workspace.mjs` — resolves the workspace root (honoring `CLAUDE_WORKSPACE_ROOT`)

The `codex:codex-rescue` subagent (`plugins/codex/agents/codex-rescue.md`) is a thin forwarding wrapper: it does exactly one `Bash` call to `codex-companion.mjs task ...` and returns stdout verbatim. It must not read the repo, reason about the problem, or do any independent work.

Hooks are declared in `plugins/codex/hooks/hooks.json`:
- `SessionStart` / `SessionEnd` → `session-lifecycle-hook.mjs` (bookkeeping)
- `Stop` → `stop-review-gate-hook.mjs` (optional review gate; opt-in via `/codex:setup --enable-review-gate`)

Skills in `plugins/codex/skills/` (`codex-cli-runtime`, `codex-result-handling`, `gpt-5-4-prompting`) are loaded by the subagent, not by the main Claude thread.

## Conventions

- ESM only (`"type": "module"` in `package.json`). All sources are `.mjs` except the generated `.ts` types and the `.d.ts` protocol file.
- TypeScript is used purely for type-checking via `checkJs` + `noEmit`; `strict` is off. Don't add `.ts` source files.
- Node.js ≥ 18.18. Use only Node built-ins; there are no runtime npm dependencies (devDeps are `typescript` and `@types/node` only).
- The plugin picks up the user's existing `codex` binary, auth state, and `~/.codex/config.toml` / `.codex/config.toml`. Don't hardcode models or endpoints; `MODEL_ALIASES` in `codex-companion.mjs` is the only alias map (`spark` → `gpt-5.3-codex-spark`).
- Task mode (`/codex:rescue`) reads `sandbox_mode` from the user's Codex config via `codex-config.mjs`. If not configured, falls back to `workspace-write` (when `--write` is set) or `read-only`. Review commands always use `read-only` regardless of config.
- Tests use temp git repos (`tests/helpers.mjs` → `initGitRepo`) and a fake codex fixture (`tests/fake-codex-fixture.mjs`) to drive the companion script without a real Codex install.
- `CLAUDE_PLUGIN_ROOT` is set by Claude Code at hook/command invocation time and points at `plugins/codex/`. Scripts resolve paths relative to `import.meta.url`, not `process.cwd()`.

## Version

Plugin version is declared in both `package.json` and `plugins/codex/.claude-plugin/plugin.json` and must stay in sync. `npm run check-version` enforces this (run in CI). `scripts/bump-version.mjs` updates both.
109 changes: 106 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Codex plugin for Claude Code

**[中文文档](README.zh-CN.md)**

Use Codex from inside Claude Code for code reviews or to delegate tasks to Codex.

This plugin is for Claude Code users who want an easy way to start using Codex from the workflow
Expand All @@ -12,6 +14,7 @@ they already have.
- `/codex:review` for a normal read-only Codex review
- `/codex:adversarial-review` for a steerable challenge review
- `/codex:rescue`, `/codex:status`, `/codex:result`, and `/codex:cancel` to delegate work and manage background jobs
- `/codex:observe` for real-time live observation of running Codex tasks with ANSI color output

## Requirements

Expand All @@ -24,13 +27,13 @@ they already have.
Add the marketplace in Claude Code:

```bash
/plugin marketplace add openai/codex-plugin-cc
/plugin marketplace add dragon84867/codex-plugin-cc
```

Install the plugin:

```bash
/plugin install codex@openai-codex
/plugin install codex@dragon-cc-codex
```

Reload plugins:
Expand Down Expand Up @@ -137,7 +140,9 @@ Use it when you want Codex to:
> [!NOTE]
> Depending on the task and the model you choose these tasks might take a long time and it's generally recommended to force the task to be in the background or move the agent to the background.

It supports `--background`, `--wait`, `--resume`, and `--fresh`. If you omit `--resume` and `--fresh`, the plugin can offer to continue the latest rescue thread for this repo.
It supports `--background`, `--wait`, `--worktree`, `--resume`, and `--fresh`. If you omit `--resume` and `--fresh`, the plugin can offer to continue the latest rescue thread for this repo.

**Sandbox mode.** Task mode reads `sandbox_mode` from your Codex config (`~/.codex/config.toml` or `.codex/config.toml`). If not configured, it falls back to `workspace-write` (when `--write` is set) or `read-only`.

Examples:

Expand All @@ -148,6 +153,7 @@ Examples:
/codex:rescue --model gpt-5.4-mini --effort medium investigate the flaky integration test
/codex:rescue --model spark fix the issue quickly
/codex:rescue --background investigate the regression
/codex:rescue --worktree investigate and fix the failing integration test
```

You can also just ask for a task to be delegated to Codex:
Expand All @@ -161,6 +167,10 @@ Ask Codex to redesign the database connection to be more resilient.
- if you do not pass `--model` or `--effort`, Codex chooses its own defaults.
- if you say `spark`, the plugin maps that to `gpt-5.3-codex-spark`
- follow-up rescue requests can continue the latest Codex task in the repo
- `--worktree` creates an isolated git worktree under `.claude/worktrees/<jobId>/` on a dedicated branch so Codex can work without touching your main working directory. `--worktree` and `--resume` are mutually exclusive.

> [!WARNING]
> **Thread exclusivity**: While a Codex task is running, do not manually run `codex resume` on the same thread from a terminal. The Codex backend enforces single-turn exclusivity per thread, and attempting to resume an active thread will block or pause your CLI session. Wait for the task to complete (check `/codex:status`), or use `/codex:cancel` to stop the task first. If you need to run Codex in parallel, start a fresh thread with `codex` (without `--resume`).

### `/codex:status`

Expand All @@ -171,6 +181,7 @@ Examples:
```bash
/codex:status
/codex:status task-abc123
/codex:status --all
```

Use it to:
Expand All @@ -179,6 +190,8 @@ Use it to:
- see the latest completed job
- confirm whether a task is still running

`--all` widens the listing to include jobs created in other Claude Code sessions and in legacy state directories (e.g., earlier plugin slugs, `$TMPDIR/codex-companion/`). Use it to recover the id of a task you started in an earlier session — by id, every other slash command (`/codex:result`, `/codex:cancel`, `/codex:observe`) already works across sessions and roots.

### `/codex:result`

Shows the final stored Codex output for a finished job.
Expand All @@ -202,6 +215,41 @@ Examples:
/codex:cancel task-abc123
```

### `/codex:observe`

Opens a real-time live observer for a running Codex job. Shows tool calls, file changes, commands, messages, and reasoning with ANSI color output.

The observer is **read-only** and does not affect the running Codex task. Press `Ctrl+C` to detach — the Codex task continues running.

**Auto-spawn (1.3.0+):** when invoked from inside a supported terminal, `/codex:observe` opens the observer in a new pane / window automatically — no copy-paste required. Detection precedence is `tmux > Ghostty > iTerm2 > none`:

- **Inside tmux** — `tmux split-window -h -c <workspace>` opens a vertical split running the observer.
- **Inside Ghostty on macOS** (1.4.0+) — opens a new Ghostty window via AppleScript and feeds the observer command into it. Always opens a new window because Ghostty 1.3's terminal object exposes no `tty` property to target the calling session reliably.
- **Inside iTerm2 on macOS** (1.4.0+) — discovers the calling shell's tty by walking the process ancestry and splits *that* session vertically (`split vertically with default profile`). When no matching session is found (different window, sandboxed shell, etc.), opens a new iTerm2 window instead of splitting an unrelated front window.
- **First run on macOS** triggers the standard Automation permission prompt (System Settings → Privacy & Security → Automation). The plugin recognises the permission-denied error and prints a one-line "grant access and retry" hint instead of the generic copy-paste fallback.
- **Outside any supported terminal** — the slash command prints the exact `node /path/to/companion.mjs observe …` invocation for you to paste into a separate terminal yourself.

Examples:

```bash
/codex:observe
/codex:observe task-abc123
/codex:observe --cwd /path/to/project
```

**Color legend:**

| Color | Event Type |
|-------|-----------|
| Cyan | Tool calls (`→ Read src/foo.ts`) |
| Blue | Commands (`$ npm test`) |
| Green | Success (`exit 0`, `● completed`) |
| Red | Failure (`exit 1`) |
| Yellow | File changes (`✎ src/auth.ts (modify)`) |
| Dim | Messages and reasoning |

If the target job is already completed, the observer renders the full event history and exits immediately.

### `/codex:setup`

Checks whether Codex is installed and authenticated.
Expand Down Expand Up @@ -242,6 +290,24 @@ When the review gate is enabled, the plugin uses a `Stop` hook to run a targeted
/codex:rescue --background investigate the flaky test
```

### Watch Codex Work in Real-Time

In a separate terminal:

```bash
/codex:observe
```

This gives you a live, color-coded view of what Codex is doing — tool calls, file edits, test runs, and its final answer — without blocking your Claude Code session.

### Isolated Work With `--worktree`

```bash
/codex:rescue --worktree fix the broken auth middleware
```

Codex works in `.claude/worktrees/<jobId>/` on a separate branch, leaving your main working directory untouched. This is useful when you want Codex to make changes without affecting your current branch.

Then check in with:

```bash
Expand Down Expand Up @@ -276,6 +342,32 @@ Delegated tasks and any [stop gate](#what-does-the-review-gate-do) run can also

This way you can review the Codex work or continue the work there.

## Development

### Pre-push Hook

Install the git pre-push hook to validate releases before pushing:

```bash
npm run setup-hooks
```

The hook checks every push for:
- **Version bump required** — blocks if plugin source files changed without a version bump
- **CHANGELOG entry required** — blocks if version was bumped but CHANGELOG.md has no matching entry
- **README update warning** — warns if version was bumped without updating README.md
- **Bump type validation** — warns if the actual bump (major/minor/patch) doesn't match what the changes suggest

Bypass with `git push --no-verify` if needed.

### Version Bumping

```bash
node scripts/bump-version.mjs <version>
```

Updates all version manifests: `package.json`, `package-lock.json`, `plugin.json`, and `marketplace.json`.

## FAQ

### Do I need a separate Codex account for this plugin?
Expand Down Expand Up @@ -303,3 +395,14 @@ Yes. If you already use Codex, the plugin picks up the same [configuration](#com
Yes. Because the plugin uses your local Codex CLI, your existing sign-in method and config still apply.

If you need to point the built-in OpenAI provider at a different endpoint, set `openai_base_url` in your [Codex config](https://developers.openai.com/codex/config-advanced/#config-and-state-locations).

### Where is my job state stored?

Job records, logs, and event streams live under a per-workspace state directory. The plugin picks the root in this order:

1. `$CLAUDE_PLUGIN_DATA/state/` — set by Claude Code when the slash command runs through the plugin host. Honored when present.
2. `~/.codex-companion/state/` — stable HOME-anchored fallback. Used when the env var is not set (e.g., running `node codex-companion.mjs` directly from a shell).

Inside that root, each workspace gets `<basename>-<sha256(realpath)[:16]>/` (slug + hash of the canonical workspace path), with `state.json`, per-job `<job>.json`, `<job>.log`, and `<job>.events.jsonl` files.

When you look up a job by id (`/codex:status <id>`, `/codex:result <id>`, `/codex:cancel <id>`, `/codex:observe <id>`), the plugin also scans legacy locations — `$TMPDIR/codex-companion/` (older fallback) and every `~/.claude/plugins/data/codex-*/state/` directory (handles marketplace plugin renames) — so jobs created before an upgrade remain findable. `/codex:status --all` extends the same multi-root view to the no-arg listing and bypasses the per-Claude-session filter, which is the recommended way to recover the id of a task started in an earlier session. The advanced env knob `CODEX_COMPANION_LEGACY_ROOTS` (path-separated) lets you replace the legacy scan list explicitly; an empty value disables legacy scanning entirely. Real users should not need to touch it.
Loading