New:Microsoft Teams Notifications Are Now Available in Socket.Learn more
Get Started

claude-runner

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

claude-runner

The easiest way to build AI agents with Claude. MCP-native, sandbox-first, 5 lines to start.

Source
npmnpm
Version
0.1.1
Version published
Weekly downloads
43
-47.56%
Maintainers
1
Weekly downloads
 
Created
Source

claude-runner

npm version License: MIT TypeScript

The easiest way to build AI agents with Claude. MCP-native, sandbox-ready, 5 lines to start.

Built on the official Claude Agent SDK. One dependency. Zero bloat.

import { Runner } from 'claude-runner';

const runner = new Runner();
const result = await runner.run('Analyze this codebase and suggest improvements');
console.log(result.text);

Why claude-runner?

The official @anthropic-ai/claude-agent-sdk is powerful but low-level — 40+ options, 20+ message types, raw async generators. Every developer builds their own wrapper.

claude-runner is that wrapper:

raw Agent SDKclaude-runner
Lines to start20+5
Message types20+ nested7 flat events
MCP configObject onlyShorthand strings
SandboxManual spawnClaudeCodeProcesssandbox: 'e2b'
Session resumeresume: id optionrunner.resume(id)
PermissionscanUseTool callbackpermissions: 'auto'
Custom toolstool() + createSdkMcpServer()defineTool()

Install

npm install claude-runner

Requires Claude Code CLI to be installed and authenticated.

Quick Start

Simple await

import { Runner } from 'claude-runner';

const runner = new Runner();
const result = await runner.run('Fix the failing tests in this project');

console.log(result.text);           // Claude's response
console.log(`Cost: $${result.cost}`); // API cost
console.log(`Turns: ${result.turns}`); // Agentic turns

Streaming

for await (const event of runner.stream('Refactor the auth module')) {
  switch (event.type) {
    case 'text':
      process.stdout.write(event.text);
      break;
    case 'tool_start':
      console.log(`\n[${event.tool}]`);
      break;
    case 'tool_end':
      console.log(`[${event.tool}] done (${event.duration}ms)`);
      break;
    case 'done':
      console.log(`\nCost: $${event.result.cost.toFixed(4)}`);
      break;
  }
}

Session Resume

// First run — Claude analyzes and asks for approval
const r1 = await runner.run('Create a test plan for the auth module');
console.log(r1.text); // "Here's the plan... approve?"

// Resume — continue the conversation with full context
const r2 = await runner.resume(r1.sessionId, 'Approved. Generate the tests.').result;
console.log(r2.text); // "Tests generated at..."

Multi-turn (mid-stream messages)

const stream = runner.stream('Build a REST API for user management');

// Inject guidance while Claude is working
setTimeout(() => stream.send('Use Express, not Fastify'), 5000);

for await (const event of stream) {
  if (event.type === 'text') process.stdout.write(event.text);
}

MCP Servers

Connect to any MCP server with shorthand strings or full config objects.

const runner = new Runner({
  mcp: {
    // Command string (auto-parsed)
    github: 'npx @modelcontextprotocol/server-github',

    // URL (HTTP/SSE server)
    docs: 'https://api.example.com/mcp',

    // Full config
    postgres: {
      command: 'npx',
      args: ['@modelcontextprotocol/server-postgres', process.env.DATABASE_URL!],
      env: { PGPASSWORD: process.env.PGPASSWORD! },
    },
  },
});

const result = await runner.run('How many users signed up last week?');

All MCP tools are auto-discovered and auto-allowed. Claude sees them and can use them immediately.

Custom Tools

Define tools that run in your process:

import { Runner, defineTool } from 'claude-runner';
import { z } from 'zod';

const weather = defineTool(
  'get_weather',
  'Get current weather for a city',
  { city: z.string() },
  async ({ city }) => ({
    content: [{ type: 'text', text: `72°F and sunny in ${city}` }],
  })
);

const runner = new Runner({ tools: [weather] });
const result = await runner.run('What is the weather in San Francisco?');

Permissions

Control what Claude can do:

// Auto-approve everything (for CI, sandboxed environments)
const runner = new Runner({ permissions: 'auto' });

// Deny unknown tools (safe default)
const runner = new Runner({ permissions: 'deny-unknown' });

// Interactive approval
const runner = new Runner({
  permissions: 'prompt',
  onPermission: async ({ tool, description }) => {
    return confirm(`Allow ${tool}? ${description}`);
  },
});

// Fine-grained policy
const runner = new Runner({
  permissions: {
    allow: ['Read', 'Glob', 'Grep', 'mcp__github__*'],
    deny: ['Bash(rm *)'],
    prompt: ['Bash', 'Write'],
  },
  onPermission: async (req) => confirm(`Allow ${req.tool}?`),
});

Sandbox (Coming Soon)

Run agents in isolated environments:

// E2B cloud sandbox
const runner = new Runner({ sandbox: 'e2b' });

// Docker container
const runner = new Runner({ sandbox: 'docker' });

