CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-openai--codex

OpenAI Codex CLI is a lightweight coding agent that runs locally, providing multimodal inputs, rich approvals workflow, and terminal-based AI-assisted development

Overview
Eval results
Files

protocol-mode.mddocs/

Protocol Mode

Protocol mode allows Codex CLI to operate as a programmatic interface, communicating via JSON-line protocol over stdin/stdout for integration with other tools and systems.

Usage

codex proto [OPTIONS]
codex p [OPTIONS]

Requirements

  • Non-terminal stdin: Protocol mode requires stdin to be a pipe, not a terminal
  • JSON-line format: All communication uses newline-delimited JSON
  • Bidirectional communication: Stdin for submissions, stdout for events

Protocol Flow

  1. Initialization: Codex starts and emits a SessionConfigured event
  2. Submission: Send JSON-line submissions via stdin
  3. Events: Receive JSON-line events via stdout
  4. Termination: Process ends on stdin close or Ctrl+C

Message Format

Submissions (stdin)

Send JSON objects representing user submissions:

{
  "id": "unique-submission-id",
  "type": "text",
  "content": "Your prompt or request here"
}

Events (stdout)

Receive JSON objects representing system events:

{
  "id": "unique-event-id",
  "msg": {
    "type": "SessionConfigured",
    "data": {
      // Session configuration details
    }
  }
}

Examples

Basic Protocol Usage

# Start protocol mode (stdin must be piped)
echo '{"id":"1","type":"text","content":"Hello"}' | codex proto

Integration Script

#!/bin/bash
# example-integration.sh

# Start codex in protocol mode
{
  # Send initial prompt
  echo '{"id":"req-1","type":"text","content":"List all files in current directory"}'

  # Send follow-up prompt
  echo '{"id":"req-2","type":"text","content":"Show me the main.py file"}'
} | codex proto | while IFS= read -r line; do
  # Process each event
  echo "Event: $line"
done

Python Integration

import subprocess
import json
import sys

def codex_protocol_session():
    # Start codex in protocol mode
    process = subprocess.Popen(
        ['codex', 'proto'],
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        text=True
    )

    # Send submission
    submission = {
        "id": "python-req-1",
        "type": "text",
        "content": "Help me write a function to sort a list"
    }

    process.stdin.write(json.dumps(submission) + '\n')
    process.stdin.flush()

    # Read events
    for line in process.stdout:
        event = json.loads(line.strip())
        print(f"Received event: {event['msg']['type']}")

        # Handle different event types
        if event['msg']['type'] == 'SessionConfigured':
            print("Session is ready")
        elif event['msg']['type'] == 'Response':
            print(f"AI Response: {event['msg']['content']}")

    process.stdin.close()
    process.wait()

if __name__ == "__main__":
    codex_protocol_session()

Node.js Integration

const { spawn } = require('child_process');
const readline = require('readline');

function startCodexProtocol() {
  const codex = spawn('codex', ['proto']);

  // Handle stdout (events)
  const rl = readline.createInterface({
    input: codex.stdout,
    crlfDelay: Infinity
  });

  rl.on('line', (line) => {
    const event = JSON.parse(line);
    console.log('Event:', event.msg.type);

    if (event.msg.type === 'SessionConfigured') {
      // Send a submission when session is ready
      const submission = {
        id: 'js-req-1',
        type: 'text',
        content: 'Create a simple Express.js server'
      };

      codex.stdin.write(JSON.dumps(submission) + '\n');
    }
  });

  // Handle stderr
  codex.stderr.on('data', (data) => {
    console.error('Error:', data.toString());
  });

  return codex;
}

const session = startCodexProtocol();

Event Types

SessionConfigured

Emitted when the protocol session is ready to accept submissions.

{
  "id": "",
  "msg": {
    "type": "SessionConfigured",
    "data": {
      "session_id": "uuid-here",
      "model": "gpt-4",
      "capabilities": ["text", "images"],
      "sandbox_mode": "workspace-read"
    }
  }
}

Response Events

Various response events are emitted during conversation processing:

  • StreamingResponse: Partial response content
  • FinalResponse: Complete response
  • Error: Error conditions
  • TokenUsage: Usage statistics

Configuration

Protocol mode inherits configuration from:

# Use configuration overrides
codex proto -c model=gpt-4 -c sandbox_mode=workspace-write

# Use configuration profile
codex --config-profile integration proto

Error Handling

Invalid JSON

If malformed JSON is sent, an error event is emitted:

{
  "id": "error-1",
  "msg": {
    "type": "Error",
    "error": "invalid submission: expected JSON object"
  }
}

Connection Issues

  • Broken pipe: Process terminates if stdin closes unexpectedly
  • Signal handling: Ctrl+C terminates gracefully
  • Invalid submissions: Logged to stderr, session continues

Signal Handling

Protocol mode responds to signals:

  • SIGINT (Ctrl+C): Graceful shutdown
  • SIGTERM: Immediate termination
  • Broken pipe: Clean exit when stdin closes

Best Practices

  1. Validate JSON: Always validate JSON before sending
  2. Handle events asynchronously: Process events as they arrive
  3. Implement timeouts: Set reasonable timeouts for responses
  4. Buffer management: Handle large responses with proper buffering
  5. Error recovery: Implement retry logic for transient errors
  6. Resource cleanup: Properly close processes and handles

Limitations

  • Terminal requirement: Cannot be run in interactive terminal mode
  • Stateful sessions: Each protocol session maintains conversation state
  • Single conversation: One conversation per protocol session
  • Resource usage: Each session consumes system resources until terminated

Install with Tessl CLI

npx tessl i tessl/npm-openai--codex

docs

authentication.md

development-utilities.md

execution-mode.md

index.md

interactive-mode.md

mcp-management.md

protocol-mode.md

session-management.md

tile.json