@gkorepanov/ccodex 0.5.0-rc.8 → 0.5.0

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.
Files changed (88) hide show
  1. package/README.md +159 -157
  2. package/config/compatibility.json +1 -1
  3. package/dist/claude/delegation.d.ts +10 -0
  4. package/dist/claude/delegation.js +41 -0
  5. package/dist/claude/delegation.js.map +1 -0
  6. package/dist/claude/native/catalog.d.ts +5 -0
  7. package/dist/claude/native/catalog.js +26 -17
  8. package/dist/claude/native/catalog.js.map +1 -1
  9. package/dist/claude/native/history.js +4 -3
  10. package/dist/claude/native/history.js.map +1 -1
  11. package/dist/claude/native/pages.d.ts +2 -0
  12. package/dist/claude/native/pages.js +6 -1
  13. package/dist/claude/native/pages.js.map +1 -1
  14. package/dist/claude/native/projector.js +33 -12
  15. package/dist/claude/native/projector.js.map +1 -1
  16. package/dist/claude/native/records.js +19 -0
  17. package/dist/claude/native/records.js.map +1 -1
  18. package/dist/claude/native/search.d.ts +7 -0
  19. package/dist/claude/native/search.js +79 -0
  20. package/dist/claude/native/search.js.map +1 -0
  21. package/dist/claude/native/summary.d.ts +6 -1
  22. package/dist/claude/native/summary.js +24 -6
  23. package/dist/claude/native/summary.js.map +1 -1
  24. package/dist/claude/peers.d.ts +2 -0
  25. package/dist/claude/peers.js +13 -4
  26. package/dist/claude/peers.js.map +1 -1
  27. package/dist/claude/processes.d.ts +2 -0
  28. package/dist/claude/processes.js +15 -0
  29. package/dist/claude/processes.js.map +1 -1
  30. package/dist/claude/sdk.d.ts +6 -5
  31. package/dist/claude/sdk.js +15 -8
  32. package/dist/claude/sdk.js.map +1 -1
  33. package/dist/claude/session.d.ts +25 -5
  34. package/dist/claude/session.js +134 -29
  35. package/dist/claude/session.js.map +1 -1
  36. package/dist/claude/threads.d.ts +43 -3
  37. package/dist/claude/threads.js +255 -60
  38. package/dist/claude/threads.js.map +1 -1
  39. package/dist/claude/toolMapper.d.ts +7 -0
  40. package/dist/claude/toolMapper.js +14 -1
  41. package/dist/claude/toolMapper.js.map +1 -1
  42. package/dist/config.d.ts +2 -0
  43. package/dist/config.js +2 -1
  44. package/dist/config.js.map +1 -1
  45. package/dist/daemon/daemon.d.ts +3 -0
  46. package/dist/daemon/daemon.js +6 -3
  47. package/dist/daemon/daemon.js.map +1 -1
  48. package/dist/daemon/supervisor.d.ts +3 -0
  49. package/dist/daemon/supervisor.js +2 -0
  50. package/dist/daemon/supervisor.js.map +1 -1
  51. package/dist/desktop/stdioFrontend.js +1 -1
  52. package/dist/desktop/stdioFrontend.js.map +1 -1
  53. package/dist/gateway/catalog.js +35 -20
  54. package/dist/gateway/catalog.js.map +1 -1
  55. package/dist/gateway/connection.d.ts +2 -0
  56. package/dist/gateway/connection.js +14 -2
  57. package/dist/gateway/connection.js.map +1 -1
  58. package/dist/gateway/lineage.d.ts +9 -1
  59. package/dist/gateway/lineage.js +134 -37
  60. package/dist/gateway/lineage.js.map +1 -1
  61. package/dist/gateway/server.d.ts +2 -1
  62. package/dist/gateway/server.js +24 -12
  63. package/dist/gateway/server.js.map +1 -1
  64. package/dist/gateway/status.d.ts +15 -5
  65. package/dist/gateway/status.js +142 -47
  66. package/dist/gateway/status.js.map +1 -1
  67. package/dist/gateway/stock.js +17 -2
  68. package/dist/gateway/stock.js.map +1 -1
  69. package/dist/instructions.d.ts +4 -0
  70. package/dist/instructions.js +13 -0
  71. package/dist/instructions.js.map +1 -0
  72. package/dist/management/commands.js +19 -2
  73. package/dist/management/commands.js.map +1 -1
  74. package/dist/meta.d.ts +39 -11
  75. package/dist/meta.js +59 -28
  76. package/dist/meta.js.map +1 -1
  77. package/dist/protocol/codex.d.ts +1 -3
  78. package/dist/protocol/codex.js +1 -4
  79. package/dist/protocol/codex.js.map +1 -1
  80. package/dist/protocol/turnPagination.d.ts +27 -2
  81. package/dist/protocol/turnPagination.js +46 -18
  82. package/dist/protocol/turnPagination.js.map +1 -1
  83. package/examples/config.toml +6 -2
  84. package/instructions/ccodex_extra_claude_instructions.md +20 -0
  85. package/instructions/ccodex_extra_common_instructions.md +23 -0
  86. package/legal/THIRD_PARTY_NOTICES.md +9 -9
  87. package/package.json +6 -5
  88. package/scripts/migrate-0.4-to-0.5.mjs +29 -18
package/README.md CHANGED
@@ -4,8 +4,8 @@
4
4
 
5
5
  **Claude models inside the official Codex App.**
