> omp can help you use the SDK. Ask it to build an integration for your use case.

# SDK

The SDK provides programmatic access to omp's agent capabilities. Use it to embed omp in other applications, build custom interfaces, or integrate with automated workflows.

**Example use cases:**

- Build a custom UI (web, desktop, mobile)
- Integrate agent capabilities into existing applications
- Create automated pipelines with agent reasoning
- Build custom tools that spawn sub-agents
- Test agent behavior programmatically

See [examples/sdk/](../examples/sdk/) for working examples from minimal to full control.

## Quick Start

```typescript
import { createAgentSession, discoverAuthStorage, discoverModels, SessionManager } from "@oh-my-pi/pi-coding-agent";

// Set up credential storage and model registry
const authStorage = await discoverAuthStorage();
const modelRegistry = await discoverModels(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?");
```

## Installation

```bash
npm install @oh-my-pi/pi-coding-agent
```

The SDK is included in the main package. No separate installation needed.

## Core Concepts

### createAgentSession()

The main factory function. Creates an `AgentSession` with configurable options.

**Philosophy:** "Omit to discover, provide to override."

- Omit an option → omp discovers/loads from standard locations
- Provide an option → your value is used, discovery skipped for that option

```typescript
import { createAgentSession } from "@oh-my-pi/pi-coding-agent";

// Minimal: all defaults (discovers everything from cwd and ~/.omp/agent)
const { session } = await createAgentSession();

// Custom: override specific options
const { session } = await createAgentSession({
	model: myModel,
	systemPrompt: "You are helpful.",
	tools: [readTool, bashTool],
	sessionManager: SessionManager.inMemory(),
});
```

### AgentSession

The session manages the agent lifecycle, message history, and event streaming.

```typescript
interface AgentSession {
	// Send a prompt and wait for completion
	prompt(text: string, options?: PromptOptions): Promise<void>;

	// Subscribe to events (returns unsubscribe function)
	subscribe(listener: (event: AgentSessionEvent) => void): () => void;

	// Session info
	sessionFile: string | undefined; // undefined for in-memory
	sessionId: string;

	// Model control
	setModel(model: Model): Promise<void>;
	setThinkingLevel(level: ThinkingLevel): void;
	cycleModel(): Promise<ModelCycleResult | undefined>;
	cycleThinkingLevel(): ThinkingLevel | undefined;

	// State access
	agent: Agent;
	model: Model | undefined;
	thinkingLevel: ThinkingLevel;
	messages: AgentMessage[];
	isStreaming: boolean;

	// Session management
	newSession(options?: { parentSession?: string }): Promise<boolean>; // Returns false if cancelled by hook
	switchSession(sessionPath: string): Promise<boolean>;

	// Branching
	branch(entryId: string): Promise<{ selectedText: string; cancelled: boolean }>; // Creates new session file
	navigateTree(
		targetId: string,
		options?: { summarize?: boolean }
	): Promise<{ editorText?: string; cancelled: boolean }>; // In-place navigation

	// Hook message injection
	sendHookMessage(message: HookMessage, triggerTurn?: boolean): Promise<void>;

	// Compaction
	compact(customInstructions?: string): Promise<CompactionResult>;
	abortCompaction(): void;

	// Abort current operation
	abort(): Promise<void>;

	// Cleanup
	dispose(): void;
}
```

### Agent and AgentState

The `Agent` class (from `@oh-my-pi/pi-agent-core`) handles the core LLM interaction. Access it via `session.agent`.

```typescript
// Access current state
const state = session.agent.state;

// state.messages: AgentMessage[] - conversation history
// state.model: Model - current model
// state.thinkingLevel: ThinkingLevel - current thinking level
// state.systemPrompt: string - system prompt
// state.tools: Tool[] - available tools

// Replace messages (useful for branching, restoration)
session.agent.replaceMessages(messages);

// Wait for agent to finish processing
await session.agent.waitForIdle();
```

### Events

Subscribe to events to receive streaming output and lifecycle notifications.

