Open-source Agent SDK that runs the full agent loop in-process — no subprocess or CLI required. Supports both Anthropic and OpenAI-compatible APIs. Deploy anywhere: cloud, serverless, Docker, CI/CD.
Also available in Go: open-agent-sdk-go
npm install @codeany/open-agent-sdk
Set your API key:
export CODEANY_API_KEY=your-api-key
Works with OpenAI, DeepSeek, Qwen, Mistral, or any OpenAI-compatible endpoint:
export CODEANY_API_TYPE=openai-completions
export CODEANY_API_KEY=sk-...
export CODEANY_BASE_URL=https://api.openai.com/v1
export CODEANY_MODEL=gpt-4o
export CODEANY_BASE_URL=https://openrouter.ai/api
export CODEANY_API_KEY=sk-or-...
export CODEANY_MODEL=anthropic/claude-sonnet-4
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);
}
}
}
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}, Tokens: ${result.usage.input_tokens + result.usage.output_tokens}`,
);
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent({
apiType: "openai-completions",
model: "gpt-4o",
apiKey: "sk-...",
baseURL: "https://api.openai.com/v1",
});
const result = await agent.prompt("What files are in this project?");
console.log(result.text);
The apiType is auto-detected from model name — models containing gpt-, o1, o3, deepseek, qwen, mistral, etc. automatically use openai-completions.
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}`);
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?",
options: { mcpServers: { weather: server } },
})) {
if (msg.type === "result")
console.log(`Done: $${msg.total_cost_usd?.toFixed(4)}`);
}
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);
Skills are reusable prompt templates that extend agent capabilities. Five bundled skills are included: simplify, commit, review, debug, test.
import {
createAgent,
registerSkill,
getAllSkills,
} from "@codeany/open-agent-sdk";
// Register a custom skill
registerSkill({
name: "explain",
description: "Explain a concept in simple terms",
userInvocable: true,
async getPrompt(args) {
return [
{
type: "text",
text: `Explain in simple terms: ${args || "Ask what to explain."}`,
},
];
},
});
console.log(`${getAllSkills().length} skills registered`);
// The model can invoke skills via the Skill tool
const agent = createAgent();
const result = await agent.prompt('Use the "explain" skill to explain git rebase');
console.log(result.text);
import { createAgent, createHookRegistry } from "@codeany/open-agent-sdk";
const hooks = createHookRegistry({
PreToolUse: [
{
handler: async (input) => {
console.log(`About to use: ${input.toolName}`);
// Return { block: true } to prevent tool execution
},
},
],
PostToolUse: [
{
handler: async (input) => {
console.log(`Tool ${input.toolName} completed`);
},
},
],
});
20 lifecycle events: PreToolUse, PostToolUse, PostToolUseFailure, SessionStart, SessionEnd, Stop, SubagentStart, SubagentStop, UserPromptSubmit, PermissionRequest, PermissionDenied, TaskCreated, TaskCompleted, ConfigChange, CwdChanged, FileChanged, Notification, PreCompact, PostCompact, TeammateIdle.
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent({
mcpServers: {
filesystem: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
},
},
});
const result = await agent.prompt("List files in /tmp");
console.log(result.text);
await agent.close();
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 === "result") console.log("Done");
}
import { query } from "@codeany/open-agent-sdk";
// Read-only agent — can only analyze, not modify
for await (const msg of query({
prompt: "Review the code in src/ for best practices.",
options: {
allowedTools: ["Read", "Glob", "Grep"],
permissionMode: "dontAsk",
},
})) {
// ...
}
A built-in web chat interface is included for testing:
npx tsx examples/web/server.ts
# Open http://localhost:8081
| Function | Description |
|---|---|
query({ prompt, options }) |
One-shot streaming query, returns AsyncGenerator<SDKMessage> |
createAgent(options) |
Create a reusable agent with session persistence |
tool(name, desc, schema, handler) |
Create a tool with Zod schema validation |
createSdkMcpServer({ name, tools }) |
Bundle tools into an in-process MCP server |
defineTool(config) |
Low-level tool definition helper |
getAllBaseTools() |
Get all 35+ built-in tools |
registerSkill(definition) |
Register a custom skill |
getAllSkills() |
Get all registered skills |
createProvider(apiType, opts) |
Create an LLM provider directly |
createHookRegistry(config) |
Create a hook registry for lifecycle events |
listSessions() |
List persisted sessions |
forkSession(id) |
Fork a session for branching |
| Method | Description |
|---|---|
agent.query(prompt) |
Streaming query, returns AsyncGenerator<SDKMessage> |
agent.prompt(text) |
Blocking query, returns Promise<QueryResult> |
agent.getMessages() |
Get conversation history |
agent.clear() |
Reset session |
agent.interrupt() |
Abort current query |
agent.setModel(model) |
Change model mid-session |
agent.setPermissionMode(mode) |
Change permission mode |
agent.getApiType() |
Get current API type |
agent.close() |
Close MCP connections, persist session |
| Option | Type | Default | Description |
|---|---|---|---|
apiType |
string |
auto-detected | 'anthropic-messages' or 'openai-completions' |
model |
string |
claude-sonnet-4-6 |
LLM model ID |
apiKey |
string |
CODEANY_API_KEY |
API key |
baseURL |
string |
— | Custom API endpoint |
cwd |
string |
process.cwd() |
Working directory |
systemPrompt |
string |
— | System prompt override |
appendSystemPrompt |
string |
— | Append to default system prompt |
tools |
ToolDefinition[] |
All built-in | Available tools |
allowedTools |
string[] |
— | Tool allow-list |
disallowedTools |
string[] |
— | Tool deny-list |
permissionMode |
string |
bypassPermissions |
default / acceptEdits / dontAsk / bypassPermissions / plan |
canUseTool |
function |
— | Custom permission callback |
maxTurns |
number |
10 |
Max agentic turns |
maxBudgetUsd |
number |
— | Spending cap |
thinking |
ThinkingConfig |
{ type: 'adaptive' } |
Extended thinking |
effort |
string |
high |
Reasoning effort: low / medium / high / max |
mcpServers |
Record<string, McpServerConfig> |
— | MCP server connections |
agents |
Record<string, AgentDefinition> |
— | Subagent definitions |
hooks |
Record<string, HookCallbackMatcher[]> |
— | Lifecycle hooks |
resume |
string |
— | Resume session by ID |
continue |
boolean |
false |
Continue most recent session |
persistSession |
boolean |
true |
Persist session to disk |
sessionId |
string |
auto | Explicit session ID |
$ claude mcp add open-agent-sdk-typescript \
-- python -m otcore.mcp_server <graph>