// Custom spawner
const runner = new Runner({
  sandbox: (options) => myCustomSpawner(options),
});

Subagents

Define programmatic subagents:

const runner = new Runner({
  agents: {
    researcher: {
      description: 'Research agent for gathering information',
      prompt: 'You are a research assistant. Search thoroughly.',
      tools: ['Read', 'Glob', 'Grep', 'WebSearch'],
      model: 'haiku',
    },
    coder: {
      description: 'Coding agent for implementation',
      prompt: 'You are an expert programmer. Write clean code.',
      tools: ['Read', 'Write', 'Edit', 'Bash'],
      model: 'sonnet',
    },
  },
});

API Reference

Runner

class Runner {
  constructor(options?: RunnerOptions);

  run(prompt: string, overrides?: RunOverrides): Promise<RunResult>;
  stream(prompt: string, overrides?: RunOverrides): RunStream;
  resume(sessionId: string, prompt?: string): RunStream;

  get lastSessionId(): string | null;
  abort(): void;
}

RunResult

interface RunResult {
  text: string;            // Final response text
  sessionId: string;       // For resume
  cost: number;            // USD
  duration: number;        // ms
  usage: { input; output }; // Token counts
  turns: number;           // Agentic turns
  toolCalls: ToolCallSummary[];
  error?: string;
}

RunEvent (7 types)

TypeFieldsWhen
texttextEach streamed text chunk
tool_starttool, idTool execution begins
tool_endtool, id, durationTool execution ends
session_initsessionId, model, toolsSession initialized
mcp_statusserver, statusMCP server connected/failed
errormessage, code?Error occurred
doneresultRun complete

RunStream

interface RunStream extends AsyncIterable<RunEvent> {
  result: Promise<RunResult>;   // Await final result
  text: Promise<string>;        // Await full text
  send(message: string): void;  // Inject mid-stream message
  interrupt(): Promise<void>;   // Pause execution
  abort(): void;                // Stop completely
  sessionId: string | null;     // Current session ID
}

RunnerOptions

OptionTypeDefaultDescription
modelstring'claude-sonnet-4-6'Claude model (shorthands supported — see below)
cwdstringprocess.cwd()Working directory
systemPromptstring | { preset: 'claude_code' }minimalSystem prompt
mcpRecord<string, McpConfig | string>{}MCP servers
toolsToolDefinition[][]Custom tools
agentsRecord<string, AgentDefinition>Subagents
sandbox'local' | 'e2b' | 'docker' | SpawnFn'local'Execution environment
permissions'auto' | 'prompt' | 'deny-unknown' | PermissionPolicy'deny-unknown'Permission handling
onPermission(req) => Promise<boolean>Permission callback
maxTurnsnumberMax agentic turns
maxBudgetnumberMax cost in USD
effort'low' | 'medium' | 'high' | 'max'Effort level
sdkOptionsobjectPass-through to Agent SDK

Models

Use shorthand names or full model IDs:

// Shorthands
const runner = new Runner({ model: 'opus' });      // claude-opus-4-6
const runner = new Runner({ model: 'sonnet' });     // claude-sonnet-4-6
const runner = new Runner({ model: 'haiku' });      // claude-haiku-4-5

// Version-specific shorthands
const runner = new Runner({ model: 'opus-4.5' });   // claude-opus-4-5-20250918
const runner = new Runner({ model: 'sonnet-4.5' }); // claude-sonnet-4-5-20250514
const runner = new Runner({ model: 'opus-4.6' });   // claude-opus-4-6
const runner = new Runner({ model: 'sonnet-4.6' }); // claude-sonnet-4-6

// Full model IDs also work
const runner = new Runner({ model: 'claude-opus-4-6' });

// Per-run override
const result = await runner.run('Quick task', { model: 'haiku' });
ShorthandFull Model ID
opusclaude-opus-4-6
opus-4.6claude-opus-4-6
opus-4.5claude-opus-4-5-20250918
sonnetclaude-sonnet-4-6
sonnet-4.6claude-sonnet-4-6
sonnet-4.5claude-sonnet-4-5-20250514
haikuclaude-haiku-4-5-20251001
haiku-4.5claude-haiku-4-5-20251001

Runtime Support

claude-runner is runtime-agnostic. No framework lock-in.

  • Node.js 18+
  • Bun
  • Deno
  • Electron (for desktop apps)
  • Any cloud — AWS, GCP, Azure, self-hosted

How It Works

claude-runner is a thin wrapper (~500 lines) around the official @anthropic-ai/claude-agent-sdk. It:

  • Normalizes your options into the SDK's 40+ field Options object
  • Starts a query() session with MCP servers, permissions, and tools configured
  • Transforms the SDK's 20+ SDKMessage types into 7 flat RunEvent types
  • Manages session lifecycle (resume, multi-turn, abort)

You get the full power of Claude Code (skills, agents, tools, MCP) through a simple API.

License

MIT

Keywords

claude

FAQs

Package last updated on 08 Apr 2026

Related posts