npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@codex-native/sdk

v0.0.38

Published

Native NAPI-based Codex SDK - complete standalone implementation.

Downloads

112

Readme

Codex Native SDK

Embed the Codex agent in your Node.js workflows and apps with native performance.

The Native SDK provides Rust-powered bindings via napi-rs, giving you direct access to Codex functionality without spawning child processes. This enables custom tool registration, agent orchestration, and native performance optimizations.

Installation

npm install @codex-native/sdk

Requires Node.js 18+.

API Compatibility

The Native SDK provides full API compatibility with the TypeScript SDK. All core functionality—threads, streaming, structured output, and basic operations—works identically across both SDKs. The Native SDK adds Rust-powered performance and custom tool registration while maintaining the same interface.

Migration from TypeScript SDK

Simply replace the import:

// Before (TypeScript SDK)
import { Codex } from "@openai/codex-sdk";

// After (Native SDK - same API!)
import { Codex } from "@codex-native/sdk";

All your existing code continues to work without changes.

Quickstart

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

const codex = new Codex();
const thread = codex.startThread();
const turn = await thread.run("Diagnose the test failure and propose a fix");

console.log(turn.finalResponse);
console.log(turn.items);

Call run() repeatedly on the same Thread instance to continue that conversation.

const nextTurn = await thread.run("Implement the fix");

Streaming responses

run() buffers events until the turn finishes. To react to intermediate progress—tool calls, streaming responses, and file diffs—use runStreamed() instead, which returns an async generator of structured events.

const { events } = await thread.runStreamed("Diagnose the test failure and propose a fix");

for await (const event of events) {
  switch (event.type) {
    case "item.completed":
      console.log("item", event.item);
      break;
    case "turn.completed":
      console.log("usage", event.usage);
      break;
  }
}

Mid-turn notifications

You can publish lightweight updates during an active turn without adding another user message. Call thread.sendBackgroundEvent() inside a runStreamed() loop after the turn has started:

const { events } = await thread.runStreamed("Generate the release notes");

for await (const event of events) {
  if (event.type === "turn.started") {
    await thread.sendBackgroundEvent("Gathering changelog entries…");
  } else if (event.type === "background_event") {
    console.log(event.message);
  }
}

The streaming API surfaces these as background_event items so downstream consumers can display progress indicators or status notifications while the agent continues its turn.

Structured output

The Codex agent can produce a JSON response that conforms to a specified schema. The schema can be provided for each turn as a plain JSON object.

const schema = {
  type: "object",
  properties: {
    summary: { type: "string" },
    status: { type: "string", enum: ["ok", "action_required"] },
  },
  required: ["summary", "status"],
  additionalProperties: false,
} as const;

const turn = await thread.run("Summarize repository status", { outputSchema: schema });
console.log(turn.finalResponse);

You can also create a JSON schema from a Zod schema using the zod-to-json-schema package and setting the target to "openAi".

const schema = z.object({
  summary: z.string(),
  status: z.enum(["ok", "action_required"]),
});

const turn = await thread.run("Summarize repository status", {
  outputSchema: zodToJsonSchema(schema, { target: "openAi" }),
});
console.log(turn.finalResponse);

Command-line interface

In addition to the programmatic API, the package ships a codex-native CLI that mirrors the Rust codex binary. The CLI is available after pnpm install (or via npx codex-native).

# Run a one-off Codex turn using the native SDK
codex-native run "Diagnose the failing integration test"

# Launch the full-screen TUI backed by the native bindings
codex-native tui

Configuration discovery

codex-native automatically merges configuration from the following locations (in priority order):

  1. The CLI flags supplied on the command line
  2. A codex.config.* file in the working directory (.js, .cjs, .mjs, .ts)
  3. A codexNative field in package.json

Configuration files can export either an object or a function. The function form receives a context { cwd, configPath } so you can derive settings dynamically.

