Trending-skills open-agent-sdk-typescript

```markdown

install
source · Clone the upstream repo
git clone https://github.com/Aradotso/trending-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Aradotso/trending-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/open-agent-sdk-typescript" ~/.claude/skills/aradotso-trending-skills-open-agent-sdk-typescript && rm -rf "$T"
manifest: skills/open-agent-sdk-typescript/SKILL.md
source content
---
name: open-agent-sdk-typescript
description: TypeScript SDK for running Claude-powered agent loops in-process without CLI dependencies
triggers:
  - use open agent sdk
  - run agent loop in typescript
  - claude agent without cli
  - open-agent-sdk setup
  - create ai agent typescript
  - agent sdk streaming query
  - mcp server integration typescript
  - subagent definition sdk
---

# Open Agent SDK (TypeScript)

> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection.

Open Agent SDK runs the full agentic loop **in-process** — no subprocess, no CLI wrapper. It's a drop-in open-source alternative to `claude-agent-sdk` that works in cloud, serverless, Docker, and CI/CD environments.

## Installation

```bash
npm install @codeany/open-agent-sdk

Required environment variable:

export CODEANY_API_KEY=your-api-key

Optional — use third-party providers (e.g. OpenRouter):

export CODEANY_BASE_URL=https://openrouter.ai/api
export CODEANY_API_KEY=sk-or-...
export CODEANY_MODEL=anthropic/claude-sonnet-4

Core Concepts

  • query()
    — one-shot streaming generator; yields
    SDKMessage
    objects
  • createAgent()
    — reusable agent with session persistence and multi-turn support
  • tool()
    /
    defineTool()
    — register custom tools (Zod or raw JSON schema)
  • createSdkMcpServer()
    — bundle tools as an in-process MCP server
  • getAllBaseTools()
    — returns all 34 built-in file/shell tools

Quick Start Patterns

Streaming one-shot query

import { query } from "@codeany/open-agent-sdk";

for await (const message of query({
  prompt: "Read package.json and tell me the project name.",
  options: {
    allowedTools: ["Read", "Glob"],
    permissionMode: "bypassPermissions",
  },
})) {
  if (message.type === "assistant") {
    for (const block of message.message.content) {
      if ("text" in block) console.log(block.text);
    }
  }
  if (message.type === "result") {
    console.log(`Cost: $${message.total_cost_usd?.toFixed(4)}`);
  }
}

Blocking prompt with
createAgent

import { createAgent } from "@codeany/open-agent-sdk";

const agent = createAgent({ model: "claude-sonnet-4-6" });
const result = await agent.prompt("What files are in this project?");

console.log(result.text);
console.log(`Turns: ${result.num_turns}`);
console.log(`Tokens: ${result.usage.input_tokens + result.usage.output_tokens}`);

Multi-turn conversation

import { createAgent } from "@codeany/open-agent-sdk";

const agent = createAgent({ maxTurns: 5 });

const r1 = await agent.prompt('Create a file /tmp/hello.txt with "Hello World"');
console.log(r1.text);

const r2 = await agent.prompt("Read back the file you just created");
console.log(r2.text);

console.log(`Session messages: ${agent.getMessages().length}`);

await agent.close(); // persists session, closes MCP connections

Custom Tools

With Zod schema (recommended)

import { z } from "zod";
import { query, tool, createSdkMcpServer } from "@codeany/open-agent-sdk";

const getWeather = tool(
  "get_weather",
  "Get the temperature for a city",
  { city: z.string().describe("City name") },
  async ({ city }) => ({
    content: [{ type: "text", text: `${city}: 22°C, sunny` }],
  }),
);

const server = createSdkMcpServer({ name: "weather", tools: [getWeather] });

for await (const msg of query({
  prompt: "What is the weather in Tokyo and London?",
  options: { mcpServers: { weather: server } },
})) {
  if (msg.type === "result") console.log(`Done: $${msg.total_cost_usd?.toFixed(4)}`);
}

Low-level tool with
defineTool

import { createAgent, getAllBaseTools, defineTool } from "@codeany/open-agent-sdk";

const calculator = defineTool({
  name: "Calculator",
  description: "Evaluate a math expression",
  inputSchema: {
    type: "object",
    properties: { expression: { type: "string" } },
    required: ["expression"],
  },
  isReadOnly: true,
  async call(input) {
    const result = Function(`'use strict'; return (${input.expression})`)();
    return `${input.expression} = ${result}`;
  },
});

const agent = createAgent({ tools: [...getAllBaseTools(), calculator] });
const r = await agent.prompt("Calculate 2**10 * 3");
console.log(r.text);

MCP Server Integration

import { createAgent } from "@codeany/open-agent-sdk";

const agent = createAgent({
  mcpServers: {
    filesystem: {
      command: "npx",
      args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
    },
    github: {
      command: "npx",
      args: ["-y", "@modelcontextprotocol/server-github"],
      env: { GITHUB_TOKEN: process.env.GITHUB_TOKEN! },
    },
  },
});

const result = await agent.prompt("List files in /tmp");
console.log(result.text);
await agent.close();

Subagents

import { query } from "@codeany/open-agent-sdk";