```typescript
session.subscribe((event) => {
	switch (event.type) {
		// Streaming text from assistant
		case "message_update":
			if (event.assistantMessageEvent.type === "text_delta") {
				process.stdout.write(event.assistantMessageEvent.delta);
			}
			if (event.assistantMessageEvent.type === "thinking_delta") {
				// Thinking output (if thinking enabled)
			}
			break;

		// Tool execution
		case "tool_execution_start":
			console.log(`Tool: ${event.toolName}`);
			break;
		case "tool_execution_update":
			// Streaming tool output
			break;
		case "tool_execution_end":
			console.log(`Result: ${event.isError ? "error" : "success"}`);
			break;

		// Message lifecycle
		case "message_start":
			// New message starting
			break;
		case "message_end":
			// Message complete
			break;

		// Agent lifecycle
		case "agent_start":
			// Agent started processing prompt
			break;
		case "agent_end":
			// Agent finished (event.messages contains new messages)
			break;

		// Turn lifecycle (one LLM response + tool calls)
		case "turn_start":
			break;
		case "turn_end":
			// event.message: assistant response
			// event.toolResults: tool results from this turn
			break;

		// Session events (auto-compaction, retry)
		case "auto_compaction_start":
		case "auto_compaction_end":
		case "auto_retry_start":
		case "auto_retry_end":
			break;
	}
});
```

## Options Reference

### Directories

```typescript
const { session } = await createAgentSession({
	// Working directory for project-local discovery
	cwd: process.cwd(), // default

	// Global config directory
	agentDir: "~/.omp/agent", // default (expands ~)
});
```

`cwd` is used for:

- Project hooks (`.omp/hooks/`)
- Project tools (`.omp/tools/`)
- Project skills (`.omp/skills/`)
- Project commands (`.omp/commands/`)
- Context files (`AGENTS.md` walking up from cwd)
- Session directory naming

`agentDir` is used for:

- Global hooks (`hooks/`)
- Global tools (`tools/`)
- Global skills (`skills/`)
- Global commands (`commands/`)
- Global context file (`AGENTS.md`)
- Settings (`settings.json`)
- Custom models (`models.json`)
- Credentials (`auth.json`)
- Sessions (`sessions/`)

### Model

```typescript
import { getModel } from "@oh-my-pi/pi-ai";
import { discoverAuthStorage, discoverModels } from "@oh-my-pi/pi-coding-agent";

const authStorage = await discoverAuthStorage();
const modelRegistry = await discoverModels(authStorage);

// Find specific built-in model (doesn't check if API key exists)
const opus = getModel("anthropic", "claude-opus-4-5");
if (!opus) throw new Error("Model not found");

// Find any model by provider/id, including custom models from models.json
// (doesn't check if API key exists)
const customModel = modelRegistry.find("my-provider", "my-model");

// Get only models that have valid API keys configured
const available = await modelRegistry.getAvailable();

const { session } = await createAgentSession({
	model: opus,
	thinkingLevel: "medium", // off, minimal, low, medium, high, xhigh

	// Models for cycling (Ctrl+P in interactive mode)
	scopedModels: [
		{ model: opus, thinkingLevel: "high" },
		{ model: haiku, thinkingLevel: "off" },
	],

	authStorage,
	modelRegistry,
});
```

If no model is provided:

1. Tries to restore from session (if continuing)
2. Uses default from settings
3. Falls back to first available model

> See [examples/sdk/02-custom-model.ts](../examples/sdk/02-custom-model.ts)

### API Keys and OAuth

API key resolution priority (handled by AuthStorage):

1. Runtime overrides (via `setRuntimeApiKey`, not persisted)
2. Stored credentials in `auth.json` (API keys or OAuth tokens)
3. Environment variables (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, etc.)
4. Fallback resolver (for custom provider keys from `models.json`)

```typescript
import { AuthStorage, ModelRegistry, discoverAuthStorage, discoverModels } from "@oh-my-pi/pi-coding-agent";

// Default: uses ~/.omp/agent/auth.json and ~/.omp/agent/models.json
const authStorage = await discoverAuthStorage();
const modelRegistry = await discoverModels(authStorage);

const { session } = await createAgentSession({
	sessionManager: SessionManager.inMemory(),
	authStorage,
	modelRegistry,
});

// Runtime API key override (not persisted to disk)
authStorage.setRuntimeApiKey("anthropic", "sk-my-temp-key");

// Custom auth storage location
const customAuth = new AuthStorage("/my/app/auth.json");
const customRegistry = new ModelRegistry(customAuth, "/my/app/models.json");

const { session } = await createAgentSession({
	sessionManager: SessionManager.inMemory(),
	authStorage: customAuth,
	modelRegistry: customRegistry,
});

// No custom models.json (built-in models only)
const simpleRegistry = new ModelRegistry(authStorage);
```