// codex.config.ts
import type { CodexNativeConfig } from "@codex-native/sdk/cli";

const config: CodexNativeConfig = {
  defaults: {
    run: { model: "gpt-5-codex" },
    tui: { resumePicker: false },
  },
  tools: [
    {
      name: "read_me",
      description: "Show the project README",
      handler: async () => ({ output: await fs.promises.readFile("README.md", "utf8") }),
    },
  ],
  interceptors: [
    {
      toolName: "shell",
      handler: async ({ invocation, callBuiltin }) => {
        console.log("shell call", invocation);
        return callBuiltin();
      },
    },
  ],
};

export default config;

Multiple --plugin flags can be passed to load additional modules. A plugin may export either a config object or a function that returns one. Plugin configs are merged on top of the base config.

Hooks and approvals

Config files can specify hooks that run before every turn (beforeStart) and when streaming events (onEvent). You can also register an approvals callback to gate sensitive tool usage. These map directly to the native bindings so the same logic applies in both CLI and SDK usage.

TUI mode

codex-native tui launches the same Ratatui-based interface used by the Rust codex tool. The CLI honors the same configuration sources listed above, so you can keep CLI, SDK, and TUI settings in a single codex.config.ts file.

Attaching images

Provide structured input entries when you need to include images alongside text. Text entries are concatenated into the final prompt while image entries are passed to Codex via the native bridge.

const turn = await thread.run([
  { type: "text", text: "Describe these screenshots" },
  { type: "local_image", path: "./ui.png" },
  { type: "local_image", path: "./diagram.jpg" },
]);

Skills (programmatic)

Register skills directly in JS (no SKILL.md files required) and reference them in prompts.

By default, skills activate when mentioned as $<name> (matching the Codex CLI/TUI). You can also enable @<name> mentions via skillMentionTriggers.

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

const codex = new Codex({
  skills: {
    "db expert": "Answer as a database expert. Be concise and include SQL when helpful.",
  },
  skillMentionTriggers: ["$", "@"],
});

const thread = codex.startThread({ skipGitRepoCheck: true });
await thread.run("Use $db expert to explain this query plan.");

Resuming an existing thread

Threads are persisted in ~/.codex/sessions. If you lose the in-memory Thread object, reconstruct it with resumeThread() and keep going.

const savedThreadId = process.env.CODEX_THREAD_ID!;
const thread = codex.resumeThread(savedThreadId);
await thread.run("Implement the fix");

Forking a conversation

Use thread.fork() to branch from an earlier user message and explore an alternate path without losing the original history. Provide the zero-based index of the user message you want to fork before.

const codex = new Codex();
const thread = codex.startThread({ skipGitRepoCheck: true });

await thread.run("List flaky integration tests");
await thread.run("Propose fixes for each flaky test");

// Fork before the second user message (index 1)
const branch = await thread.fork({
  nthUserMessage: 1,
  threadOptions: { model: "gpt-5-codex-mini" },
});

await branch.run("Focus on the payment suite instead");

The original thread continues unchanged while branch contains the forked history and a fresh thread id.

Running code reviews

Invoke the native review workflow without crafting prompts manually. The SDK provides presets that mirror the /review slash command:

const codex = new Codex();

// Review everything that is staged, unstaged, or untracked
const review = await codex.review({
  target: { type: "current_changes" },
});

for (const finding of review.items) {
  if (finding.type === "agent_message") {
    console.log(finding.text);
  }
}

Additional presets let you review against another branch or a specific commit:

await codex.review({
  target: { type: "branch", baseBranch: "main" },
});

await codex.review({
  target: {
    type: "commit",
    sha: "abc1234def5678",
    subject: "Tighten input validation",
  },
});

For bespoke instructions, pass a custom prompt and optional hint:

await codex.review({
  target: {
    type: "custom",
    prompt: "Review only the data-access layer for regression risks.",
    hint: "data-access layer",
  },
});

