SDK
The SDK is the in-process integration surface for @oh-my-pi/pi-coding-agent. Use it when you want direct access to agent state, event streaming, tool wiring, and session control from your own Bun/Node process.
If you need cross-language/process isolation, use RPC mode instead.
Installation
bun add @oh-my-pi/pi-coding-agentEntry points
@oh-my-pi/pi-coding-agent exports the SDK APIs from the package root (and also via @oh-my-pi/pi-coding-agent/sdk).
Core exports for embedders:
createAgentSessionSessionManagerSettingsAuthStorageModelRegistrydiscoverAuthStorage- Discovery helpers (
discoverExtensions,discoverSkills,discoverContextFiles,discoverPromptTemplates,discoverSlashCommands,discoverCustomTSCommands,discoverMCPServers) - Tool factory surface (
createTools,BUILTIN_TOOLS, tool classes)
Quick start (auto-discovery defaults)
import { createAgentSession } from "@oh-my-pi/pi-coding-agent";
const { session, modelFallbackMessage } = await createAgentSession();
if (modelFallbackMessage) {
process.stderr.write(`${modelFallbackMessage}\n`);
}
const unsubscribe = session.subscribe(event => {
if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
process.stdout.write(event.assistantMessageEvent.delta);
}
});
await session.prompt("Summarize this repository in 3 bullets.");
unsubscribe();
await session.dispose();What createAgentSession() discovers by default
createAgentSession() follows “provide to override, omit to discover”.
If omitted, it resolves:
cwd:getProjectDir()agentDir:~/.pisces/agent(viagetAgentDir())authStorage:discoverAuthStorage(agentDir)modelRegistry:new ModelRegistry(authStorage)+await refresh()settings:await Settings.init({ cwd, agentDir })sessionManager:SessionManager.create(cwd)(file-backed)- skills/context files/prompt templates/slash commands/extensions/custom TS commands
- built-in tools via
createTools(...) - MCP tools (enabled by default)
- LSP integration (enabled by default)
Required vs optional inputs
Typically you must provide only what you want to control:
- Must provide: nothing for a minimal session
- Usually provide explicitly in embedders:
sessionManager(if you need in-memory or custom location)authStorage+modelRegistry(if you own credential/model lifecycle)modelormodelPattern(if deterministic model selection matters)settings(if you need isolated/test config)
Session manager behavior (persistent vs in-memory)
AgentSession always uses a SessionManager; behavior depends on which factory you use.
File-backed (default)
import { createAgentSession, SessionManager } from "@oh-my-pi/pi-coding-agent";
const { session } = await createAgentSession({
sessionManager: SessionManager.create(process.cwd()),
});
console.log(session.sessionFile); // absolute .jsonl path- Persists conversation/messages/state deltas to session files.
- Supports resume/open/list/fork workflows.
session.sessionFileis defined.
In-memory
import { createAgentSession, SessionManager } from "@oh-my-pi/pi-coding-agent";
const { session } = await createAgentSession({
sessionManager: SessionManager.inMemory(),
});
console.log(session.sessionFile); // undefined- No filesystem persistence.
- Useful for tests, ephemeral workers, request-scoped agents.
- Session methods still work, but persistence-specific behaviors (file resume/fork paths) are naturally limited.
Resume/open/list helpers
import { SessionManager } from "@oh-my-pi/pi-coding-agent";
const recent = await SessionManager.continueRecent(process.cwd());
const listed = await SessionManager.list(process.cwd());
const opened = listed[0] ? await SessionManager.open(listed[0].path) : null;Model and auth wiring
createAgentSession() uses ModelRegistry + AuthStorage for model selection and API key resolution.
Explicit wiring
import {
createAgentSession,
discoverAuthStorage,
ModelRegistry,
SessionManager,
} from "@oh-my-pi/pi-coding-agent";
const authStorage = await discoverAuthStorage();
const modelRegistry = new ModelRegistry(authStorage);
await modelRegistry.refresh();
const available = modelRegistry.getAvailable();
if (available.length === 0) throw new Error("No authenticated models available");
const { session } = await createAgentSession({
authStorage,
modelRegistry,
model: available[0],
thinkingLevel: "medium",
sessionManager: SessionManager.inMemory(),
});Selection order when model is omitted
When no explicit model/modelPattern is provided:
- restore model from existing session (if restorable + key available)
- settings default model role (
default) - first available model with valid auth
If restore fails, modelFallbackMessage explains fallback.
Auth priority
AuthStorage.getApiKey(...) resolves in this order:
- runtime override (
setRuntimeApiKey) - stored credentials in
agent.db - provider environment variables
- custom-provider resolver fallback (if configured)
Event subscription model
Subscribe with session.subscribe(listener); it returns an unsubscribe function.
const unsubscribe = session.subscribe(event => {
switch (event.type) {
case "agent_start":
case "turn_start":
case "tool_execution_start":
break;
case "message_update":
if (event.assistantMessageEvent.type === "text_delta") {
process.stdout.write(event.assistantMessageEvent.delta);
}
break;
}
});AgentSessionEvent includes core AgentEvent plus session-level events:
auto_compaction_start/auto_compaction_endauto_retry_start/auto_retry_endttsr_triggeredtodo_reminder
Prompt lifecycle
session.prompt(text, options?) is the primary entry point.
Behavior:
- optional command/template expansion (
/commands, custom commands, file slash commands, prompt templates) - if currently streaming:
- requires
streamingBehavior: "steer" | "followUp" - queues instead of throwing work away
- requires
- if idle:
- validates model + API key
- appends user message
- starts agent turn
Related APIs:
sendUserMessage(content, { deliverAs? })steer(text, images?)followUp(text, images?)sendCustomMessage({ customType, content, ... }, { deliverAs?, triggerTurn? })abort()
Tools and extension integration
Built-ins and filtering
- Built-ins come from
createTools(...)andBUILTIN_TOOLS. toolNamesacts as an allowlist for built-ins.customToolsand extension-registered tools are still included.- Hidden tools (for example
submit_result) are opt-in unless required by options.
const { session } = await createAgentSession({
toolNames: ["read", "grep", "find", "write"],
requireSubmitResultTool: true,
});Extensions
extensions: inlineExtensionFactory[]additionalExtensionPaths: load extra extension filesdisableExtensionDiscovery: disable automatic extension scanningpreloadedExtensions: reuse already loaded extension set
Runtime tool set changes
AgentSession supports runtime activation updates:
getActiveToolNames()getAllToolNames()setActiveToolsByName(names)refreshMCPTools(mcpTools)
System prompt is rebuilt to reflect active tool changes.
Discovery helpers
Use these when you want partial control without recreating internal discovery logic:
discoverAuthStorage(agentDir?)discoverExtensions(cwd?)discoverSkills(cwd?, _agentDir?, settings?)discoverContextFiles(cwd?, _agentDir?)discoverPromptTemplates(cwd?, agentDir?)discoverSlashCommands(cwd?)discoverCustomTSCommands(cwd?, agentDir?)discoverMCPServers(cwd?)buildSystemPrompt(options?)
Subagent-oriented options
For SDK consumers building orchestrators (similar to task executor flow):
outputSchema: passes structured output expectation into tool contextrequireSubmitResultTool: forcessubmit_resulttool inclusiontaskDepth: recursion-depth context for nested task sessionsparentTaskPrefix: artifact naming prefix for nested task outputs
These are optional for normal single-agent embedding.
createAgentSession() return value
type CreateAgentSessionResult = {
session: AgentSession;
extensionsResult: LoadExtensionsResult;
setToolUIContext: (uiContext: ExtensionUIContext, hasUI: boolean) => void;
mcpManager?: MCPManager;
modelFallbackMessage?: string;
lspServers?: Array<{ name: string; status: "ready" | "error"; fileTypes: string[]; error?: string }>;
};Use setToolUIContext(...) only if your embedder provides UI capabilities that tools/extensions should call into.
Minimal controlled embed example
import {
createAgentSession,
discoverAuthStorage,
ModelRegistry,
SessionManager,
Settings,
} from "@oh-my-pi/pi-coding-agent";
const authStorage = await discoverAuthStorage();
const modelRegistry = new ModelRegistry(authStorage);
await modelRegistry.refresh();
const settings = Settings.isolated({
"compaction.enabled": true,
"retry.enabled": true,
});
const { session } = await createAgentSession({
authStorage,
modelRegistry,
settings,
sessionManager: SessionManager.inMemory(),
toolNames: ["read", "grep", "find", "edit", "write"],
enableMCP: false,
enableLsp: true,
});
session.subscribe(event => {
if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
process.stdout.write(event.assistantMessageEvent.delta);
}
});
await session.prompt("Find all TODO comments in this repo and propose fixes.");
await session.dispose();