codex-grok-bridge 1.0.3 → 1.0.5

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/README.md CHANGED
@@ -1,163 +1,638 @@
1
1
  # codex-grok-bridge
2
2
 
3
- Run **Grok 4.6 as the model inside Codex**, with Codex still owning tools,
4
- permissions, history and MCP. No xAI API key: inference goes through the login
5
- session of the installed `grok` CLI.
3
+ Run **Grok 4.6 as the model inside Codex**. Codex still owns tools, permissions,
4
+ history and MCP. Inference uses the installed `grok` CLI login session — not an
5
+ xAI API key.
6
6
 
7
7
  ```
8
- Codex UI/CLI → app-server → codex-wrapper.mjs (adds grok-4.6 to the model list)
8
+ Codex UI/CLI → app-server → scripts/codex-wrapper.mjs (adds grok-4.6 to the model list)
9
9
  → localhost /v1/responses (the bridge)
10
10
  → cli-chat-proxy.grok.com
11
11
  → Codex executes every tool call; results return as the next input
12
12
  ```
13
13
 
14
- **Requirements** — macOS, Node.js ≥ 22, `/Applications/Codex.app`, the `grok`
15
- CLI at `~/.grok/bin/grok` with a completed `grok login`. Zero runtime
16
- dependencies; the whole bridge is thirteen files under `src/`.
14
+ The published npm package installs on **macOS and Linux** (`"os": ["darwin",
15
+ "linux"]`). Windows installs are rejected by npm. The official ChatGPT/Codex
16
+ `.deb` stays untouched; `scripts/install-codex-grok-app.sh` writes a separate
17
+ wrapper.
17
18
 
18
- **Quick start**
19
+
20
+ ---
21
+ ## What this is
22
+
23
+ A local bridge that puts Grok 4.6 on Codex’s model list and sends Codex
24
+ `/v1/responses` traffic to `cli-chat-proxy.grok.com`. Grok does the inference.
25
+ Codex runs every tool call (shell, patch, MCP, …) and feeds the results back as
26
+ the next request’s `input`. That is the same agent loop as the GPT path.
27
+
28
+ The bridge does **not** execute Grok-native tools. It translates Codex tools into
29
+ function calling, streams the upstream Responses events, and rewrites names back
30
+ so Codex still recognizes them.
31
+
32
+ Thirteen files under `src/`. Zero runtime dependencies. Node.js ≥ 22.
33
+
34
+ This is not a second-opinion review product, not a Grok 4.7 adapter, and not a
35
+ Grok-native search product. If Codex exposes a web-search tool, Grok can call
36
+ that tool the same way it calls any other Codex tool.
37
+
38
+ ## Requirements
39
+
40
+ - macOS, or Linux with the official ChatGPT/Codex desktop package
41
+ - Node.js ≥ 22
42
+ - `/Applications/Codex.app` (macOS) or `/usr/lib/chatgpt/ChatGPT` (Linux)
43
+ - `grok` CLI at `~/.grok/bin/grok`
44
+ - a completed `grok login`
45
+
46
+ The `.command` launcher resolves paths from its own location, so moving the
47
+ folder does not require edits. Set `NODE=/path/to/node` if `node` is not on
48
+ `PATH`.
49
+
50
+ Verified against: Codex 0.153.4 / app 26.901.51231, Grok CLI 1.0.25, Node 22.23.0.
51
+ An app update that changes `CODEX_CLI_PATH` or the app-server protocol needs
52
+ re-verification.
53
+
54
+ ## Install and run
55
+
56
+ ### Terminal (npm)
19
57
 
20
58
  ```sh
21
- npm install -g codex-grok-bridge # macOS, Node ≥ 22
22
- codex-grok # Codex in the terminal, Grok 4.6 selected
59
+ npm install -g codex-grok-bridge # macOS or Linux, Node ≥ 22
60
+ codex-grok # launches Codex with Grok 4.6 available
61
+ codex-grok exec --skip-git-repo-check --sandbox workspace-write 'your task'
23
62
  ```
24
63
 
25
- From a checkout:
64
+ `codex-grok` registers the bridge as a model provider for the Codex process it
65
+ starts, and tears the provider down with that process.
66
+
67
+ ### From a checkout
26
68
 
27
69
  ```sh
28
70
  git clone https://github.com/deximple/codex-grok-bridge.git
29
71
  cd codex-grok-bridge
30
- npm test # 131 tests, no network, no inference
72
+ npm test # 150 tests, no network, no inference
31
73
  node scripts/codex-grok.mjs
32
74
  ```
33
75
 