Working directory controls

Codex runs in the current working directory by default. To avoid unrecoverable errors, Codex requires the working directory to be a Git repository. You can skip the Git repository check by passing the skipGitRepoCheck option when creating a thread.

const thread = codex.startThread({
  workingDirectory: "/path/to/project",
  skipGitRepoCheck: true,
});

Native-Specific Features

The Native SDK provides additional capabilities beyond the TypeScript SDK:

Custom Tool Registration

Register JavaScript functions as tools that Codex can discover and invoke during execution. Tools are registered globally on the Codex instance and become available to all threads and agents.

Override built-ins: If you register a tool whose name matches one of Codex's built-in tools (for example read_file, local_shell, or apply_patch), the native implementation is replaced for the lifetime of that Codex instance. This lets you customize or disable default behaviors while keeping the same tool interface.

Built-in tool override cheat sheet

All snippets assume you already created an instance with const codex = new Codex();. Registering any of these names swaps out Codex's default implementation.

  • shell – sandboxed shell command runner (models without unified exec)

    codex.registerTool({
      name: "shell",
      handler: () => ({ error: "Shell disabled by policy", success: false }),
    });
  • exec_command – streaming command execution (available when unified exec is enabled)

    codex.registerTool({
      name: "exec_command",
      handler: (_, invocation) => ({
        output: `Pretend ran: ${invocation.arguments}`,
        success: true,
      }),
    });
  • write_stdin – feeds additional input into an in-flight exec_command

    codex.registerTool({
      name: "write_stdin",
      handler: () => ({ output: "stdin blocked", success: false }),
    });
  • local_shell – simplified shell command helper (models that prefer local shell over unified exec)

    codex.registerTool({
      name: "local_shell",
      handler: () => ({ output: "local shell override", success: true }),
    });
  • list_mcp_resources, list_mcp_resource_templates, read_mcp_resource – MCP discovery helpers

    for (const name of [
      "list_mcp_resources",
      "list_mcp_resource_templates",
      "read_mcp_resource",
    ]) {
      codex.registerTool({
        name,
        handler: () => ({ output: JSON.stringify({ notice: `${name} overridden` }) }),
      });
    }
  • update_plan – emits high-level plan updates back to the host UI

    codex.registerTool({
      name: "update_plan",
      handler: () => ({ output: "Plan updates disabled" }),
    });
  • apply_patch – applies patches authored by the agent

    codex.registerTool({
      name: "apply_patch",
      handler: (_, { arguments }) => ({
        output: `Custom patch handler received: ${arguments}`,
        success: true,
      }),
    });
  • web_search – performs outbound web searches (only on models with the feature enabled)

    codex.registerTool({
      name: "web_search",
      handler: (_, { arguments }) => ({
        output: `Search stub: ${arguments}`,
        success: true,
      }),
    });
  • view_image – attaches a local image for the model to inspect

    codex.registerTool({
      name: "view_image",
      handler: (_, { arguments }) => ({
        output: `Ignoring image path ${arguments}`,
        success: true,
      }),
    });
  • grep_files, read_file, list_dir – workspace inspection helpers (enabled via experimental flags)

    for (const name of ["grep_files", "read_file", "list_dir"]) {
      codex.registerTool({
        name,
        handler: (_, { arguments }) => ({
          output: JSON.stringify({ name, arguments, overridden: true }),
          success: true,
        }),
      });
    }
  • test_sync_tool – synchronization helper used in concurrency tests

    codex.registerTool({
      name: "test_sync_tool",
      handler: () => ({ output: "Barrier skipped" }),
    });
  • MCP server tools – any name of the form server::tool

    codex.registerTool({
      name: "jira::create_issue",
      handler: (_, { arguments }) => ({
        output: `Custom Jira integration received ${arguments}`,
        success: true,
      }),
    });
const codex = new Codex();