6
6
 
7
- *Claude Code'x — or just **CCodex** — is a compatibility bridge that teaches the
8
- Codex desktop and mobile apps to run Claude models.*
7
+ *Claude Code'x — or just **CCodex** — lets the Codex desktop app, the ChatGPT mobile app
8
+ and the Codex CLI run Claude models next to GPT.*
9
9
 
10
10
  </div>
11
11
 
@@ -26,200 +26,202 @@ curl -fsSL https://github.com/gkorepanov/ccodex/releases/latest/download/install
26
26
 
27
27
  ---
28
28
 
29
- ## Why
29
+ Want Fable and Opus writing your code, but prefer the Codex App and its remote sessions
30
+ from desktop and phone? CCodex puts the **native Claude Code harness** (official Claude
31
+ Agent SDK, your own Claude login) behind that UI. GPT chats still go to your installed
32
+ Codex unchanged. No CCodex servers, no telemetry; MIT-licensed.
30
33
 
31
- Want Fable and Opus writing your code, but can't stand the Claude Code app? Same.
32
- The Codex App is everything it isn't: a genuinely great agentic UI with remote
33
- sessions from desktop and mobile that just *work*, from anywhere. CCodex is the
34
- missing bridge.
34
+ > [!WARNING]
35
+ > CCodex is young. Expect bugs — and please [report them](https://github.com/gkorepanov/ccodex/issues).
35
36
 
36
37
  ## What you get
37
38
 
38
- - 🤖 **Claude models in the official Codex App** — `claude:*` models appear right in
39
- the stock model picker, next to `gpt-*`.
40
- - 📱 **Rock-solid remote sessions** — drive Claude tasks from the Codex App and the
41
- official ChatGPT mobile app over SSH, exactly the way you already use OpenAI models.
42
- - 🔀 **Seamless provider switching** — jump between OpenAI and Claude mid-project with
43
- a compact context handoff, so your chat doesn't start from zero.
44
- - ⚡ **Native-feeling Codex features** — threads, turns, tools, approvals, `/compact`,
45
- Fork, effort and fast-mode settings all work with Claude models like they were built in.
46
- - 🧩 **Claude skills in `$` autocomplete** — project and user skills appear beside Codex
47
- skills and invoke Claude's native slash commands.
48
- - 📊 **Status commands** — `/ccstatus` shows provider health and quotas for ❋ Claude
49
- and ֎ Codex; `/ccstate` shows the current task's model, context, traffic, cost, and
50
- session stats.
51
- - ✨ **Bonus: better thread titles** — threads in the Codex App get auto-named in a
52
- fun, readable way with an emoji prefix, so you can tell them apart at a glance.
53
- Want your own naming style? Drop any custom prompt into `~/.ccodex/config.toml`.
54
-
55
- ### Not a hack
56
-
57
- CCodex is **not** a Codex harness bolted onto a reverse-engineered Anthropic
58
- subscription. It is the **native Claude Code harness** (official Claude Agent SDK +
59
- Claude Code runtime), surfaced through the excellent Codex App UI. You log in to each
60
- provider with its own official CLI, and no Anthropic or OpenAI terms are violated.
61
-
62
- ### 100% local, 100% open source
63
-
64
- CCodex sends **nothing anywhere**. There are no CCodex servers, no telemetry, no
65
- proxies of ours in the middle — traffic goes over the exact same infrastructure the
66
- stock Claude CLI and Codex CLI already use, straight to the providers. Everything else
67
- lives on your machine, and the entire codebase is MIT-licensed and open.
68
-
69
- ## Project status
70
-
71
- > [!WARNING]
72
- > CCodex is very early and not extensively tested yet. Expect bugs — and please
73
- > [report them](https://github.com/gkorepanov/ccodex/issues).
39
+ - **Claude models in the model picker**, next to `gpt-*` (ids `claude:…`), with Claude's
40
+ effort levels and Fast mode. Codex's `ultra` effort runs Claude at `max` and has it
41
+ delegate to sub-agents proactively, as stock does for GPT.
42
+ - **Switch providers mid-chat.** Pick a GPT model in a Claude chat (or the other way
43
+ round) and the conversation is compacted into a summary that the other provider
44
+ continues from. The App keeps showing one chat with one history; edits and forks across
45
+ the switch work.
46
+ - **Codex App features on Claude chats**: approvals, Plan mode, `/goal`, `/compact`, fork,
47
+ message edits, steering and queued messages, Stop, side chats (`/side`, served by
48
+ Claude's `/btw`), images, Claude's questions as the App's question prompts, its task
49
+ list as the turn's to-do list, and thinking as reasoning summaries.
50
+ - **Sub-agents and background commands like stock's**: Claude sub-agents open as their
51
+ own threads, background shell commands show as background terminals, and messages
52
+ between Claude chats show as the App's messages between tasks.
53
+ - **Claude skills in the `$` picker**, beside Codex skills, in Claude and GPT chats.
54
+ - **Search**: the sidebar search and find-in-chat cover Claude chats too.
55
+ - **Phone**: turn on remote control in the Codex App (or
56
+ `codex app-server daemon enable-remote-control` on the host) and pair the ChatGPT
57
+ mobile app as usual; it drives Claude chats like GPT ones.
58
+ - **Your `claude` CLI sessions show up** in the App, and chats from the App resume in
59
+ `claude --resume <id>` (a Claude chat's id is its Claude session id). While another live
60
+ Claude process has a chat open, the App can't start a turn in it.
61
+ - **Claude can delegate to Codex** through the `codex-wrapper` agent that setup installs;
62
+ what Codex does streams into the Claude chat.
63
+ - **`/cc` status card** (also `/ccstatus`, `/ccodex`, `/ccstate`, with or without the
64
+ slash, or *CCodex status* in the `/` menu): the chat's model, effort, permission mode,
65
+ context use, session state, and Claude and Codex plan limits. Sent while a turn runs,
66
+ it answers at once and never reaches the model.
67
+ - **Emoji thread titles** from a small GPT model and an editable prompt; Claude chats get
68
+ a ` ✳️` suffix.
74
69
 
75
70
  ## Install
76
71
 
77
- The one-liner above is all you need (it installs the Codex CLI too if it is missing).
78
- Prefer npm?
72
+ ### Requirements
73
+
74
+ | | |
75
+ |---|---|
76
+ | **OS** | macOS 11+ on Apple silicon · Linux x64 or arm64 with glibc ≥ 2.31 (no Alpine/musl) · Bash, Zsh or Fish |
77
+ | **Node.js** | `>=22.13 <27` (22 or 24 LTS recommended), npm `>=10` |
78
+ | **Codex CLI** | any recent version; installed for you if missing. Tested with `0.156` and `0.157` |
79
+ | **Claude Code** | nothing to install: the Agent SDK brings it (`0.3.284` / Claude Code `2.1.284`) |
80
+
81
+ Don't run the installer or setup as root or with `sudo`.
82
+
83
+ ### 1. Install
84
+
85
+ Either the script (it checks the platform, installs `@openai/codex` if there is no
86
+ `codex`, then runs `ccodex setup`):
79
87
 
80
88
  ```sh
81
- npm install -g @openai/codex # CCodex runs the Codex you have installed, any version
82
- npm install -g @gkorepanov/ccodex
83
- ccodex setup
89
+ curl -fsSL https://github.com/gkorepanov/ccodex/releases/latest/download/install.sh | sh
84
90
  ```
85
91
 
86
- Provider login is optional at install time — add or repair it whenever:
92
+ or npm:
87
93
 
88
94
  ```sh
89
- ccodex auth codex
90
- ccodex auth claude
95
+ npm install -g @gkorepanov/ccodex
91
96
  ccodex setup
92
97
  ```
93
98
 
94
- Keeping it healthy, updated, or removing it:
99
+ ### 2. Log in
100
+
101
+ Skip what you are already logged in to; rerun any time:
95
102
 
96
103
  ```sh
97
- ccodex doctor # (or --json)
98
- ccodex update # npm latest; --check / --next available
99
- ccodex uninstall # preserves config and state; add --purge --yes to wipe
104
+ ccodex auth codex # codex login
105
+ ccodex auth claude # Claude Code login (the SDK's bundled claude)
100
106
  ```
101
107
 
102
- The release asset also ships a matching `uninstall.sh` that works even if your shell
103
- `PATH` no longer resolves `ccodex`.
104
-
105
- ## How it works
108
+ ### 3. Activate
106
109
 
107
- CCodex is a thin layer in front of the `codex app-server` you already have installed:
108
-
109
- - **gpt threads are stock, byte for byte.** One stock `codex app-server` serves every App
110
- connection (each over a connection of its own); CCodex forwards its traffic unchanged.
111
- No pinned Codex: update Codex whenever you like.
112
- - **Claude threads are Claude Code sessions.** `claude:*` models run on the official
113
- Claude Agent SDK, and `~/.claude/projects` is the only source of truth: every session
114
- (including ones made in the `claude` CLI) is listed at once. Claude's own `/goal`,
115
- compaction, sub-agents, skills, and background tasks show up as native Codex items.
116
- Like stock's threads, a Claude chat nobody has open is unloaded after 30 idle minutes,
117
- unless a command it runs still works (a background command idle for 30 minutes counts
118
- as hung and is ended).
119
- - **Provider switch = compaction.** Switching model provider mid-thread compacts the
120
- conversation with the Codex prompt, then continues in a new native thread of the other
121
- provider seeded with the summary; the App keeps showing one thread with one history.
122
- Forks and rollbacks across the switch land in the right segment.
123
- - Codex approval modes map onto Claude permissions: *Full Access* →
124
- `bypassPermissions`, *Ask for approval* → `default`, *Approve for me* → `auto`.
125
- Claude effort and fast mode map from Codex reasoning / priority settings.
126
- - The only state CCodex keeps is a tiny optional `~/.ccodex/state/meta.json`
127
- (provider-switch lineages, archive flags and sections of Claude threads).
128
- - Plain `codex …` commands (TUI, `exec`, login) go straight to your installed Codex.
129
- `codex mcp-server` (removed from Codex in 0.154) is served by CCodex on top of
130
- `codex exec`, and Claude threads stream what those Codex sessions do.
131
-
132
- Setup activates a new version atomically and never restarts a running gateway: the new
133
- version takes over after `codex app-server daemon restart`.
134
-
135
- ### Upgrading from 0.4
136
-
137
- 0.5 drops the 0.4 databases. `ccodex setup` (also when 0.4's setup hands over to 0.5)
138
- carries thread ids, provider-switch history, archive flags, sections and names over once,
139
- before it activates 0.5; a failed migration activates nothing. Claude chats whose
140
- transcripts Claude's 30-day cleanup deleted come back from 0.4's turns as text. Then:
110
+ Open a new shell, then restart the gateway:
141
111
 
142
112
  ```sh
143
113
  codex app-server daemon restart
144
114
  ```
145
115
 
146
- ### Local Codex App (same-Mac)
147
-
148
- Over SSH the App resolves `codex` through your `PATH`, so the shim engages. The **local
149
- Codex App**, however, launches its bundled `codex app-server` directly and ignores
150
- `PATH`, so ccodex never sees it and no `claude:*` models appear. On macOS `ccodex setup`
151
- closes that gap without ever touching the signed `.app` bundle (so Sparkle auto-updates
152
- keep working):
153
-
154
- - `ccodex setup` points the App at ccodex automatically via
155
- `CODEX_CLI_PATH=~/.ccodex/bin/codex` — it runs `launchctl setenv` for the live
156
- session, installs a one-shot login LaunchAgent (`dev.ccodex.codex-cli-path`) so the GUI
157
- session re-publishes it on every login/reboot, and exports it in the managed shell
158
- blocks for terminal-launched instances. The same managed `codex` entrypoint is used
159
- locally and over SSH. **Fully quit the Codex App (`Cmd+Q`) and relaunch it**
160
- (or log out and back in) so it picks up the variable.
161
- - A bare `app-server` launch runs a thin **stdio frontend**: it forwards the App's
162
- newline-delimited JSON to the existing app-server-control socket, lazily starts the
163
- gateway when cold, and reconnects after gateway restarts. Provider state and lifecycle
164
- remain exclusively inside the existing gateway.
165
- - There is **no extra macOS gateway service**. The same PID-managed gateway used over SSH
166
- starts lazily when the App connects and stops through the existing daemon contract.
167
- Setup/update/rollback only switch files and ask you to reconnect; they never restart a
168
- live gateway underneath a task.
169
- - `ccodex uninstall` removes the login hook, restores any previous `CODEX_CLI_PATH`,
170
- strips the managed shell export, and stops only CCodex's own PID-managed gateway.
171
-
172
- ## Technical details
116
+ - **Codex App over SSH:** reconnect to the host. The App finds CCodex's `codex` first on
117
+ `PATH` (and at `~/.local/bin/codex`).
118
+ - **Local Codex App on macOS:** fully quit the App (`Cmd+Q`) and open it again (or log
119
+ out and back in).
120
+ - **Local Codex App on Linux:** setup doesn't configure it; start the App with
121
+ `CODEX_CLI_PATH=~/.ccodex/bin/codex` in its environment.
122
+
123
+ ### What setup changes
124
+
125
+ - Installs the version under `~/.ccodex/versions/` and the `codex` / `ccodex` shims in
126
+ `~/.ccodex/bin`, which a managed block (`# >>> ccodex >>>`) puts first on `PATH` in your
127
+ Bash, Zsh and Fish startup files.
128
+ - Links `~/.local/bin/codex` to the shim; a `codex` found there moves to
129
+ `~/.ccodex/backups/remote-codex` and stays the Codex CCodex runs.
130
+ - macOS: sets `CODEX_CLI_PATH` for the local App (`launchctl setenv` plus a login
131
+ LaunchAgent `dev.ccodex.codex-cli-path`), so the App starts CCodex instead of its bundled
132
+ `codex`. The signed `.app` is never touched, so its auto-updates keep working.
133
+ - Claude Code: sets `cleanupPeriodDays: 36500` in `~/.claude/settings.json` when unset
134
+ (Claude deletes transcripts older than 30 days by default, and with them your Claude
135
+ chats), and installs the `codex-wrapper` agent, the `workforce` skill and the `codex` MCP
136
+ server (user scope).
137
+ - Never restarts a running gateway: a new version takes over after
138
+ `codex app-server daemon restart`.
139
+
140
+ ## Update, upgrade from 0.4, uninstall
173
141
 
174
- | | |
175
- |---|---|
176
- | **CCodex** | `0.5.0` |
177
- | **Codex CLI** | whatever is installed (`npm i -g @openai/codex`); tested with `0.156` |
178
- | **Claude Agent SDK / Claude Code** | `0.3.280` / `2.1.280` |
179
- | **Runtime** | Node.js `>=22.13 <27`, npm `>=10` |
180
- | **Platforms** | macOS 11+ (arm64) · Linux arm64 & x64, glibc ≥2.31 (Ubuntu 22.04+, Debian 11+, Fedora/RHEL equivalents). Alpine/musl not supported |
181
- | **Shells** | Bash, Zsh, Fish |
182
- | **Relay** | Prebuilt per-platform `@gkorepanov/ccodex-relay-*` optional packages — installs never compile Rust or native addons |
183
-
184
- Fresh setup writes the editable title prompt to `~/.ccodex/config.toml`:
185
-
186
- ```toml
187
- rename_prompt = """
188
- Create a concise, vivid, memorable title for the task.
189
- Start with exactly one rare, expressive, context-relevant emoji followed by one space.
190
- Avoid generic decorative emoji when a more specific symbol fits.
191
- Keep the complete title, including emoji, within 36 characters.
192
- Return only the title.
193
- """
194
-
195
- # title_model = "gpt-6-luna" # default: a small visible Codex model
142
+ ```sh
143
+ ccodex update # to npm latest; --check only reports, --next takes the pre-release
144
+ ccodex doctor # health check (--json available)
145
+ ccodex uninstall # keeps ~/.ccodex/config.toml and ~/.ccodex/state
146
+ ccodex uninstall --purge --yes # also deletes ~/.ccodex
196
147
  ```
197
148
 
198
- Remove or comment out `rename_prompt` for stock Codex title generation. With it, new
199
- threads are titled by the title model (Claude threads get a ` ✳️` suffix); manual names
200
- take priority. Setup never restores a prompt removed from an existing config. Other
201
- optional keys are listed in [`examples/config.toml`](examples/config.toml).
149
+ Uninstall stops CCodex's gateway and undoes the `PATH`, `~/.local/bin/codex` and
150
+ `CODEX_CLI_PATH` changes; what setup added to `~/.claude` stays. If `ccodex` is gone from
151
+ `PATH`, use the release's `uninstall.sh` (`… | sh -s -- --purge` to purge):
152
+ `curl -fsSL https://github.com/gkorepanov/ccodex/releases/latest/download/uninstall.sh | sh`
153
+
154
+ **From 0.4:** run `ccodex update` (or reinstall), then `codex app-server daemon restart`.
155
+ 0.5 keeps no databases of its own; setup migrates 0.4's state once before it activates
156
+ 0.5 (a failed migration activates nothing). Provider-switch history, archive flags,
157
+ sections and names carry over. Claude chats get their Claude session ids (links to 0.4
158
+ thread ids stop working), 0.4's side chats are archived, and chats whose transcripts
159
+ Claude's 30-day cleanup deleted come back as text. The 0.4 databases move to
160
+ `~/.ccodex.0.4-backup`.
202
161
 
203
- RPC capture is on by default under `~/.ccodex/state` (mode `0600`, rolls at a combined
204
- 1 GiB) and includes prompts/outputs (`rpc_capture = false` turns it off) — and it never
205
- leaves your disk.
162
+ ## Settings
206
163
 
207
- Client quirk worth knowing: the built-in `/status` differs by client (Mobile consumes
208
- provider-labelled quota events; Desktop may render its own OpenAI-account view).
209
- `/ccstatus` is the client-independent source of truth.
164
+ Claude chats follow the App's own controls:
165
+
166
+ | Codex App | Claude Code |
167
+ |---|---|
168
+ | *Full Access* / *Ask for approval* / *Approve for me* | permission mode `bypassPermissions` / `default` / `auto` |
169
+ | Plan mode | permission mode `plan` |
170
+ | Reasoning effort | effort (`ultra` = `max` + proactive sub-agents) |
171
+ | Fast | Claude fast mode |
172
+
173
+ `~/.ccodex/config.toml` (every key optional; all of them are in
174
+ [`examples/config.toml`](examples/config.toml)):
175
+
176
+ - `rename_prompt` — the title prompt; remove it for stock Codex titles (manual names
177
+ always win). `title_model` — the model that writes them.
178
+ - `improve_models_formatting_for_codex_app` (default `true`) — adds
179
+ [`instructions/ccodex_extra_common_instructions.md`](instructions/ccodex_extra_common_instructions.md)
180
+ (formulas and plots the App renders) to the App's instructions for Codex models and to
181
+ Claude's; Claude also gets
182
+ [`instructions/ccodex_extra_claude_instructions.md`](instructions/ccodex_extra_claude_instructions.md)
183
+ (what the App shows beyond a terminal).
184
+ - `log_level` — `debug`, `info` (default), `warn`, `error`.
185
+ - `codex_binary`, `delegate_codex`, `claude_binary` — use a specific `codex` or `claude`.
186
+
187
+ ## Troubleshooting
188
+
189
+ - `ccodex doctor` checks Node, Codex and Claude and their logins, the prebuilt native
190
+ relay (`@gkorepanov/ccodex-relay-*`), the gateway and the install, and says what to run.
191
+ - `codex app-server daemon restart` restarts the gateway (chats running in it stop).
192
+ - The gateway's log is `~/.codex/app-server-daemon/app-server.stderr.log`, rewritten at
193
+ each gateway start; set `log_level = "debug"` for more.
194
+ - For a bug report, `rpc_capture = true` records every App message to
195
+ `~/.ccodex/state/rpc.jsonl` (mode `0600`, capped at 1 GiB, prompts and outputs
196
+ included). Off by default; it never leaves your disk.
197
+ - The App's built-in `/status` differs by client (Desktop may show only its OpenAI account);
198
+ `/cc` shows the same in every client.
199
+ - On a Mac, the local App replaces a gateway started from a terminal (or by an earlier App
200
+ launch) with its own, so that Browser Use works; chats running in the old one stop.
201
+
202
+ ## How it works
203
+
204
+ CCodex is a thin gateway in front of your installed `codex app-server`: the App starts
205
+ CCodex's `codex`, one stock app-server serves every GPT chat unchanged, and `claude:*`
206
+ chats run on the Claude Agent SDK with Claude's transcripts in `~/.claude/projects` as
207
+ their only source of truth. The only state CCodex adds is an optional
208
+ `~/.ccodex/state/meta.json` (provider-switch history, archive flags and sections of Claude
209
+ chats). Plain `codex …` commands (TUI, `exec`, `login`) run your installed Codex; `codex
210
+ mcp-server`, removed from Codex in `0.154`, is served by CCodex on top of `codex exec`.
210
211
 
211
212
  ## Development
212
213
 
213
214
  ```sh
214
215
  npm ci --ignore-scripts
215
216
  npm run check
216
- npm test # black-box gateway tests + schema check against the installed codex
217
- scripts/e2e/run.sh # podman, real models, copies of your credentials (never your live state)
217
+ npm test # unit and black-box gateway tests, relay tests
218
+ scripts/e2e/run.sh # rootless podman, real models, copies of your credentials
218
219
  ```
219
220
 
220
- Release workflows build and execute all three native relay packages, publish platform
221
- packages before the main package, generate checksums / SBOM / notices, and use npm
222
- trusted publishing with provenance.
221
+ ## License
222
+
223
+ MIT — see [`LICENSE`](LICENSE). Third-party licenses and notices:
224
+ [`legal/LICENSES.md`](legal/LICENSES.md), [`legal/THIRD_PARTY_NOTICES.md`](legal/THIRD_PARTY_NOTICES.md).
223
225
 
224
226
  <div align="center">
225
227
  <sub>Claude Code'x is an independent open-source project — not affiliated with, sponsored, or endorsed by OpenAI or Anthropic.</sub>
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "productVersion": "0.5.0-rc.8",
3
+ "productVersion": "0.5.0",
4
4
  "note": "Read by CCodex 0.4's setup, which checks productVersion before handing setup over to this version."
5
5
  }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Codex's `ultra` effort on Claude models: Claude's top effort plus proactive delegation to sub-agents. Stock turns the
3
+ * delegation on and off with a mode message in the thread; its guidance lives in the spawn_agent tool, here adapted to
4
+ * Claude Code's Agent tool.
5
+ */
6
+ export declare const ULTRA = "ultra";
7
+ /** The effort Claude runs at. */
8
+ export declare function claudeEffort(effort: string | null): string | null;
9
+ export declare const DELEGATION_ON = "Proactive multi-agent delegation is active. Any earlier developer instruction requiring an explicit user request before spawning sub-agents no longer applies. This mode remains active until a later multi-agent mode developer message changes it. User requests override this hint.\n\nDelegate with the Agent tool (not the Workflow tool, unless the user asks for a workflow). Sub-agents inherit your model: set `model` only when the user or their instructions ask for another one.\n\n### When to delegate vs. do the subtask yourself\n- First, quickly analyze the overall user task and form a succinct high-level plan. Identify which tasks are immediate blockers on the critical path, and which tasks are sidecar tasks that are needed but can run in parallel without blocking the next local step. As part of that plan, explicitly decide what immediate task you should do locally right now. Do this planning step before delegating to agents so you do not hand off the immediate blocking task to a sub-agent and then waste time waiting on it.\n- Use a sub-agent when a subtask is easy enough for it to handle and can run in parallel with your local work. Prefer delegating concrete, bounded sidecar tasks that materially advance the main task without blocking your immediate next local step.\n- Do not delegate urgent blocking work when your immediate next step depends on that result. If the very next action is blocked on that task, the main thread should usually do it locally to keep the critical path moving.\n- Keep work local when the subtask is too difficult to delegate well and when it is tightly coupled, urgent, or likely to block your immediate next step.\n### Designing delegated subtasks\n- Subtasks must be concrete, well-defined, and self-contained.\n- Delegated subtasks must materially advance the main task.\n- Do not duplicate work between the main thread and delegated subtasks.\n- Avoid issuing multiple delegate calls on the same unresolved thread unless the new delegated task is genuinely different and necessary.\n- Narrow the delegated ask to the concrete output you need next.\n- For coding tasks, prefer delegating concrete code-change worker subtasks over read-only explorer analysis when the sub-agent can make a bounded patch in a clear write scope.\n- When delegating coding work, instruct the sub-agent to edit files directly and list the file paths it changed in the final answer.\n- For code-edit subtasks, decompose work so each delegated task has a disjoint write set.\n### After you delegate\n- Wait for a sub-agent very sparingly. Only wait when you need the result immediately for the next critical-path step and you are blocked until it returns.\n- Do not redo delegated sub-agent tasks yourself; focus on integrating results or tackling non-overlapping work.\n- While the sub-agent is running in the background, do meaningful non-overlapping work immediately.\n- Do not repeatedly wait by reflex.\n- When a delegated coding task returns, quickly review the changes, then integrate or refine them.\n### Parallel delegation patterns\n- Run multiple independent information-seeking subtasks in parallel when you have distinct questions that can be answered independently.\n- Split implementation into disjoint codebase slices and spawn multiple agents for them in parallel when the write scopes do not overlap.\n- Delegate verification only when it can run in parallel with ongoing implementation and is likely to catch a concrete risk before final integration.\n- The key is to find opportunities to spawn multiple independent subtasks in parallel within the same round, while ensuring each subtask is well-defined, self-contained, and materially advances the main task.";
10
+ export declare const DELEGATION_OFF = "Any earlier instruction enabling proactive multi-agent delegation no longer applies. Do not spawn sub-agents unless the user or applicable CLAUDE.md/skill instructions explicitly ask for sub-agents, delegation, or parallel agent work.";
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Codex's `ultra` effort on Claude models: Claude's top effort plus proactive delegation to sub-agents. Stock turns the
3
+ * delegation on and off with a mode message in the thread; its guidance lives in the spawn_agent tool, here adapted to
4
+ * Claude Code's Agent tool.
5
+ */
6
+ export const ULTRA = "ultra";
7
+ /** The effort Claude runs at. */
8
+ export function claudeEffort(effort) {
9
+ return effort === ULTRA ? "max" : effort;
10
+ }
11
+ export const DELEGATION_ON = `Proactive multi-agent delegation is active. Any earlier developer instruction requiring an explicit user request before spawning sub-agents no longer applies. This mode remains active until a later multi-agent mode developer message changes it. User requests override this hint.
12
+
13
+ Delegate with the Agent tool (not the Workflow tool, unless the user asks for a workflow). Sub-agents inherit your model: set \`model\` only when the user or their instructions ask for another one.
14
+
15
+ ### When to delegate vs. do the subtask yourself
16
+ - First, quickly analyze the overall user task and form a succinct high-level plan. Identify which tasks are immediate blockers on the critical path, and which tasks are sidecar tasks that are needed but can run in parallel without blocking the next local step. As part of that plan, explicitly decide what immediate task you should do locally right now. Do this planning step before delegating to agents so you do not hand off the immediate blocking task to a sub-agent and then waste time waiting on it.
17
+ - Use a sub-agent when a subtask is easy enough for it to handle and can run in parallel with your local work. Prefer delegating concrete, bounded sidecar tasks that materially advance the main task without blocking your immediate next local step.
18
+ - Do not delegate urgent blocking work when your immediate next step depends on that result. If the very next action is blocked on that task, the main thread should usually do it locally to keep the critical path moving.
19
+ - Keep work local when the subtask is too difficult to delegate well and when it is tightly coupled, urgent, or likely to block your immediate next step.
20
+ ### Designing delegated subtasks
21
+ - Subtasks must be concrete, well-defined, and self-contained.
22
+ - Delegated subtasks must materially advance the main task.
23
+ - Do not duplicate work between the main thread and delegated subtasks.
24
+ - Avoid issuing multiple delegate calls on the same unresolved thread unless the new delegated task is genuinely different and necessary.
25
+ - Narrow the delegated ask to the concrete output you need next.
26
+ - For coding tasks, prefer delegating concrete code-change worker subtasks over read-only explorer analysis when the sub-agent can make a bounded patch in a clear write scope.
27
+ - When delegating coding work, instruct the sub-agent to edit files directly and list the file paths it changed in the final answer.
28
+ - For code-edit subtasks, decompose work so each delegated task has a disjoint write set.
29
+ ### After you delegate
30
+ - Wait for a sub-agent very sparingly. Only wait when you need the result immediately for the next critical-path step and you are blocked until it returns.
31
+ - Do not redo delegated sub-agent tasks yourself; focus on integrating results or tackling non-overlapping work.
32
+ - While the sub-agent is running in the background, do meaningful non-overlapping work immediately.
33
+ - Do not repeatedly wait by reflex.
34
+ - When a delegated coding task returns, quickly review the changes, then integrate or refine them.
35
+ ### Parallel delegation patterns
36
+ - Run multiple independent information-seeking subtasks in parallel when you have distinct questions that can be answered independently.
37
+ - Split implementation into disjoint codebase slices and spawn multiple agents for them in parallel when the write scopes do not overlap.
38
+ - Delegate verification only when it can run in parallel with ongoing implementation and is likely to catch a concrete risk before final integration.
39
+ - The key is to find opportunities to spawn multiple independent subtasks in parallel within the same round, while ensuring each subtask is well-defined, self-contained, and materially advances the main task.`;
40
+ export const DELEGATION_OFF = "Any earlier instruction enabling proactive multi-agent delegation no longer applies. Do not spawn sub-agents unless the user or applicable CLAUDE.md/skill instructions explicitly ask for sub-agents, delegation, or parallel agent work.";
41
+ //# sourceMappingURL=delegation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delegation.js","sourceRoot":"","sources":["../../src/claude/delegation.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,CAAC,MAAM,KAAK,GAAG,OAAO,CAAC;AAE7B,iCAAiC;AACjC,MAAM,UAAU,YAAY,CAAC,MAAqB;IAChD,OAAO,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;AAC3C,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;iNA4BoL,CAAC;AAElN,MAAM,CAAC,MAAM,cAAc,GAAG,4OAA4O,CAAC"}
@@ -8,6 +8,8 @@ export interface SessionSummary extends TranscriptHeader {
8
8
  readonly projectKey: string;
9
9
  readonly sizeBytes: number;
10
10
  readonly hasSubagents: boolean;
11
+ /** Proactive delegation (the `ultra` effort) as the transcript last told Claude. */
12
+ readonly delegating: boolean;
11
13
  }
12
14
  /** Where the summaries are kept between runs; `key` (the package version) drops them when the summarizer may differ. */
13
15
  export interface CatalogCache {
@@ -23,6 +25,7 @@ export declare class NativeSessionCatalog implements PeerDirectory {
23
25
  private ordered;
24
26
  private bySessionId;
25
27
  private refreshInFlight;
28
+ private refreshQueued;
26
29
  private readonly projections;
27
30
  private readonly pagers;
28
31
  private senders;
@@ -36,6 +39,8 @@ export declare class NativeSessionCatalog implements PeerDirectory {
36
39
  sender(msgId: string): string | undefined;
37
40
  receiver(msgId: string): string | undefined;
38
41
  has(sessionId: string): boolean;
42
+ /** Session id → snippet for the sessions whose visible messages hold `term` (see `searchTranscripts`). */
43
+ search(claudeBinary: string, term: string): Promise<Map<string, string>>;
39
44
  projection(sessionId: string, leafUuid?: string): Promise<TranscriptProjection>;
40
45
  /** Paged reads of a session's transcript (a page of history reads that page's part of the file), per history leaf. */
41
46
  pages(sessionId: string, leafUuid?: string): {
@@ -6,6 +6,7 @@ import { basename, join, resolve } from "node:path";
6
6
  import { TranscriptPages } from "./pages.js";
7
7
  import { projectTranscript } from "./projector.js";
8
8
  import { readTranscriptRecords } from "./records.js";
9
+ import { searchTranscripts } from "./search.js";
9
10
  import { TranscriptSummarizer, } from "./summary.js";
10
11
  const HEAD_BYTES = 4_096;
11
12
  const CACHE_WRITE_DELAY_MS = 1_000;
@@ -35,6 +36,13 @@ function readCache(cache) {
35
36
  return new Map();
36
37
  }
37
38
  }
39
+ function summaryOf(file, state) {
40
+ return {
41
+ ...new TranscriptSummarizer(state).header(),
42
+ sessionId: file.sessionId, path: file.path, projectKey: file.projectKey, sizeBytes: file.size, hasSubagents: file.hasSubagents,
43
+ delegating: state.delegating,
44
+ };
45
+ }
38
46
  async function hashHead(path, length) {
39
47
  const handle = await open(path, "r");
40
48
  try {
@@ -55,6 +63,7 @@ export class NativeSessionCatalog {
55
63
  ordered = [];
56
64
  bySessionId = new Map();
57
65
  refreshInFlight;
66
+ refreshQueued;
58
67
  projections = new Map();
59
68
  pagers = new Map();
60
69
  senders = new Map();
@@ -68,8 +77,14 @@ export class NativeSessionCatalog {
68
77
  this.entries = readCache(cache);
69
78
  }
70
79
  refresh(_sessionId) {
71
- if (this.refreshInFlight)
72
- return this.refreshInFlight;
80
+ // A scan in flight may have begun before what the caller just wrote: one more follows it, for all who wait meanwhile.
81
+ if (this.refreshInFlight) {
82
+ this.refreshQueued ??= this.refreshInFlight.catch(() => undefined).then(() => {
83
+ this.refreshQueued = undefined;
84
+ return this.refresh();
85
+ });
86
+ return this.refreshQueued;
87
+ }
73
88
  const refresh = this.scan().finally(() => {
74
89
  if (this.refreshInFlight === refresh)
75
90
  this.refreshInFlight = undefined;
@@ -86,6 +101,11 @@ export class NativeSessionCatalog {
86
101
  sender(msgId) { return this.senders.get(msgId); }
87
102
  receiver(msgId) { return this.receivers.get(msgId); }
88
103
  has(sessionId) { return this.bySessionId.has(sessionId); }
104
+ /** Session id → snippet for the sessions whose visible messages hold `term` (see `searchTranscripts`). */
105
+ async search(claudeBinary, term) {
106
+ const found = await searchTranscripts(claudeBinary, this.projectsDir, term);
107
+ return new Map(this.ordered.flatMap((summary) => found.has(summary.path) ? [[summary.sessionId, found.get(summary.path)]] : []));
108
+ }
89
109
  async projection(sessionId, leafUuid) {
90
110
  const entry = this.entriesBySessionId.get(sessionId);
91
111
  if (!entry)
@@ -237,7 +257,7 @@ export class NativeSessionCatalog {
237
257
  this.cacheWrite = setTimeout(() => {
238
258
  this.cacheWrite = undefined;
239
259
  const temporary = `${cache.path}.${process.pid}.tmp`;
240
- void writeFile(temporary, JSON.stringify({ key: cache.key, entries: [...this.entries.values()] }), { mode: 0o600 })
260
+ void writeFile(temporary, JSON.stringify({ key: cache.key, entries: [...this.entries.values()].map((entry) => ({ ...entry, summary: undefined })) }), { mode: 0o600 })
241
261
  .then(() => rename(temporary, cache.path))
242
262
  .catch(() => undefined);
243
263
  }, CACHE_WRITE_DELAY_MS);
@@ -297,12 +317,8 @@ export class NativeSessionCatalog {
297
317
  }
298
318
  async summarize(file) {
299
319
  const previous = this.entries.get(file.path);
300
- if (previous && previous.mtimeMs === file.mtimeMs && previous.size === file.size) {
301
- return {
302
- ...previous,
303
- summary: { ...previous.summary, hasSubagents: file.hasSubagents },
304
- };
305
- }
320
+ if (previous && previous.mtimeMs === file.mtimeMs && previous.size === file.size)
321
+ return { ...previous, summary: summaryOf(file, previous.state) };
306
322
  let start = 0;
307
323
  let summarizer = new TranscriptSummarizer();
308
324
  if (previous && file.size >= previous.offset
@@ -328,14 +344,7 @@ export class NativeSessionCatalog {
328
344
  headLength,
329
345
  headHash: await hashHead(file.path, headLength),
330
346
  state: summarizer.snapshot(),
331
- summary: {
332
- ...summarizer.header(),
333
- sessionId: file.sessionId,
334
- path: file.path,
335
- projectKey: file.projectKey,
336
- sizeBytes: file.size,
337
- hasSubagents: file.hasSubagents,
338
- },
347
+ summary: summaryOf(file, summarizer.snapshot()),
339
348
  };
340
349
  }
341
350
  }