| name | codex-plusplus-tweak-system |
| description | Expert in developing, installing, and managing tweaks for the Codex++ desktop app extension system |
| triggers | ["help me create a Codex++ tweak","install codex-plusplus on my machine","how do I extend Codex with custom features","write a tweak for the Codex desktop app","fix my codex-plusplus installation","add custom keyboard shortcuts to Codex","manage Codex++ tweaks","update my Codex app with codex-plusplus installed"] |
Codex++ Tweak System
Skill by ara.so — Codex Skills collection.
Codex++ is a tweak system for the Codex desktop app that lets you inject custom features, fix UI bugs, and manage extensions without rebuilding the app. It patches the local Codex installation to load a runtime that discovers and executes small ESM modules (tweaks) with full access to the Electron renderer process.
Installation
macOS/Linux (Homebrew)
brew install b-nnett/codex-plusplus/codexplusplus
codexplusplus install
macOS/Linux (Source Bootstrap)
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
Using Bun
bun install -g github:b-nnett/codex-plusplus
codexplusplus install
What the installer does:
- Backs up Codex.app to
~/.codex-plusplus/backup/
- Patches
app.asar to load the Codex++ runtime
- Re-signs the app with a local signing identity (macOS)
- Installs a watcher that auto-repairs on Codex updates
- Installs default tweaks from GitHub releases
Installation flags:
--no-default-tweaks — Skip installing default tweaks
--local — Use stable local signing identity (macOS)
Key Commands
codexplusplus status
codexplusplus doctor
codexplusplus repair
codexplusplus update
codexplusplus update --ref main
codexplusplus update-codex
codexplusplus create-tweak my-tweak
codexplusplus validate-tweak ~/path/to/tweak
codexplusplus safe-mode
codexplusplus safe-mode --off
codexplusplus dev
codexplusplus uninstall
User Data Directories
| OS | Location |
|---|
| macOS | ~/Library/Application Support/codex-plusplus/ |
| Linux | ~/.local/share/codex-plusplus/ |
| Windows | %APPDATA%/codex-plusplus/ |
Directory structure:
codex-plusplus/
├── runtime/ # Codex++ runtime code
├── tweaks/ # Installed tweaks
│ ├── my-tweak/
│ │ ├── manifest.json
│ │ └── index.js
├── config.json # Runtime configuration
└── backup/ # Codex.app backup
Creating a Tweak
Minimal Tweak Structure
my-tweak/
├── manifest.json
└── index.js
manifest.json
{
"id": "com.example.my-tweak",
"name": "My Tweak",
"version": "1.0.0",
"githubRepo": "username/my-tweak",
"author": "Your Name",
"description": "Adds custom functionality to Codex",
"minRuntime": "0.1.0"
}
Required fields:
id — Reverse-DNS unique identifier
name — Display name
version — Semver version
githubRepo — owner/repo for update checks
minRuntime — Minimum Codex++ runtime version
Basic Tweak (JavaScript)
export default {
start(api) {
api.log.info('Tweak started');
api.settings.register({
id: 'my-tweak',
title: 'My Tweak Settings',
render: (root) => {
root.innerHTML = `
<div>
<h3>Custom Settings</h3>
<button id="test-btn">Click me</button>
</div>
`;
root.querySelector('#test-btn').addEventListener('click', () => {
api.log.info('Button clicked!');
});
}
});
},
stop() {
}
};
TypeScript Tweak with Full API
import type { Tweak, CodexPlusPlusAPI } from "@codex-plusplus/sdk";
interface MyTweakConfig {
enabled: boolean;
customColor: string;
}
export default {
start(api: CodexPlusPlusAPI) {
const config = api.config.get<MyTweakConfig>('my-tweak', {
enabled: true,
customColor: '#ff0000'
});
api.log.info('Starting tweak with config:', config);
api.log.warn('This is a warning');
api.log.error('This is an error');
const observer = new MutationObserver(() => {
const chatInput = document.querySelector('[contenteditable="true"]');
if (chatInput && config.enabled) {
chatInput.. = config.;
}
});
observer.(., {
: ,
:
});
api..({
: ,
: ,
: {
root. = ;
root.()?.(, {
enabled = (root.() ).;
customColor = (root.() ).;
api..(, { enabled, customColor });
api..();
location.();
});
}
});
(api ). = observer;
},
() {
observer = ( ).;
(observer) {
observer.();
}
}
} ;
Advanced: Injecting Custom UI
export default {
start(api) {
const injectCustomButton = () => {
const toolbar = document.querySelector('.chat-toolbar');
if (!toolbar) return;
const btn = document.createElement('button');
btn.textContent = '✨ Custom Action';
btn.className = 'toolbar-button';
btn.onclick = () => {
api.log.info('Custom action triggered');
};
toolbar.appendChild(btn);
};
const observer = new MutationObserver(() => {
injectCustomButton();
});
observer.observe(document.body, {
childList: true,
subtree: true
});
injectCustomButton();
},
stop() {}
};
Keyboard Shortcuts Tweak
export default {
start(api) {
const handleKeydown = (e: KeyboardEvent) => {
if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key === 'k') {
e.preventDefault();
api.log.info('Custom shortcut triggered');
}
};
document.addEventListener('keydown', handleKeydown);
(api as any)._keyHandler = handleKeydown;
},
stop() {
const handler = (this as any)._keyHandler;
if (handler) {
document.removeEventListener('keydown', handler);
}
}
};
Configuration
Runtime Config
Located at <user-data-dir>/config.json:
{
"enabledTweaks": [
"com.example.my-tweak",
"co.bennett.custom-keyboard-shortcuts"
],
"autoUpdate": true,
"safeMode": false,
"logLevel": "info"
}
Per-Tweak Config
Tweaks can store configuration using the API:
const config = api.config.get('my-tweak', { theme: 'dark' });
api.config.set('my-tweak', { theme: 'light' });
Tweak Distribution & Updates
Publishing a Tweak
- Create a GitHub repository for your tweak
- Add tweak files (manifest.json, index.js/ts)
- Create a GitHub Release with a semver tag (e.g.,
v1.0.0)
- Attach a
.zip of the tweak folder to the release
Release structure:
my-tweak-v1.0.0.zip
└── my-tweak/
├── manifest.json
└── index.js
Installing Tweaks
Users copy tweak folders to <user-data-dir>/tweaks/ and enable them in Settings → Tweaks.
Update Checking
Codex++ checks githubRepo in manifest.json for newer releases once per day. Users review release notes and manually update.
Common Patterns
Persistent State
let myState = api.config.get('my-tweak', { count: 0 });
function incrementCounter() {
myState.count++;
api.config.set('my-tweak', myState);
}
React to Codex Events
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (node instanceof HTMLElement && node.matches('.message')) {
api.log.info('New message detected');
}
});
});
});
observer.observe(document.querySelector('#chat-container'), {
childList: true,
subtree: true
});
CSS Injection
const style = document.createElement('style');
style.textContent = `
.custom-theme {
--primary-color: #00ff00;
}
.chat-message {
border-left: 3px solid var(--primary-color);
}
`;
document.head.appendChild(style);
(api as any)._styleElement = style;
Troubleshooting
Codex won't launch after install
codexplusplus status
codexplusplus repair
codexplusplus uninstall
codexplusplus install
Tweak not loading
codexplusplus validate-tweak ~/Library/Application\ Support/codex-plusplus/tweaks/my-tweak
tail -f ~/Library/Logs/codex-plusplus/runtime.log
Safe mode (disable all tweaks)
codexplusplus safe-mode
codexplusplus safe-mode --off
macOS Gatekeeper issues
After first launch of re-signed Codex:
- System Preferences → Privacy & Security
- Click "Open Anyway" for Codex.app
- Or:
xattr -cr /Applications/Codex.app
Codex update breaks Codex++
codexplusplus update-codex
codexplusplus repair
Windows: Wrong app launches
Launch Codex++ from Start Menu/Desktop, not the Microsoft Store Codex shortcut. The Store version is unpatched.
Development workflow
codexplusplus dev
Clear all config
rm ~/Library/Application\ Support/codex-plusplus/config.json
rm -rf ~/Library/Application\ Support/codex-plusplus/
codexplusplus install
Security Notes
- Tweaks run with full Electron renderer privileges
- Only install tweaks from trusted sources
- Review tweak code before installing
githubRepo in manifest enables update notifications but doesn't auto-update
- Codex++ never executes code without user consent
Example: Complete UI Tweak
import type { Tweak } from "@codex-plusplus/sdk";
export default {
start(api) {
const config = api.config.get('dark-mode', { enabled: false });
const applyTheme = (dark: boolean) => {
document.body.classList.toggle('dark-theme', dark);
};
applyTheme(config.enabled);
api.settings.register({
id: 'dark-mode',
title: 'Dark Mode',
render: (root) => {
root.innerHTML = `
<label>
<input type="checkbox" id="toggle" ${config.enabled ? 'checked' : ''}>
Enable dark mode
</label>
`;
root.querySelector('#toggle')?.addEventListener('change', (e) => {
const enabled = (e.target ).;
api..(, { enabled });
(enabled);
});
}
});
style = .();
style. = ;
..(style);
(api ). = style;
},
() {
...();
style = ( ).;
(style) style.();
}
} ;