codex.registerTool({
  name: "calculator",
  description: "Performs arithmetic operations",
  parameters: {
    type: "object",
    properties: {
      operation: { type: "string", enum: ["add", "subtract", "multiply", "divide"] },
      a: { type: "number" },
      b: { type: "number" },
    },
    required: ["operation", "a", "b"],
  },
  handler: (err, invocation) => {
    if (err) {
      return { error: err.message };
    }

    const { operation, a, b } = JSON.parse(invocation.arguments);
    let result: number;

    switch (operation) {
      case "add": result = a + b; break;
      case "subtract": result = a - b; break;
      case "multiply": result = a * b; break;
      case "divide": result = a / b; break;
    }

    return {
      output: `Result: ${result}`,
      success: true
    };
  },
});

const thread = codex.startThread();
await thread.run("Calculate 42 times 17");

Tool Handler Signature:

Handlers use Node.js error-first callback convention:

  • err: Error object if invocation failed, null otherwise
  • invocation: Object containing:
    • callId: Unique identifier for this tool call
    • toolName: Name of the tool being invoked
    • arguments: JSON string of the tool arguments (if parameters provided)
    • input: JSON string of the tool input (for custom tools)

Return Value:

Return an object with:

  • output: String output to send back to the model
  • success (optional): Boolean indicating success/failure
  • error (optional): Error message if the tool execution failed

Tool Interceptors

For more advanced use cases, register tool interceptors that can wrap built-in Codex tools with pre/post-processing logic while still executing the original implementation.

const codex = new Codex();

// Intercept exec_command calls to add custom timeout and logging
codex.registerToolInterceptor("exec_command", async (invocation) => {
  // Pre-processing: modify the arguments
  const args = JSON.parse(invocation.arguments ?? "{}");
  const enhancedArgs = {
    ...args,
    timeout_ms: args.timeout_ms ?? 10000, // Default 10s timeout
    justification: args.justification ?? "intercepted",
  };

  // For now, interceptors return a placeholder response
  // Future versions will support calling the builtin implementation
  return {
    output: `[INTERCEPTED] Would execute: ${JSON.stringify(enhancedArgs)}`,
    success: true,
  };
});

// Intercept apply_patch to add validation
codex.registerToolInterceptor("apply_patch", async (invocation) => {
  const args = JSON.parse(invocation.arguments ?? "{}");

  // Add custom validation or preprocessing
  if (!args.patch_content?.includes("diff")) {
    return {
      output: "Invalid patch format - must contain diff data",
      success: false,
    };
  }

  // Return modified result
  return {
    output: `[VALIDATED] ${args.patch_content}`,
    success: true,
  };
});

Key Differences from Tool Overrides:

  • Interceptors wrap built-in tools instead of replacing them entirely
  • Preserve sandboxing - interceptors cannot bypass Codex's security policies
  • Chainable - multiple interceptors can be registered for the same tool
  • Future enhancement - interceptors will be able to call the underlying builtin implementation

Current Notes:

  • Tool interceptors support decorating responses by calling context.callBuiltin()
  • Multiple interceptors per tool will be composed in registration order in a future release

Agent Orchestration

Create specialized agents with custom system prompts and tools for multi-agent workflows.

const codex = new Codex();

// Register tools available to agents
codex.registerTool({
  name: "search_codebase",
  description: "Search the codebase for specific patterns",
  parameters: { /* ... */ },
  handler: (err, inv) => {
    // Search implementation
    return { output: "Found 5 matches", success: true };
  },
});

// Create a specialized agent
const reviewAgent = codex.createAgent({
  name: "code_reviewer",
  instructions: "You are a senior code reviewer. Focus on security, performance, and maintainability.",
});

const result = await reviewAgent.run("Review the authentication module");
console.log(result.finalResponse);

Agent Handoffs

Agents can hand off tasks to other agents for specialized processing.

const codex = new Codex();

