coding-agent-sdk
Unified SDK for Claude Code, Codex CLI, and Gemini CLI - Programmatic access to AI coding agents with a consistent interface.
Features
✅ Unified API - Single query() function works across all three backends
✅ CLI Mode - Run queries directly from command line with npx coding-agent-sdk
✅ Auto-detection - Automatically selects backend based on environment variables
✅ Streaming Events - Real-time event streaming with unified event schema
✅ Session Management - Resume previous sessions across all backends
✅ TypeScript - Full type definitions included
✅ Zero Config - Works out of the box with sensible defaults
Installation
npm install coding-agent-sdk
Backend Requirements
Each backend requires its CLI to be installed globally:
npm install -g @openai/codex
Important: The SDK spawns CLI processes directly (claude, codex, gemini). Make sure the binaries are in your PATH.
Quick Start
Option A: CLI Mode (Easiest)
Run queries directly from the command line:
npx coding-agent-sdk -p "Fix the failing tests"
npx coding-agent-sdk -p "Add type annotations" -b claude
npx coding-agent-sdk --help
CLI Options:
-p, --prompt <text> - Prompt to send to the agent (required)
-b, --backend <name> - Backend to use: claude, codex, or gemini (auto-detected if not specified)
-w, --working-dir <dir> - Working directory (default: current directory)
-r, --resume <id> - Resume from a previous session ID
-h, --help - Show help message
-v, --version - Show version number
Option B: Programmatic API
1. Set up API Keys
The SDK auto-detects which backend to use based on environment variables:
export ANTHROPIC_API_KEY=your_anthropic_key
export CODEX_API_KEY=your_codex_key
export GEMINI_API_KEY=your_gemini_key
2. Basic Usage
import { query } from 'coding-agent-sdk';
const result = await query("Fix the failing tests");
for await (const event of result.events) {
if (event.type === 'message') {
console.log(`[${event.role}]:`, event.content);
}
}
console.log('Session ID:', result.sessionId);
console.log('Backend used:', result.backend);
3. Explicit Backend Selection
import { query } from 'coding-agent-sdk';
const result = await query("Deploy the application", {
backend: 'claude',
workingDir: '/path/to/project',
});
4. Resume Previous Session
import { query } from 'coding-agent-sdk';
const result1 = await query("Start implementing the feature");
const sessionId = result1.sessionId;
const result2 = await query("Continue from where we left off", {
resume: sessionId,
});
Unified Event Schema
The SDK provides 7 unified event types that work across all backends:
1. SessionEvent - Session lifecycle
{
type: 'session',
subtype: 'init' | 'end',
session_id: string,
backend: 'claude' | 'codex' | 'gemini',
timestamp?: string,
metadata?: { ... }
}
2. TurnEvent - Conversation turn boundaries
{
type: 'turn',
subtype: 'started' | 'completed' | 'failed',
usage?: {
input_tokens?: number,
output_tokens?: number,
cached_tokens?: number,
thinking_tokens?: number,
},
error?: string
}
3. MessageEvent - User/assistant text messages
{
type: 'message',
role: 'user' | 'assistant',
content: string,
is_delta?: boolean,
content_index?: number,
parent_id?: string
}
4. ActionEvent - Tool execution, commands, file changes
{
type: 'action',
subtype: 'tool' | 'command' | 'file_change' | 'web_search' | 'reasoning' | 'mcp_tool',
action_id?: string,
status: 'started' | 'in_progress' | 'completed' | 'failed',
tool_name?: string,
tool_input?: unknown,
tool_output?: unknown,
command?: string,
command_output?: string,
exit_code?: number,
file_path?: string,
change_type?: 'add' | 'update' | 'delete',
}
5. ProgressEvent - Long-running operations
{
type: 'progress',
subtype: 'todo_update' | 'status_update' | 'elapsed_time',
todo_items?: Array<{ title: string, status: string }>,
status_message?: string,
elapsed_ms?: number
}
6. ErrorEvent - Errors and warnings
{
type: 'error',
severity: 'warning' | 'error' | 'fatal',
message: string,
related_action_id?: string
}
7. MetricsEvent - Usage statistics
{
type: 'metrics',
subtype: 'usage_update' | 'session_summary',
per_model?: Record<string, { ... }>,
per_tool?: Record<string, { ... }>,
files?: { ... }
}
Advanced Usage
Backend-Specific Options
Each backend supports custom configuration:
import { query } from 'coding-agent-sdk';
const result = await query("Complex task", {
backend: 'claude',
backendOptions: {
claude: {
maxThinkingTokens: 10000,
mcpServers: ['next-devtools-mcp'],
permissionMode: 'prompt',
},
},
});
Filtering Events
import { query } from 'coding-agent-sdk';
const result = await query("Refactor the codebase");
for await (const event of result.events) {
if (event.type === 'message' && event.role === 'assistant') {
console.log(event.content);
}
if (event.type === 'action' && event.subtype === 'tool') {
console.log(`Tool: ${event.tool_name} (${event.status})`);
}
if (event.type === 'error') {
console.error(`[${event.severity}]`, event.message);
}
}
Collecting All Events
import { query } from 'coding-agent-sdk';
const result = await query("Analyze the project");
const events: UnifiedEvent[] = [];
for await (const event of result.events) {
events.push(event);
}
const messages = events.filter(e => e.type === 'message');
const actions = events.filter(e => e.type === 'action');
console.log(`Total messages: ${messages.length}`);
console.log(`Total actions: ${actions.length}`);
API Reference
query(prompt, options?)
Main function to query AI coding agents.
Parameters:
prompt: string - The prompt to send to the agent
options?: QueryOptions - Optional configuration
Returns: Promise<QueryResult>
QueryOptions
interface QueryOptions {
backend?: 'claude' | 'codex' | 'gemini';
resume?: string;
workingDir?: string;
autoApprove?: boolean;
backendOptions?: {
claude?: ClaudeBackendOptions;
codex?: CodexBackendOptions;
gemini?: GeminiBackendOptions;
};
}
QueryResult
interface QueryResult {
sessionId: string;
events: AsyncGenerator<UnifiedEvent>;
backend: 'claude' | 'codex' | 'gemini';
}
isBackendAvailable(backend)
Check if a specific backend is available.
import { isBackendAvailable } from 'coding-agent-sdk';
if (isBackendAvailable('claude')) {
console.log('Claude is available!');
}
Backend Comparison
| Installation | https://claude.com/code | npm i -g @openai/codex | https://github.com/google-gemini/gemini-cli |
| Binary | claude | codex | gemini |
| API Key Env | ANTHROPIC_API_KEY | CODEX_API_KEY | GEMINI_API_KEY |
| Output Format | --output-format stream-json | --experimental-json | --output-format stream-json |
| Session Resume | ✅ --resume | ✅ resume arg | ✅ --resume |
| MCP Support | ✅ | ✅ | ✅ |
| Extended Thinking | ✅ | ✅ | ❌ |
| Structured Output | ❌ | ✅ | ❌ |
| Web Search | ✅ | ✅ | ❌ |
| Todo Tracking | ❌ | ✅ | ❌ |
Error Handling
import { query, BackendNotAvailableError, NoBackendFoundError } from 'coding-agent-sdk';
try {
const result = await query("Deploy the app");
for await (const event of result.events) {
if (event.type === 'error') {
console.error(`Error: ${event.message}`);
}
}
} catch (error) {
if (error instanceof NoBackendFoundError) {
console.error('No API key found. Set ANTHROPIC_API_KEY, CODEX_API_KEY, or GEMINI_API_KEY');
} else if (error instanceof BackendNotAvailableError) {
console.error(`Backend ${error.backend} is not available: ${error.message}`);
} else {
console.error('Unexpected error:', error);
}
}
Examples
Simple Task
import { query } from 'coding-agent-sdk';
const result = await query("Add type annotations to all functions");
for await (const event of result.events) {
if (event.type === 'message' && event.role === 'assistant') {
console.log(event.content);
}
}
Monitor Progress
import { query } from 'coding-agent-sdk';
const result = await query("Refactor the authentication module");
for await (const event of result.events) {
if (event.type === 'progress' && event.subtype === 'todo_update') {
console.log('Todo List:');
event.todo_items?.forEach(todo => {
console.log(` [${todo.status}] ${todo.title}`);
});
}
}
Track Token Usage
import { query } from 'coding-agent-sdk';
const result = await query("Optimize database queries");
for await (const event of result.events) {
if (event.type === 'turn' && event.subtype === 'completed') {
console.log('Token Usage:', event.usage);
}
}
Testing
The SDK includes a comprehensive test suite with >95% coverage.
Running Tests
npm test
npm run test:watch
npm run test:coverage
Test Structure
src/**/*.test.ts - Unit and integration tests
- Tests cover:
- Event mappers for all backends
- Backend auto-detection
- Error handling
- Type definitions
- Query function behavior
Coverage
Current test coverage: 95%+
Contributing
Contributions are welcome! Please open an issue or submit a pull request.
Before submitting a PR:
- Run
npm test to ensure all tests pass
- Run
npm run test:coverage to verify coverage remains high
- Run
npm run build to ensure the build succeeds
License
MIT
Related Projects