codex_cli_sdk 1.2.0
codex_cli_sdk: ^1.2.0 copied to clipboard
A powerful Dart SDK for interacting with OpenAI Codex CLI, providing seamless integration with AI-powered coding assistance through the Codex CLI tool.
Codex CLI SDK for Dart #
A powerful Dart SDK for interacting with OpenAI Codex CLI, providing seamless integration with AI-powered coding assistance through the Codex CLI tool.
Features #
- π Easy Integration: Simple API for creating chat sessions with Codex
- π File Support: Send files along with text prompts for context-aware responses
- πΎ Bytes Support: Send in-memory data as temporary files (auto-cleanup on dispose)
- π Schema Support: Get structured responses using JSON schemas
- π Session Management: Resume and continue conversations seamlessly
- π οΈ Auto-Installation: Built-in methods to check and install Codex CLI
- π MCP Support: Full Model Context Protocol integration for connecting to external tools
- π§Ή Resource Management: Proper cleanup and disposal of chat sessions and temp files
- π Secure: API key management with environment variable support
- β‘ Reliable: Simple Process.run based implementation (no streaming complexity)
- π Streaming: Support for real-time streaming responses
- π― Multiple Modes: Support for suggest, auto-edit, and full-auto modes
Prerequisites #
Before using this SDK, you need:
-
Node.js and npm (for Codex CLI)
- Download from nodejs.org
-
Codex CLI
- Install globally:
npm install -g @openai/codex - Or use the SDK's built-in installer (see below)
- Install globally:
-
OpenAI API Key
- Get your API key from OpenAI Platform
- Or sign in with ChatGPT Plus/Pro/Team subscription
Installation #
Add this to your package's pubspec.yaml file:
dependencies:
codex_cli_sdk: ^1.2.0
Then run:
dart pub get
Available Models #
The SDK supports the latest OpenAI models through Codex CLI:
- GPT-5 - Default model for fast reasoning
- gpt-oss-120b - Open-source 117B parameter model with high reasoning capabilities
- codex-mini-latest - Fine-tuned version of o4-mini for Codex CLI
- codex-1 - Version of o3 optimized for software engineering
Reasoning Effort (v1.1.0+) #
The SDK now supports configurable reasoning effort levels for models that support it:
- minimal - Fast responses without extensive reasoning
- medium - Balanced speed and reasoning depth (default)
- high - Deep and detailed analysis for complex tasks
Using Reasoning Effort #
// Create a chat with specific reasoning effort
final chat = codexSDK.createNewChat(
options: CodexChatOptions(
model: 'gpt-oss-120b',
reasoningEffort: 'high', // For complex tasks requiring deep analysis
),
);
// Or change model and effort during conversation
chat.changeModelWithEffort('gpt-5', 'medium');
Quick Start #
Basic Usage #
import 'package:codex_cli_sdk/codex_cli_sdk.dart';
void main() async {
// Initialize the SDK with your API key
final codexSDK = Codex('YOUR_API_KEY');
// Create a new chat session
final codexChat = codexSDK.createNewChat();
try {
// Send a simple text message
final result = await codexChat.sendMessage([
CodexSdkContent.text('What is the capital of France?'),
]);
print('Codex says: $result');
} finally {
// Always dispose of the chat when done
await codexChat.dispose();
}
}
Sending Files with Messages #
import 'dart:io';
import 'package:codex_cli_sdk/codex_cli_sdk.dart';
void main() async {
final codexSDK = Codex('YOUR_API_KEY');
final codexChat = codexSDK.createNewChat();
try {
// Send a message with a file
final result = await codexChat.sendMessage([
CodexSdkContent.text('Please analyze this HTML file and extract the user name'),
CodexSdkContent.file(File('example.html')),
]);
print('Analysis result: $result');
} finally {
await codexChat.dispose();
}
}
Sending Bytes as Temporary Files #
You can send in-memory data (like images, documents, or any binary data) without creating permanent files:
import 'dart:typed_data';
import 'package:codex_cli_sdk/codex_cli_sdk.dart';
void main() async {
final codexSDK = Codex('YOUR_API_KEY');
final codexChat = codexSDK.createNewChat();
try {
// Example 1: Send image bytes
final imageBytes = await File('photo.jpg').readAsBytes();
final result = await codexChat.sendMessage([
CodexSdkContent.text('What is in this image?'),
CodexSdkContent.bytes(
data: imageBytes,
fileExtension: 'jpg',
),
]);
// Example 2: Send text as bytes
final textContent = 'Hello, this is dynamic content!';
final textBytes = Uint8List.fromList(textContent.codeUnits);
final result2 = await codexChat.sendMessage([
CodexSdkContent.text('Read this text:'),
CodexSdkContent.bytes(
data: textBytes,
fileExtension: 'txt',
),
]);
print('Result: $result2');
} finally {
// Temporary files are automatically deleted when disposed
await codexChat.dispose();
}
}
Using Schemas for Structured Responses #
import 'dart:io';
import 'package:codex_cli_sdk/codex_cli_sdk.dart';
void main() async {
final codexSDK = Codex('YOUR_API_KEY');
final codexChat = codexSDK.createNewChat();
try {
// Define a schema with nullable properties
final schema = SchemaObject(
properties: {
'userName': SchemaProperty.string(
description: 'The name of the user found in the HTML',
nullable: false, // Required field
),
'userEmail': SchemaProperty.string(
description: 'The email of the user if found',
nullable: true, // Optional field
),
'userRole': SchemaProperty.string(
description: 'The role or title of the user',
nullable: true, // Optional field
),
},
);
// Send message with schema
final result = await codexChat.sendMessageWithSchema(
messages: [
CodexSdkContent.text('Extract user information from this HTML file'),
CodexSdkContent.file(File('profile.html')),
],
schema: schema,
);
print('Model message: ${result.modelMessage}');
print('Extracted data: ${result.data}');
// Access specific fields
final userName = result.data['userName'];
print('User name: $userName');
} finally {
await codexChat.dispose();
}
}
Streaming Responses #
import 'package:codex_cli_sdk/codex_cli_sdk.dart';
void main() async {
final codexSDK = Codex('YOUR_API_KEY');
final codexChat = codexSDK.createNewChat();
try {
// Stream the response
await for (final chunk in codexChat.streamResponse([
CodexSdkContent.text('Write a detailed explanation of quantum computing'),
])) {
print(chunk); // Print each chunk as it arrives
}
} finally {
await codexChat.dispose();
}
}
Advanced Configuration #
Chat Options #
final codexChat = codexSDK.createNewChat(
options: CodexChatOptions(
systemPrompt: 'You are a helpful coding assistant',
maxTurns: 5,
model: 'codex-mini-latest',
mode: 'auto-edit', // or 'suggest', 'full-auto'
cwd: '/path/to/project',
outputJson: true,
quiet: true, // Non-interactive JSON mode
timeoutMs: 30000,
enableMcp: true,
profile: 'custom-profile', // Use profile from config.toml
),
);
Operation Modes #
Codex CLI supports three distinct operation modes:
- suggest: Reviews proposed changes before applying
- auto-edit: Automatically reads and writes files but asks permission for shell commands
- full-auto: Fully autonomous operation within a sandboxed environment
// Suggest mode - review changes before applying
final suggestChat = codexSDK.createNewChat(
options: CodexChatOptions(mode: 'suggest'),
);
// Auto-edit mode - automatic file operations
final autoEditChat = codexSDK.createNewChat(
options: CodexChatOptions(mode: 'auto-edit'),
);
// Full-auto mode - fully autonomous
final fullAutoChat = codexSDK.createNewChat(
options: CodexChatOptions(mode: 'full-auto'),
);
Session Management #
// Continue the last session
final chat = codexSDK.createNewChat(
options: CodexChatOptions(continueLastSession: true),
);
// Resume a specific session
final chat = codexSDK.createNewChat(
options: CodexChatOptions(resumeSessionId: 'session-id-here'),
);
// Reset conversation mid-session
chat.resetConversation();
Checking and Installing Codex CLI #
void main() async {
final codexSDK = Codex('YOUR_API_KEY');
// Check if Codex CLI is installed
final isInstalled = await codexSDK.isCodexCLIInstalled();
if (!isInstalled) {
print('Codex CLI is not installed. Installing...');
try {
// Install the CLI globally
await codexSDK.installCodexCLI(global: true);
print('Installation complete!');
} catch (e) {
print('Installation failed: $e');
}
}
// Get SDK information
final info = await codexSDK.getSDKInfo();
print('SDK Info: $info');
}
Auto-Update SDK #
The SDK provides a convenient method to automatically check for and install updates:
void main() async {
final codexSDK = Codex('YOUR_API_KEY');
// Automatically check for updates and install if needed
await codexSDK.updateToNewestVersionIfNeeded(global: true);
// The function will:
// 1. Check if CLI is installed (installs if not)
// 2. Compare current version with latest npm version
// 3. Update if a newer version is available
}
MCP (Model Context Protocol) Support #
The SDK provides comprehensive support for MCP, allowing Codex to connect to external tools and services.
Checking MCP Installation #
final mcpInfo = await codexSDK.isMcpInstalled();
print('MCP enabled: ${mcpInfo.hasMcpSupport}');
print('Configured servers: ${mcpInfo.servers.length}');
for (final server in mcpInfo.servers) {
print(' - ${server.name}: ${server.status}');
}
Installing Popular MCP Servers #
// Install filesystem MCP server
await codexSDK.installPopularMcpServer('filesystem');
// Install GitHub MCP with environment variables
await codexSDK.installPopularMcpServer('github',
environment: {'GITHUB_TOKEN': 'your-github-token'}
);
// Available popular servers:
// - filesystem: File system access
// - github: GitHub integration
// - postgres: PostgreSQL database
// - git: Git operations
// - puppeteer: Web automation
// - sequential-thinking: Problem solving
// - slack: Slack integration
// - google-drive: Google Drive access
Adding Custom MCP Servers #
// Add a custom MCP server
final customServer = McpServer(
name: 'my-custom-server',
command: 'node',
args: ['path/to/server.js'],
env: {'API_KEY': 'your-api-key'},
);
await codexSDK.addMcpServer(
'my-custom-server',
customServer: customServer,
);
// Or add an npm package as MCP server
await codexSDK.addMcpServer(
'my-npm-server',
packageName: '@company/mcp-server',
options: McpAddOptions(
scope: McpScope.user,
useNpx: true,
environment: {'CONFIG': 'value'},
),
);
Managing MCP Servers #
// List all configured servers
final servers = await codexSDK.listMcpServers();
// Get details about a specific server
final details = await codexSDK.getMcpServerDetails('filesystem');
// Remove a server
await codexSDK.removeMcpServer('my-custom-server');
Using MCP in Chat Sessions #
Once MCP servers are configured, they're automatically available in chat sessions:
final chat = codexSDK.createNewChat();
// Codex can now use the configured MCP tools
final result = await chat.sendMessage([
CodexSdkContent.text(
'List all files in my Documents folder' // Works if filesystem MCP is installed
),
]);
Schema Building #
The SDK provides convenient factory methods for building schemas with nullable control:
final schema = SchemaObject(
properties: {
'name': SchemaProperty.string(
description: 'User name',
defaultValue: 'Anonymous',
nullable: false, // Required field
),
'age': SchemaProperty.number(
description: 'User age',
nullable: false, // Required field
),
'email': SchemaProperty.string(
description: 'User email',
nullable: true, // Optional field (default)
),
'isActive': SchemaProperty.boolean(
description: 'Whether the user is active',
defaultValue: true,
nullable: false, // Required with default value
),
'tags': SchemaProperty.array(
items: SchemaProperty.string(),
description: 'List of tags',
nullable: true, // Optional array
),
'metadata': SchemaProperty.object(
properties: {
'created': SchemaProperty.string(nullable: false),
'updated': SchemaProperty.string(nullable: true),
},
description: 'Metadata object',
nullable: true, // Optional nested object
),
},
description: 'User information schema',
);
Nullable Property Behavior #
nullable: false- The property is required and must be present in the responsenullable: true(default) - The property is optional and may be omitted or null- Properties with
nullable: falseare automatically added to the JSON schema'srequiredarray
Error Handling #
The SDK provides specific exception types for different error scenarios:
import 'package:codex_cli_sdk/codex_cli_sdk.dart';
void main() async {
final codexSDK = Codex('YOUR_API_KEY');
final codexChat = codexSDK.createNewChat();
try {
final result = await codexChat.sendMessage([
CodexSdkContent.text('Hello, Codex!'),
]);
print(result);
} on CLINotFoundException {
print('Codex CLI is not installed. Please install it first.');
} on ProcessException catch (e) {
print('Process error: ${e.message}');
if (e.exitCode != null) {
print('Exit code: ${e.exitCode}');
}
} on JSONDecodeException catch (e) {
print('Failed to parse response: ${e.message}');
} on CodexSDKException catch (e) {
print('SDK error: ${e.message}');
} finally {
await codexChat.dispose();
}
}
Implementation Details #
This SDK uses a simple and reliable approach:
- Process.run: Each message is sent as a separate process call
- Session Management: Uses
--resumeand--continueflags for conversation continuity - JSON Output: Uses
--quietand--jsonflags for consistent parsing - MCP Configuration: Manages
~/.codex/config.tomlfor MCP servers
Resource Management #
Important: Always Dispose Chat Sessions #
Always dispose of chat sessions when done to ensure proper cleanup:
// Method 1: Using try-finally
final chat = codexSDK.createNewChat();
try {
// Use the chat
await chat.sendMessage([...]);
} finally {
await chat.dispose();
}
// Method 2: Dispose all sessions at once
await codexSDK.dispose(); // Disposes all active sessions
API Reference #
Codex Class #
Codex(String apiKey)- Creates a new SDK instancecreateNewChat({CodexChatOptions? options})- Creates a new chat sessionisCodexCLIInstalled()- Checks if Codex CLI is installedinstallCodexCLI({bool global = true})- Installs the Codex CLIupdateToNewestVersionIfNeeded({bool global = true})- Updates SDK to newest version if availablegetSDKInfo()- Gets information about installed SDKsisMcpInstalled()- Checks MCP installation statuslistMcpServers()- Lists all configured MCP serversinstallPopularMcpServer(name, {environment})- Installs a popular MCP serveraddMcpServer(name, {packageName, customServer, options})- Adds an MCP servergetMcpServerDetails(name)- Gets details about a specific serverremoveMcpServer(name)- Removes an MCP serverdispose()- Disposes all active chat sessions
CodexChat Class #
sendMessage(List<CodexSdkContent> contents)- Sends a message and returns the responsesendMessageWithSchema({messages, schema})- Sends a message with a schema for structured responsestreamResponse(List<CodexSdkContent> contents)- Streams the responseget sessionId- Gets the current session ID (null until first message)resetConversation()- Resets the conversation, starting a new sessiondispose()- Disposes the chat session and cleans up resources (including temp files)
CodexSdkContent #
CodexSdkContent.text(String text)- Creates text contentCodexSdkContent.file(File file)- Creates file contentCodexSdkContent.bytes({data, fileExtension})- Creates content from bytes (temporary file)
Environment Variables #
You can also set your API key as an environment variable:
export OPENAI_API_KEY="your-api-key-here"
Then use it in your code:
final apiKey = Platform.environment['OPENAI_API_KEY'] ?? '';
final codexSDK = Codex(apiKey);
Troubleshooting #
Codex CLI not found #
If you get a CLINotFoundException, make sure Codex CLI is installed:
npm install -g @openai/codex
Or use the SDK's built-in installer:
await codexSDK.installCodexCLI();
Permission Errors #
On Unix-like systems, you might need to use sudo for global npm installations:
sudo npm install -g @openai/codex
Process Cleanup #
Always dispose of chat sessions to prevent resource leaks:
await codexChat.dispose();
// or
await codexSDK.dispose(); // Disposes all sessions
Rate Limits #
Be aware of OpenAI's rate limits based on your subscription:
- ChatGPT Plus/Pro/Team users get access through their subscription
- API key users pay per token usage
- Check OpenAI pricing for current rates
Examples #
Check the example/ directory for more comprehensive examples:
example/basic_usage.dart- Simple text messagingexample/file_analysis.dart- Analyzing files with Codexexample/schema_example.dart- Using schemas for structured responsesexample/streaming_example.dart- Streaming responsesexample/installation_check.dart- Checking and installing dependenciesexample/mcp_management.dart- Managing MCP serversexample/bytes_content_example.dart- Working with in-memory dataexample/modes_example.dart- Using different operation modes
Contributing #
Contributions are welcome! Please feel free to submit a Pull Request.
License #
This project is licensed under the MIT License - see the LICENSE file for details.
Support #
For issues and questions:
- Open an issue on GitHub
- Check the OpenAI documentation
- Visit the Codex GitHub repository
Acknowledgments #
- Built on top of the official Codex CLI by OpenAI
- Inspired by the Claude Code SDK and Gemini CLI SDK architectures
- Supports Model Context Protocol (MCP) for extensibility