const testAgent = codex.createAgent({
  name: "test_writer",
  instructions: "You write comprehensive unit tests with high coverage.",
});

const securityAgent = codex.createAgent({
  name: "security_auditor",
  instructions: "You perform security audits and identify vulnerabilities.",
});

// Start with test agent
const testResult = await testAgent.run("Write tests for the auth module");

// Hand off to security agent
const securityResult = await securityAgent.run(
  "Review the tests from the previous agent and add security-focused test cases"
);

Agents automatically have access to the conversation history, enabling seamless handoffs between specialized agents.

Reverie Archive APIs

Query past Codex sessions directly from Node.js to surface relevant prior work without leaving the terminal.

import {
  reverieListConversations,
  reverieSearchConversations,
  reverieGetConversationInsights,
} from "@codex-native/sdk";

const codexHome = process.env.CODEX_HOME ?? `${process.env.HOME}/.codex`;

// List the newest conversations (newest first)
const conversations = await reverieListConversations(codexHome, 10);

// Search for conversations mentioning "authentication"
const matches = await reverieSearchConversations(codexHome, "authentication issue", 5);

// Read the highlights/insights from a specific conversation rollout
const insights = await reverieGetConversationInsights(matches[0].conversation.path, "JWT");

Results include headRecords and tailRecords, plus the TOON-encoded headRecordsToon and tailRecordsToon previews used by the Rust CLI/TUI, so you can plug them into custom dashboards or route them back into an agent as <system notification>s without wasting tokens.

Need to compact your own JSON payloads before feeding them to an LLM? Call encodeToToon(value) from JavaScript to get the same Token-Oriented Object Notation that Codex now uses for reverie search/indexing.

Tokenizer Helpers (tiktoken)

Access the same tiktoken-powered tokenizer used by Codex from JavaScript for budgeting prompts or implementing local ranking logic.

import {
  tokenizerCount,
  tokenizerEncode,
  tokenizerDecode,
} from "@codex-native/sdk";

const text = "hello world";

// Count tokens using a specific encoding or model alias
const tokens = tokenizerEncode(text, { encoding: "cl100k_base" });
const count = tokenizerCount(text, { encoding: "cl100k_base" });

// Round-trip
const decoded = tokenizerDecode(tokens, { encoding: "cl100k_base" });

encoding accepts "o200k_base" or "cl100k_base", and you can also pass model: "gpt-5" to mirror Codex’s model-to-encoding mapping. Set withSpecialTokens: true when you need precise accounting for schema-guided prompts.

API Options

Codex Constructor Options

interface CodexOptions {
  apiKey?: string;              // Responses API key (defaults to OPENAI_API_KEY env var)
  baseUrl?: string;             // API base URL override
  skipGitRepoCheck?: boolean;   // Skip Git repository validation
}

Thread Options

interface ThreadOptions {
  model?: string;               // Model to use (e.g., "gpt-5-codex")
  sandboxMode?: "read-only" | "workspace-write" | "danger-full-access";
  approvalMode?: "never" | "on-request" | "on-failure" | "untrusted";
  workspaceWriteOptions?: {
    networkAccess?: boolean;    // Enable network in workspace-write mode (default: false)
    writableRoots?: string[];   // Additional writable directories
    excludeTmpdirEnvVar?: boolean; // Exclude TMPDIR from writable roots
    excludeSlashTmp?: boolean;  // Exclude /tmp from writable roots (Unix only)
  };
  workingDirectory?: string;    // Directory to run Codex in
  skipGitRepoCheck?: boolean;   // Skip Git repository validation
  fullAuto?: boolean;           // @deprecated Use sandboxMode and approvalMode
}

Sandbox Modes

  • read-only: AI can only read files, must approve all edits
  • workspace-write: AI can edit workspace files freely (with optional network)
  • danger-full-access: No sandbox (dangerous!)