> See [examples/sdk/09-api-keys-and-oauth.ts](../examples/sdk/09-api-keys-and-oauth.ts)

### System Prompt

```typescript
const { session } = await createAgentSession({
	// Replace entirely
	systemPrompt: "You are a helpful assistant.",

	// Or modify default (receives default, returns modified)
	systemPrompt: (defaultPrompt) => {
		return `${defaultPrompt}\n\n## Additional Rules\n- Be concise`;
	},
});
```

> See [examples/sdk/03-custom-prompt.ts](../examples/sdk/03-custom-prompt.ts)

### Tools

By default, `createAgentSession` creates all built-in tools automatically. You can filter which tools are available using `toolNames`:

```typescript
// Use all built-in tools (default)
const { session } = await createAgentSession();

// Filter to specific tools
const { session } = await createAgentSession({
	toolNames: ["read", "grep", "find", "ls"], // Read-only tools
});
```

#### Available Built-in Tools

All tools are defined in `BUILTIN_TOOLS`:

- `ask` - Interactive user prompts (requires UI)
- `bash` - Shell command execution
- `edit` - Surgical file editing
- `find` - File search by glob patterns
- `git` - Git operations (can be disabled via settings)
- `grep` - Content search with regex
- `ls` - Directory listing
- `lsp` - Language server protocol integration
- `notebook` - Jupyter notebook editing
- `output` - Task output retrieval
- `read` - File reading (text and images)
- `task` - Subagent spawning
- `fetch` - URL fetching
- `web_search` - Web search
- `write` - File writing

#### Creating Tools Manually

For advanced use cases, you can create tools directly using `createTools`:

```typescript
import { BUILTIN_TOOLS, createTools, type ToolSession } from "@oh-my-pi/pi-coding-agent";

const session: ToolSession = {
	cwd: "/path/to/project",
	hasUI: false,
	getSessionFile: () => null,
	getSessionSpawns: () => "*",
};

const tools = await createTools(session);
```

**When you don't need factories:**

- If you omit `tools`, omp automatically creates them with the correct `cwd`
- If you use `process.cwd()` as your `cwd`, the pre-built instances work fine

**When you must use factories:**

- When you specify both `cwd` (different from `process.cwd()`) AND `tools`

> See [examples/sdk/05-tools.ts](../examples/sdk/05-tools.ts)

### Custom Tools

```typescript
import { Type } from "@sinclair/typebox";
import { createAgentSession, discoverCustomTools, type CustomTool } from "@oh-my-pi/pi-coding-agent";

// Inline custom tool
const myTool: CustomTool = {
	name: "my_tool",
	label: "My Tool",
	description: "Does something useful",
	parameters: Type.Object({
		input: Type.String({ description: "Input value" }),
	}),
	execute: async (toolCallId, params) => ({
		content: [{ type: "text", text: `Result: ${params.input}` }],
		details: {},
	}),
};

// Replace discovery with inline tools
const { session } = await createAgentSession({
	customTools: [{ tool: myTool }],
});

// Merge with discovered tools
const discovered = await discoverCustomTools();
const { session } = await createAgentSession({
	customTools: [...discovered, { tool: myTool }],
});

// Add paths without replacing discovery
const { session } = await createAgentSession({
	additionalCustomToolPaths: ["/extra/tools"],
});
```

> See [examples/sdk/05-tools.ts](../examples/sdk/05-tools.ts)

### Hooks

```typescript
import { createAgentSession, discoverHooks, type HookFactory } from "@oh-my-pi/pi-coding-agent";

