@jasonbelmonti/claudex
v1.0.2
Published
Provider-agnostic normalized TypeScript interface over CLI-authenticated Claude and Codex SDKs.
Downloads
199
Maintainers
Readme
claudex
claudex is a Bun-hosted TypeScript library that exposes one normalized API over the CLI-authenticated Claude and Codex SDKs, plus a passive @jasonbelmonti/claudex/ingest surface for replaying local provider artifacts.
The goal is provider-agnostic orchestration, not fake parity. The stable contract covers readiness, session lifecycle, buffered and streamed turns, structured output, and normalized event/result/error shapes. Anything that does not normalize cleanly stays capability-gated or provider-specific.
Status
- ClaudexAdapter default resolver: merged
- Claude adapter: merged
- Codex adapter: merged
- Shared contract harness: merged
- Bun-hosted CLI smoke tests: passing for Claude and Codex
- Node fallback for Codex: not needed at the moment
Docs
- Implementation record: docs/normalized-sdk-plan.md
- Verified capability matrix: docs/capability-matrix.md
- Consumer guide: docs/consumer-guide.md
- Ingest audit harness: docs/ingest-audit-harness.md
Install
bun add @jasonbelmonti/claudex@jasonbelmonti/claudex 1.0 is Bun-first. The published package ships built ESM
entrypoints for install-time and packed-artifact import checks, while Bun
remains the supported consumer runtime for this release.
Quick Start
import { ClaudexAdapter, supportsCapability } from "@jasonbelmonti/claudex";
const adapter = new ClaudexAdapter();
const readiness = await adapter.checkReadiness();
if (readiness.status !== "ready" && readiness.status !== "degraded") {
throw new Error(
`Provider is not runnable: ${readiness.provider} (${readiness.status})`,
);
}
const session = await adapter.createSession({
executionMode: "plan",
approvalMode: "deny",
});
const result = await session.run({
prompt: "Summarize the repository state.",
});
console.log(result.text);
if (supportsCapability(session.capabilities, "session:fork") && session.fork) {
const forked = await session.fork();
await forked.run({
prompt: "Take a different approach.",
});
}The stable root entrypoint intentionally exposes the provider-agnostic surface.
When you need explicit provider wiring or test doubles, pass adapters through
ClaudexAdapter's providers option.
What The Contract Guarantees
checkReadiness()returns a normalized readiness object with provider status, checks, capabilities, and raw provider diagnostics.createSession()andresumeSession()return anAgentSessionwith the samerun()andrunStreamed()surface for both providers.run()returns a normalizedTurnResult.runStreamed()yields normalizedAgentEventvalues and normally finishes with a terminal event; consumers should treat that as the common contract shape, not as a hard duplicate-suppression guarantee.- Structured output accepts one JSON Schema shape for both providers and returns parsed
structuredOutputor a typedAgentError. - Every event, result, and error preserves the originating provider and keeps raw provider payloads in
raw.extensionsmay appear on some event shapes, but they are not a universal result/error guarantee.
What Callers Still Need To Gate
Do not branch on provider name when a capability flag will do.
session:fork: Claude onlyattachment:image: Codex only in v1, and only for local file pathsstream:message-delta: Claude onlyevent:reasoning-summary: Codex only in the current normalized surfaceevent:file-change: both providers, but payload detail differsusage:cost: Claude only
See docs/capability-matrix.md for the full matrix and docs/consumer-guide.md for orchestration guidance.
Passive Ingest
@jasonbelmonti/claudex/ingest is the read-only companion surface for best-effort observation of local provider artifacts. It does not create sessions, resume sessions, or represent authoritative live control state.
Supported passive sources in the current contract:
- Claude transcript
.jsonl - Claude snapshot/task
.json - Codex transcript
.jsonl - Codex session-index
.jsonl
Outside the current ingest contract:
- other provider-native logs, temp files, or extension metadata
- live approvals, hooks, plugins, MCP state, and other control-plane behavior
- authoritative live session status
Use the live adapter surface when you need to start or resume sessions, or when terminal turn state must be authoritative. Use @jasonbelmonti/claudex/ingest when you need best-effort history backfill, watch/reconcile over local artifacts, or a read-only observability view. See docs/consumer-guide.md for examples and boundary guidance.
Development
If you're working on the repository itself:
bun installThen run the usual checks:
bun run typecheck
bun testAuthenticated local smoke tests are opt-in:
bun run test:smokeTo limit smoke to one provider:
CLAUDEX_SMOKE=1 CLAUDEX_SMOKE_PROVIDERS=codex bun test ./test/smoke/codex.smoke.tsCI Contract
Pull requests and pushes to main run the repository CI contract from
.github/workflows/ci.yml:
bun install --frozen-lockfilebun run lintbun run typecheckbun run test:coveragebun run package:check
To run the same checks locally:
bun run checkTo run the exact CI command, including LCOV coverage output in coverage/lcov.info:
bun run ciTo verify the packed artifact import surface before publish:
bun run package:check