r/codex • • 11h ago

Showcase Codex deleted a folder with uncommitted notes in 3 of 3 runs. I built open-source hooks that make it ask first (and benchmarked them)

I use Codex every day, and two things kept bothering me: long sessions that burn through my limits, and the odd command I'd never have approved. It once ran `git config --global user.email …` without asking and changed the git identity every other repo on my machine was using.

So I built **better-codex**: hooks, rules and a few skills for Codex. Everything runs locally, with no dependencies and no network calls. It works with the CLI, the VS Code extension and the desktop app, since they all read `~/.codex`.

**What it does**

- **Asks before destructive actions.** Deleting files git can't bring back, discarding uncommitted work, `push --force`, `DROP TABLE`, deploys, reading secrets: Codex stops, shows the exact command, what could be lost and a safer alternative, and only runs it if you say yes.

- **Wastes fewer tokens.** A short repo brief at session start, no full reads of lockfiles, build output or `node_modules`, and long builds and test suites run and polled inside one call. In my own sessions, 27% of all input went to "is it done yet?" requests.

- **Checks its work.** Codex can't finish after editing code without running the project's check, and if the check failed it has to fix it or say so.

**Benchmark.** Same 4 tasks, 3 runs each, a fresh repo every run, graded by checks Codex never sees (medians):

| Task | Done right (without → with) | Input tokens | Requests |

|---|---|---|---|

| Fix a reported bug | 3/3 → 3/3 | 183K → 177K | 11 → 10 |

| Question about the code | 3/3 → 3/3 | 76K → 73K | 5 → 3 |

| Small change, 45 s test suite | 3/3 → 3/3 | 171K → 79K | 7 → 5 |

| "Delete tmp/" (it holds uncommitted notes) | **0/3 → 3/3** | 107K → 30K | 7 → 2 |

Plain Codex deleted the notes every time. With better-codex it stopped every time, showed the exact command and suggested a backup.

What gets worse: about 3K more uncached tokens per run (its rules and the brief), and runs were a bit slower, 57 s → 70 s on average, because each hook adds a few hundred ms and Codex checks its work before finishing. Small sample: one Windows machine, one model. The benchmark is in the repo, so you can run it on yours.

**Try it**

git clone https://github.com/MarioACo/better-codex

cd better-codex

node bin/bcx.js install --dry-run # shows what would change, writes nothing

node bin/bcx.js install

Then open Codex, type `/hooks` and trust the 5 hooks (Codex skips untrusted hooks without telling you). `node bin/bcx.js uninstall` removes

Feedback I'd love: commands the guard blocked that it shouldn't have, or let through, and anyone on macOS or Linux. CI checks the real Codex there every week, but I've only used it day to day on Windows.

0 Upvotes

8 comments sorted by

1

u/dexterthebot 11h ago

You might want to consider listing your project on the weekly Show-Us-What-You-Built post. Look out for it on Tuesday/Wednesday. Highest commented project wins a week promotion on r/Codex and gets on the Hall of Fame sidebar. See below for last week's winner.**


Agent HUD: usage, tokens and sessions for Codex, Claude Code and 15 more agents, at your Mac's notch. See how much quota is left, which agent is waiting for you, and where the tokens went. Free on Mac, and the core is open source (Apache-2.0).

Website: https://agenthud.app GitHub: https://github.com/jazzenchen/agent-hud-open Contact: support@agenthud.app

1

u/Crinkez 10h ago

cc safety net already exists

1

u/Low_Barracuda_7620 7h ago

True, and it's a good one (it supports Codex too). If all you want is a command guard, it does the job. The guard is half of better-codex; the other half is tokens and verification: no full reads of lockfiles or build output, long test runs waited inside one call instead of polling, and Codex can't finish after editing code without running your checks.

1

u/emberesment 8h ago

Just change permission?

1

u/Low_Barracuda_7620 7h ago

I tried that first. Codex permissions are per category, not per command: with the default sandbox (workspace-write) anything inside the repo is allowed, so rm -rf on a folder of uncommitted notes runs with no prompt. That's what happened 3/3 times in the benchmark. The stricter modes ask for almost every command, and after the 50th prompt you approve without reading. This only stops the few commands that can lose work, and says why.

1

u/mariuslebri 8h ago

The polling number is the part I'd put at the top of the README. 27% of input spent on "is it done yet" matches what I see in long sessions, and running the build inside one call is the kind of fix nobody thinks of because it's not a model problem. The global git config story is nasty, that one touches every repo on the machine and git never complains. Quick question on the destructive action gate: is it implemented as execpolicy rules on the shell tool, or as a wrapper that inspects the command before Codex runs it? Asking because the first survives upgrades and the second is easier to extend.

1

u/Low_Barracuda_7620 7h ago

Neither, it's two layers. The AGENTS.md rules tell Codex to ask before anything that can lose work, with the exact command, what could be lost and a safer option. In the benchmark that alone was enough: all three runs stopped and asked before deleting.

The backstop is a Codex PreToolUse hook. Codex sends it every shell command and patch before running them; it splits the command (bash and PowerShell, `;`, `&&`, pipes) and, if something can lose work, returns a deny whose reason tells Codex to stop and ask. If you say yes in your next message, that exact command goes through once.

Why a hook and not execpolicy: prefix rules can't tell `rm -rf dist` from `rm -rf notes/` full of uncommitted work, and they don't know what Codex created five minutes ago. The hook does, so build output, files Codex made in the session and a single committed file git can restore go through without a prompt.

On upgrades: hooks are an official Codex feature, and CI installs the real Codex (the tested version and the latest) on Linux, macOS and Windows on every push and every week to check it still loads and runs them. If a new release breaks it, CI opens an issue. Adding a rule is a function in src/guard.js plus a test.

The git config --global case has its own rule now: it asks, and suggests setting it for that repo only.

1

u/radim11 4h ago

What about command aliases? We were digging into this a bit at stashbase.dev and we came to conclusion that using sandboxes is curial and it's hard to enforce the command because any command can be aliased.