codex-plusplus-tweak-system
codex-plusplus Tweak System
Skill by ara.so — Daily 2026 Skills collection.
codex-plusplus is a tweak injection system for the Codex desktop app (Electron-based). It patches app.asar, injects a loader stub, and runs a hot-reloadable runtime from the user directory. Tweaks are small ESM modules with a manifest and start/stop lifecycle — no app rebuild required.
Installation
Homebrew (macOS, recommended)
brew install b-nnett/codex-plusplus/codexplusplus
codexplusplus install
Bun (global)
bun install -g github:b-nnett/codex-plusplus
codexplusplus install
Source bootstrap (macOS / Linux)
curl -fsSL https://raw.githubusercontent.com/b-nnett/codex-plusplus/main/install.sh | bash
Windows PowerShell
irm https://raw.githubusercontent.com/b-nnett/codex-plusplus/main/install.ps1 | iex
The installer:
- Locates
Codex.app(or Windows equivalent) - Backs up the original to
~/.codex-plusplus/backup/ - Patches
app.asarto require the loader - Recomputes asar header SHA-256, writes it into
Info.plist - Flips
EnableEmbeddedAsarIntegrityValidationin the Electron Framework binary - Re-signs ad-hoc on macOS (
codesign --force --deep --sign -) - Installs a launch agent / login item for auto-repair on Codex updates
- Installs default tweaks unless
--no-default-tweaksis passed
Key CLI Commands
codexplusplus install # Patch Codex and install runtime
codexplusplus install --no-default-tweaks # Skip default tweak set
codexplusplus status # Show patch status and runtime version
codexplusplus doctor # Diagnose issues (integrity, signing, etc.)
codexplusplus repair # Re-apply patch (e.g. after Codex update)
codexplusplus repair --quiet # Silent repair (used by watcher/launch agent)
codexplusplus update # Pull latest codex-plusplus source, rebuild, repair
codexplusplus update-codex # Restore official-signed Codex for Sparkle updater
codexplusplus uninstall # Revert all patches, restore backup
codexplusplus tweaks list # List installed tweaks and enabled state
codexplusplus tweaks open # Open user tweaks directory in Finder/Explorer
File Locations
| Artifact | Path |
|---|---|
| Loader stub | Codex.app/Contents/Resources/app.asar |
| Runtime | <user-data-dir>/runtime/ |
| Tweaks | <user-data-dir>/tweaks/ |
| Config | <user-data-dir>/config.json |
| Backup | <user-data-dir>/backup/ |
<user-data-dir> per OS:
- macOS:
~/Library/Application Support/codex-plusplus/ - Linux:
$XDG_DATA_HOME/codex-plusplus/(default~/.local/share/codex-plusplus/) - Windows:
%APPDATA%/codex-plusplus/
Writing a Tweak
Folder Structure
<user-data-dir>/tweaks/my-tweak/
├── manifest.json
└── index.ts # or .js / .mjs
manifest.json
{
"id": "com.yourname.my-tweak",
"name": "My Tweak",
"version": "0.1.0",
"githubRepo": "yourname/my-tweak",
"author": "yourname",
"description": "Short description of what this tweak does.",
"minRuntime": "0.1.0"
}
Required fields: id (reverse-domain), name, version, githubRepo (for update checks), author, description, minRuntime.
index.ts — Minimal Tweak
import type { Tweak } from "@codex-plusplus/sdk";
export default {
start(api) {
api.log.info("My tweak started");
},
stop() {
// Cleanup: remove event listeners, DOM nodes, etc.
},
} satisfies Tweak;
index.ts — Settings Panel
import type { Tweak } from "@codex-plusplus/sdk";
export default {
start(api) {
api.settings.register({
id: "my-tweak",
title: "My Tweak",
render(root) {
root.innerHTML = `
<div style="padding: 16px;">
<h2>My Tweak Settings</h2>
<label>
<input type="checkbox" id="my-tweak-toggle" />
Enable feature
</label>
</div>
`;
const toggle = root.querySelector<HTMLInputElement>("#my-tweak-toggle")!;
toggle.checked = api.storage.get("enabled") ?? false;
toggle.addEventListener("change", () => {
api.storage.set("enabled", toggle.checked);
});
},
});
},
stop() {},
} satisfies Tweak;
index.ts — DOM Injection with Cleanup
import type { Tweak } from "@codex-plusplus/sdk";
let cleanup: (() => void) | null = null;
export default {
start(api) {
// Wait for DOM element to appear
const unobserve = api.dom.waitFor(".codex-toolbar", (toolbar) => {
const btn = document.createElement("button");
btn.textContent = "My Action";
btn.className = "codex-plusplus-btn";
btn.addEventListener("click", () => {
api.log.info("Button clicked");
});
toolbar.appendChild(btn);
cleanup = () => btn.remove();
});
api.onStop(() => {
unobserve();
cleanup?.();
});
},
stop() {},
} satisfies Tweak;
index.ts — Keyboard Shortcut
import type { Tweak } from "@codex-plusplus/sdk";
export default {
start(api) {
const handler = (e: KeyboardEvent) => {
if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key === "k") {
e.preventDefault();
api.log.info("Shortcut triggered: Cmd/Ctrl+Shift+K");
// your action here
}
};
document.addEventListener("keydown", handler);
api.onStop(() => document.removeEventListener("keydown", handler));
},
stop() {},
} satisfies Tweak;
Tweak API Reference (api object in start)
| API | Description |
|---|---|
api.log.info(msg) |
Log to Codex++ console |
api.log.warn(msg) |
Warning log |
api.log.error(msg) |
Error log |
api.settings.register({ id, title, render }) |
Add a panel under Settings → Tweaks |
api.storage.get(key) |
Read persisted value for this tweak |
api.storage.set(key, value) |
Persist value (JSON-serializable) |
api.dom.waitFor(selector, cb) |
Watch for a DOM element; returns unobserve fn |
api.onStop(fn) |
Register a cleanup callback called on stop() |
Config (config.json)
{
"autoRepair": true,
"autoUpdateRuntime": true,
"tweaks": {
"com.yourname.my-tweak": {
"enabled": true
}
}
}
autoRepair— watcher re-patches after Codex updates (defaulttrue)autoUpdateRuntime— daily runtime refresh from CLI (defaulttrue); disable in Settings → Codex Plus Plus → Config
Tweak Update Checks
Every tweak with githubRepo set is checked against GitHub Releases once per day. Codex++ compares the latest release tag (semver) to the local manifest.json version.
- No auto-update — users see "Update Available" in Settings → Tweaks with a link to the release.
- To publish a tweak update: create a GitHub Release with a semver tag (e.g.
v0.2.0) and attach the tweak folder as a zip.
Default Tweaks
Installed on first run (skip with --no-default-tweaks):
| ID | Repo |
|---|---|
co.bennett.custom-keyboard-shortcuts |
b-nnett/codex-plusplus-keyboard-shortcuts |
co.bennett.ui-improvements |
b-nnett/codex-plusplus-bennett-ui |
Updating Codex (macOS — Sparkle conflict)
Codex++ ad-hoc signs the app, breaking Sparkle's integrity check. Use:
codexplusplus update-codex
This restores an official Developer ID–signed build for the updater. After Codex updates and restarts, the launch agent watcher re-applies Codex++ automatically.
Uninstall
codexplusplus uninstall
Restores the backed-up original app.asar, removes the launch agent, and removes <user-data-dir>. Tweaks you wrote remain on disk unless you delete them manually.
Troubleshooting
"App is damaged and can't be opened" (macOS)
The ad-hoc signature isn't trusted on first launch. Run:
xattr -cr /Applications/Codex.app
Then open the app again.
Patch not persisting after Codex update
The launch agent should re-run repair automatically. Check status:
codexplusplus status
codexplusplus doctor
If the launch agent isn't running, reinstall:
codexplusplus uninstall && codexplusplus install
Tweak not loading
- Check
manifest.jsonhas all required fields (id,name,version,githubRepo,author,description,minRuntime). - Ensure
index.js/index.tsexports a default object withstartandstop. - Check logs:
api.log.erroroutput appears in Codex DevTools console. - Run
codexplusplus doctorfor runtime integrity checks.
Runtime version mismatch
codexplusplus repair # refreshes runtime from CLI
Tweaks directory location
codexplusplus tweaks open # opens in Finder/Explorer
Security Model
- Tweaks run in the renderer process with the same privileges as Codex's own renderer code.
- Codex++ does not auto-update tweak code — users must manually review and install updates.
githubRepois only used for version checks via the GitHub Releases API, not for auto-downloading code.- See
SECURITY.mdfor the full policy and vulnerability reporting process.
Community
- Discord —
#tweak-devchannel for tweak authors - GitHub Issues — bug reports and feature requests
- Docs:
docs/WRITING-TWEAKS.mdanddocs/ARCHITECTURE.md