34
- That is the whole setup for terminal use — the bridge registers itself as a
35
- model provider for the Codex process it launches and tears down with it.
76
+ ### Desktop
77
+
78
+ Double-click **Open Codex with Grok.command** in this folder, or keep a
79
+ **separate** desktop wrapper in sync with
80
+ `scripts/install-codex-grok-app.sh` (see [Desktop install and update](#desktop-install-and-update)).
81
+ On Linux that wrapper is `~/.local/share/codex-grok-bridge/app` plus a user
82
+ `.desktop` entry; the stock `/usr/lib/chatgpt` tree is not patched.
83
+
84
+ In the new Codex window, **select Grok 4.6 / xAI before starting a new
85
+ thread**. Existing GPT models stay on the list. A Codex window that was already
86
+ open does not get this extension.
87
+
88
+ The dedicated window stores UI data under
89
+ `~/.local/share/codex-grok-bridge/desktop` and **shares** the normal Codex home
90
+ for account, threads and settings. Work and setting changes can show up in other
91
+ Codex windows.
92
+
93
+ The installer never writes the stock Codex.app bundle, `/usr/lib/chatgpt`,
94
+ their signatures, `~/.codex/config.toml`, or Grok auth files. It does not
95
+ register a launch agent or a global environment variable.
96
+
97
+ Stop by closing the Codex window this extension opened. Ordinary Codex still
98
+ launches from its usual icon.
99
+
100
+ ## How it connects
101
+
102
+ 1. A wrapper set as `CODEX_CLI_PATH` starts the Codex app-server.
103
+ 2. The wrapper adds Grok to the model catalog and sets the provider of a new
104
+ Grok thread to `grok_build_cli`.
105
+ 3. Codex `/v1/responses` requests go to the localhost bridge.
106
+ 4. The bridge flattens Codex tools (plain functions, namespaced functions,
107
+ freeform custom tools, `web_search`) into function tools, then pipes the
108
+ `cli-chat-proxy.grok.com` Responses stream through.
109
+ 5. Tool results return as the next Codex request `input`.
110
+
111
+ Authentication is the `grok login` session. `XAI_API_KEY` is not used.
112
+
113
+ Upstream sockets use `node:http(s)` with a keep-alive `Agent` (30 s, max 4
114
+ sockets) and a 5-minute DNS cache. A failed lookup still uses a valid cached
115
+ address when one exists, so a 5–20 s tool gap does not force a fresh name
116
+ lookup every time. `GROK_BRIDGE_TRANSPORT=fetch` restores the older `fetch`
117
+ path.
118
+
119
+ A request that dies **before** the first SSE block is written to Codex is
120
+ retried once. After the first block, the bridge never retries — Codex already
121
+ saw bytes, so a replay would duplicate them. Deterministic refusals (422) and
122
+ user aborts are not retried either.
123
+
124
+ If the Responses path misbehaves, `GROK_BRIDGE_INFERENCE=cli` falls back to the
125
+ older CLI envelope. That path pastes the whole JSON into a prompt each turn, so
126
+ it is slower and more expensive, has no token-by-token streaming, and is capped
127
+ at three minutes per request.
128
+
129
+ The default Responses path streams. Codex `prompt_cache_key` is forwarded as
130
+ `x-grok-conv-id`.
131
+
132
+ ## What works and what does not
133
+
134
+ Measured, not guessed:
135
+
136
+ - Mixed catalog of the six GPT models plus `grok-4.6`, with Grok provider
137
+ routing, on a real app-server.
138
+ - Live Grok CLI → Codex `exec_command` → result → Grok final reply
139
+ (`BRIDGE_TOOL_OK`).
140
+ - A separate Codex window showing `Grok 4.6 / xAI Extra High`.
141
+ - cli-chat-proxy accepted a 339-function-tool request. The public API’s 200-tool
142
+ cap does not apply on this login path.
143
+
144
+ ### Provenance lines
145
+
146
+ Codex does not put provider or model into the prompt. The bridge appends a
147
+ `Transport:` line to `instructions` so the model can answer “is Grok attached?”
148
+ without opening config files. That line is transport provenance, in the same
149
+ category as a `User-Agent` header.
150
+
151
+ When image generation is on, an `Images:` line is appended as well: pictures on
152
+ this transport use Grok’s `image_generation` tool already on the request; do
153
+ not read Codex’s `imagegen` skill and do not send the picture to OpenAI.
154
+ `GROK_BRIDGE_IMAGE_GEN=off` drops both the tool and that line.
155
+
156
+ ### Reasoning
157
+
158
+ Plain-text summaries on Codex `reasoning` items are forwarded. Encrypted
159
+ `encrypted_content` and Codex’s own item ids are stripped. This is so a
160
+ multi-call turn can continue its own reasoning. The upstream has been observed
161
+ to accept this shape. The same pass keeps only the fields Grok’s Responses
162
+ input accepts on each item and content part — `status`, unknown Codex keys,
163
+ and every `internal_*` field are dropped so a new client field cannot 422 the
164
+ upstream.
165
+
166
+ ### Concurrency
167
+
168
+ Up to **4** inferences run at once per bridge; the rest wait in a queue of 8.
169
+ Only a full queue returns `429`. Waiting is better than refusing because the
170
+ bridge has already sent response headers and is holding the stream with
171
+ keepalive. Setting concurrency to 1 kills Codex `spawn_agent` child inferences
172
+ that overlap the parent turn.
173
+
174
+ ### Tools
175
+
176
+ Ordinary function tools, namespaced function tools, and freeform custom tools
177
+ are translated. File edits, MCP, and similar work inside whatever Codex
178
+ exposed, at whatever approval policy the user set. Not every tool has been
179
+ live-tested individually.
180
+
181
+ ### Image attachments (vision)
182
+
183
+ PNG / JPEG / WebP. **10 MiB per image, 20 MiB per request**, up to four distinct
184
+ images, PNG up to 32 megapixels. The cap is measured: the upstream answered a
185
+ 12.5 MiB PNG, and the limit sits below that.
186
+
187
+ One unusable attachment no longer kills the conversation. The bridge walks the
188
+ whole history; a single over-limit image used to make every later turn fail
189
+ with 400. Now that attachment is replaced with an explanation and the rest
190
+ goes through. Usable images stay `input_image` (Grok reads them). Remote URLs
191
+ are not fetched.
36
192
 
37
- `scripts/install-codex-grok-app.sh` keeps a **separate** `Codex Grok.app`
38
- bundle in sync with a checkout, so the desktop app can use the bridge too. It
39
- updates an existing bundle; it does not create one, and it will not touch the
40
- normal `Codex.app`. It never deletes a live bundle and refuses to run while a
41
- Codex Grok window is open. ESM is not hot-reloaded, so reopen the window after
42
- an update.
193
+ ### Image generation
43
194
 
44
- **Docs** — `docs/HANDOFF.md` is the short version (state, pitfalls, open items).
45
- `docs/solution-20260909.md` is the long one: how a fixed 15-second failure was
46
- traced, what it turned out to be, and every measurement behind the fixes.
47
- `docs/experiments/` reproduces those measurements.
195
+ The bridge declares `{ type: "image_generation" }` on the upstream request.
196
+ Codex does not offer an image-generation tool to this provider (263 tools, none
197
+ of them generate — `view_image` only), so without the declaration Codex’s
198
+ `imagegen` skill falls back to OpenAI (`image_gen` or `OPENAI_API_KEY` +
199
+ `gpt-image-*`): thinking on Grok, pixels on another vendor.
200
+
201
+ Returned bytes are written to
202
+ `~/.local/share/codex-grok-bridge/generated-images/` as mode `0600`. Codex
203
+ cannot host those bytes, so the bridge turns the result into an assistant
204
+ message whose path is a markdown `file://` link:
48
205
 
49
- **Diagnostics** — every turn is recorded to
50
- `~/.local/share/codex-grok-bridge/logs/bridge.jsonl`: structural facts only,
51
- never prompt text, tool output or tokens. Start there when something breaks.
206
+ `[ /path/to/grok-….jpg ](file:///path/to/grok-….jpg)`
207
+
208
+ Whether that link is clickable depends on Codex’s markdown renderer. Codex
209
+ events it does not know (`response.image_generation_call.*`) are dropped.
210
+
211
+ Grok’s `image_generation` is text-to-image only:
212
+
213
+ | Capability | Result |
214
+ |---|---|
215
+ | Text → image | Works |
216
+ | Transparent background | **No.** Always JPEG, no alpha. The model will say “transparent” and paint a checkerboard into the picture |
217
+ | Tool parameters (`background`, `output_format`) | Accepted and **silently ignored** |
218
+ | Image edit (image-to-image) | **Not a real edit.** The input is described in text and regenerated; composition and resolution change |
219
+
220
+ The bridge inspects the saved file. If there is no alpha channel it tells the
221
+ model not to describe the picture as transparent. If you need a real alpha
222
+ channel or accurate inpainting, use Codex’s OpenAI path.
223
+
224
+ ### GPT ↔ Grok switching
225
+
226
+ Supported on an idle persisted root thread. `turn/start`,
227
+ `thread/settings/update` and `turn/settings/update` cannot change
228
+ `modelProvider`; extra provider fields are ignored. The wrapper unsubscribes,
229
+ resumes the same id with an explicit model/provider, checks the returned
230
+ provider and permissions, then forwards the original request. Active threads,
231
+ ephemeral threads and child agents refuse a switch. Other subscribers can block
232
+ the reload; if they do, no inference is sent. Pick the model you want when
233
+ starting a new thread, before the first turn is saved.
234
+
235
+ ### Not guaranteed
236
+
237
+ Voice, cloud tasks, and video generation are not promised.
238
+
239
+ Upstream sometimes resets the connection mid-response (three measured cases:
240
+ 25 s / 27 s / 253 s, 726 KB–22 MB). The bridge cannot retry after the first
241
+ SSE byte. The provider sets Codex `request_max_retries` / `stream_max_retries`
242
+ to 2 so **Codex** can resend the same request. Only the side that owns the
243
+ conversation can retry safely.
244
+
245
+ ## Diagnostics
246
+
247
+ Every turn is one JSONL line at
248
+ `~/.local/share/codex-grok-bridge/logs/bridge.jsonl` (directory `0700`, file
249
+ `0600`, rotated once to `.1` above 4 MiB). `GROK_BRIDGE_DIAGNOSTICS=off` disables
250
+ it.
251
+
252
+ ```jsonl
253
+ {"at":"…","event":"turn_ok","mode":"proxy","elapsedMs":14118,"requestBytes":469749,"items":4,"tools":29}
254
+ {"at":"…","event":"turn_failed","kind":"dns","signature":"TypeError <- Error[EAI_AGAIN]","elapsedMs":15071,…}
255
+ ```
256
+
257
+ Structural facts only: time, success/failure, error class, error-chain names
258
+ and codes, elapsed ms, request bytes, item and tool counts. **No prompt text,
259
+ tool output, upstream body, or tokens.** `detail` is redacted (bearer tokens,
260
+ JWTs, API keys, home paths) and truncated to 400 characters.
261
+
262
+ Completed turns are logged too: an empty log on failure means the bridge was
263
+ never called.
264
+
265
+ `turn_failed.kind` is one of: `aborted`, `auth`, `dns`, `connect`,
266
+ `upstream_timeout`, `upstream_closed`, `upstream_protocol`, `payload`,
267
+ `internal`. Codex UI shows the same class as `bridge_<kind>`.
268
+
269
+ Start here when something breaks. Do not open `~/.grok/auth.json` or
270
+ `~/.codex/auth.json` to “check” the bridge.
271
+
272
+ ## Environment variables
273
+
274
+ | Variable | Effect |
275
+ |---|---|
276
+ | `GROK_BRIDGE_IMAGE_GEN=off` | Do not declare Grok `image_generation`; do not append the `Images:` line |
277
+ | `GROK_BRIDGE_TRANSPORT=fetch` | Use Node `fetch` instead of `node:http(s)` |
278
+ | `GROK_BRIDGE_INFERENCE=cli` | Fall back to the CLI envelope path |
279
+ | `GROK_BRIDGE_DIAGNOSTICS=off` | Do not write the JSONL log |
280
+ | `NODE` | Absolute `node` binary for the `.command` launcher / desktop scripts |
281
+ | `CODEX_GROK_APP` | Alternate app path for `install-codex-grok-app.sh` (macOS: `/Applications/Codex Grok.app`; Linux: `~/.local/share/codex-grok-bridge/app`) |
282
+
283
+ ## Verify
284
+
285
+ ```sh
286
+ npm test # 150 tests, no remote inference
287
+ npm run test:coverage # 80% line / branch / function gate
288
+ npm run verify:app-server # real app-server routing; also runs against an installed bundle
289
+ npm audit --omit=dev
290
+ ```
291
+
292
+ `npm test` does not call remote inference. `verify:app-server` talks to a real
293
+ app-server for the model list and a temporary thread; it does not run model
294
+ inference. A live CLI check spends the user’s quota.
295
+
296
+ ## Desktop install and update
297
+
298
+ ```sh
299
+ sh scripts/install-codex-grok-app.sh # sync bridge JS only (default)
300
+ sh scripts/install-codex-grok-app.sh --full # macOS: rebuild and sign the launcher applet
301
+ ```
302
+
303
+ The default copies this checkout’s `src/` and `scripts/*.mjs` into the bundle,
304
+ prunes files the checkout no longer has, and `cmp`s every file at the end. It
305
+ never `rm -rf`s the live bundle. It refuses while a Codex Grok window is open
306
+ (`--force` to override). ESM is not hot-reloaded: **reopen the window** after a
307
+ sync.
308
+
309
+ On macOS the script updates an existing `Codex Grok.app`. It does not create
310
+ one, and it does not touch `/Applications/Codex.app`. On Linux it creates
311
+ `~/.local/share/codex-grok-bridge/app` and
312
+ `~/.local/share/applications/codex-grok.desktop`, and it does not write
313
+ `/usr/lib/chatgpt` or `/usr/share/applications/chatgpt.desktop`.
314
+
315
+ ## Security notes
316
+
317
+ The bridge binds loopback only. Each inference request needs a per-run
318
+ temporary token. Browser `Origin` requests, unsupported models, oversized
319
+ bodies, and unknown tool calls are rejected. Grok prompt temp files are `0600`
320
+ and deleted on exit. CLI error text and credentials are not returned in
321
+ responses. Codex’s and Grok’s own retention policies still apply.
322
+
323
+ ## Further docs
324
+
325
+ - `docs/HANDOFF.md` — current state, pitfalls, open items
326
+ - `docs/solution-20260909.md` — how a fixed 15-second failure was traced, and
327
+ every measurement behind the fixes
328
+ - `docs/experiments/` — scripts that reproduce those measurements
329
+
330
+ ## References
331
+
332
+ - [Grok Build headless scripting](https://docs.x.ai/build/cli/headless-scripting)
333
+ - [Grok Build source](https://github.com/xai-org/grok-build)
334
+ - [Codex source](https://github.com/openai/codex)
52
335
 
53
336
  ---
54
337
 
55
- 아래는 한국어 상세 설명입니다.
338
+ # 한국어
56
339
 
57
- ## Codex + Grok Build CLI
340
+ ## 이게 뭔가
58
341
 
59
- Grok 4.6 / xAI를 Codex 모델 목록에 추가하고, Grok의 도구 요청을 Codex가 실행하도록 연결하는 로컬 확장입니다. xAI API 키를 사용하지 않습니다. 설치된 `grok` CLI의 로그인 세션으로 추론합니다.
342
+ Grok 4.6을 Codex 모델 목록에 넣고, Codex의 `/v1/responses`를
343
+ `cli-chat-proxy.grok.com`으로 넘기는 로컬 브리지입니다. 추론은 Grok이 합니다.
344
+ 도구 호출(셸, 패치, MCP, …)은 Codex가 실행하고, 결과는 다음 요청의 `input`으로
345
+ 돌아갑니다. GPT 경로와 같은 에이전트 루프입니다.
60
346
 
61
- ## 실행
347
+ 브리지는 Grok 네이티브 도구를 실행하지 않습니다. Codex 도구를 function
348
+ calling으로 옮기고, 상류 Responses 스트림을 전달한 뒤, Codex가 알아보는
349
+ 이름으로 되돌립니다.
62
350
 
63
- 이 폴더의 **Open Codex with Grok.command**를 더블 클릭합니다. 별도로 열린 Codex 창에서 **새 작업을 시작하기 전에 Grok 4.6 / xAI를 선택**하세요. 기존 GPT 모델도 목록에 유지됩니다. 현재 실행 중인 일반 Codex 창에는 이 확장이 주입되지 않습니다.
351
+ `src/` 아래 파일 13개. 런타임 의존성 없음. Node.js 22 이상.
64
352
 
65
- 터미널에서는 다음과 같이 실행할 수 있습니다.
353
+ 코드 리뷰 전용 제품이 아니고, Grok 4.7 어댑터도 아니며, Grok 네이티브 검색
354
+ 제품도 아닙니다. Codex가 웹 검색 도구를 노출하면 Grok은 다른 Codex 도구와 같이
355
+ 그 도구를 호출할 수 있습니다.
356
+
357
+ ## 필요한 것
358
+
359
+ - macOS, 또는 공식 ChatGPT/Codex 데스크톱 패키지가 있는 Linux
360
+ - Node.js 22 이상
361
+ - `/Applications/Codex.app` (macOS) 또는 `/usr/lib/chatgpt/ChatGPT` (Linux)
362
+ - `~/.grok/bin/grok`
363
+ - 완료된 `grok login`
364
+
365
+ `.command` 런처는 자기 위치를 기준으로 경로를 잡으므로 폴더를 옮겨도 수정할
366
+ 필요가 없습니다. `PATH`에 `node`가 없으면 `NODE=/path/to/node`로 지정합니다.
367
+
368
+ 검증 버전: Codex 0.153.4 / 앱 26.901.51231, Grok CLI 1.0.25, Node 22.23.0.
369
+ 앱 업데이트가 `CODEX_CLI_PATH`나 app-server 프로토콜을 바꾸면 재검증이
370
+ 필요합니다.
371
+
372
+ ## 설치와 실행
373
+
374
+ ### 터미널 (npm)
66
375
 
67
376
  ```sh
68
- npm install -g codex-grok-bridge
69
- codex-grok
377
+ npm install -g codex-grok-bridge # macOS or Linux, Node ≥ 22
378
+ codex-grok # Grok 4.6이 있는 Codex를 띄움
70
379
  codex-grok exec --skip-git-repo-check --sandbox workspace-write '작업 내용'
71
380
  ```
72
381
 
73
- 체크아웃에서는 `node scripts/codex-grok.mjs`가 같은 진입점입니다. 필요한 설치: Node.js 22 이상, `/Applications/Codex.app`, `~/.grok/bin/grok`, 완료된 `grok login`. `.command` 런처는 자기 위치를 기준으로 경로를 잡으므로 폴더를 옮겨도 수정할 필요가 없습니다. `NODE=/path/to/node`로 Node를 지정할 수 있습니다.
382
+ `codex-grok`는 자기가 띄운 Codex 프로세스에만 브리지를 모델 제공자로 등록하고,
383
+ 그 프로세스와 함께 내립니다.
74
384
 
75
- ## 연결 방식
385
+ ### 체크아웃에서
76
386
 
77
- 기본 경로는 Codex-GPT와 같은 Responses 루프입니다. Grok 네이티브 도구는 실행하지 않습니다. 인증은 `grok login` 세션이며 `XAI_API_KEY`를 쓰지 않습니다.
387
+ ```sh
388
+ git clone https://github.com/deximple/codex-grok-bridge.git
389
+ cd codex-grok-bridge
390
+ npm test # 150건, 네트워크·추론 없음
391
+ node scripts/codex-grok.mjs
392
+ ```
393
+
394
+ ### 데스크톱
395
+
396
+ 이 폴더의 **Open Codex with Grok.command**를 더블 클릭하거나,
397
+ `scripts/install-codex-grok-app.sh`로 **별도의** 데스크톱 래퍼를 체크아웃과
398
+ 맞춥니다([데스크톱 설치와 갱신](#데스크톱-설치와-갱신)).
399
+ Linux에서는 `~/.local/share/codex-grok-bridge/app`과 사용자 `.desktop`이고,
400
+ 정품 `/usr/lib/chatgpt`는 패치하지 않습니다.
401
+
402
+ 새로 열린 Codex 창에서 **새 작업을 시작하기 전에 Grok 4.6 / xAI를 선택**하세요.
403
+ 기존 GPT 모델도 목록에 남습니다. 이미 열려 있던 일반 Codex 창에는 이 확장이
404
+ 주입되지 않습니다.
405
+
406
+ 전용 창은 UI 데이터를 `~/.local/share/codex-grok-bridge/desktop`에 두고,
407
+ 계정·작업·설정은 기존 Codex 홈을 **공유**합니다. 작업 내용과 설정 변경은 다른
408
+ Codex 창에도 보일 수 있습니다.
409
+
410
+ 설치 스크립트는 정품 Codex.app 번들, `/usr/lib/chatgpt`, 코드 서명,
411
+ `~/.codex/config.toml`, Grok 인증 파일을 수정하지 않습니다. 자동 시작
412
+ 서비스나 전역 환경변수도 등록하지 않습니다.
413
+
414
+ 중지하려면 이 확장으로 연 Codex 창을 닫으면 됩니다. 일반 Codex는 기존 아이콘으로
415
+ 실행합니다.
416
+
417
+ ## 연결 방식
78
418
 
79
419
  1. `CODEX_CLI_PATH`로 지정한 래퍼가 Codex app-server를 실행합니다.
80
- 2. 래퍼가 모델 목록에 Grok를 추가하고 새 Grok 작업의 제공자를 `grok_build_cli`로 설정합니다.
81
- 3. Codex의 `/v1/responses` 요청은 localhost 변환기로 갑니다.
82
- 4. 변환기는 Codex 도구를 function calling으로 옮긴 뒤 `cli-chat-proxy.grok.com` Responses 스트림을 그대로 이어줍니다. MCP/셸/패치 실행은 Codex가 합니다.
83
- 5. 도구 결과는 다음 Codex 요청의 `input`으로 다시 들어갑니다. GPT 경로와 같은 에이전트 루프입니다.
420
+ 2. 래퍼가 모델 목록에 Grok를 추가하고, 새 Grok 작업의 제공자를
421
+ `grok_build_cli`로 설정합니다.
422
+ 3. Codex의 `/v1/responses` 요청은 localhost 브리지로 갑니다.
423
+ 4. 브리지는 Codex 도구(일반 함수, namespace 함수, freeform 커스텀, `web_search`)를
424
+ function tool로 펼친 뒤 `cli-chat-proxy.grok.com` Responses 스트림을 이어줍니다.
425
+ 5. 도구 결과는 다음 Codex 요청의 `input`으로 돌아갑니다.
84
426
 
85
- 상류 연결은 `node:http(s)`와 keep-alive `Agent`(소켓 30초 유지, 최대 4개)로 직접 엽니다. DNS는 5분 TTL로 캐시하며, 조회가 실패해도 유효한 캐시가 있으면 그것으로 버팁니다. 도구 실행으로 5–20초가 비는 사이에 소켓이 닫혀 매번 새로 이름을 찾는 상황을 피하기 위한 것입니다. `GROK_BRIDGE_TRANSPORT=fetch`로 이전 `fetch` 경로로 되돌릴 수 있습니다.
427
+ 인증은 `grok login` 세션입니다. `XAI_API_KEY`는 쓰지 않습니다.
86
428
 
87
- Codex에 첫 SSE 블록을 쓰기 **전**에 죽은 요청은 한 번 다시 보냅니다. 아직 아무것도 전달하지 않았으므로 재전송이 대화를 오염시키지 않기 때문입니다. 첫 블록을 쓴 뒤에는 절대 재시도하지 않고, 422 같은 결정적 거절과 사용자 중단도 재시도하지 않습니다.
429
+ 상류 소켓은 `node:http(s)` keep-alive `Agent`(30초, 최대 4개)와 TTL 5분 DNS
430
+ 캐시를 씁니다. 조회가 실패해도 유효한 캐시가 있으면 그것으로 버팁니다. 도구
431
+ 실행으로 5–20초가 비어도 매번 이름을 다시 찾지 않기 위해서입니다.
432
+ `GROK_BRIDGE_TRANSPORT=fetch`로 이전 `fetch` 경로로 되돌릴 수 있습니다.
88
433
 
89
- 문제가 있으면 `GROK_BRIDGE_INFERENCE=cli`로 이전 CLI 봉투 경로를 쓸 수 있습니다. CLI 경로는 매 턴 전체 JSON을 프롬프트로 넣기 때문에 토큰과 지연이 큽니다.
434
+ Codex에 첫 SSE 블록을 쓰기 **전**에 죽은 요청은 한 번 다시 보냅니다. 아직
435
+ 아무것도 전달하지 않았으므로 재전송이 대화를 오염시키지 않습니다. 첫 블록을
436
+ 쓴 뒤에는 절대 재시도하지 않습니다. 422 같은 결정적 거절과 사용자 중단도
437
+ 재시도하지 않습니다.
90
438
 
91
- 설치된 Codex 앱 번들, 코드 서명, `~/.codex/config.toml`, Grok 인증 파일은 수정하지 않습니다. 전용 창은 `~/.local/share/codex-grok-bridge/desktop`에 UI 데이터를 저장하고 기존 Codex 홈의 계정·작업·설정을 공유합니다. 따라서 실제 사용자 작업 내용과 설정 변경은 다른 Codex 창에서도 보일 수 있습니다.
439
+ Responses 경로가 이상하면 `GROK_BRIDGE_INFERENCE=cli`로 이전 CLI 봉투 경로를
440
+ 씁니다. 매 턴 전체 JSON을 프롬프트로 넣으므로 더 느리고 비싸며, 토큰 단위
441
+ 실시간 출력이 없고, 요청당 3분 제한입니다.
442
+
443
+ 기본 Responses 경로는 스트림을 전달합니다. Codex `prompt_cache_key`는
444
+ `x-grok-conv-id`로 넘깁니다.
92
445
 
93
446
  ## 확인된 동작과 제한
94
447
 
95
- - 실제 app-server에서 GPT 6개 모델과 `grok-4.6`의 혼합 목록 및 Grok 제공자 라우팅 확인.
96
- - 실제 Grok CLI → Codex `exec_command` → 실행 결과 → Grok 최종 응답을 확인. 결과: `BRIDGE_TOOL_OK`.
97
- - 별도로 연 Codex 창에 `Grok 4.6 / xAI Extra High` 표시 확인.
98
- - 브리지는 상류로 보내는 `instructions` 끝에 출처 한 줄(`Transport: …`)을 붙입니다. Codex는 provider·model을 프롬프트에 넣지 않기 때문에, 이 줄이 없으면 "Grok이 붙었는지"를 모델이 확인할 방법이 없어 설정 파일을 뒤지거나 답을 얼버무립니다. 대화 내용을 판단하는 것이 아니라 전송이 자기 출처를 밝히는 것이며, `user-agent` 헤더와 같은 범주입니다.
99
- - Codex `reasoning` 항목의 평문 요약은 상류로 전달합니다. 암호화된 `encrypted_content`와 Codex 자체 아이템 id는 제거합니다. 여러 번 호출이 이어지는 턴에서 모델이 자기 추론을 이어받게 하기 위한 것으로, 실제 상류가 이 형태를 수락하는지 확인했습니다.
100
- - 추론은 변환기당 **동시 4건**까지 실행하고, 그 이상은 큐(기본 8)에서 대기합니다. 큐까지 가득 찼을 때만 `429`를 냅니다. 대기가 거절보다 나은 이유는 브리지가 이미 응답 헤더를 보냈고 keepalive로 스트림을 살려 두기 때문입니다. 동시 1로 조이면 Codex `spawn_agent` 자식 추론이 부모 턴과 겹쳐 죽습니다.
101
- - 일반 함수 도구, namespace 함수 도구, freeform 커스텀 도구를 변환합니다. 파일 변경·MCP 등은 Codex가 노출한 도구 및 권한 범위에서 사용할 수 있지만, 개별 기능을 모두 실검증한 것은 아닙니다.
102
- - 이미지 첨부·인식을 지원합니다. PNG/JPEG/WebP, **이미지당 10 MiB, 요청 전체 20 MiB**, 서로 다른 이미지 4장까지, PNG는 32메가픽셀까지입니다. 한도는 추측이 아니라 실측입니다 — 상류가 12.5 MiB PNG를 받아 답하는 것을 확인하고 그 아래로 잡았습니다.
103
- - **쓸 수 없는 첨부 하나가 대화를 죽이지 않습니다.** 브리지는 대화 전체를 훑기 때문에, 예전에는 한도를 넘는 이미지가 히스토리에 한 번 들어가면 이후 모든 턴이 영구히 400으로 실패했습니다. 지금은 그런 첨부만 이유를 밝힌 텍스트로 바꾸고 나머지는 그대로 보냅니다. 쓸 수 있는 이미지는 `input_image` 그대로 넘어가며(Grok가 직접 읽습니다), 원격 URL은 가져오지 않습니다.
104
- - 음성, 클라우드 작업, 영상 생성은 아직 보장하지 않습니다.
105
- - 기본 Responses 경로는 스트림을 전달합니다. 프롬프트 캐시 키는 Codex `prompt_cache_key`를 `x-grok-conv-id`로 넘깁니다.
106
- - cli-chat-proxy는 function tool 339개 요청을 수락했습니다. 공개 API 문서의 200개 한도는 이 로그인 경로에 적용되지 않습니다.
107
- - 저장된 루트 작업이 대기 중이면 GPT ↔ Grok 전환을 지원합니다. `turn/start`와 설정 변경 API는 제공자를 바꾸지 못하므로, 래퍼가 구독 해제 → 같은 ID로 제공자를 지정해 재개 → 제공자·권한 확인 후 원래 요청을 전달합니다. 실행 중인 작업, 임시 작업, 하위 에이전트는 제공자 전환을 거부하며, 다른 구독자가 전환을 막으면 추론을 보내지 않습니다. 첫 턴이 저장되기 전에는 새 작업을 시작할 때 원하는 모델을 선택하세요.
108
- - **이미지 생성도 Grok이 합니다.** 브리지가 상류 요청에 `{ type: "image_generation" }`을 직접 선언하므로, Codex가 이미지 도구를 노출하지 않아도 Grok이 서버 쪽에서 생성합니다. 도구가 켜져 있으면 `instructions` 끝에 `Images:` 출처 한 줄을 붙여 Codex `imagegen` 스킬을 읽지 말라고 합니다. 돌아온 바이트는 `~/.local/share/codex-grok-bridge/generated-images/`에 0600으로 저장하고, Codex에는 `[경로](file:///…)` 마크다운 링크로 전달합니다. Codex가 모르는 `response.image_generation_call.*` 이벤트는 걸러냅니다. `GROK_BRIDGE_IMAGE_GEN=off`로 끄면 도구와 그 줄이 같이 빠집니다.
109
- - **한계도 실측했습니다.** Grok의 `image_generation`은 텍스트→이미지 생성만 제대로 됩니다.
110
-
111
- | 기능 | 결과 |
112
- |---|---|
113
- | 텍스트→이미지 생성 | 됨 |
114
- | 투명 배경 | **안 됨.** 항상 JPEG로 오고 알파 채널이 없습니다. 모델은 "투명 배경"이라고 말하면서 **체커보드를 그림에 칠해서** 보냅니다 |
115
- | 도구 파라미터(`background`, `output_format`) | 거부되지 않고 **조용히 무시**됩니다 |
116
- | 이미지 편집(image-to-image) | **진짜 편집이 아닙니다.** 입력 이미지를 텍스트로 묘사해 재생성하므로 구도·크기·해상도가 달라집니다 |
117
-
118
- 그래서 브리지는 저장한 파일의 실제 포맷을 확인해, 알파가 없으면 "이 포맷은 알파 채널이 없으니 투명하다고 설명하지 말라"고 모델에게 명시합니다. 투명 배경이나 정확한 인페인팅이 꼭 필요하면 Codex의 OpenAI 경로를 쓰는 편이 맞습니다.
119
- - 이게 없으면 Codex의 `imagegen` 시스템 스킬이 OpenAI 경로(내장 `image_gen` 또는 `OPENAI_API_KEY` + `gpt-image-*`)로 갑니다. 실제로 Codex가 이 프로바이더에 보내는 263개 도구 중 이미지 생성 도구는 하나도 없습니다 — `view_image`뿐입니다. 즉 추론은 Grok인데 그림만 다른 벤더에서 나오는 상태가 됩니다.
120
- - CLI 폴백은 응답이 끝난 뒤 Codex에 결과를 전달하므로 토큰 단위 실시간 출력이 없습니다. 요청당 3분 제한입니다.
121
- - 상류가 응답 중간에 연결을 리셋하는 경우가 간헐적으로 있습니다(실측 3건: 25s/27s/253s, 726 KB–22 MB). 브리지는 이걸 재시도할 수 없습니다 — Codex가 이미 응답 일부를 받았으므로 재전송하면 중복됩니다. 대신 provider에 `stream_max_retries: 2`를 설정해 **Codex가 같은 요청을 다시 보내도록** 했습니다. 대화를 소유한 쪽만 안전하게 재시도할 수 있습니다.
122
- - 앱 업데이트가 `CODEX_CLI_PATH`나 app-server 프로토콜을 바꾸면 재검증이 필요합니다. 검증 버전: Codex 0.153.4 / 앱 26.901.51231, Grok CLI 1.0.24, Node 22.23.0.
448
+ 추측이 아니라 실측입니다.
449
+
450
+ - 실제 app-server에서 GPT 6개 모델과 `grok-4.6`의 혼합 목록, Grok 제공자 라우팅.
451
+ - 실제 Grok CLI → Codex `exec_command` → 결과 → Grok 최종 응답
452
+ (`BRIDGE_TOOL_OK`).
453
+ - 별도 Codex 창에 `Grok 4.6 / xAI Extra High` 표시.
454
+ - cli-chat-proxy가 function tool 339개 요청을 수락. 공개 API 문서의 200개 한도는
455
+ 이 로그인 경로에 적용되지 않음.
456
+
457
+ ### 출처 한 줄
458
+
459
+ Codex는 provider·model을 프롬프트에 넣지 않습니다. 브리지는 `instructions` 끝에
460
+ `Transport:` 줄을 붙여, 모델이 설정 파일을 열지 않고도 “Grok이 붙었는가”에
461
+ 답하게 합니다. 대화 내용을 판단하는 것이 아니라 전송이 자기 출처를 밝히는
462
+ 것이며, `User-Agent` 헤더와 같은 범주입니다.
463
+
464
+ 이미지 생성이 켜져 있으면 `Images:` 줄도 붙습니다. 이 전송의 그림은 요청에 이미
465
+ 있는 Grok `image_generation` 도구로 만들고, Codex `imagegen` 스킬을 읽거나
466
+ OpenAI로 보내지 말라는 뜻입니다. `GROK_BRIDGE_IMAGE_GEN=off`면 도구와 그 줄이
467
+ 같이 빠집니다.
468
+
469
+ ### reasoning
470
+
471
+ Codex `reasoning` 항목의 평문 요약은 상류로 전달합니다. 암호화된
472
+ `encrypted_content`와 Codex 자체 아이템 id는 제거합니다. 여러 번 호출이 이어지는
473
+ 턴에서 모델이 자기 추론을 이어받게 하기 위한 것이며, 상류가 이 형태를 수락하는
474
+ 것을 확인했습니다. 같은 과정에서 아이템과 content part는 Grok Responses가
475
+ 받는 필드만 남깁니다. `status`, 알 수 없는 Codex 키, `internal_*` 필드는
476
+ 버려서 새 클라이언트 필드가 상류 422를 내지 않게 합니다.
477
+
478
+ ### 동시성
479
+
480
+ 변환기당 추론은 **동시 4건**, 나머지는 큐(기본 8)에서 대기합니다. 큐까지 가득
481
+ 찼을 때만 `429`입니다. 브리지가 이미 응답 헤더를 보냈고 keepalive로 스트림을
482
+ 살려 두기 때문에 대기가 거절보다 낫습니다. 동시 1로 조이면 Codex `spawn_agent`
483
+ 자식 추론이 부모 턴과 겹쳐 죽습니다.
484
+
485
+ ### 도구
486
+
487
+ 일반 함수 도구, namespace 함수 도구, freeform 커스텀 도구를 변환합니다. 파일
488
+ 변경·MCP 등은 Codex가 노출한 도구와 사용자가 정한 승인 정책 안에서 동작합니다.
489
+ 개별 기능을 모두 실검증한 것은 아닙니다.
490
+
491
+ ### 이미지 첨부 (인식)
492
+
493
+ PNG / JPEG / WebP. **이미지당 10 MiB, 요청 전체 20 MiB**, 서로 다른 이미지
494
+ 4장까지, PNG는 32메가픽셀까지. 한도는 실측입니다 — 상류가 12.5 MiB PNG를 받아
495
+ 답하는 것을 확인하고 그 아래로 잡았습니다.
496
+
497
+ 쓸 수 없는 첨부 하나가 대화를 죽이지 않습니다. 브리지는 대화 전체를 훑기
498
+ 때문에, 예전에는 한도를 넘는 이미지가 히스토리에 한 번 들어가면 이후 모든 턴이
499
+ 영구히 400이었습니다. 지금은 그 첨부만 이유를 밝힌 텍스트로 바꾸고 나머지는
500
+ 그대로 보냅니다. 쓸 수 있는 이미지는 `input_image` 그대로 넘어가며 Grok가 직접
501
+ 읽습니다. 원격 URL은 가져오지 않습니다.
502
+
503
+ ### 이미지 생성
504
+
505
+ 브리지가 상류 요청에 `{ type: "image_generation" }`을 직접 선언합니다. Codex는
506
+ 이 프로바이더에 이미지 생성 도구를 주지 않습니다(263개 중 없음, `view_image`
507
+ 뿐). 선언이 없으면 Codex `imagegen` 스킬이 OpenAI 경로(`image_gen` 또는
508
+ `OPENAI_API_KEY` + `gpt-image-*`)로 가서, 추론은 Grok인데 그림만 다른 벤더가
509
+ 그립니다.
510
+
511
+ 돌아온 바이트는 `~/.local/share/codex-grok-bridge/generated-images/`에 `0600`으로
512
+ 저장합니다. Codex는 그 바이트를 둘 곳이 없어서, 브리지는 경로를 마크다운
513
+ `file://` 링크로 넣은 assistant 메시지로 바꿉니다.
514
+
515
+ `[ /path/to/grok-….jpg ](file:///path/to/grok-….jpg)`
516
+
517
+ 클릭 여부는 Codex 마크다운 렌더러에 달립니다. Codex가 모르는
518
+ `response.image_generation_call.*` 이벤트는 걸러냅니다.
519
+
520
+ Grok의 `image_generation`은 텍스트→이미지만 제대로 됩니다.
521
+
522
+ | 기능 | 결과 |
523
+ |---|---|
524
+ | 텍스트→이미지 | 됨 |
525
+ | 투명 배경 | **안 됨.** 항상 JPEG, 알파 없음. 모델은 “투명”이라고 말하면서 체커보드를 그림에 칠함 |
526
+ | 도구 파라미터(`background`, `output_format`) | 받아 주고 **조용히 무시** |
527
+ | 이미지 편집(image-to-image) | **진짜 편집이 아님.** 입력을 텍스트로 묘사해 재생성하므로 구도·해상도가 바뀜 |
528
+
529
+ 브리지는 저장한 파일의 포맷을 확인합니다. 알파가 없으면 모델에게 투명하다고
530
+ 설명하지 말라고 적습니다. 진짜 알파나 정확한 인페인팅이 필요하면 Codex의
531
+ OpenAI 경로가 맞습니다.
532
+
533
+ ### GPT ↔ Grok 전환
534
+
535
+ 대기 중인 저장된 루트 작업에서만 됩니다. `turn/start`,
536
+ `thread/settings/update`, `turn/settings/update`는 `modelProvider`를 바꾸지
537
+ 못하고, 추가 provider 필드는 무시됩니다. 래퍼가 구독 해제 → 같은 ID로
538
+ 모델/제공자를 지정해 재개 → 돌아온 제공자·권한을 확인한 뒤 원래 요청을
539
+ 전달합니다. 실행 중인 작업, 임시 작업, 하위 에이전트는 전환을 거부합니다. 다른
540
+ 구독자가 재로드를 막으면 추론을 보내지 않습니다. 첫 턴이 저장되기 전에 새
541
+ 작업을 시작할 때 원하는 모델을 고르세요.
542
+
543
+ ### 아직 보장하지 않는 것
544
+
545
+ 음성, 클라우드 작업, 영상 생성은 약속하지 않습니다.
546
+
547
+ 상류가 응답 중간에 연결을 리셋하는 경우가 있습니다(실측 3건: 25초 / 27초 /
548
+ 253초, 726 KB–22 MB). 첫 SSE 바이트 이후에는 브리지가 재시도할 수 없습니다.
549
+ provider에 Codex `request_max_retries` / `stream_max_retries`를 2로 두어
550
+ **Codex**가 같은 요청을 다시 보내게 했습니다. 대화를 소유한 쪽만 안전하게
551
+ 재시도할 수 있습니다.
123
552
 
124
553
  ## 진단 로그
125
554
 
126
- 브리지는 매 턴을 `~/.local/share/codex-grok-bridge/logs/bridge.jsonl`에 한 줄씩 기록합니다(디렉터리 0700, 파일 0600, 4 MiB 초과 시 `.1`로 1회 회전). 끄려면 `GROK_BRIDGE_DIAGNOSTICS=off`.
555
+ 매 턴을 `~/.local/share/codex-grok-bridge/logs/bridge.jsonl`에 한 줄씩 기록합니다
556
+ (디렉터리 `0700`, 파일 `0600`, 4 MiB 초과 시 `.1`로 1회 회전).
557
+ `GROK_BRIDGE_DIAGNOSTICS=off`로 끕니다.
127
558
 
128
559
  ```jsonl
129
560
  {"at":"…","event":"turn_ok","mode":"proxy","elapsedMs":14118,"requestBytes":469749,"items":4,"tools":29}
130
561
  {"at":"…","event":"turn_failed","kind":"dns","signature":"TypeError <- Error[EAI_AGAIN]","elapsedMs":15071,…}
131
562
  ```
132
563
 
133
- 구조적 사실만 남깁니다 — 시각, 성공/실패, 오류 분류, 오류 체인의 이름·코드, 경과 시간, 요청 바이트, 아이템·도구 개수. **프롬프트 본문, 도구 출력, 상류 응답 본문, 토큰은 기록하지 않습니다.** `detail`에 들어가는 오류 메시지는 Bearer 토큰·JWT·API 키·홈 경로를 치환한 뒤 400자로 자릅니다.
564
+ 구조적 사실만 남깁니다 — 시각, 성공/실패, 오류 분류, 오류 체인의 이름·코드,
565
+ 경과 시간, 요청 바이트, 아이템·도구 개수. **프롬프트 본문, 도구 출력, 상류 응답
566
+ 본문, 토큰은 기록하지 않습니다.** `detail`은 Bearer 토큰·JWT·API 키·홈 경로를
567
+ 지운 뒤 400자로 자릅니다.
134
568
 
135
- 성공 턴도 남기는 이유는, 실패 시 로그가 비어 있다는 사실 자체가 "브리지가 호출되지도 않았다"는 진단이 되기 때문입니다.
569
+ 성공 턴도 남깁니다. 실패했는데 로그가 비어 있으면 브리지가 호출되지 않은
570
+ 것입니다.
136
571
 
137
- `event: "turn_failed"`의 `kind`는 다음 중 하나입니다 — `aborted`(사용자가 중단), `auth`(로그인 만료), `dns`, `connect`, `upstream_timeout`, `upstream_closed`, `upstream_protocol`, `payload`, `internal`. Codex UI에는 같은 분류가 `bridge_<kind>` 코드와 함께 표시됩니다.
572
+ `turn_failed.kind`는 다음 중 하나입니다 — `aborted`, `auth`, `dns`, `connect`,
573
+ `upstream_timeout`, `upstream_closed`, `upstream_protocol`, `payload`,
574
+ `internal`. Codex UI에는 같은 분류가 `bridge_<kind>`로 보입니다.
575
+
576
+ 문제가 있으면 여기부터 봅니다. 브리지를 “확인”하려고 `~/.grok/auth.json`이나
577
+ `~/.codex/auth.json`을 열지 마세요.
578
+
579
+ ## 환경 변수
580
+
581
+ | 변수 | 효과 |
582
+ |---|---|
583
+ | `GROK_BRIDGE_IMAGE_GEN=off` | Grok `image_generation`을 선언하지 않고 `Images:` 줄도 붙이지 않음 |
584
+ | `GROK_BRIDGE_TRANSPORT=fetch` | `node:http(s)` 대신 Node `fetch` |
585
+ | `GROK_BRIDGE_INFERENCE=cli` | CLI 봉투 경로로 폴백 |
586
+ | `GROK_BRIDGE_DIAGNOSTICS=off` | JSONL 로그를 쓰지 않음 |
587
+ | `NODE` | `.command` / 데스크톱 스크립트가 쓸 `node` 절대 경로 |
588
+ | `CODEX_GROK_APP` | `install-codex-grok-app.sh`가 쓸 앱 경로 (macOS: `/Applications/Codex Grok.app`; Linux: `~/.local/share/codex-grok-bridge/app`) |
138
589
 
139
590
  ## 검증
140
591
 
141
592
  ```sh
142
- npm test # 131건, 외부 추론 없음
593
+ npm test # 150건, 외부 추론 없음
143
594
  npm run test:coverage # line/branch/function 80% 게이트
144
- npm run verify:app-server # 실제 app-server 라우팅. 설치된 앱 번들에서도 실행됩니다
595
+ npm run verify:app-server # 실제 app-server 라우팅. 설치된 앱 번들에서도 실행
145
596
  npm audit --omit=dev
146
597
  ```
147
598
 
148
- ## 설치와 갱신
599
+ `npm test`는 외부 추론을 호출하지 않습니다. `verify:app-server`는 실제
600
+ app-server에 모델 목록과 임시 작업을 요청하며, 모델 추론은 하지 않습니다. 실제
601
+ CLI 검증은 사용자 계정 사용량을 씁니다.
602
+
603
+ ## 데스크톱 설치와 갱신
149
604
 
150
605
  ```sh
151
606
  sh scripts/install-codex-grok-app.sh # 브리지 JS만 동기화 (기본)
152
- sh scripts/install-codex-grok-app.sh --full # 런처 applet 재빌드 + 서명까지
607
+ sh scripts/install-codex-grok-app.sh --full # macOS: 런처 applet 재빌드 + 서명
153
608
  ```
154
609
 
155
- 기본 동작은 번들의 `src/`·`scripts/`를 이 저장소와 일치시키는 것입니다. 디렉터리를 지우지 않고, 저장소에 없는 파일만 골라서 제거하며, 끝에 내용이 일치하는지 확인합니다. Codex Grok 창이 열려 있으면 거부합니다(`--force`로 무시). ESM은 핫리로드되지 않으므로 **동기화 후 창을 다시 열어야** 새 코드가 적용됩니다.
610
+ 기본 동작은 이 체크아웃의 `src/`와 `scripts/*.mjs`를 번들에 복사하고, 저장소에
611
+ 없는 파일만 고른 뒤, 끝에서 모든 파일을 `cmp`합니다. 살아있는 번들을
612
+ `rm -rf`하지 않습니다. Codex Grok 창이 열려 있으면 거부합니다(`--force`로
613
+ 무시). ESM은 핫리로드되지 않으므로 **동기화 후 창을 다시 열어야** 합니다.
614
+
615
+ macOS에서는 이미 있는 `Codex Grok.app`을 갱신하며 `/Applications/Codex.app`은
616
+ 건드리지 않습니다. Linux에서는 `~/.local/share/codex-grok-bridge/app`과
617
+ `~/.local/share/applications/codex-grok.desktop`을 만들고 `/usr/lib/chatgpt`와
618
+ 정품 `chatgpt.desktop`은 쓰지 않습니다.
619
+
620
+ ## 보안
621
+
622
+ 브리지는 loopback에만 붙습니다. 추론 요청마다 실행 단위 임시 토큰이 필요합니다.
623
+ 브라우저 `Origin` 요청, 지원하지 않는 모델, 과대 본문, 알 수 없는 도구 호출은
624
+ 거절합니다. Grok 프롬프트 임시 파일은 `0600`으로 만들고 종료 후 지웁니다. CLI
625
+ 오류 원문과 인증 정보는 응답에 넣지 않습니다. Codex와 Grok 자체의 보관 정책은
626
+ 그대로입니다.
156
627
 
157
- 테스트는 외부 추론을 호출하지 않습니다. `verify:app-server`는 실제 app-server에 모델 목록과 임시 작업 생성을 요청하며, 모델 추론은 하지 않습니다. 실제 CLI 검증은 사용자 계정 사용량을 소비합니다.
628
+ ## 더 깊은 문서
158
629
 
159
- 변환기는 loopback에만 바인딩하며, 추론 요청에 매 실행마다 생성한 임시 토큰을 요구합니다. 브라우저 Origin 요청, 지원하지 않는 모델, 과대 요청, 알 수 없는 도구 호출은 거부합니다. Grok 프롬프트 임시 파일은 0600 권한으로 생성하고 종료 후 제거합니다. CLI 오류 원문과 인증 정보는 응답에 포함하지 않습니다. Codex와 Grok 자체의 대화 저장 정책은 그대로 적용됩니다.
630
+ - `docs/HANDOFF.md` — 현재 상태, 함정, 남은 항목
631
+ - `docs/solution-20260909.md` — 15초 고정 실패를 추적한 기록과 측정
632
+ - `docs/experiments/` — 그 측정을 재현하는 스크립트
160
633
 
161
- 중지하려면 확장으로 연 Codex 창을 종료하세요. 일반 Codex는 기존 아이콘으로 실행하면 됩니다. 자동 시작 서비스나 전역 환경변수는 등록하지 않았습니다.
634
+ ## 참고
162
635
 
163
- 참고: [Grok Build headless scripting](https://docs.x.ai/build/cli/headless-scripting), [Grok Build source](https://github.com/xai-org/grok-build), [Codex source](https://github.com/openai/codex).
636
+ - [Grok Build headless scripting](https://docs.x.ai/build/cli/headless-scripting)
637
+ - [Grok Build source](https://github.com/xai-org/grok-build)
638
+ - [Codex source](https://github.com/openai/codex)