Trending-skills open-agent-sdk
Build and deploy autonomous AI agents in-process using Open Agent SDK, an open-source alternative to @anthropic-ai/claude-agent-sdk that works anywhere without CLI dependencies.
git clone https://github.com/Aradotso/trending-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" ~/.claude/skills/aradotso-trending-skills-open-agent-sdk && rm -rf "$T"
skills/open-agent-sdk/SKILL.mdOpen Agent SDK
Skill by ara.so — Daily 2026 Skills collection.
Open Agent SDK (
@shipany/open-agent-sdk) is a fully open-source, in-process AI agent framework for TypeScript/Node.js. It runs the complete Claude Code agent engine directly — no local CLI subprocess required — making it suitable for cloud servers, serverless functions, Docker containers, and CI/CD pipelines. It is API-compatible with @anthropic-ai/claude-agent-sdk.
Installation
npm install @shipany/open-agent-sdk
Requires Node.js 18+.
Authentication & Configuration
Set the Anthropic API key as an environment variable:
export ANTHROPIC_API_KEY=your-api-key
Or use a third-party provider (e.g. OpenRouter):
export ANTHROPIC_BASE_URL=https://openrouter.ai/api export ANTHROPIC_API_KEY=your-openrouter-key export ANTHROPIC_MODEL=anthropic/claude-sonnet-4-6
These can also be passed programmatically via
options.env or apiKey/baseURL in createAgent().
Core API
query({ prompt, options })
— Streaming, compatible with official SDK
query({ prompt, options })Returns an
AsyncGenerator<SDKMessage>. Drop-in replacement for @anthropic-ai/claude-agent-sdk.
import { query } from '@shipany/open-agent-sdk' for await (const message of query({ prompt: 'Find and fix the bug in auth.ts', options: { allowedTools: ['Read', 'Edit', 'Bash'], permissionMode: 'acceptEdits', }, })) { if (message.type === 'assistant' && message.message?.content) { for (const block of message.message.content) { if ('text' in block) process.stdout.write(block.text) else if ('name' in block) console.log(`\n[Tool used: ${block.name}]`) } } else if (message.type === 'result') { console.log(`\nDone: ${message.subtype}`) } }
createAgent(options)
— Reusable agent with session state
createAgent(options)import { createAgent } from '@shipany/open-agent-sdk' const agent = createAgent({ model: 'claude-sonnet-4-6', systemPrompt: 'You are a senior TypeScript engineer. Be concise.', maxTurns: 20, }) // Blocking call const result = await agent.prompt('Read package.json and describe the project') console.log(result.text) console.log(`Tokens used: ${result.usage.input_tokens + result.usage.output_tokens}`) // Streaming call for await (const msg of agent.query('Now add JSDoc to all exported functions')) { if (msg.type === 'assistant' && msg.message?.content) { for (const block of msg.message.content) { if ('text' in block) process.stdout.write(block.text) } } } // Session management const history = agent.getMessages() // full conversation history agent.clear() // reset session
Options Reference
| Option | Type | Default | Description |
|---|---|---|---|
| | | Claude model ID |
| | env | API key |
| | Anthropic API | Override for third-party providers |
| | | Working directory for file/shell tools |
| | — | Custom system prompt prepended to agent |
| | All built-in | Override the full tool list |
| | all | Whitelist specific tools by name |
| | | , , , |
| | | Maximum agentic loop iterations |
| | — | Spend cap in USD |
| | — | MCP server configs (stdio/SSE/HTTP) |
| | — | Named subagent definitions |
| | — | Lifecycle hooks: , , |
| | — | Extended thinking config |
| | — | Environment variables passed to tools |
| | — | Resume prior session by session ID |
| | — | Custom permission callback |
| | | Emit raw streaming events |
Common Patterns
Multi-turn conversation with context
import { createAgent } from '@shipany/open-agent-sdk' const agent = createAgent({ model: 'claude-sonnet-4-6' }) const r1 = await agent.prompt('Read src/index.ts and explain the architecture') console.log(r1.text) // Context from r1 is preserved automatically const r2 = await agent.prompt('Refactor the error handling to use a Result type') console.log(r2.text)
Restrict to read-only tools
import { query } from '@shipany/open-agent-sdk' for await (const message of query({ prompt: 'Review this codebase for security issues', options: { allowedTools: ['Read', 'Glob', 'Grep'], // No Write, Edit, or Bash — agent cannot modify files }, })) { if (message.type === 'result') console.log('Review complete') }
Custom tools
import { createAgent, getAllBaseTools } from '@shipany/open-agent-sdk' const dbQueryTool = { name: 'QueryDatabase', description: 'Run a read-only SQL query and return results as JSON', inputJSONSchema: { type: 'object', properties: { sql: { type: 'string', description: 'The SQL query to run' }, }, required: ['sql'], }, get inputSchema() { return { safeParse: (v: unknown) => ({ success: true, data: v }) } }, async prompt() { return this.description }, async call(input: { sql: string }) { // Replace with your actual DB client const rows = [{ id: 1, name: 'Example' }] return { data: JSON.stringify(rows) } }, userFacingName: () => 'QueryDatabase', isReadOnly: () => true, isConcurrencySafe: () => true, mapToolResultToToolResultBlockParam: (data: string, id: string) => ({ type: 'tool_result' as const, tool_use_id: id, content: data, }), } const agent = createAgent({ tools: [...getAllBaseTools(), dbQueryTool], }) const result = await agent.prompt('How many users signed up in the last 7 days?') console.log(result.text)
MCP server integration
import { createAgent } from '@shipany/open-agent-sdk' const agent = createAgent({ mcpServers: { filesystem: { command: 'npx', args: ['-y', '@modelcontextprotocol/server-filesystem', '/tmp'], }, playwright: { command: 'npx', args: ['@playwright/mcp@latest'], }, }, }) const result = await agent.prompt('List all .json files in /tmp') console.log(result.text)
Subagents for parallel / delegated work
import { query } from '@shipany/open-agent-sdk' for await (const message of query({ prompt: 'Use the security-auditor agent to audit src/ for vulnerabilities', options: { allowedTools: ['Read', 'Glob', 'Grep', 'Agent'], agents: { 'security-auditor': { description: 'Expert security auditor for TypeScript codebases.', prompt: 'Identify OWASP Top 10 vulnerabilities and suggest fixes.', tools: ['Read', 'Glob', 'Grep'], }, }, }, })) { if (message.type === 'assistant' && message.message?.content) { for (const block of message.message.content) { if ('text' in block) console.log(block.text) } } }
Custom permission callback
import { createAgent } from '@shipany/open-agent-sdk' const agent = createAgent({ canUseTool: (toolName: string, input: unknown) => { // Prevent deletion commands if (toolName === 'Bash') { const cmd = (input as { command?: string }).command ?? '' if (cmd.includes('rm ') || cmd.includes('drop table')) return false } return true }, })
Lifecycle hooks
import { createAgent } from '@shipany/open-agent-sdk' const agent = createAgent({ hooks: { PreToolUse: async ({ tool, input }) => { console.log(`About to run tool: ${tool} with input:`, input) }, PostToolUse: async ({ tool, output }) => { console.log(`Tool ${tool} finished`) }, Stop: async ({ result }) => { console.log('Agent stopped. Final result:', result) }, }, })
Resume a previous session
import { createAgent } from '@shipany/open-agent-sdk' // First session const agent1 = createAgent({ model: 'claude-sonnet-4-6' }) const r1 = await agent1.prompt('Read ARCHITECTURE.md') const sessionId = r1.sessionId // save this // Later — resume where you left off const agent2 = createAgent({ model: 'claude-sonnet-4-6', resume: sessionId, }) const r2 = await agent2.prompt('Now implement the TODO in section 3')
Built-in Tools Reference
| Tool | Read-only | Description |
|---|---|---|
| ✅ | Read files, images, PDFs with line numbers |
| ✅ | Find files by glob pattern |
| ✅ | Search file contents with regex (uses ripgrep) |
| ✅ | Fetch and parse web pages |
| ✅ | Web search |
| ❌ | Create or overwrite files |
| ❌ | Precise string replacement in files |
| ❌ | Execute shell commands |
| — | Spawn subagents |
| ❌ | Manage todo lists |
| ❌ | Edit Jupyter notebooks |
| — | Task management |
| — | Agent team management |
| — | Plan approval workflow |
| — | Git worktree isolation |
| ✅ | MCP resource access |
Architecture: How It Differs from Official SDK
Official
:@anthropic-ai/claude-agent-sdk
Your code → SDK → spawn cli.js subprocess → stdin/stdout JSON → Anthropic API
Open Agent SDK:
Your code → SDK → QueryEngine (in-process) → Anthropic API (direct HTTP)
This means:
- No CLI installation required in the deployment environment
- Works in serverless (AWS Lambda, Vercel, Cloudflare Workers with Node.js compat)
- Works in Docker with just
npm install - Works in CI/CD without CLI setup steps
- Programmatic access to the full agent engine
Troubleshooting
→ Export the env var or pass Error: ANTHROPIC_API_KEY is not set
apiKey directly in createAgent({ apiKey: process.env.MY_KEY }).
Agent exceeds
without completing
→ Increase maxTurns
maxTurns or narrow the task. Check message.subtype === 'max_turns' in the result.
Tool not found /
not working
→ Tool names are case-sensitive: allowedTools
'Read', 'Edit', 'Bash', 'Glob', 'Grep', 'WebFetch', etc.
Using with OpenRouter or other providers → Set
ANTHROPIC_BASE_URL to the provider's base URL and use their model string format, e.g. anthropic/claude-sonnet-4-6 for OpenRouter.
Agent modifies files unexpectedly → Use
allowedTools: ['Read', 'Glob', 'Grep'] to restrict to read-only tools, or set permissionMode: 'plan' to require approval before edits.
MCP server fails to start → Ensure the MCP server package is installed or accessible via
npx. Check command and args match what the MCP package expects.
TypeScript types missing → The package ships its own types. Ensure
"moduleResolution": "bundler" or "node16" in tsconfig.json and "esModuleInterop": true.
Quick Reference
// Minimal one-shot agent import { createAgent } from '@shipany/open-agent-sdk' const agent = createAgent({ model: 'claude-sonnet-4-6' }) const { text } = await agent.prompt('Summarize README.md in 3 bullet points') console.log(text)