Loading...
Loading...
Expert in developing, installing, and managing tweaks for the Codex++ desktop app extension system
npx skill4agent add aradotso/codex-skills codex-plusplus-tweak-systemSkill by ara.so — Codex Skills collection.
brew install b-nnett/codex-plusplus/codexplusplus
codexplusplus installcurl -fsSL https://raw.githubusercontent.com/b-nnett/codex-plusplus/main/install.sh | bashirm https://raw.githubusercontent.com/b-nnett/codex-plusplus/main/install.ps1 | iexbun install -g github:b-nnett/codex-plusplus
codexplusplus install~/.codex-plusplus/backup/app.asar--no-default-tweaks--local# Check installation status
codexplusplus status
# Validate and repair installation
codexplusplus doctor
codexplusplus repair
# Update Codex++ to latest release
codexplusplus update
# Update Codex++ from development branch (advanced)
codexplusplus update --ref main
# Update Codex app itself (macOS - required for patched apps)
codexplusplus update-codex
# Create a new tweak from template
codexplusplus create-tweak my-tweak
# Validate tweak manifest and structure
codexplusplus validate-tweak ~/path/to/tweak
# Enter safe mode (disable all tweaks)
codexplusplus safe-mode
codexplusplus safe-mode --off
# Development mode (watch and reload)
codexplusplus dev
# Uninstall Codex++ completely
codexplusplus uninstall| OS | Location |
|---|---|
| macOS | |
| Linux | |
| Windows | |
codex-plusplus/
├── runtime/ # Codex++ runtime code
├── tweaks/ # Installed tweaks
│ ├── my-tweak/
│ │ ├── manifest.json
│ │ └── index.js
├── config.json # Runtime configuration
└── backup/ # Codex.app backupmy-tweak/
├── manifest.json
└── index.js{
"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"
}idnameversiongithubRepoowner/repominRuntime// index.js
export default {
start(api) {
api.log.info('Tweak started');
// Add settings panel
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() {
// Cleanup resources
}
};// index.ts
import type { Tweak, CodexPlusPlusAPI } from "@codex-plusplus/sdk";
interface MyTweakConfig {
enabled: boolean;
customColor: string;
}
export default {
start(api: CodexPlusPlusAPI) {
// Access configuration
const config = api.config.get<MyTweakConfig>('my-tweak', {
enabled: true,
customColor: '#ff0000'
});
// Logging
api.log.info('Starting tweak with config:', config);
api.log.warn('This is a warning');
api.log.error('This is an error');
// DOM manipulation
const observer = new MutationObserver(() => {
const chatInput = document.querySelector('[contenteditable="true"]');
if (chatInput && config.enabled) {
chatInput.style.borderColor = config.customColor;
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
// Settings panel with persistence
api.settings.register({
id: 'my-tweak',
title: 'My Tweak',
render: (root) => {
root.innerHTML = `
<div class="tweak-settings">
<label>
<input type="checkbox" id="enabled" ${config.enabled ? 'checked' : ''}>
Enable custom styling
</label>
<label>
Custom color:
<input type="color" id="color" value="${config.customColor}">
</label>
<button id="save">Save</button>
</div>
`;
root.querySelector('#save')?.addEventListener('click', () => {
const enabled = (root.querySelector('#enabled') as HTMLInputElement).checked;
const customColor = (root.querySelector('#color') as HTMLInputElement).value;
api.config.set('my-tweak', { enabled, customColor });
api.log.info('Settings saved');
// Reload to apply changes
location.reload();
});
}
});
// Store observer for cleanup
(api as any)._observer = observer;
},
stop() {
const observer = (this as any)._observer;
if (observer) {
observer.disconnect();
}
}
} satisfies Tweak;export default {
start(api) {
// Wait for Codex UI to be ready
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');
// Your custom logic
};
toolbar.appendChild(btn);
};
// Observe for toolbar appearance
const observer = new MutationObserver(() => {
injectCustomButton();
});
observer.observe(document.body, {
childList: true,
subtree: true
});
injectCustomButton(); // Try immediately
},
stop() {}
};export default {
start(api) {
const handleKeydown = (e: KeyboardEvent) => {
// Cmd/Ctrl + Shift + K
if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key === 'k') {
e.preventDefault();
api.log.info('Custom shortcut triggered');
// Your action here
}
};
document.addEventListener('keydown', handleKeydown);
// Store for cleanup
(api as any)._keyHandler = handleKeydown;
},
stop() {
const handler = (this as any)._keyHandler;
if (handler) {
document.removeEventListener('keydown', handler);
}
}
};<user-data-dir>/config.json{
"enabledTweaks": [
"com.example.my-tweak",
"co.bennett.custom-keyboard-shortcuts"
],
"autoUpdate": true,
"safeMode": false,
"logLevel": "info"
}// Get config with defaults
const config = api.config.get('my-tweak', { theme: 'dark' });
// Update config
api.config.set('my-tweak', { theme: 'light' });
// Config is persisted automaticallyv1.0.0.zipmy-tweak-v1.0.0.zip
└── my-tweak/
├── manifest.json
└── index.js<user-data-dir>/tweaks/githubRepolet myState = api.config.get('my-tweak', { count: 0 });
function incrementCounter() {
myState.count++;
api.config.set('my-tweak', myState);
}// Watch for new messages
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
});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);
// Store for cleanup
(api as any)._styleElement = style;# Check status
codexplusplus status
# Repair installation
codexplusplus repair
# If repair fails, uninstall and reinstall
codexplusplus uninstall
codexplusplus install# Validate tweak structure
codexplusplus validate-tweak ~/Library/Application\ Support/codex-plusplus/tweaks/my-tweak
# Check runtime logs (look for errors)
tail -f ~/Library/Logs/codex-plusplus/runtime.logcodexplusplus safe-mode
# Launch Codex, fix issues, then:
codexplusplus safe-mode --offxattr -cr /Applications/Codex.app# macOS: Use official updater
codexplusplus update-codex
# After Codex updates, watcher auto-repairs
# Or manually:
codexplusplus repair# Watch for changes and auto-reload
codexplusplus dev
# Edit tweak files in:
# macOS: ~/Library/Application Support/codex-plusplus/tweaks/my-tweak/
# Reload Codex (Cmd+R / Ctrl+R) to see changes# Remove config but keep tweaks
rm ~/Library/Application\ Support/codex-plusplus/config.json
# Full reset
rm -rf ~/Library/Application\ Support/codex-plusplus/
codexplusplus installgithubRepo// Dark mode toggle 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 as HTMLInputElement).checked;
api.config.set('dark-mode', { enabled });
applyTheme(enabled);
});
}
});
// Inject CSS
const style = document.createElement('style');
style.textContent = `
.dark-theme {
background: #1a1a1a;
color: #ffffff;
}
`;
document.head.appendChild(style);
(api as any)._style = style;
},
stop() {
document.body.classList.remove('dark-theme');
const style = (this as any)._style;
if (style) style.remove();
}
} satisfies Tweak;