// Inline hook
const loggingHook: HookFactory = (api) => {
	// Log tool calls
	api.on("tool_call", async (event) => {
		console.log(`Tool: ${event.toolName}`);
		return undefined; // Don't block
	});

	// Block dangerous commands
	api.on("tool_call", async (event) => {
		if (event.toolName === "bash" && event.input.command?.includes("rm -rf")) {
			return { block: true, reason: "Dangerous command" };
		}
		return undefined;
	});

	// Register custom slash command
	api.registerCommand("stats", {
		description: "Show session stats",
		handler: async (ctx) => {
			const entries = ctx.sessionManager.getEntries();
			ctx.ui.notify(`${entries.length} entries`, "info");
		},
	});

	// Inject messages
	api.sendMessage(
		{
			customType: "my-hook",
			content: "Hook initialized",
			display: false, // Hidden from TUI
		},
		false
	); // Don't trigger agent turn

	// Persist hook state
	api.appendEntry("my-hook", { initialized: true });
};

// Replace discovery
const { session } = await createAgentSession({
	hooks: [{ factory: loggingHook }],
});

// Disable all hooks
const { session } = await createAgentSession({
	hooks: [],
});

// Merge with discovered
const discovered = await discoverHooks();
const { session } = await createAgentSession({
	hooks: [...discovered, { factory: loggingHook }],
});

// Add paths without replacing
const { session } = await createAgentSession({
	additionalHookPaths: ["/extra/hooks"],
});
```

Hook API methods:

- `api.on(event, handler)` - Subscribe to events
- `api.sendMessage(message, triggerTurn?)` - Inject message (creates `CustomMessageEntry`)
- `api.appendEntry(customType, data?)` - Persist hook state (not in LLM context)
- `api.registerCommand(name, options)` - Register custom slash command
- `api.registerMessageRenderer(customType, renderer)` - Custom TUI rendering
- `api.exec(command, args, options?)` - Execute shell commands

> See [examples/sdk/06-hooks.ts](../examples/sdk/06-hooks.ts) and [docs/hooks.md](hooks.md)

### Skills

```typescript
import { createAgentSession, discoverSkills, type Skill } from "@oh-my-pi/pi-coding-agent";

// Discover and filter
const { skills: allSkills, warnings } = discoverSkills();
const filtered = allSkills.filter((s) => s.name.includes("search"));

// Custom skill
const mySkill: Skill = {
	name: "my-skill",
	description: "Custom instructions",
	filePath: "/path/to/SKILL.md",
	baseDir: "/path/to",
	source: "custom",
};

const { session } = await createAgentSession({
	skills: [...filtered, mySkill],
});

// Disable skills
const { session } = await createAgentSession({
	skills: [],
});

// Discovery with settings filter
const { skills } = discoverSkills(process.cwd(), undefined, {
	ignoredSkills: ["browser-*"], // glob patterns to exclude
	includeSkills: ["search-*"], // glob patterns to include (empty = all)
});
```

> See [examples/sdk/04-skills.ts](../examples/sdk/04-skills.ts)

### Context Files

```typescript
import { createAgentSession, discoverContextFiles } from "@oh-my-pi/pi-coding-agent";

// Discover AGENTS.md files
const discovered = discoverContextFiles();

// Add custom context
const { session } = await createAgentSession({
	contextFiles: [
		...discovered,
		{
			path: "/virtual/AGENTS.md",
			content: "# Guidelines\n\n- Be concise\n- Use TypeScript",
		},
	],
});

// Disable context files
const { session } = await createAgentSession({
	contextFiles: [],
});
```

> See [examples/sdk/07-context-files.ts](../examples/sdk/07-context-files.ts)

### Slash Commands

```typescript
import { createAgentSession, discoverSlashCommands, type FileSlashCommand } from "@oh-my-pi/pi-coding-agent";

const discovered = discoverSlashCommands();

const customCommand: FileSlashCommand = {
	name: "deploy",
	description: "Deploy the application",
	source: "(custom)",
	content: "# Deploy\n\n1. Build\n2. Test\n3. Deploy",
};

const { session } = await createAgentSession({
	slashCommands: [...discovered, customCommand],
});
```

> See [examples/sdk/08-slash-commands.ts](../examples/sdk/08-slash-commands.ts)

### Session Management

Sessions use a tree structure with `id`/`parentId` linking, enabling in-place branching.

```typescript
import { createAgentSession, SessionManager } from "@oh-my-pi/pi-coding-agent";

// In-memory (no persistence)
const { session } = await createAgentSession({
	sessionManager: SessionManager.inMemory(),
});

// New persistent session
const { session } = await createAgentSession({
	sessionManager: SessionManager.create(process.cwd()),
});

