Build an orchestrator once, run it anywhere. This SDK gives you a single runtime/session API that works across providers, so you can swap Claude or Codex at the composition root without rewriting your orchestration logic.
If you’ve ever thought “I want a single agent layer that won’t lock me into one provider,” this is for you.
- One interface, many providers:
UnifiedAgentRuntime+UnifiedSessioncover run lifecycle, streaming events, and structured output. - Portable config: workspace, model, access, reasoning effort, output schema, cancellation.
- Predictable event stream: every provider maps into the same
RuntimeEventshape.
This is the boring, reliable core you can build real orchestrators on.
[Your App / Orchestrator]
|
v
UnifiedAgentRuntime
|
+-------+-----------------+--------------------+
| | |
v v v
Claude Adapter Codex Adapter (Planned) OpenCode
(Planned) Gemini CLI
(Replace with an image path later, e.g. docs/assets/diagram.png.)
Install the runtime:
npm install @unified-agent-sdk/runtimeThen:
import { createRuntime, SessionBusyError } from "@unified-agent-sdk/runtime";
const runtime = createRuntime({
provider: "@openai/codex-sdk", // or "@anthropic-ai/claude-agent-sdk"
home: null, // inherit ~/.codex or ~/.claude (unless env overrides it)
defaultOpts: { model: "gpt-5" },
});
const session = await runtime.openSession({
config: {
workspace: { cwd: process.cwd() },
reasoningEffort: "medium",
access: { auto: "medium" },
},
});
try {
const run = await session.run({
input: { parts: [{ type: "text", text: "Return JSON: {\"ok\": true}." }] },
config: { outputSchema: { type: "object", additionalProperties: true } },
});
for await (const ev of run.events) {
if (ev.type === "assistant.delta") process.stdout.write(ev.textDelta);
if (ev.type === "run.completed") console.log("\n", ev.status, ev.structuredOutput);
}
} catch (e) {
if (e instanceof SessionBusyError) console.error("Session busy:", e.activeRunId);
else throw e;
} finally {
await session.dispose();
await runtime.close();
}uagent is a tiny CLI that lets you test the runtime with real providers.
Install:
npm install -g @unified-agent-sdk/uagentOne‑shot exec:
mkdir -p .cache/uagent/codex
uagent codex exec \
--home .cache/uagent/codex \
--workspace . \
"List the files in the workspace."Interactive mode:
mkdir -p .cache/uagent/claude
uagent claude \
--home .cache/uagent/claude \
--workspace .Verbose exec (shows tools + reasoning blocks):
mkdir -p .cache/uagent/codex
uagent codex exec \
--home .cache/uagent/codex \
--workspace . \
--verbose \
"List the files in the workspace."| Config | Where | What it does |
|---|---|---|
workspace |
openSession({ config }) |
Filesystem scope for the session |
model |
openSession({ config }) |
Provider model id |
reasoningEffort |
openSession({ config }) |
Portable thinking budget |
access |
openSession({ config }) |
Portable permission surface |
outputSchema |
run({ config }) |
Structured output (JSON Schema) |
signal |
run({ config }) |
Cancellation |
Access is unified across providers. You control it with access.auto.
Presets:
access.auto |
Meaning |
|---|---|
low |
Read‑only (no edits). WebSearch is available when supported; shell networking (e.g. curl) is intentionally conservative. |
medium |
Workspace-write sandbox, with WebSearch + network (including localhost). |
high |
Unrestricted (use with care). |
Control how much “thinking” the model uses:
none · low · medium · high · xhigh
Example:
const session = await runtime.openSession({
config: { reasoningEffort: "low" },
});Models are provider‑specific but configured the same way:
const session = await runtime.openSession({
config: { model: "gpt-5.2" },
});- Claude (
@anthropic-ai/claude-agent-sdk) - Codex (
@openai/codex-sdk)
Both map into the same runtime and event model.
Planned: OpenCode, Gemini CLI
docs/guides/config.md— full config referencedocs/specs/permission.md— access mapping detailsdocs/guides/orchestrator.md— orchestration patternsdocs/specs/testing.md— smoke/integration tests
What does --home mean?
--home points to the provider’s config directory. It lets you keep per‑profile settings
and auth separate (for example, .profiles/codex/yescode or .profiles/claude/yescode).
If omitted, the provider uses its default location (e.g. ~/.codex or ~/.claude). The
directory must already exist; uagent will not create it.