Codex SDK Automation skill for Codex

Drive Codex from TypeScript with real guardrails. Codex writes SDK integrations that set working directory, sandbox, approval policy, timeout and output schema on every thread, stream events for logging, verify results outside the agent, and record thread ids and token usage, so batch jobs and internal tools fail loudly and can be resumed instead of hanging or silently succeeding.

  • Codex Mastery
  • $codex-sdk-automation
  • 178 lines
  • 2 files
  • ~1,950 tokens
  • MIT
  • Updated

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- codex-sdk-automation

Installs to ~/.agents/skills/codex-sdk-automation/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $codex-sdk-automation, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Scripts Codex from Node.js with the @openai/codex-sdk TypeScript library, covering threads, run versus runStreamed, per-turn outputSchema, AbortSignal timeouts, sandbox and approval thread options, env isolation, resumeThread and token usage, for batch jobs, internal tools and CI pipelines. Use when the user wants to call Codex from TypeScript or JavaScript, build an agent pipeline around Codex, process many repos or tasks programmatically, or replace a fragile shell loop around codex exec.

Use it when

  • Calling Codex from TypeScript or JavaScript code
  • Building a batch job or internal tool around Codex turns
  • You need streamed progress, cancellation or multi-turn threads in a program
  • A shell loop around codex exec has grown branching and retries

Use something else when

How to check the result

Run one task end to end: finalResponse, items and usage are logged, the abort timeout fires on a forced hang, and a failing task yields a recorded error and non-zero exit.

The mistake it prevents

Passing a custom env without PATH and HOME, so the spawned Codex CLI cannot find tools or its own config.

~/.agents/skills/codex-sdk-automation/SKILL.md

--- name: codex-sdk-automation description: Scripts Codex from Node.js with the @openai/codex-sdk TypeScript library, covering threads, run versus runStreamed, per-turn outputSchema,… license: MIT ---

An SDK integration is done well when every run has an explicit working directory, sandbox, approval policy, timeout and output contract; failures surface as thrown errors or non-zero exits; and thread ids and token usage are recorded so runs can be resumed and costed.

Choose the integration

NeedUse
One-off scripted run from a shell or CI stepcodex exec (see codex-exec-ci)
Program logic around Codex turns: loops, branching, retries, parsing@openai/codex-sdk (this skill)
Python serviceopenai-codex Python SDK (pip install openai-codex, Python 3.10+)
Custom client UI with your own approvals and historyCodex app server protocol

The TypeScript SDK spawns the Codex CLI and exchanges JSONL events with it, so the same config layers, AGENTS.md discovery, sandbox and auth apply. It needs Node.js 18+ and runs server-side only.

Setup

npm install @openai/codex-sdk

Auth: reuse the machine’s saved Codex login, or pass apiKey (sent to the CLI as CODEX_API_KEY). In CI, read the key from the secret store at the call site, never from a job-wide environment variable that build scripts can read.

Core API

import { Codex } from "@openai/codex-sdk";

const codex = new Codex({
  apiKey: process.env.CODEX_API_KEY,          // optional; omit to use saved login
  config: { sandbox_workspace_write: { network_access: false } }, // flattened to --config
});

const thread = codex.startThread({
  workingDirectory: "/srv/checkouts/payments",
  sandboxMode: "workspace-write",              // read-only | workspace-write | danger-full-access
  approvalPolicy: "never",                     // nobody is there to approve
  model: "gpt-6.1-sol",                        // omit to use the configured default
  modelReasoningEffort: "medium",
});

const turn = await thread.run("Run the tests, fix the failing one, rerun the tests.");
console.log(turn.finalResponse);   // last agent message
console.log(turn.items);           // commands, file changes, MCP calls, todo lists...
console.log(turn.usage);           // input, cached_input, output, reasoning_output tokens
console.log(thread.id);            // persist this to resume later
  • thread.run() again continues the same thread with full prior context.
  • codex.resumeThread(id) rebuilds a thread from ~/.codex/sessions after a restart.
  • run() throws when the turn fails; catch it per task so one failure does not stop the batch.

Thread and client options

OptionWherePurpose
workingDirectorythreadRepo to operate on; must be a git repo unless skipGitRepoCheck: true
sandboxModethreadFilesystem boundary for commands
approvalPolicythreadUse "never" for unattended runs; "on-request" has nobody to answer
networkAccessEnabledthreadCommand network access in workspace-write
webSearchModethread"disabled", "cached" or "live"
additionalDirectoriesthreadExtra writable roots
model, modelReasoningEffortthreadPer-thread model and effort
config / configOverridesclientAny config key; raw TOML strings for keys dotted paths cannot express
envclientFull environment for the CLI; when set, process.env is NOT inherited
codexPathOverrideclientPin a specific codex binary