// Continue most recent
const { session, modelFallbackMessage } = await createAgentSession({
	sessionManager: SessionManager.continueRecent(process.cwd()),
});
if (modelFallbackMessage) {
	console.log("Note:", modelFallbackMessage);
}

// Open specific file
const { session } = await createAgentSession({
	sessionManager: SessionManager.open("/path/to/session.jsonl"),
});

// List available sessions
const sessions = SessionManager.list(process.cwd());
for (const info of sessions) {
	console.log(`${info.id}: ${info.firstMessage} (${info.messageCount} messages)`);
}

// Custom session directory (no cwd encoding)
const customDir = "/path/to/my-sessions";
const { session } = await createAgentSession({
	sessionManager: SessionManager.create(process.cwd(), customDir),
});
```

**SessionManager tree API:**

```typescript
const sm = SessionManager.open("/path/to/session.jsonl");

// Tree traversal
const entries = sm.getEntries(); // All entries (excludes header)
const tree = sm.getTree(); // Full tree structure
const path = sm.getPath(); // Path from root to current leaf
const leaf = sm.getLeafEntry(); // Current leaf entry
const entry = sm.getEntry(id); // Get entry by ID
const children = sm.getChildren(id); // Direct children of entry

// Labels
const label = sm.getLabel(id); // Get label for entry
sm.appendLabelChange(id, "checkpoint"); // Set label

// Branching
sm.branch(entryId); // Move leaf to earlier entry
sm.branchWithSummary(id, "Summary..."); // Branch with context summary
sm.createBranchedSession(leafId); // Extract path to new file
```

> See [examples/sdk/11-sessions.ts](../examples/sdk/11-sessions.ts) and [docs/session.md](session.md)

### Settings Management

```typescript
import { createAgentSession, SettingsManager, SessionManager } from "@oh-my-pi/pi-coding-agent";

// Default: loads from files (global + project merged)
const { session } = await createAgentSession({
	settingsManager: await SettingsManager.create(),
});

// With overrides
const settingsManager = await SettingsManager.create();
settingsManager.applyOverrides({
	compaction: { enabled: false },
	retry: { enabled: true, maxRetries: 5 },
});
const { session } = await createAgentSession({ settingsManager });

// In-memory (no file I/O, for testing)
const { session } = await createAgentSession({
	settingsManager: SettingsManager.inMemory({ compaction: { enabled: false } }),
	sessionManager: SessionManager.inMemory(),
});

// Custom directories
const { session } = await createAgentSession({
	settingsManager: await SettingsManager.create("/custom/cwd", "/custom/agent"),
});
```

**Static factories:**

- `SettingsManager.create(cwd?, agentDir?)` - Load from files (async)
- `SettingsManager.inMemory(settings?)` - No file I/O

**Project-specific settings:**

Settings load from two locations and merge:

1. Global: `~/.omp/agent/settings.json`
2. Project: `<cwd>/.omp/settings.json`

Project overrides global. Nested objects merge keys. Setters only modify global (project is read-only for version control).

> See [examples/sdk/10-settings.ts](../examples/sdk/10-settings.ts)

## Discovery Functions

All discovery functions accept optional `cwd` and `agentDir` parameters.

```typescript
import { getModel } from "@oh-my-pi/pi-ai";
import {
	AuthStorage,
	ModelRegistry,
	discoverAuthStorage,
	discoverModels,
	discoverSkills,
	discoverHooks,
	discoverCustomTools,
	discoverContextFiles,
	discoverSlashCommands,
	loadSettings,
	buildSystemPrompt,
} from "@oh-my-pi/pi-coding-agent";

// Auth and Models
const authStorage = await discoverAuthStorage(); // ~/.omp/agent/agent.db
const modelRegistry = await discoverModels(authStorage); // + ~/.omp/agent/models.json
const allModels = modelRegistry.getAll(); // All models (built-in + custom)
const available = await modelRegistry.getAvailable(); // Only models with API keys
const model = modelRegistry.find("provider", "id"); // Find specific model
const builtIn = getModel("anthropic", "claude-opus-4-5"); // Built-in only

// Skills
const { skills, warnings } = discoverSkills(cwd, agentDir, skillsSettings);

// Hooks (async - loads TypeScript)
const hooks = await discoverHooks(cwd, agentDir);

