Skip to main content

Programmatic Usage

Pi can be embedded in your own applications using the SDK. This enables building custom workflows, IDE integrations, chatbots, and automated agents.

Installation

npm install @mariozechner/pi-coding-agent
The SDK includes all necessary dependencies for agent functionality.

Quick Start

import { createAgentSession } from '@mariozechner/pi-coding-agent';

const { session } = await createAgentSession();

// Send a prompt
await session.prompt('What files are in the current directory?');

// The agent will use tools (read, bash, etc.) to fulfill the request

Core API

createAgentSession

Creates a new agent session with optional configuration.
import {
  createAgentSession,
  SessionManager,
  AuthStorage,
  ModelRegistry,
} from '@mariozechner/pi-coding-agent';

const { session, extensionsResult, modelFallbackMessage } = await createAgentSession({
  // Working directory for project-local discovery
  cwd: process.cwd(),
  
  // Global config directory (default: ~/.pi/agent)
  agentDir: '~/.pi/agent',
  
  // Model configuration
  model: getModel('anthropic', 'claude-sonnet-4'),
  thinkingLevel: 'medium',
  
  // Built-in tools (default: [read, bash, edit, write])
  tools: [readTool, bashTool, editTool, writeTool],
  
  // Custom tools
  customTools: [
    {
      name: 'deploy',
      description: 'Deploy the application',
      parameters: Type.Object({
        environment: Type.String(),
      }),
      execute: async (args) => {
        // Deploy logic
        return { success: true };
      },
    },
  ],
  
  // Session persistence
  sessionManager: SessionManager.create(cwd),
  // Or in-memory:
  // sessionManager: SessionManager.inMemory(),
  
  // Authentication
  authStorage: AuthStorage.create(),
  modelRegistry: new ModelRegistry(authStorage),
});

AgentSession

The main interface for interacting with the agent.
// Send a prompt
await session.prompt('Refactor this function');

// Send a message with file attachments
await session.sendMessage([
  { type: 'text', text: 'Review this code' },
  { type: 'image', data: imageBase64, mimeType: 'image/png' },
]);

// Execute bash command
const result = await session.executeBash('npm test');
console.log(result.output);

// Change model
await session.changeModel(getModel('openai', 'gpt-4o'));

// Change thinking level
await session.changeThinkingLevel('high');

// Manual compaction
await session.compact({ customInstructions: 'Focus on recent code changes' });

// Access state
const model = session.state.model;
const thinkingLevel = session.state.thinkingLevel;
const messages = session.state.messages;

Built-in Tools

Pi provides pre-built tools for common operations.
import {
  // Individual tools
  readTool,      // Read files
  bashTool,      // Execute bash commands
  editTool,      // Edit files with find/replace
  writeTool,     // Write/create files
  grepTool,      // Search file contents
  findTool,      // Find files by glob
  lsTool,        // List directory contents
  
  // Tool sets
  codingTools,      // [read, bash, edit, write]
  readOnlyTools,    // [read, grep, find, ls]
  allBuiltInTools,  // All built-in tools
  
  // Tool factories (for custom working directory)
  createReadTool,
  createBashTool,
  createEditTool,
  createWriteTool,
  createCodingTools,
} from '@mariozechner/pi-coding-agent';

// Use default tools (use process.cwd())
const { session } = await createAgentSession({
  tools: codingTools,
});

// Or create tools with custom cwd
const customTools = createCodingTools('/path/to/project');
const { session } = await createAgentSession({
  cwd: '/path/to/project',
  tools: customTools,
});

Custom Tools

Define custom tools with TypeBox schemas for type safety.
import { createAgentSession } from '@mariozechner/pi-coding-agent';
import { Type } from '@mariozechner/pi-ai';
import { exec } from 'child_process';
import { promisify } from 'util';

const execAsync = promisify(exec);

const deployTool = {
  name: 'deploy',
  description: 'Deploy application to specified environment',
  parameters: Type.Object({
    environment: Type.Union([
      Type.Literal('staging'),
      Type.Literal('production'),
    ], { description: 'Target environment' }),
    branch: Type.Optional(Type.String({ description: 'Git branch to deploy' })),
    skipTests: Type.Optional(Type.Boolean({ default: false })),
  }),
  execute: async (args, update) => {
    // Update callback for progress
    update({ status: 'Running tests...' });
    
    if (!args.skipTests) {
      const { stdout } = await execAsync('npm test');
      if (stdout.includes('FAIL')) {
        return { success: false, error: 'Tests failed' };
      }
    }
    
    update({ status: 'Building...' });
    await execAsync('npm run build');
    
    update({ status: `Deploying to ${args.environment}...` });
    const { stdout } = await execAsync(
      `./scripts/deploy.sh ${args.environment} ${args.branch || 'main'}`
    );
    
    return {
      success: true,
      url: `https://${args.environment}.example.com`,
      logs: stdout,
    };
  },
};

const { session } = await createAgentSession({
  customTools: [deployTool],
});

await session.prompt('Deploy the latest changes to staging');

Session Management

import { createAgentSession, SessionManager } from '@mariozechner/pi-coding-agent';

// Create with default session manager (saves to ~/.pi/agent/sessions/)
const { session } = await createAgentSession({
  cwd: process.cwd(),
});

// Session is automatically saved
await session.prompt('What is 2 + 2?');

// Continue later
const { session: resumedSession } = await createAgentSession({
  cwd: process.cwd(),
  sessionManager: SessionManager.create(process.cwd()),
});

