What it is, how it works, and why a Codex update forced a full rewrite from v1.1 to v1.2.
Codex++ is a community plugin/tweak framework for Codex Desktop — the native macOS app for interacting with AI models. It extends Codex through a system of tweaks: self-contained packages that hook into Codex's UI lifecycle, settings system, and Electron runtime.
Each tweak lives in ~/Library/Application Support/codex-plusplus/tweaks/ and consists of two parts: a main-process source patcher that monkey-patches Electron's protocol.handle to rewrite JavaScript bundles on the fly, and a renderer UI that provides toggles in the settings panel.
The reasoning-fixes tweak (package ID co.shivam94.reasoning-fixes) addresses a set of long-standing UI annoyances in Codex's conversation view:
Reasoning messages appear as standalone chat items instead of being nested inside exploration accordions.
split-itemsRemoves the pulsing color animation on reasoning text while it's streaming — reduces visual noise.
shimmerCommand outputs start expanded instead of collapsed, so you see results immediately.
threadTool call sections (like file edits, web searches) start expanded by default.
threadSearches the entire agent items array for an assistant message instead of assuming it's the last element.
split-itemsExploration items (tool calls, file reads) appear as standalone entries in the conversation.
split-itemsA floating button that toggles all reasoning sections collapsed/expanded at once.
DOM effectPrevents file-edit patches from being grouped inside tool-activity accordions.
split-itemsThe tweak operates in two layers: a main-process source patcher that rewrites JavaScript before it reaches the renderer, and a renderer settings UI that controls which patches are active.
At app startup: source-patcher.js replaces Electron's protocol.handle with a wrapper. Every time Codex loads a renderer bundle (like local-conversation-thread-xxxxx.js), the wrapper intercepts the response, runs it through patchSource(), and serves the patched version.
Each patch is a { bundle, unpatched, patched, replacement } rule. inspectRule() runs both regexes against the source — if only unpatched matches, the patch is applied. If only patched matches, it's already done. If neither matches, Codex has changed shape and the patch is "unsupported."
v1.1 was built for Codex 26.506.11943. When Codex updated, the renderer bundle shapes changed — the regex patterns in v1.1 no longer matched the new JavaScript, so all patches silently stopped applying.
v1.2.0-alpha was a full re-write targeting Codex 26.506.20924, with a new patch-wiring architecture and additional patches. The fix>codex_update_26.506.20924 branch then fixed 5 bugs in that adaptation.
split-items, shimmer, threadPATCHES list, manual enable/disableSETTING_FEATURES groups, inspectRule() diagnostics, IPC sync, aggregated status APIbuildStatus() API, per-feature observations, patched-assets tracking
Net diff: 5 commits, 2 files changed (index.js, source-patcher.js), −40/+31 net lines. The branch restored all 12 patches to working order against Codex 26.506.31004.
Click each card to expand.
Most impactful bug. The fix-assistant-order patch injected let O=null; into existing code that already had let T=...,E=...,. Result: let X,let Y in a single comma-separated declaration = SyntaxError in strict mode. The bundle failed to parse entirely → React never mounted → white screen.
Lesson: A replacement correct in isolation can break the surrounding declaration. Always read 20 characters before and after the injection point.
Codex updates shuffle JavaScript between bundle files. Three patches were targeting bundles where the patterns no longer existed:
| Patch | Old bundle | Actual bundle |
|---|---|---|
auto-expand-exec | lt | thread |
expand-tool-activity | settings-page | thread |
no-layout-position-composer | composer | removed |
Also fixed: inspectRule used === 1 instead of >= 1, so expand-tool-activity (matches 3×) was misclassified as "mixed" and skipped.
collapse-all-toggle appeared in the settings UI but had no FEATURES entry. When toggled, activateFeature() logged "unknown feature" and returned. The button was created once at startup — toggling had no runtime effect.
Fix: Always create the button (hidden if disabled), add a FEATURES entry to show/hide it, make creation idempotent for hot-reload safety.
The idempotency guard (if (btn exists) return) was added to prevent duplicate buttons on hot-reload. But the cleanup closure captured btn — which is null when the guard fires. Cleanup silently did nothing, leaving orphan DOM elements.
Fix: Query the DOM at cleanup time (document.getElementById) instead of capturing in a closure.
Three patches silently never activated because the PATCHES / SETTING_FEATURES / FEATURES registries drifted apart:
no-layout-position-composer defined in PATCHES but missing from every SETTING_FEATURES groupfix-assistant-order replacement and patched regex out of sync — the patched checker always returned "unsupported" even when the replacement was applied