for await (const msg of query({
  prompt: "Use the code-reviewer agent to review src/index.ts",
  options: {
    agents: {
      "code-reviewer": {
        description: "Expert code reviewer",
        prompt: "Analyze code quality. Focus on security and performance.",
        tools: ["Read", "Glob", "Grep"],
      },
    },
  },
})) {
  if (msg.type === "assistant") {
    for (const block of msg.message.content) {
      if ("text" in block) process.stdout.write(block.text);
    }
  }
}

Permission Modes

ModeBehavior
bypassPermissions
All tools allowed without prompting (default)
acceptEdits
Auto-accept file edits, prompt for others
dontAsk
Silently skip disallowed tools
default
Prompt user for each sensitive operation
plan
Plan only, no writes
// Read-only analysis agent
for await (const msg of query({
  prompt: "Review src/ for security issues.",
  options: {
    allowedTools: ["Read", "Glob", "Grep"],
    permissionMode: "dontAsk",
  },
})) { /* ... */ }

// Custom permission callback
const agent = createAgent({
  canUseTool: async (tool, input) => {
    if (tool.name === "Write") return { granted: false, reason: "Read-only mode" };
    return { granted: true };
  },
});

Session Management

import {
  createAgent,
  listSessions,
  getSessionMessages,
  forkSession,
} from "@codeany/open-agent-sdk";

// Resume a previous session
const agent = createAgent({ resume: "session-id-here" });

// Continue most recent session
const agent2 = createAgent({ continue: true });

// List all persisted sessions
const sessions = await listSessions();

// Retrieve messages from a session
const messages = await getSessionMessages("session-id");

// Fork a session for branching experiments
const forkedId = await forkSession("session-id");

// Disable persistence
const ephemeral = createAgent({ persistSession: false });

Structured Output

import { createAgent } from "@codeany/open-agent-sdk";

const agent = createAgent({
  outputFormat: {
    type: "json_schema",
    schema: {
      type: "object",
      properties: {
        summary: { type: "string" },
        issues: { type: "array", items: { type: "string" } },
        severity: { type: "string", enum: ["low", "medium", "high"] },
      },
      required: ["summary", "issues", "severity"],
    },
  },
});

const result = await agent.prompt("Review src/auth.ts for security issues");
const parsed = JSON.parse(result.text);
console.log(parsed.severity, parsed.issues);

Lifecycle Hooks

import { createAgent } from "@codeany/open-agent-sdk";

const agent = createAgent({
  hooks: {
    preToolCall: [
      {
        matcher: { toolName: "Write" },
        callback: async (tool, input) => {
          console.log(`Writing to: ${input.path}`);
        },
      },
    ],
    postToolCall: [
      {
        matcher: { toolName: "*" },
        callback: async (tool, input, output) => {
          console.log(`Tool ${tool.name} completed`);
        },
      },
    ],
  },
});

Agent Methods Reference

const agent = createAgent({ maxTurns: 10, model: "claude-sonnet-4-6" });

// Streaming
for await (const msg of agent.query("Explain this codebase")) { /* ... */ }

// Blocking
const result = await agent.prompt("Write tests for utils.ts");

// Session control
agent.getMessages();           // full conversation history
agent.clear();                 // reset session
agent.interrupt();             // abort current query
agent.setModel("claude-opus-4");
agent.setPermissionMode("dontAsk");
await agent.close();           // persist + cleanup

Key Options

createAgent({
  model: "claude-sonnet-4-6",          // LLM model
  apiKey: process.env.CODEANY_API_KEY, // or set env var
  baseURL: process.env.CODEANY_BASE_URL,
  cwd: "/path/to/project",             // working directory
  systemPrompt: "You are a...",        // override system prompt
  appendSystemPrompt: "Always...",     // append to default
  maxTurns: 10,
  maxBudgetUsd: 0.50,                  // spending cap
  thinking: { type: "adaptive" },      // extended thinking
  effort: "high",                      // low | medium | high | max
  env: { MY_VAR: "value" },            // env vars for tools
  abortController: new AbortController(),
});

Web UI (Testing)

npx tsx examples/web/server.ts
# Open http://localhost:8081

SDKMessage Types

// Message types yielded by query() and agent.query()
type SDKMessage =
  | { type: "assistant"; message: { content: ContentBlock[] } }
  | { type: "user"; message: { content: ContentBlock[] } }
  | { type: "result"; total_cost_usd?: number; usage: Usage }
  | { type: "system"; subtype: string; [key: string]: unknown };

// Check for text content
if (message.type === "assistant") {
  for (const block of message.message.content) {
    if ("text" in block) console.log(block.text);
    if (block.type === "tool_use") console.log(`Using: ${block.name}`);
  }
}

Troubleshooting

Error: CODEANY_API_KEY is not set
→ Export the env var:
export CODEANY_API_KEY=your-key

Agent runs too many turns / hits limit → Increase

maxTurns
or check if the task is resolvable with given
allowedTools

MCP server not connecting → Ensure the MCP server binary is installed (

npx -y @modelcontextprotocol/server-*
), call
await agent.close()
to clean up

Tools not available → By default all 34 built-in tools are available; if you pass

tools: [...]
it replaces them. Use
[...getAllBaseTools(), myTool]
to extend

Session not persisting → Confirm

persistSession: true
(default) and that
agent.close()
is awaited

Custom base URL with OpenRouter → Set

CODEANY_BASE_URL=https://openrouter.ai/api
and
CODEANY_MODEL=anthropic/claude-sonnet-4
alongside your OpenRouter API key