// Conversation history is restored
await resumedSession.prompt('What was my last question?');
// Agent: "Your last question was 'What is 2 + 2?'"

Resource Loading

Load skills, prompt templates, and other resources.
import {
  createAgentSession,
  DefaultResourceLoader,
  SettingsManager,
} from '@mariozechner/pi-coding-agent';

// Create resource loader
const loader = new DefaultResourceLoader({
  cwd: process.cwd(),
  agentDir: '~/.pi/agent',
  settingsManager: SettingsManager.create(),
});

// Load resources
await loader.reload();

// Create session with loaded resources
const { session } = await createAgentSession({
  resourceLoader: loader,
});

// Access loaded resources
const skills = loader.getSkills();
const prompts = loader.getPromptTemplates();
const themes = loader.getThemes();

console.log(`Loaded ${skills.length} skills`);
console.log(`Loaded ${prompts.length} prompt templates`);

Real-World Examples

import { createAgentSession, readTool, bashTool } from '@mariozechner/pi-coding-agent';
import { getModel } from '@mariozechner/pi-ai';
import { Octokit } from '@octokit/rest';

const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });

async function reviewPullRequest(owner: string, repo: string, prNumber: number) {
  // Create agent session
  const { session } = await createAgentSession({
    model: getModel('anthropic', 'claude-sonnet-4'),
    thinkingLevel: 'high',
    tools: [readTool, bashTool],
  });
  
  // Get PR files
  const { data: files } = await octokit.pulls.listFiles({
    owner,
    repo,
    pull_number: prNumber,
  });
  
  // Build file list
  const fileList = files.map(f => f.filename).join('\n');
  
  // Run code review
  const reviewComments: string[] = [];
  
  session.on((event) => {
    if (event.type === 'text_delta') {
      reviewComments.push(event.delta);
    }
  });
  
  await session.prompt(`
    Review this pull request:
    
    Changed files:
    ${fileList}
    
    Please:
    1. Read each changed file
    2. Check for:
       - Security vulnerabilities
       - Performance issues
       - Code style violations
       - Missing tests
    3. Provide specific feedback with file:line references
  `);
  
  // Post review comment
  const reviewBody = reviewComments.join('');
  
  await octokit.pulls.createReview({
    owner,
    repo,
    pull_number: prNumber,
    body: reviewBody,
    event: 'COMMENT',
  });
  
  console.log('Review posted!');
}

// Usage
await reviewPullRequest('owner', 'repo', 123);
#!/usr/bin/env node
import { createAgentSession } from '@mariozechner/pi-coding-agent';
import { getModel } from '@mariozechner/pi-ai';
import { Command } from 'commander';

const program = new Command();

program
  .name('ai-helper')
  .description('AI-powered development helper')
  .version('1.0.0');

program
  .command('refactor <file>')
  .description('Refactor a file')
  .option('-s, --style <style>', 'Code style', 'functional')
  .action(async (file, options) => {
    const { session } = await createAgentSession({
      model: getModel('anthropic', 'claude-sonnet-4'),
    });
    
    session.on((event) => {
      if (event.type === 'text_delta') {
        process.stdout.write(event.delta);
      }
    });
    
    await session.prompt(`
      Refactor ${file} to use ${options.style} style.
      Preserve all functionality and add tests.
    `);
  });

program
  .command('test <file>')
  .description('Generate tests for a file')
  .action(async (file) => {
    const { session } = await createAgentSession();
    
    await session.prompt(`
      Read ${file} and generate comprehensive unit tests.
      Cover edge cases and error handling.
    `);
  });

program.parse();
import * as vscode from 'vscode';
import { createAgentSession, SessionManager } from '@mariozechner/pi-coding-agent';
import { getModel } from '@mariozechner/pi-ai';

let session: Awaited<ReturnType<typeof createAgentSession>>['session'];

export async function activate(context: vscode.ExtensionContext) {
  // Create persistent session
  const { session: agentSession } = await createAgentSession({
    cwd: vscode.workspace.workspaceFolders?.[0].uri.fsPath,
    sessionManager: SessionManager.create(
      vscode.workspace.workspaceFolders?.[0].uri.fsPath || process.cwd()
    ),
  });
  
  session = agentSession;
  
  // Register command
  const disposable = vscode.commands.registerCommand(
    'extension.aiRefactor',
    async () => {
      const editor = vscode.window.activeTextEditor;
      if (!editor) return;
      
      const selection = editor.selection;
      const text = editor.document.getText(selection);
      
      const outputChannel = vscode.window.createOutputChannel('AI Helper');
      outputChannel.show();
      
      session.on((event) => {
        if (event.type === 'text_delta') {
          outputChannel.append(event.delta);
        } else if (event.type === 'tool_call_end' && event.toolName === 'edit') {
          // Refresh editor when file is edited
          vscode.commands.executeCommand('workbench.action.files.revert');
        }
      });
      
      await session.prompt(`
        Refactor this code to improve readability:
        
        ${text}
      `);
    }
  );
  
  context.subscriptions.push(disposable);
}

export function deactivate() {
  session?.abort();
}

API Reference

For complete API documentation, see:

TypeScript Types

All APIs are fully typed. Import types from the SDK:
import type {
  AgentSession,
  Tool,
  ToolDefinition,
  ExtensionAPI,
  Skill,
  PromptTemplate,
} from '@mariozechner/pi-coding-agent';

import type {
  Model,
  Message,
  AssistantMessage,
  Context,
} from '@mariozechner/pi-ai';

Build docs developers (and LLMs) love