@raylin01/codex-client
v0.2.3
Published
Node.js client for controlling Codex CLI app-server over JSON-RPC.
Maintainers
Readme
@raylin01/codex-client
Node.js client for controlling Codex CLI app-server over JSON-RPC, with both the raw transport API and a structured thread/turn wrapper.
Install
npm install @raylin01/codex-clientRequirements
- Node.js 18+
- Codex CLI available on your PATH (or pass
codexPath)
Quickstart
import { CodexClient } from '@raylin01/codex-client';
const client = await CodexClient.init({
cwd: process.cwd(),
approvalPolicy: 'on-request'
});
const turn = client.send('Summarize this repository and mention the riskiest area.');
for await (const update of turn.updates()) {
if (update.kind === 'output' && update.snapshot.currentOutputKind === 'text') {
process.stdout.write(update.snapshot.text);
}
if (update.kind === 'request') {
console.log('\nRequest:', update.snapshot.currentMessage.content);
}
}
await turn.done;
await client.close();Structured API
CodexClient.init(options)starts the app-server and initializes or resumes a threadclient.send(input, options?)returns a turn handle immediatelyturn.current(),turn.history(),turn.updates(), andturn.doneexpose normalized turn stateclient.getOpenRequests()returns pending approvals, questions, and tool callsclient.getOpenRequest(id)returns one pending request by idclient.approveRequest(...),client.answerQuestion(...), andclient.respondToToolCall(...)respond to Codex RPC requests without handling raw JSON-RPC directlyclient.createQuestionSession(id)incrementally collects multi-question answers beforesubmit()
For approvals, the structured helper now only exposes Codex capabilities that actually exist in the app-server protocol:
scope: 'once' | 'session'for plain allow decisionsexecPolicyAmendmentfor command approvals that should returnacceptWithExecpolicyAmendment
const [request] = client.getOpenRequests();
if (request?.kind === 'question') {
const session = client.createQuestionSession(request.id);
session.setCurrentAnswer('A');
session.next();
session.setCurrentAnswer(['B', 'C']);
await session.submit();
}Session Browser Examples
Codex thread history is available through the read-only helpers in the sessions subpath.
import { CodexClient } from '@raylin01/codex-client';
import {
listCodexSessionSummaries,
readCodexSessionRecord
} from '@raylin01/codex-client/sessions';
const client = new CodexClient({ cwd: process.cwd() });
await client.start();
const summaries = await listCodexSessionSummaries(client, { limit: 10 });
const latest = summaries[0];
if (latest) {
const record = await readCodexSessionRecord(client, latest.id);
console.log('Thread:', record.summary.id);
console.log('Transcript blocks:', record.transcript.length);
console.log('Raw messages:', record.rawMessages.length);
}
await client.shutdown();record.transcript normalizes prior Codex history, while record.rawSession and record.rawMessages keep the original thread data.
Raw Transport API
If you need direct JSON-RPC control, the original new CodexClient(...) API is unchanged.
Event Model
ready: initialize handshake completerequest: incoming JSON-RPC server request requiring a responsenotification: incoming JSON-RPC notificationlog: stderr output from app-servererror: protocol/process errors
API
new CodexClient(options)
cwd,codexPath,args,envanalyticsDefaultEnabledclientInfoandcapabilities
await CodexClient.init(options)
- returns a
StructuredCodexClient - accepts thread bootstrap options like
resumeThreadId,forkThread,approvalPolicy,sandbox, and instructions - keeps the raw client available at
client.raw
Core methods
start()andshutdown()sendRequest(method, params)sendResponse(id, result)sendError(id, error)
Convenience wrappers
- Threads:
startThread,resumeThread,forkThread,listThreads,readThread, ... - Models:
listModels,setDefaultModel - Config:
readConfig,writeConfigValue,batchWriteConfig - Turns:
startTurn,interruptTurn
Examples
See /examples:
basic.tsevents.tserror-handling.ts
Troubleshooting
- If startup fails, verify
codex app-serverruns from your shell. - Listen for
loganderrorevents to debug handshake failures.
Versioning
This package uses independent semver releases.
Used by DisCode
DisCode uses this package as a real-world integration example:
License
ISC