Per-turn options

const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 15 * 60_000);
try {
  const turn = await thread.run(prompt, { outputSchema: schema, signal: controller.signal });
} finally {
  clearTimeout(timer);
}

outputSchema makes the final message JSON matching the schema (strict structured output rules apply; see codex-output-schemas). Parse finalResponse with JSON.parse and validate it anyway.

Streaming

Use runStreamed() when you need progress, early cancellation or per-item logging:

const { events } = await thread.runStreamed("Diagnose the flaky test in tests/sync");
for await (const ev of events) {
  if (ev.type === "item.completed" && ev.item.type === "command_execution")
    log.info({ cmd: ev.item.command, exit: ev.item.exit_code });
  if (ev.type === "item.completed" && ev.item.type === "file_change")
    log.info({ files: ev.item.changes.map((c) => `${c.kind} ${c.path}`) });
  if (ev.type === "turn.completed") log.info({ usage: ev.usage });
  if (ev.type === "turn.failed") throw new Error(ev.error.message);
}

Event types: thread.started, turn.started, turn.completed, turn.failed, item.started, item.updated, item.completed, error. Item types: agent_message, reasoning, command_execution, file_change, mcp_tool_call, web_search, todo_list, error.

Batch pipeline pattern

- [ ] 1. Prepare one isolated checkout per task (fresh clone or git worktree)
- [ ] 2. Start a thread per task with explicit options
- [ ] 3. Run with a timeout and an output schema
- [ ] 4. Verify outside the agent (tests, git diff)
- [ ] 5. Record thread id, usage, verdict; continue on failure
- [ ] 6. Exit non-zero if any task failed
import { spawnSync } from "node:child_process";
import { writeFileSync } from "node:fs";

const results = [];
for (const task of tasks) {              // run sequentially, or with a small pool (2-4)
  const thread = codex.startThread({ workingDirectory: task.dir, sandboxMode: "workspace-write",
                                     approvalPolicy: "never" });
  try {
    const turn = await thread.run(task.prompt, { outputSchema, signal: AbortSignal.timeout(900_000) });
    const out = JSON.parse(turn.finalResponse);
    const testsOk = spawnSync("npm", ["test"], { cwd: task.dir }).status === 0; // trust, but verify
    results.push({ id: task.id, thread: thread.id, usage: turn.usage, out, testsOk });
  } catch (err) {
    results.push({ id: task.id, thread: thread.id, error: String(err) });
  }
}
writeFileSync("codex-results.json", JSON.stringify(results, null, 2));
process.exit(results.some((r) => r.error || r.testsOk === false) ? 1 : 0);

Keep concurrency low: each thread is a CLI process plus model calls, and parallel threads in the same checkout will overwrite each other.

Gotchas

  • Passing env replaces the whole environment. Include PATH and HOME (and CODEX_HOME if you use one) or the CLI cannot find tools or its config.
  • approvalPolicy: "on-request" in an unattended job means requests that need approval cannot be granted. Choose the sandbox that makes approvals unnecessary.
  • danger-full-access belongs only in a disposable container or VM; never on a developer laptop or shared runner with credentials.
  • thread.id is only known after the first turn starts; store it after run() or on the thread.started event.
  • The SDK inherits the user’s ~/.codex/config.toml, AGENTS.md files and MCP servers. For reproducible jobs, set CODEX_HOME to a job-specific directory with a minimal config.
  • Retired model ids fail at runtime; read the model from configuration rather than hard-coding it across scripts.
  • Do not let the agent push, merge or deploy from a pipeline; have the pipeline do those steps after verification, gated on human approval for anything irreversible.

Verification

  • A dry run on one task prints finalResponse, a non-empty items list and usage.
  • Killing a run with the abort signal leaves the job reporting a timeout, not hanging.
  • A deliberately failing task produces a recorded error and a non-zero exit while the other tasks still complete.
  • codex resume <thread id> opens a recorded thread for inspection.

What the zip contains

SKILL.md plus the interface file below. Nothing runs on install.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "Codex SDK Automation"
  short_description: "Drive Codex from TypeScript with real guardrails"
  default_prompt: "$codex-sdk-automation Write a Node script that runs Codex over these 20 repos and collects a JSON report"

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc
New

Introducing Codex Skills Pro

79 professional skills that take Codex through complete engagements, each with its own scripts, references and a report that verifies the result.

All-AccessOne-time payment, no subscription
$49
Get All-AccessOr browse individual skills from $2.99 →

Secure checkout by Creem