@jxstjh/codex-app-server-sdk
v0.1.0
Published
TypeScript SDK for Codex App-Server with interactive bidirectional support
Readme
@jxstjh/codex-app-server-sdk
TypeScript SDK for Codex App-Server with full interactive support, including approval handling and bidirectional communication.
Current status: this package has moved past the prototype stage into a usable SDK skeleton with typed session APIs, lifecycle controls, errors/retry, and a growing examples system. Start with Getting Started and the examples map. The target architecture and staged implementation plan live in ARCHITECTURE.md, and runtime distribution decisions are collected in RUNTIME_PACKAGING.md.
Features
- ✅ Full JSON-RPC 2.0 support - Bidirectional communication with app-server
- ✅ Approval handling - Typed approval hooks for commands, file changes, permissions, user input, and MCP elicitation
- ✅ Type-safe - Complete TypeScript type definitions
- ✅ Event-driven - Subscribe to thread events in real-time
- ✅ Modern ESM - Native ES modules support
Installation
npm install @jxstjh/codex-app-server-sdk
# or
pnpm add @jxstjh/codex-app-server-sdk
# or
yarn add @jxstjh/codex-app-server-sdkQuick Start
Basic Usage
import { Codex } from "@jxstjh/codex-app-server-sdk";
const codex = await Codex.create({
baseUrl: process.env.CODEX_BASE_URL,
apiKey: process.env.OPENAI_API_KEY,
codexBin: process.env.CODEX_EXECUTABLE,
cwd: process.cwd(),
});
const thread = await codex.threadStart({
model: "gpt-5.4",
sandbox: "workspace-write",
approvalPolicy: "on-failure",
});
const result = await thread.run("Hello, Codex! Create a simple web app.");
console.log(result.finalAgentMessageText);
codex.close();Cloud / WebSocket Usage
import { Codex } from "@jxstjh/codex-app-server-sdk";
const codex = await Codex.create({
remoteUrl: process.env.CODEX_REMOTE_URL!,
remoteAuthToken: process.env.CODEX_REMOTE_AUTH_TOKEN!,
});Cloud config connects to an already-running app-server and does not accept local launch fields such as codexBin, launchArgs, baseUrl, configOverrides, cwd, or env.
Typed Approval Hooks
import { Codex } from "@jxstjh/codex-app-server-sdk";
import type { ApprovalHooks } from "@jxstjh/codex-app-server-sdk";
const approvalHooks: ApprovalHooks = {
onCommandApproval: async (params) => {
if ((params.command ?? "").startsWith("rg ")) {
return { decision: "accept" };
}
return { decision: "decline" };
},
onFileChangeApproval: async () => ({ decision: "accept" }),
onUserInputRequest: async () => ({ answers: {} }),
onUnknownRequest: async () => ({}),
};
const codex = await Codex.create({}, approvalHooks);For low-level compatibility, the older raw ApprovalHandler shape is still supported, but typed hooks are the recommended public surface.
More docs:
Event Handling
import { Codex } from "@jxstjh/codex-app-server-sdk";
const codex = await Codex.create();
const thread = await codex.threadStart();
// Subscribe to events
thread.onEvent((event) => {
switch (event.method) {
case "turn/started":
console.log("Turn started:", event.threadId);
break;
case "turn/completed":
console.log("Turn completed:", event.threadId);
break;
case "item/completed":
console.log("Item completed:", event.data);
break;
}
});
await thread.run("List all files in the current directory");API Reference
Codex
Main entry point for the SDK.
Constructor / Factory
new Codex(config?: AppServerConfig, approval?: ApprovalProvider)
Codex.create(config?: AppServerConfig, approval?: ApprovalProvider)Parameters:
config- App-Server configurationtransport-stdiofor a local app-server process orwebsocketfor a remote app-server;remoteUrlimplies websocketremoteUrl- Remote app-server websocket endpoint;host:port,ws://..., andwss://...are acceptedremoteAuthToken- Bearer token for the websocket handshakecodexBin- Local-only custom path to thecodexbinary; highest-priority runtime override for local Rust buildsbaseUrl- Local-only OpenAI-compatible Responses API base URL passed to the launched app-serverapiKey- API key used foraccount/login/startcwd- Local-only working directory for the app-server processenv- Local-only extra environment variables for the app-server process
approval- TypedApprovalHooksor the low-level legacyApprovalHandler
Methods
threadStart(params)- Create a new thread- Main place to set thread/session defaults such as
model,sandbox, andapprovalPolicy
- Main place to set thread/session defaults such as
threadResume(threadId, params)- Resume an existing threadthreadFork(threadId, params)- Fork an existing threadthreadList(params)- List threadsmodels(includeHidden?)- List visible modelsfsRemove({ path, recursive, force })- Remove a file or directory tree throughfs/removeprojectDelete({ dirPath })- Remove a project directory throughfs/removegetClient()- Get underlying JSON-RPC clientclose()- Close connection to app-server
projectDelete uses fsRemove({ path: dirPath, recursive: true, force: true }). The app-server
protocol does not provide a project/delete RPC; Gateway project record deletion remains the
responsibility of the application layer.
Thread
Represents a conversation session.
Methods
submit(input)- Submit a user messageturn(input, options)- Start a turn and get aTurnHandlerun(input, options)- Run a turn to completionread(includeTurns?)- Refresh thread metadatalistTurns(params?)- Experimental historical turn pagination viathread/turns/list; intended for persisted history loading, not live runtime projectionsetName(name)- Set thread namearchive()/unarchive()- Archive lifecyclecompact()- Start thread compactiononEvent(handler)- Subscribe to eventsoffEvent(handler)- Unsubscribe from events
Samples
The package now includes a small set of validation-oriented samples under samples:
samples/basic_client.ts- low-levelJsonRpcClienthandshake and rawthread/startvalidationsamples/basic_thread.ts- dev-heavy validation for initialize,threadStart(),turn()streaming, and aggregated run outputsamples/approval_handler.ts- validate typed approval hooks and command/file/user-input wiring
By default the samples look for the local debug Codex binary at ../../codex-rs/target/debug/codex.
You can override it with CODEX_EXECUTABLE=/absolute/path/to/codex.
Runtime resolution priority is config.codexBin -> CODEX_EXECUTABLE -> bundled runtime -> PATH codex.
pnpm sample:client
pnpm sample:thread
pnpm sample:approvalExamples
The package also includes Python-style examples under examples:
examples/01_quickstart.tsexamples/02_turn_run.tsexamples/03_turn_stream_events.tsexamples/04_models_and_metadata.tsexamples/05_existing_thread.tsexamples/06_thread_controls.tsexamples/07_image_and_text.tsexamples/08_local_image_and_text.tsexamples/09_async_parity.tsexamples/10_error_handling_and_retry.tsexamples/11_cli_mini_app.tsexamples/12_turn_params_kitchen_sink.tsexamples/13_model_select_and_turn_params.tsexamples/14_turn_controls.tsexamples/15_cloud_initialize.tsexamples/16_cloud_project_list.tsexamples/17_cloud_turn_run.tsexamples/18_cloud_turn_stream_events.ts
Run them with:
pnpm example:01
pnpm example:02
pnpm example:03
pnpm example:04
pnpm example:05
pnpm example:06
pnpm example:07
pnpm example:08
pnpm example:09
pnpm example:10
pnpm example:11
pnpm example:12
pnpm example:13
pnpm example:14
pnpm example:15
pnpm example:16
pnpm example:17
pnpm example:1809_async_parity intentionally documents that the TypeScript SDK already uses the async-style public surface by default, so there is no separate AsyncCodex class.
Architecture
This SDK differs from the official @openai/codex-sdk in key ways:
| Feature | Official SDK | App-Server SDK |
| ---------------- | -------------------- | ------------------- |
| Mode | codex exec | codex app-server |
| Communication | Unidirectional | Bidirectional |
| Approval Support | ❌ Not supported | ✅ Full support |
| User Input | ❌ Not supported | ✅ Supported |
| Protocol | JSONL (stdin/stdout) | JSON-RPC 2.0 |
Development
# Install dependencies
pnpm install
# Build
pnpm build
# Watch mode
pnpm build:watch
# Run tests
pnpm test
# Lint
pnpm lint
# Format
pnpm format:fixLicense
MIT
