Installation
npm install @mariozechner/pi-coding-agent
Quick Start
import {
AuthStorage,
createAgentSession,
ModelRegistry,
SessionManager
} from "@mariozechner/pi-coding-agent";
const authStorage = AuthStorage.create();
const modelRegistry = new ModelRegistry(authStorage);
const { session } = await createAgentSession({
sessionManager: SessionManager.inMemory(),
authStorage,
modelRegistry,
});
session.subscribe((event) => {
if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
process.stdout.write(event.assistantMessageEvent.delta);
}
});
await session.prompt("What files are in the current directory?");
Core Concepts
Model Selection
- Built-in Models
- Available Models
- Custom Models
import { getModel } from "@mariozechner/pi-ai";
import { AuthStorage, ModelRegistry } from "@mariozechner/pi-coding-agent";
const authStorage = AuthStorage.create();
const modelRegistry = new ModelRegistry(authStorage);
const opus = getModel("anthropic", "claude-opus-4-5");
if (!opus) throw new Error("Model not found");
const { session } = await createAgentSession({
model: opus,
thinkingLevel: "medium",
authStorage,
modelRegistry,
});
// Get only models with valid API keys
const available = await modelRegistry.getAvailable();
const { session } = await createAgentSession({
model: available[0],
authStorage,
modelRegistry,
});
// Find custom models from models.json
const customModel = modelRegistry.find("my-provider", "my-model");
const { session } = await createAgentSession({
model: customModel,
authStorage,
modelRegistry,
});
Tools Configuration
Session Management
- In-Memory
- New Session
- Continue Recent
- Open Specific
- List Sessions
// No persistence
const { session } = await createAgentSession({
sessionManager: SessionManager.inMemory(),
});
// New persistent session
const { session } = await createAgentSession({
sessionManager: SessionManager.create(process.cwd()),
});
// Continue most recent session
const { session, modelFallbackMessage } = await createAgentSession({
sessionManager: SessionManager.continueRecent(process.cwd()),
});
if (modelFallbackMessage) {
console.log("Note:", modelFallbackMessage);
}
// Open specific session file
const { session } = await createAgentSession({
sessionManager: SessionManager.open("/path/to/session.jsonl"),
});
// List available sessions
const sessions = await SessionManager.list(process.cwd());
for (const info of sessions) {
console.log(`${info.id}: ${info.firstMessage}`);
}
// List all sessions across all projects
const allSessions = await SessionManager.listAll((loaded, total) => {
console.log(`Loading ${loaded}/${total}...`);
});
Extensions and Resources
Settings Management
- From Files
- With Overrides
- In-Memory
import { SettingsManager } from "@mariozechner/pi-coding-agent";
// Loads from ~/.pi/agent/settings.json and .pi/settings.json
const { session } = await createAgentSession({
settingsManager: SettingsManager.create(),
});
const settingsManager = SettingsManager.create();
settingsManager.applyOverrides({
compaction: { enabled: false },
retry: { enabled: true, maxRetries: 5 },
});
const { session } = await createAgentSession({ settingsManager });
// No file I/O, for testing
const { session } = await createAgentSession({
settingsManager: SettingsManager.inMemory({
compaction: { enabled: false }
}),
sessionManager: SessionManager.inMemory(),
});
Complete Example
Here’s a complete working example:import { getModel } from "@mariozechner/pi-ai";
import { Type } from "@sinclair/typebox";
import {
AuthStorage,
createAgentSession,
DefaultResourceLoader,
ModelRegistry,
SessionManager,
SettingsManager,
readTool,
bashTool,
type ToolDefinition,
} from "@mariozechner/pi-coding-agent";
// Set up auth storage
const authStorage = AuthStorage.create("/custom/agent/auth.json");
// Runtime API key override (not persisted)
if (process.env.MY_KEY) {
authStorage.setRuntimeApiKey("anthropic", process.env.MY_KEY);
}
// Model registry
const modelRegistry = new ModelRegistry(authStorage);
// Custom tool
const statusTool: ToolDefinition = {
name: "status",
label: "Status",
description: "Get system status",
parameters: Type.Object({}),
execute: async () => ({
content: [{ type: "text", text: `Uptime: ${process.uptime()}s` }],
details: {},
}),
};
const model = getModel("anthropic", "claude-opus-4-5");
if (!model) throw new Error("Model not found");
// In-memory settings with overrides
const settingsManager = SettingsManager.inMemory({
compaction: { enabled: false },
retry: { enabled: true, maxRetries: 2 },
});
const loader = new DefaultResourceLoader({
cwd: process.cwd(),
agentDir: "/custom/agent",
settingsManager,
systemPromptOverride: () => "You are a minimal assistant. Be concise.",
});
await loader.reload();
const { session } = await createAgentSession({
cwd: process.cwd(),
agentDir: "/custom/agent",
model,
thinkingLevel: "off",
authStorage,
modelRegistry,
tools: [readTool, bashTool],
customTools: [statusTool],
resourceLoader: loader,
sessionManager: SessionManager.inMemory(),
settingsManager,
});
session.subscribe((event) => {
if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
process.stdout.write(event.assistantMessageEvent.delta);
}
});
await session.prompt("Get status and list files.");
Run Modes
Build custom interfaces on top of the SDK:- Interactive Mode
- Print Mode
- RPC Mode
Full TUI with editor and commands:
import { createAgentSession, InteractiveMode } from "@mariozechner/pi-coding-agent";
const { session } = await createAgentSession({ /* ... */ });
const mode = new InteractiveMode(session, {
initialMessage: "Hello",
initialImages: [],
initialMessages: [],
});
await mode.run(); // Blocks until exit
Single-shot output:
import { createAgentSession, runPrintMode } from "@mariozechner/pi-coding-agent";
const { session } = await createAgentSession({ /* ... */ });
await runPrintMode(session, {
mode: "text", // "text" or "json"
initialMessage: "Hello",
initialImages: [],
messages: ["Follow up"],
});
JSON-RPC for subprocess integration:
import { createAgentSession, runRpcMode } from "@mariozechner/pi-coding-agent";
const { session } = await createAgentSession({ /* ... */ });
await runRpcMode(session); // Reads stdin, writes stdout
API Reference
AgentSession
interface AgentSession {
// Prompting
prompt(text: string, options?: PromptOptions): Promise<void>;
steer(text: string): Promise<void>;
followUp(text: string): Promise<void>;
// Events
subscribe(listener: (event: AgentSessionEvent) => void): () => void;
// State
sessionFile: string | undefined;
sessionId: string;
agent: Agent;
model: Model | undefined;
thinkingLevel: ThinkingLevel;
messages: AgentMessage[];
isStreaming: boolean;
// Model control
setModel(model: Model): Promise<void>;
setThinkingLevel(level: ThinkingLevel): void;
cycleModel(): Promise<ModelCycleResult | undefined>;
cycleThinkingLevel(): ThinkingLevel | undefined;
// Session management
newSession(options?: { parentSession?: string }): Promise<boolean>;
switchSession(sessionPath: string): Promise<boolean>;
fork(entryId: string): Promise<{ selectedText: string; cancelled: boolean }>;
navigateTree(targetId: string, options?: NavigateTreeOptions): Promise<NavigateTreeResult>;
// Compaction
compact(customInstructions?: string): Promise<CompactionResult>;
abortCompaction(): void;
// Control
abort(): Promise<void>;
dispose(): void;
}
Next Steps
- See Building Extensions for custom tools and event handlers
- See Creating Skills for specialized workflows
- See Custom Providers for adding LLM providers
- Check
packages/coding-agent/examples/sdk/for more examples