Skip to content

Commit 70906e8

Browse files
garrytanclaude
andauthored
fix: Codex hang fixes — plan visibility, stdout buffering, reasoning effort (v0.12.4.0) (garrytan#536)
* fix: unbuffer Python stdout in codex --json streaming Python fully buffers stdout when piped (not a TTY). The `codex exec --json | python3 -c "..."` pattern meant zero output visible until process exit — users saw nothing for 30+ minutes. Add PYTHONUNBUFFERED=1 env var, python3 -u flag, and flush=True to all print() calls in all three Python parser blocks (Challenge, Consult new session, Consult resumed session). Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: per-mode reasoning effort defaults, add --xhigh override xhigh reasoning uses ~23x more tokens and causes 50+ minute hangs on large context tasks (OpenAI issues #8545, #8402, #6931). Per-mode defaults for /codex skill: - Review: high (bounded diff, needs thoroughness) - Challenge: high (adversarial but bounded by diff) - Consult: medium (large context, interactive, needs speed) Also changes all Outside Voice / adversarial codex invocations across gstack (resolvers, gen-skill-docs) from xhigh to high. Users can override with --xhigh flag when they want max reasoning. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: explicit plan content embedding for codex sandbox visibility Codex runs sandboxed to repo root (-C) and cannot access ~/.claude/plans/. The template already instructed content embedding but wasn't explicit enough — Claude sometimes shortcut to referencing the file path, causing Codex to waste 10+ tool calls searching before giving up. Strengthen the instruction to make embedding unambiguous: "embed FULL CONTENT, do NOT reference the file path." Also extract referenced source file paths from the plan so Codex reads them directly instead of discovering via rg/find. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: add --xhigh reminder to challenge and consult modes The --xhigh override was only documented in Step 2A (review). Steps 2B (challenge) and 2C (consult) lacked the reminder, so the flag would silently do nothing for those modes. Found by adversarial review. * chore: bump version and changelog (v0.12.4.0) Co-Authored-By: Claude Opus 4.6 <[email protected]> --------- Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
1 parent 7a7dc07 commit 70906e8

13 files changed

Lines changed: 138 additions & 59 deletions

File tree

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# Changelog
22

3+
## [0.12.5.0] - 2026-03-26 — Fix Codex Hangs: 30-Minute Waits Are Gone
4+
5+
Three bugs in `/codex` caused 30+ minute hangs with zero output during plan reviews and adversarial checks. All three are fixed.
6+
7+
### Fixed
8+
9+
- **Plan files now visible to Codex sandbox.** Codex runs sandboxed to the repo root and couldn't see plan files at `~/.claude/plans/`. It would waste 10+ tool calls searching before giving up. Now the plan content is embedded directly in the prompt, and referenced source files are listed so Codex reads them immediately.
10+
- **Streaming output actually streams.** Python's stdout buffering meant zero output visible until the process exited. Added `PYTHONUNBUFFERED=1`, `python3 -u`, and `flush=True` on every print call across all three Codex modes.
11+
- **Sane reasoning effort defaults.** Replaced hardcoded `xhigh` (23x more tokens, known 50+ min hangs per OpenAI issues #8545, #8402, #6931) with per-mode defaults: `high` for review and challenge, `medium` for consult. Users can override with `--xhigh` flag when they want maximum reasoning.
12+
- **`--xhigh` override works in all modes.** The override reminder was missing from challenge and consult mode instructions. Found by adversarial review.
13+
314
## [0.12.4.0] - 2026-03-26 — Full Commit Coverage in /ship
415

516
When you ship a branch with 12 commits spanning performance work, dead code removal, and test infra, the PR should mention all three. It wasn't. The CHANGELOG and PR summary biased toward whatever happened most recently, silently dropping earlier work.

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.12.4.0
1+
0.12.5.0

codex/SKILL.md

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,14 @@ Parse the user's input to determine which mode to run:
407407
- Otherwise, ask: "What would you like to ask Codex?"
408408
4. `/codex <anything else>` — **Consult mode** (Step 2C), where the remaining text is the prompt
409409
410+
**Reasoning effort override:** If the user's input contains `--xhigh` anywhere,
411+
note it and remove it from the prompt text before passing to Codex. When `--xhigh`
412+
is present, use `model_reasoning_effort="xhigh"` for all modes regardless of the
413+
per-mode default below. Otherwise, use the per-mode defaults:
414+
- Review (2A): `high` — bounded diff input, needs thoroughness
415+
- Challenge (2B): `high` — adversarial but bounded by diff
416+
- Consult (2C): `medium` — large context, interactive, needs speed
417+
410418
---
411419
412420
## Step 2A: Review Mode
@@ -420,13 +428,15 @@ TMPERR=$(mktemp /tmp/codex-err-XXXXXX.txt)
420428

421429
2. Run the review (5-minute timeout):
422430
```bash
423-
codex review --base <base> -c 'model_reasoning_effort="xhigh"' --enable web_search_cached 2>"$TMPERR"
431+
codex review --base <base> -c 'model_reasoning_effort="high"' --enable web_search_cached 2>"$TMPERR"
424432
```
425433

434+
If the user passed `--xhigh`, use `"xhigh"` instead of `"high"`.
435+
426436
Use `timeout: 300000` on the Bash call. If the user provided custom instructions
427437
(e.g., `/codex review focus on security`), pass them as the prompt argument:
428438
```bash
429-
codex review "focus on security" --base <base> -c 'model_reasoning_effort="xhigh"' --enable web_search_cached 2>"$TMPERR"
439+
codex review "focus on security" --base <base> -c 'model_reasoning_effort="high"' --enable web_search_cached 2>"$TMPERR"
430440
```
431441

432442
3. Capture the output. Then parse cost from stderr:
@@ -563,8 +573,11 @@ With focus (e.g., "security"):
563573
"Review the changes on this branch against the base branch. Run `git diff origin/<base>` to see the diff. Focus specifically on SECURITY. Your job is to find every way an attacker could exploit this code. Think about injection vectors, auth bypasses, privilege escalation, data exposure, and timing attacks. Be adversarial."
564574

565575
2. Run codex exec with **JSONL output** to capture reasoning traces and tool calls (5-minute timeout):
576+
577+
If the user passed `--xhigh`, use `"xhigh"` instead of `"high"`.
578+
566579
```bash
567-
codex exec "<prompt>" -C "$(git rev-parse --show-toplevel)" -s read-only -c 'model_reasoning_effort="xhigh"' --enable web_search_cached --json 2>/dev/null | python3 -c "
580+
codex exec "<prompt>" -C "$(git rev-parse --show-toplevel)" -s read-only -c 'model_reasoning_effort="high"' --enable web_search_cached --json 2>/dev/null | PYTHONUNBUFFERED=1 python3 -u -c "
568581
import sys, json
569582
for line in sys.stdin:
570583
line = line.strip()
@@ -577,17 +590,17 @@ for line in sys.stdin:
577590
itype = item.get('type','')
578591
text = item.get('text','')
579592
if itype == 'reasoning' and text:
580-
print(f'[codex thinking] {text}')
581-
print()
593+
print(f'[codex thinking] {text}', flush=True)
594+
print(flush=True)
582595
elif itype == 'agent_message' and text:
583-
print(text)
596+
print(text, flush=True)
584597
elif itype == 'command_execution':
585598
cmd = item.get('command','')
586-
if cmd: print(f'[codex ran] {cmd}')
599+
if cmd: print(f'[codex ran] {cmd}', flush=True)
587600
elif t == 'turn.completed':
588601
usage = obj.get('usage',{})
589602
tokens = usage.get('input_tokens',0) + usage.get('output_tokens',0)
590-
if tokens: print(f'\ntokens used: {tokens}')
603+
if tokens: print(f'\ntokens used: {tokens}', flush=True)
591604
except: pass
592605
"
593606
```
@@ -636,20 +649,34 @@ ls -t ~/.claude/plans/*.md 2>/dev/null | xargs grep -l "$(basename $(pwd))" 2>/d
636649
```
637650
If no project-scoped match, fall back to `ls -t ~/.claude/plans/*.md 2>/dev/null | head -1`
638651
but warn: "Note: this plan may be from a different project — verify before sending to Codex."
639-
Read the plan file and prepend the persona to the user's prompt:
652+
653+
**IMPORTANT — embed content, don't reference path:** Codex runs sandboxed to the repo
654+
root (`-C`) and cannot access `~/.claude/plans/` or any files outside the repo. You MUST
655+
read the plan file yourself and embed its FULL CONTENT in the prompt below. Do NOT tell
656+
Codex the file path or ask it to read the plan file — it will waste 10+ tool calls
657+
searching and fail.
658+
659+
Also: scan the plan content for referenced source file paths (patterns like `src/foo.ts`,
660+
`lib/bar.py`, paths containing `/` that exist in the repo). If found, list them in the
661+
prompt so Codex reads them directly instead of discovering them via rg/find.
662+
663+
Prepend the persona to the user's prompt:
640664
"You are a brutally honest technical reviewer. Review this plan for: logical gaps and
641665
unstated assumptions, missing error handling or edge cases, overcomplexity (is there a
642666
simpler approach?), feasibility risks (what could go wrong?), and missing dependencies
643667
or sequencing issues. Be direct. Be terse. No compliments. Just the problems.
668+
Also review these source files referenced in the plan: <list of referenced files, if any>.
644669

645670
THE PLAN:
646-
<plan content>"
671+
<full plan content, embedded verbatim>"
647672

648673
4. Run codex exec with **JSONL output** to capture reasoning traces (5-minute timeout):
649674

675+
If the user passed `--xhigh`, use `"xhigh"` instead of `"medium"`.
676+
650677
For a **new session:**
651678
```bash
652-
codex exec "<prompt>" -C "$(git rev-parse --show-toplevel)" -s read-only -c 'model_reasoning_effort="xhigh"' --enable web_search_cached --json 2>"$TMPERR" | python3 -c "
679+
codex exec "<prompt>" -C "$(git rev-parse --show-toplevel)" -s read-only -c 'model_reasoning_effort="medium"' --enable web_search_cached --json 2>"$TMPERR" | PYTHONUNBUFFERED=1 python3 -u -c "
653680
import sys, json
654681
for line in sys.stdin:
655682
line = line.strip()
@@ -659,31 +686,31 @@ for line in sys.stdin:
659686
t = obj.get('type','')
660687
if t == 'thread.started':
661688
tid = obj.get('thread_id','')
662-
if tid: print(f'SESSION_ID:{tid}')
689+
if tid: print(f'SESSION_ID:{tid}', flush=True)
663690
elif t == 'item.completed' and 'item' in obj:
664691
item = obj['item']
665692
itype = item.get('type','')
666693
text = item.get('text','')
667694
if itype == 'reasoning' and text:
668-
print(f'[codex thinking] {text}')
669-
print()
695+
print(f'[codex thinking] {text}', flush=True)
696+
print(flush=True)
670697
elif itype == 'agent_message' and text:
671-
print(text)
698+
print(text, flush=True)
672699
elif itype == 'command_execution':
673700
cmd = item.get('command','')
674-
if cmd: print(f'[codex ran] {cmd}')
701+
if cmd: print(f'[codex ran] {cmd}', flush=True)
675702
elif t == 'turn.completed':
676703
usage = obj.get('usage',{})
677704
tokens = usage.get('input_tokens',0) + usage.get('output_tokens',0)
678-
if tokens: print(f'\ntokens used: {tokens}')
705+
if tokens: print(f'\ntokens used: {tokens}', flush=True)
679706
except: pass
680707
"
681708
```
682709

683710
For a **resumed session** (user chose "Continue"):
684711
```bash
685-
codex exec resume <session-id> "<prompt>" -C "$(git rev-parse --show-toplevel)" -s read-only -c 'model_reasoning_effort="xhigh"' --enable web_search_cached --json 2>"$TMPERR" | python3 -c "
686-
<same python streaming parser as above>
712+
codex exec resume <session-id> "<prompt>" -C "$(git rev-parse --show-toplevel)" -s read-only -c 'model_reasoning_effort="medium"' --enable web_search_cached --json 2>"$TMPERR" | PYTHONUNBUFFERED=1 python3 -u -c "
713+
<same python streaming parser as above, with flush=True on all print() calls>
687714
"
688715
```
689716

@@ -718,7 +745,14 @@ Session saved — run /codex again to continue this conversation.
718745
agentic coding model). This means as OpenAI ships newer models, /codex automatically
719746
uses them. If the user wants a specific model, pass `-m` through to codex.
720747

721-
**Reasoning effort:** All modes use `xhigh` — maximum reasoning power. When reviewing code, breaking code, or consulting on architecture, you want the model thinking as hard as possible.
748+
**Reasoning effort (per-mode defaults):**
749+
- **Review (2A):** `high` — bounded diff input, needs thoroughness but not max tokens
750+
- **Challenge (2B):** `high` — adversarial but bounded by diff size
751+
- **Consult (2C):** `medium` — large context (plans, codebase), interactive, needs speed
752+
753+
`xhigh` uses ~23x more tokens than `high` and causes 50+ minute hangs on large context
754+
tasks (OpenAI issues #8545, #8402, #6931). Users can override with `--xhigh` flag
755+
(e.g., `/codex review --xhigh`) when they want maximum reasoning and are willing to wait.
722756

723757
**Web search:** All codex commands use `--enable web_search_cached` so Codex can look up
724758
docs and APIs during review. This is OpenAI's cached index — fast, no extra cost.

codex/SKILL.md.tmpl

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ Parse the user's input to determine which mode to run:
6767
- Otherwise, ask: "What would you like to ask Codex?"
6868
4. `/codex <anything else>` — **Consult mode** (Step 2C), where the remaining text is the prompt
6969

70+
**Reasoning effort override:** If the user's input contains `--xhigh` anywhere,
71+
note it and remove it from the prompt text before passing to Codex. When `--xhigh`
72+
is present, use `model_reasoning_effort="xhigh"` for all modes regardless of the
73+
per-mode default below. Otherwise, use the per-mode defaults:
74+
- Review (2A): `high` — bounded diff input, needs thoroughness
75+
- Challenge (2B): `high` — adversarial but bounded by diff
76+
- Consult (2C): `medium` — large context, interactive, needs speed
77+
7078
---
7179

7280
## Step 2A: Review Mode
@@ -80,13 +88,15 @@ TMPERR=$(mktemp /tmp/codex-err-XXXXXX.txt)
8088

8189
2. Run the review (5-minute timeout):
8290
```bash
83-
codex review --base <base> -c 'model_reasoning_effort="xhigh"' --enable web_search_cached 2>"$TMPERR"
91+
codex review --base <base> -c 'model_reasoning_effort="high"' --enable web_search_cached 2>"$TMPERR"
8492
```
8593

94+
If the user passed `--xhigh`, use `"xhigh"` instead of `"high"`.
95+
8696
Use `timeout: 300000` on the Bash call. If the user provided custom instructions
8797
(e.g., `/codex review focus on security`), pass them as the prompt argument:
8898
```bash
89-
codex review "focus on security" --base <base> -c 'model_reasoning_effort="xhigh"' --enable web_search_cached 2>"$TMPERR"
99+
codex review "focus on security" --base <base> -c 'model_reasoning_effort="high"' --enable web_search_cached 2>"$TMPERR"
90100
```
91101

92102
3. Capture the output. Then parse cost from stderr:
@@ -158,8 +168,11 @@ With focus (e.g., "security"):
158168
"Review the changes on this branch against the base branch. Run `git diff origin/<base>` to see the diff. Focus specifically on SECURITY. Your job is to find every way an attacker could exploit this code. Think about injection vectors, auth bypasses, privilege escalation, data exposure, and timing attacks. Be adversarial."
159169

160170
2. Run codex exec with **JSONL output** to capture reasoning traces and tool calls (5-minute timeout):
171+
172+
If the user passed `--xhigh`, use `"xhigh"` instead of `"high"`.
173+
161174
```bash
162-
codex exec "<prompt>" -C "$(git rev-parse --show-toplevel)" -s read-only -c 'model_reasoning_effort="xhigh"' --enable web_search_cached --json 2>/dev/null | python3 -c "
175+
codex exec "<prompt>" -C "$(git rev-parse --show-toplevel)" -s read-only -c 'model_reasoning_effort="high"' --enable web_search_cached --json 2>/dev/null | PYTHONUNBUFFERED=1 python3 -u -c "
163176
import sys, json
164177
for line in sys.stdin:
165178
line = line.strip()
@@ -172,17 +185,17 @@ for line in sys.stdin:
172185
itype = item.get('type','')
173186
text = item.get('text','')
174187
if itype == 'reasoning' and text:
175-
print(f'[codex thinking] {text}')
176-
print()
188+
print(f'[codex thinking] {text}', flush=True)
189+
print(flush=True)
177190
elif itype == 'agent_message' and text:
178-
print(text)
191+
print(text, flush=True)
179192
elif itype == 'command_execution':
180193
cmd = item.get('command','')
181-
if cmd: print(f'[codex ran] {cmd}')
194+
if cmd: print(f'[codex ran] {cmd}', flush=True)
182195
elif t == 'turn.completed':
183196
usage = obj.get('usage',{})
184197
tokens = usage.get('input_tokens',0) + usage.get('output_tokens',0)
185-
if tokens: print(f'\ntokens used: {tokens}')
198+
if tokens: print(f'\ntokens used: {tokens}', flush=True)
186199
except: pass
187200
"
188201
```
@@ -231,20 +244,34 @@ ls -t ~/.claude/plans/*.md 2>/dev/null | xargs grep -l "$(basename $(pwd))" 2>/d
231244
```
232245
If no project-scoped match, fall back to `ls -t ~/.claude/plans/*.md 2>/dev/null | head -1`
233246
but warn: "Note: this plan may be from a different project — verify before sending to Codex."
234-
Read the plan file and prepend the persona to the user's prompt:
247+
248+
**IMPORTANT — embed content, don't reference path:** Codex runs sandboxed to the repo
249+
root (`-C`) and cannot access `~/.claude/plans/` or any files outside the repo. You MUST
250+
read the plan file yourself and embed its FULL CONTENT in the prompt below. Do NOT tell
251+
Codex the file path or ask it to read the plan file — it will waste 10+ tool calls
252+
searching and fail.
253+
254+
Also: scan the plan content for referenced source file paths (patterns like `src/foo.ts`,
255+
`lib/bar.py`, paths containing `/` that exist in the repo). If found, list them in the
256+
prompt so Codex reads them directly instead of discovering them via rg/find.
257+
258+
Prepend the persona to the user's prompt:
235259
"You are a brutally honest technical reviewer. Review this plan for: logical gaps and
236260
unstated assumptions, missing error handling or edge cases, overcomplexity (is there a
237261
simpler approach?), feasibility risks (what could go wrong?), and missing dependencies
238262
or sequencing issues. Be direct. Be terse. No compliments. Just the problems.
263+
Also review these source files referenced in the plan: <list of referenced files, if any>.
239264
240265
THE PLAN:
241-
<plan content>"
266+
<full plan content, embedded verbatim>"
242267

243268
4. Run codex exec with **JSONL output** to capture reasoning traces (5-minute timeout):
244269

270+
If the user passed `--xhigh`, use `"xhigh"` instead of `"medium"`.
271+
245272
For a **new session:**
246273
```bash
247-
codex exec "<prompt>" -C "$(git rev-parse --show-toplevel)" -s read-only -c 'model_reasoning_effort="xhigh"' --enable web_search_cached --json 2>"$TMPERR" | python3 -c "
274+
codex exec "<prompt>" -C "$(git rev-parse --show-toplevel)" -s read-only -c 'model_reasoning_effort="medium"' --enable web_search_cached --json 2>"$TMPERR" | PYTHONUNBUFFERED=1 python3 -u -c "
248275
import sys, json
249276
for line in sys.stdin:
250277
line = line.strip()
@@ -254,31 +281,31 @@ for line in sys.stdin:
254281
t = obj.get('type','')
255282
if t == 'thread.started':
256283
tid = obj.get('thread_id','')
257-
if tid: print(f'SESSION_ID:{tid}')
284+
if tid: print(f'SESSION_ID:{tid}', flush=True)
258285
elif t == 'item.completed' and 'item' in obj:
259286
item = obj['item']
260287
itype = item.get('type','')
261288
text = item.get('text','')
262289
if itype == 'reasoning' and text:
263-
print(f'[codex thinking] {text}')
264-
print()
290+
print(f'[codex thinking] {text}', flush=True)
291+
print(flush=True)
265292
elif itype == 'agent_message' and text:
266-
print(text)
293+
print(text, flush=True)
267294
elif itype == 'command_execution':
268295
cmd = item.get('command','')
269-
if cmd: print(f'[codex ran] {cmd}')
296+
if cmd: print(f'[codex ran] {cmd}', flush=True)
270297
elif t == 'turn.completed':
271298
usage = obj.get('usage',{})
272299
tokens = usage.get('input_tokens',0) + usage.get('output_tokens',0)
273-
if tokens: print(f'\ntokens used: {tokens}')
300+
if tokens: print(f'\ntokens used: {tokens}', flush=True)
274301
except: pass
275302
"
276303
```
277304

278305
For a **resumed session** (user chose "Continue"):
279306
```bash
280-
codex exec resume <session-id> "<prompt>" -C "$(git rev-parse --show-toplevel)" -s read-only -c 'model_reasoning_effort="xhigh"' --enable web_search_cached --json 2>"$TMPERR" | python3 -c "
281-
<same python streaming parser as above>
307+
codex exec resume <session-id> "<prompt>" -C "$(git rev-parse --show-toplevel)" -s read-only -c 'model_reasoning_effort="medium"' --enable web_search_cached --json 2>"$TMPERR" | PYTHONUNBUFFERED=1 python3 -u -c "
308+
<same python streaming parser as above, with flush=True on all print() calls>
282309
"
283310
```
284311

@@ -313,7 +340,14 @@ Session saved — run /codex again to continue this conversation.
313340
agentic coding model). This means as OpenAI ships newer models, /codex automatically
314341
uses them. If the user wants a specific model, pass `-m` through to codex.
315342

316-
**Reasoning effort:** All modes use `xhigh` — maximum reasoning power. When reviewing code, breaking code, or consulting on architecture, you want the model thinking as hard as possible.
343+
**Reasoning effort (per-mode defaults):**
344+
- **Review (2A):** `high` — bounded diff input, needs thoroughness but not max tokens
345+
- **Challenge (2B):** `high` — adversarial but bounded by diff size
346+
- **Consult (2C):** `medium` — large context (plans, codebase), interactive, needs speed
347+
348+
`xhigh` uses ~23x more tokens than `high` and causes 50+ minute hangs on large context
349+
tasks (OpenAI issues #8545, #8402, #6931). Users can override with `--xhigh` flag
350+
(e.g., `/codex review --xhigh`) when they want maximum reasoning and are willing to wait.
317351

318352
**Web search:** All codex commands use `--enable web_search_cached` so Codex can look up
319353
docs and APIs during review. This is OpenAI's cached index — fast, no extra cost.

office-hours/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,7 @@ Write the full prompt (context block + instructions) to this file. Use the mode-
714714

715715
```bash
716716
TMPERR_OH=$(mktemp /tmp/codex-oh-err-XXXXXXXX)
717-
codex exec "$(cat "$CODEX_PROMPT_FILE")" -C "$(git rev-parse --show-toplevel)" -s read-only -c 'model_reasoning_effort="xhigh"' --enable web_search_cached 2>"$TMPERR_OH"
717+
codex exec "$(cat "$CODEX_PROMPT_FILE")" -C "$(git rev-parse --show-toplevel)" -s read-only -c 'model_reasoning_effort="high"' --enable web_search_cached 2>"$TMPERR_OH"
718718
```
719719

720720
Use a 5-minute timeout (`timeout: 300000`). After the command completes, read stderr:

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "gstack",
3-
"version": "0.12.3.0",
3+
"version": "0.12.5.0",
44
"description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.",
55
"license": "MIT",
66
"type": "module",

0 commit comments

Comments
 (0)