Approval Policies

  • never: Never ask for approval (commands execute automatically)
  • on-request: Model decides when to ask (default)
  • on-failure: Auto-approve but escalate on failure
  • untrusted: Only trusted commands auto-approved

Network Access Configuration

Enable network access in workspace-write mode:

const thread = codex.startThread({
  sandboxMode: "workspace-write",
  workspaceWriteOptions: {
    networkAccess: true
  }
});

Advanced Sandbox Configuration

Configure additional writable directories:

const thread = codex.startThread({
  sandboxMode: "workspace-write",
  workspaceWriteOptions: {
    writableRoots: ["/path/to/additional/dir"],
    excludeTmpdirEnvVar: false,
    excludeSlashTmp: false
  }
});

Turn Options

interface TurnOptions {
  outputSchema?: JsonValue;     // JSON schema for structured output
}

Tool Registration Options

interface ToolRegistration {
  name: string;                 // Tool name (used by model to invoke)
  description?: string;         // Description of what the tool does
  parameters?: JsonValue;       // JSON Schema for tool parameters
  strict?: boolean;             // Enable strict schema validation
  supportsParallel?: boolean;   // Whether tool supports parallel execution
  handler: (err: Error | null, invocation: ToolInvocation) => ToolResponse;
}

Architecture

The Native SDK uses napi-rs to bridge JavaScript and Rust:

  • Native Bindings: Direct Rust FFI via NAPI for zero-copy performance
  • Tool Registration: JavaScript functions are stored as ThreadsafeFunction callbacks
  • Event Streaming: Async generators powered by Tokio runtime
  • Session Management: Native threads and agents run in the Rust codex-core

Platform-specific binaries are automatically selected at runtime:

  • macOS: codex_native.darwin-{arm64,x64}.node
  • Windows: codex_native.win32-{x64,arm64,ia32}-msvc.node
  • Linux: codex_native.linux-{x64,arm64}-{gnu,musl}.node

Development

Build from source:

pnpm install
pnpm --filter @codex-native/sdk run build

Run tests:

pnpm --filter @codex-native/sdk test

The build emits:

  • Platform-specific .node binaries under npm/<platform>/
  • TypeScript declarations in dist/index.d.ts
  • ESM wrapper in dist/index.mjs

Publishing

The Native SDK uses napi-rs's multi-platform publishing strategy with automated release scripts.

Release Scripts

# Patch release (0.0.x)
pnpm run release:patch

# Minor release (0.x.0)
pnpm run release:minor

# Major release (x.0.0)
pnpm run release:major

# Dry run (test without publishing)
pnpm run release:dry

What Happens During Release

  1. Version bump: Updates version in package.json
  2. Build: Compiles native binary into npm/<platform> + TypeScript wrapper
  3. Test: Runs the JS test suite
  4. Prepublish: napi prepublish -t npm --skip-gh-release updates optionalDependencies and publishes any platform packages whose binaries are present under npm/
  5. Publish: npm publish --access public publishes @codex-native/sdk

Multi-Platform CI/CD

For full cross-platform support, build on CI for all 8 targets:

# .github/workflows/release.yml
strategy:
  matrix:
    settings:
      - host: macos-latest
        target: aarch64-apple-darwin
      - host: macos-latest
        target: x86_64-apple-darwin
      - host: ubuntu-latest
        target: x86_64-unknown-linux-gnu
      - host: ubuntu-latest
        target: aarch64-unknown-linux-gnu
      # ... other platforms

After building all platforms:

pnpm run artifacts  # Download and organize binaries into npm/<platform>
pnpm run release    # Publish platform packages + main SDK

npm automatically installs the correct platform package as an optional dependency.

Releasing

  1. Update the version in package.json and record changes in CHANGELOG.md.
  2. Regenerate build artifacts: pnpm run build.
  3. Run the test suite: pnpm run test.
  4. Run pnpm run release (runs napi prepublish + npm publish).
  5. Tag the release in git.

License

See LICENSE