npx skills add ...
npx skills add reason-machines/codex-skills --skill opencodex-gateway
Local gateway for Codex Desktop with custom API support, web dashboard, Computer Use engine, and Vision Bridge for text-only models
npx skills add reason-machines/codex-skills --skill opencodex-gateway
Skill by ara.so — Codex Skills collection.
OpenCodex is a zero-config local gateway that enables Codex Desktop to use third-party APIs (OpenAI-compatible endpoints). It features a bilingual web dashboard for model management, a custom Computer Use engine with native macOS control, and Vision Bridge that lets text-only models handle visual tasks by automatically describing screenshots.
The server starts on http://localhost:8765 and automatically:
~/.codex/config.toml (creates backup)OpenCodex sits between Codex Desktop and third-party APIs:
Access at http://localhost:8765/dashboard
https://api.openai.com/v1 or https://api.deepseek.com)~/.codex/config.toml)gpt-4, deepseek-chat)OpenCodex modifies ~/.codex/config.toml:
Original config backed up to ~/.codex/config.toml.backup
For development or custom deployments:
Vision Bridge enables text-only models to handle Computer Use tasks by converting screenshots to text descriptions.
sipsIn the dashboard, configure Vision Bridge settings:
If extending OpenCodex, here's how Vision Bridge is invoked:
OpenCodex implements custom Computer Use actions for macOS using native CGEvent APIs.
Codex sends tool calls in this format:
Response includes base64 image:
All OpenAI-compatible requests go through:
Headers:
Stream format:
To switch from OpenAI to DeepSeek:
https://api.deepseek.comdeepseek-chatUse a different vision model for Vision Bridge:
Symptom: Codex shows "API Error" or "Connection Failed"
Solution:
curl http://localhost:8765/health~/.codex/config.toml has base_url = "http://localhost:8765/v1"http://localhost:8765/dashboard → scroll to logsSymptom: Added models don't show in Codex
Solution:
~/.codex/config.toml includes the model with enabled = trueSymptom: Text-only model fails on Computer Use tasks
Solution:
curl -X POST <vision_endpoint>/chat/completionssips is available (which sips)Symptom: 429 errors in logs
Solution:
Symptom: Error: listen EADDRINUSE: address already in use :::8765
Solution:
Symptom: Codex behaves unexpectedly after config changes
Solution:
~/.codex/config.toml.backupSymptom: Vision API rejects screenshots
Solution:
sips outputExtend Computer Use engine:
Register in action handler:
Add custom logs visible in dashboard:
For the ultimate experience, pair with OpenCodexBar:
npm startOption + Space for system-wide voice activationBoth projects work independently but are designed to complement each other.
[api]
base_url = "http://localhost:8765/v1"
api_key = "your-actual-api-key"
[[models]]
name = "gpt-4"
enabled = true
[[models]]
name = "deepseek-chat"
enabled = trueexport OPENCODEX_PORT=8765
export OPENCODEX_API_KEY=sk-your-key-here
export OPENCODEX_BASE_URL=https://api.openai.com/v1{
"vision_bridge": {
"enabled": true,
"endpoint": "https://api.openai.com/v1",
"model": "gpt-4-vision-preview",
"api_key": "process.env.VISION_API_KEY",
"max_dimension": 1200
}
}import { VisionBridge } from './vision-bridge';
const bridge = new VisionBridge({
endpoint: process.env.VISION_ENDPOINT,
model: 'gpt-4-vision-preview',
apiKey: process.env.VISION_API_KEY
});
// Automatically converts screenshot to description
const description = await bridge.describeImage(screenshotBase64);
// Injects into prompt for text-only model
const modifiedPrompt = bridge.injectDescription(originalPrompt, description);{
"type": "computer_use",
"action": "mouse_click",
"params": {
"x": 500,
"y": 300,
"button": "left"
}
}{
"action": "mouse_click",
"params": { "x": 500, "y": 300, "button": "left" }
}{
"action": "type_text",
"params": { "text": "Hello, world!" }
}{
"action": "screenshot",
"params": { "max_dimension": 1200 }
}{
"success": true,
"image": "iVBORw0KGgoAAAANS..."
}POST http://localhost:8765/v1/chat/completionsAuthorization: Bearer <your-api-key>
Content-Type: application/jsoncurl http://localhost:8765/api/configcurl -X POST http://localhost:8765/api/config \
-H "Content-Type: application/json" \
-d '{
"base_url": "https://api.deepseek.com",
"api_key": "sk-...",
"models": [
{"name": "deepseek-chat", "enabled": true}
]
}'curl -X POST http://localhost:8765/api/restart-codexcurl -X POST http://localhost:8765/api/reset-nativecurl -N http://localhost:8765/api/logsdata: {"timestamp": "2026-06-04T10:30:00Z", "level": "info", "message": "Request to gpt-4"}
data: {"timestamp": "2026-06-04T10:30:01Z", "level": "info", "message": "Response 200"}const models = [
{ name: 'gpt-4-turbo', enabled: true },
{ name: 'gpt-4', enabled: true },
{ name: 'claude-3-opus', enabled: false }
];
await fetch('http://localhost:8765/api/config', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ models })
});{
"vision_bridge": {
"enabled": true,
"endpoint": "https://api.anthropic.com/v1",
"model": "claude-3-opus-20240229",
"api_key": "process.env.ANTHROPIC_API_KEY"
}
}# Find process on port 8765
lsof -i :8765
# Kill it
kill -9 <PID>
# Or change port
export OPENCODEX_PORT=8766
npm start{ "max_dimension": 800 }opencodex/
├── src/
│ ├── server.ts # Main Express server
│ ├── vision-bridge.ts # Vision Bridge logic
│ ├── computer-use.ts # macOS automation
│ └── config.ts # Config patching
├── public/
│ └── dashboard.html # Web UI
└── package.jsonnpm run dev # Enables hot-reload// src/computer-use.ts
export async function customAction(params: any) {
// Use node-mac-automation or applescript
const result = execSync(`osascript -e 'tell application "Finder" to ...'`);
return { success: true, result: result.toString() };
}case 'custom_action':
return await customAction(params);import { logger } from './logger';
logger.info('Custom event', { data: someData });
logger.error('Something failed', { error });