// Custom tools (async - loads TypeScript)
const tools = await discoverCustomTools(cwd, agentDir);

// Context files
const contextFiles = discoverContextFiles(cwd, agentDir);

// Slash commands
const commands = discoverSlashCommands(cwd, agentDir);

// Settings (global + project merged)
const settings = await loadSettings(cwd, agentDir);

// Build system prompt manually
const prompt = buildSystemPrompt({
	skills,
	contextFiles,
	appendPrompt: "Additional instructions",
	cwd,
});
```

## Return Value

`createAgentSession()` returns:

```typescript
interface CreateAgentSessionResult {
	// The session
	session: AgentSession;

	// Custom tools (for UI setup)
	customToolsResult: {
		tools: LoadedCustomTool[];
		setUIContext: (ctx, hasUI) => void;
	};

	// Warning if session model couldn't be restored
	modelFallbackMessage?: string;
}
```

## Complete Example

```typescript
import { getModel } from "@oh-my-pi/pi-ai";
import { Type } from "@sinclair/typebox";
import {
	AuthStorage,
	createAgentSession,
	ModelRegistry,
	SessionManager,
	SettingsManager,
	readTool,
	bashTool,
	type HookFactory,
	type CustomTool,
} from "@oh-my-pi/pi-coding-agent";

// Set up auth storage (custom location)
const authStorage = new AuthStorage("/custom/agent/auth.json");

// Runtime API key override (not persisted)
if (process.env.MY_KEY) {
	authStorage.setRuntimeApiKey("anthropic", process.env.MY_KEY);
}

// Model registry (no custom models.json)
const modelRegistry = new ModelRegistry(authStorage);

// Inline hook
const auditHook: HookFactory = (api) => {
	api.on("tool_call", async (event) => {
		console.log(`[Audit] ${event.toolName}`);
		return undefined;
	});
};

// Inline tool
const statusTool: CustomTool = {
	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 { session } = await createAgentSession({
	cwd: process.cwd(),
	agentDir: "/custom/agent",

	model,
	thinkingLevel: "off",
	authStorage,
	modelRegistry,

	systemPrompt: "You are a minimal assistant. Be concise.",

	tools: [readTool, bashTool],
	customTools: [{ tool: statusTool }],
	hooks: [{ factory: auditHook }],
	skills: [],
	contextFiles: [],
	slashCommands: [],

	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.");
```

## RPC Mode Alternative

For subprocess-based integration, use RPC mode instead of the SDK:

```bash
omp --mode rpc --no-session
```

See [RPC documentation](rpc.md) for the JSON protocol.

The SDK is preferred when:

- You want type safety
- You're in the same Node.js process
- You need direct access to agent state
- You want to customize tools/hooks programmatically

RPC mode is preferred when:

- You're integrating from another language
- You want process isolation
- You're building a language-agnostic client

## Exports

The main entry point exports:

```typescript
// Factory
createAgentSession

// Auth and Models
AuthStorage
ModelRegistry
discoverAuthStorage
discoverModels

// Discovery
discoverSkills
discoverHooks
discoverCustomTools
discoverContextFiles
discoverSlashCommands

// Helpers
loadSettings
buildSystemPrompt

// Session management
SessionManager
SettingsManager

// Tool registry and factory
BUILTIN_TOOLS              // Map of tool name to factory
createTools                // Create all tools from ToolSession
type ToolSession           // Session context for tool creation

// Individual tool factories
createReadTool, createBashTool, EditTool, createWriteTool
createGrepTool, createFindTool, createLsTool, createGitTool

// Types
type CreateAgentSessionOptions
type CreateAgentSessionResult
type CustomTool
type HookFactory
type Skill
type FileSlashCommand
type Settings
type SkillsSettings
type Tool
```

For hook types, import from the hooks subpath:

```typescript
import type {
	HookAPI,
	HookMessage,
	HookFactory,
	HookEventContext,
	HookCommandContext,
	ToolCallEvent,
	ToolResultEvent,
} from "@oh-my-pi/pi-coding-agent/hooks";
```

For message utilities:

```typescript
import { isHookMessage, createHookMessage } from "@oh-my-pi/pi-coding-agent";
```

For config utilities:

```typescript
import { getAgentDir } from "@oh-my-pi/pi-coding-agent/config";
```
