300 lines
8.4 KiB
Markdown
300 lines
8.4 KiB
Markdown
# Codex SDK Binary Investigation Report
|
||
|
||
**Date:** 2025-12-20
|
||
**SDK Version:** @openai/codex-sdk@0.76.0
|
||
**Status:** ✅ System binary usage is fully supported
|
||
|
||
---
|
||
|
||
## Executive Summary
|
||
|
||
The `@openai/codex-sdk` library **DOES support using a system-installed Codex binary** instead of the embedded one. This is accomplished via the `codexPathOverride` configuration option in the `CodexOptions` interface.
|
||
|
||
---
|
||
|
||
## How the SDK Currently Locates the Codex Binary
|
||
|
||
### Default Behavior (Embedded Binary)
|
||
|
||
When no override is provided, the SDK uses the `findCodexPath()` function to locate the embedded binary:
|
||
|
||
**Source:** `dist/index.js:278-330`
|
||
|
||
```typescript
|
||
function findCodexPath() {
|
||
const { platform, arch } = process;
|
||
let targetTriple = null;
|
||
|
||
// Determines platform-specific binary path
|
||
// e.g., "aarch64-apple-darwin" for Apple Silicon Macs
|
||
|
||
const vendorRoot = path2.join(scriptDirName, "..", "vendor");
|
||
const archRoot = path2.join(vendorRoot, targetTriple);
|
||
const codexBinaryName = process.platform === "win32" ? "codex.exe" : "codex";
|
||
const binaryPath = path2.join(archRoot, "codex", codexBinaryName);
|
||
return binaryPath;
|
||
}
|
||
```
|
||
|
||
### Binary Location Structure
|
||
|
||
The SDK ships with pre-compiled binaries in the `vendor/` directory:
|
||
|
||
```
|
||
node_modules/@openai/codex-sdk/
|
||
├── vendor/
|
||
│ ├── aarch64-apple-darwin/codex/codex (40MB - Apple Silicon)
|
||
│ ├── x86_64-apple-darwin/codex/codex (Intel Mac)
|
||
│ ├── aarch64-unknown-linux-musl/codex/codex (ARM Linux)
|
||
│ ├── x86_64-unknown-linux-musl/codex/codex (x86_64 Linux)
|
||
│ ├── aarch64-pc-windows-msvc/codex/codex.exe (ARM Windows)
|
||
│ └── x86_64-pc-windows-msvc/codex/codex.exe (x86_64 Windows)
|
||
```
|
||
|
||
---
|
||
|
||
## Configuration Options Available
|
||
|
||
### `codexPathOverride` Option
|
||
|
||
**Type Definition:** `dist/index.d.ts:209-218`
|
||
|
||
```typescript
|
||
type CodexOptions = {
|
||
codexPathOverride?: string; // ← THIS IS THE KEY OPTION
|
||
baseUrl?: string;
|
||
apiKey?: string;
|
||
env?: Record<string, string>;
|
||
};
|
||
```
|
||
|
||
**Implementation:** `dist/index.js:336-338`
|
||
|
||
```typescript
|
||
constructor(options = {}) {
|
||
this.exec = new CodexExec(options.codexPathOverride, options.env);
|
||
this.options = options;
|
||
}
|
||
```
|
||
|
||
**How it works:** `dist/index.js:145-147`
|
||
|
||
```typescript
|
||
constructor(executablePath = null, env) {
|
||
this.executablePath = executablePath || findCodexPath();
|
||
this.envOverride = env;
|
||
}
|
||
```
|
||
|
||
The `codexPathOverride` is passed as `executablePath`. If provided, it bypasses the `findCodexPath()` function entirely.
|
||
|
||
---
|
||
|
||
## How to Use a System Codex Binary
|
||
|
||
### Method 1: Direct Path Specification
|
||
|
||
```typescript
|
||
import { Codex } from '@openai/codex-sdk';
|
||
|
||
const codex = new Codex({
|
||
codexPathOverride: '/Users/moboudra/.asdf/installs/nodejs/22.20.0/bin/codex'
|
||
});
|
||
```
|
||
|
||
### Method 2: Dynamic PATH Resolution
|
||
|
||
```typescript
|
||
import { Codex } from '@openai/codex-sdk';
|
||
import { execSync } from 'child_process';
|
||
|
||
const systemCodexPath = execSync('which codex', { encoding: 'utf8' }).trim();
|
||
|
||
const codex = new Codex({
|
||
codexPathOverride: systemCodexPath
|
||
});
|
||
```
|
||
|
||
### Method 3: Environment Variable Based (Custom Implementation)
|
||
|
||
```typescript
|
||
import { Codex } from '@openai/codex-sdk';
|
||
|
||
const codex = new Codex({
|
||
codexPathOverride: process.env.CODEX_BINARY_PATH || undefined
|
||
});
|
||
```
|
||
|
||
**Note:** The SDK does NOT have a built-in environment variable for this purpose. The `CODEX_BINARY_PATH` above is a custom convention you'd need to implement in your application.
|
||
|
||
---
|
||
|
||
## Verification Test Results
|
||
|
||
### Test Configuration
|
||
|
||
- **System Codex:** `/Users/moboudra/.asdf/installs/nodejs/22.20.0/bin/codex`
|
||
- **Embedded Codex:** `node_modules/@openai/codex-sdk/vendor/aarch64-apple-darwin/codex/codex`
|
||
- **Versions:** Both are `codex-cli 0.76.0`
|
||
|
||
### Test Results
|
||
|
||
```bash
|
||
$ node test-codex-path-override.mjs
|
||
Testing codexPathOverride option...
|
||
|
||
Test 1: Using default embedded binary
|
||
✓ Created Codex instance with default settings
|
||
|
||
Test 2: Using system binary via codexPathOverride
|
||
✓ Created Codex instance with codexPathOverride
|
||
|
||
Test 3: Using which codex result
|
||
System codex location: /Users/moboudra/.asdf/installs/nodejs/22.20.0/bin/codex
|
||
✓ Created Codex instance with system codex from PATH
|
||
|
||
✅ All tests passed!
|
||
```
|
||
|
||
---
|
||
|
||
## Benefits of Using System Codex
|
||
|
||
### 1. **Version Control**
|
||
- Update codex independently via package manager (npm, brew, asdf, etc.)
|
||
- No need to wait for SDK release to get latest codex features
|
||
- Easier to test beta/development versions
|
||
|
||
### 2. **Disk Space Savings**
|
||
- Embedded binary: ~40MB per architecture
|
||
- In a monorepo with multiple node_modules: Saves 40MB × number of installations
|
||
- System binary: Single installation regardless of projects
|
||
|
||
### 3. **Consistency**
|
||
- Same codex version across all tools and SDKs
|
||
- Easier debugging when CLI and SDK use identical binaries
|
||
- Simplified version management
|
||
|
||
### 4. **Development Workflow**
|
||
- Test local codex builds without reinstalling SDK
|
||
- Point to custom-compiled binaries for debugging
|
||
- A/B test different codex versions easily
|
||
|
||
---
|
||
|
||
## Potential Considerations
|
||
|
||
### 1. **Version Compatibility**
|
||
- SDK expects specific codex CLI behavior
|
||
- Using mismatched versions might cause issues
|
||
- SDK is at v0.76.0, ensure system codex matches or is compatible
|
||
|
||
### 2. **PATH Availability**
|
||
- System binary must be accessible when Node.js process runs
|
||
- Consider environment differences (development vs production)
|
||
- Absolute paths are safer than relying on PATH resolution
|
||
|
||
### 3. **No Fallback**
|
||
- If codexPathOverride points to invalid/missing binary, execution will fail
|
||
- SDK doesn't automatically fall back to embedded binary
|
||
- Implement error handling if using dynamic resolution
|
||
|
||
---
|
||
|
||
## Environment Variables (Built-in)
|
||
|
||
The SDK does NOT provide a built-in environment variable for binary path override, but it does use these:
|
||
|
||
### Used by SDK
|
||
|
||
1. **`CODEX_INTERNAL_ORIGINATOR_OVERRIDE`** (Internal)
|
||
- Source: `dist/index.js:140-141`
|
||
- Set to `"codex_sdk_ts"` to identify SDK usage
|
||
- Not for user configuration
|
||
|
||
2. **`OPENAI_BASE_URL`** (Configurable)
|
||
- Override via `CodexOptions.baseUrl`
|
||
- Also injectable via env
|
||
|
||
3. **`CODEX_API_KEY`** (Configurable)
|
||
- Override via `CodexOptions.apiKey`
|
||
- Also injectable via env
|
||
|
||
### NOT Provided
|
||
|
||
- ❌ `CODEX_BINARY_PATH` - Not a built-in feature
|
||
- ❌ `CODEX_PATH` - Not a built-in feature
|
||
- ❌ Auto-discovery via system PATH - Not implemented
|
||
|
||
---
|
||
|
||
## Recommended Implementation Pattern
|
||
|
||
For maximum flexibility, consider this pattern:
|
||
|
||
```typescript
|
||
import { Codex } from '@openai/codex-sdk';
|
||
import { execSync } from 'child_process';
|
||
import { existsSync } from 'fs';
|
||
|
||
function createCodexInstance(options = {}) {
|
||
// Priority order:
|
||
// 1. Explicit override in options
|
||
// 2. Environment variable
|
||
// 3. System PATH
|
||
// 4. Embedded binary (SDK default)
|
||
|
||
let codexPath = options.codexPathOverride;
|
||
|
||
if (!codexPath && process.env.CODEX_BINARY_PATH) {
|
||
codexPath = process.env.CODEX_BINARY_PATH;
|
||
}
|
||
|
||
if (!codexPath) {
|
||
try {
|
||
codexPath = execSync('which codex', { encoding: 'utf8' }).trim();
|
||
if (!existsSync(codexPath)) {
|
||
codexPath = undefined;
|
||
}
|
||
} catch {
|
||
// Fall back to embedded binary
|
||
codexPath = undefined;
|
||
}
|
||
}
|
||
|
||
return new Codex({
|
||
...options,
|
||
codexPathOverride: codexPath
|
||
});
|
||
}
|
||
|
||
// Usage
|
||
const codex = createCodexInstance();
|
||
```
|
||
|
||
---
|
||
|
||
## Summary
|
||
|
||
| Question | Answer |
|
||
|----------|--------|
|
||
| **Can SDK use system codex?** | ✅ Yes, via `codexPathOverride` |
|
||
| **Is configuration option available?** | ✅ Yes, in `CodexOptions` interface |
|
||
| **Built-in env variable support?** | ❌ No, must implement custom logic |
|
||
| **Automatic PATH resolution?** | ❌ No, must provide explicit path |
|
||
| **Fallback to embedded?** | ❌ No, fails if override is invalid |
|
||
| **Version tested** | 0.76.0 (both system and embedded) |
|
||
|
||
---
|
||
|
||
## Conclusion
|
||
|
||
The `@openai/codex-sdk` library provides full support for using a system-installed Codex binary through the `codexPathOverride` configuration option. This feature is well-designed and allows developers to choose between the convenience of embedded binaries and the flexibility of system-managed installations.
|
||
|
||
To use a system binary:
|
||
1. Install codex globally (via npm, brew, asdf, etc.)
|
||
2. Pass the path via `codexPathOverride` when instantiating `Codex`
|
||
3. Optionally implement PATH resolution logic for automatic discovery
|
||
|
||
The embedded binary remains the default, ensuring the SDK works out-of-the-box without requiring system-wide codex installation.
|