@getdiff/sdk
v0.1.3
Published
Open source, model-agnostic reimplementation of the Claude Agent SDK. Same API, any model.
Maintainers
Readme
@getdiff/sdk
Open source, model-agnostic reimplementation of the Claude Agent SDK. Same API, any model.
// Before (Claude Agent SDK — Claude only)
import { query } from "@anthropic-ai/claude-agent-sdk";
// After (OpenAgent SDK — any model)
import { query } from "@getdiff/sdk";
for await (const message of query({
prompt: "Fix the auth bug",
options: {
provider: "anthropic", // or "openai", "google", "bedrock", "ollama", etc.
model: "claude-sonnet-4-6",
cwd: "/workspace",
},
})) {
if (message.type === "assistant") {
// Stream assistant responses
}
if (message.type === "result") {
console.log(`Done in ${message.numTurns} turns`);
}
}Why
The Claude Agent SDK is the foundation of the Claude Code product suite — skills, hooks, subagents, channels, and more all compose through its query() / AgentDefinition / streaming interface. But it only works with Claude.
GetDiff SDK gives you the same API with pluggable model providers. Swap one string, keep your code.
Features
- Same API —
query(),AgentDefinition,SDKMessage, streamingAsyncIterable - 11 providers — Anthropic, OpenAI, Google Gemini, AWS Bedrock, OpenRouter, Groq, Together, Fireworks, Ollama, and any OpenAI-compatible endpoint
- 11 built-in tools — Bash, Read, Write, Edit, Glob, Grep, WebFetch, WebSearch, AskUserQuestion, TodoWrite, NotebookEdit
- Subagents —
agentsconfig for spawning child agents, recursive delegation - Permissions — 5 modes (default, acceptEdits, plan, bypassPermissions, dontAsk) + allow/deny lists +
canUseToolcallback - Hooks — 11 lifecycle events, blocking/non-blocking, PreToolUse/PostToolUse/SessionStart/Stop
- Sessions — JSONL persistence, list/resume/rename/tag
- MCP servers — Connect to MCP servers via stdio, HTTP, or SSE; auto-discover tools
- Project instructions — Auto-loads CLAUDE.md, AGENTS.md, .cursorrules, .windsurfrules, and more
Install
npm install @getdiff/sdkProviders
Anthropic (Claude)
export ANTHROPIC_API_KEY=sk-ant-...const messages = query({
prompt: "Hello",
options: { provider: "anthropic", model: "claude-sonnet-4-6" },
});OpenAI (GPT)
export OPENAI_API_KEY=sk-...const messages = query({
prompt: "Hello",
options: { provider: "openai", model: "gpt-4o" },
});Tools
All 8 built-in tools are available by default. Restrict with tools:
query({
prompt: "Read the code",
options: {
tools: ["Read", "Glob", "Grep"], // Only these tools
// tools: "none", // No tools
},
});Tool safety features (inspired by OpenCode):
- Bash: banned commands, safe whitelist, output truncation at 30K chars, timeouts
- Edit: fails on ambiguous matches, requires exact string match
- All tools: permission checks before execution
Subagents
query({
prompt: "Review the code and fix any issues",
options: {
agents: {
reviewer: {
description: "Reviews code for issues",
prompt: "You review code for bugs and style issues.",
tools: ["Read", "Grep", "Glob"],
model: "haiku",
},
fixer: {
description: "Fixes code issues",
prompt: "You fix bugs identified by the reviewer.",
},
},
},
});Permissions
query({
prompt: "Refactor the auth module",
options: {
permissionMode: "acceptEdits", // Auto-approve file edits
disallowedTools: ["Bash"], // Block shell access
canUseTool: async (tool, input, ctx) => {
if (tool === "Write" && input.file_path?.toString().includes(".env")) {
return { behavior: "deny", message: "Cannot modify .env files" };
}
return { behavior: "allow" };
},
},
});Hooks
import { createHook, createToolBlocker } from "@getdiff/sdk";
query({
prompt: "Fix the bug",
options: {
hooks: {
PreToolUse: [
createToolBlocker("Bash", "Shell access disabled"),
],
PostToolUse: [
createHook(async (input) => ({
hookSpecificOutput: {
additionalContext: "Remember to run tests after editing.",
},
})),
],
UserPromptSubmit: [
createHook(async (input) => {
if (input.prompt.includes("DROP TABLE")) {
return { decision: "block", reason: "Dangerous prompt" };
}
return {};
}),
],
},
},
});Sessions
import { query, listSessions, renameSession } from "@getdiff/sdk";
// Sessions are auto-persisted
let sessionId;
for await (const msg of query({ prompt: "Start a task", options: { cwd: "/project" } })) {
if (msg.type === "result") sessionId = msg.sessionId;
}
// Resume later
for await (const msg of query({
prompt: "Continue where we left off",
options: { resume: sessionId, cwd: "/project" },
})) { ... }
// List and manage
const sessions = await listSessions({ directory: "/project" });
await renameSession(sessionId, "Auth refactor", "/project");MCP Servers
query({
prompt: "Query the staging database",
options: {
mcpServers: {
postgres: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-postgres"],
env: { DATABASE_URL: "postgresql://..." },
},
},
},
});MCP tools are namespaced: mcp__postgres__query, mcp__postgres__list_tables, etc.
Project Instructions
The SDK auto-loads project instructions from known locations:
| File | Provider |
|------|----------|
| .openagent/instructions.md | OpenAgent (highest priority) |
| CLAUDE.md | Claude |
| AGENTS.md | Codex |
| .cursorrules, .cursor/rules/*.mdc | Cursor |
| .windsurfrules, .windsurf/rules/*.md | Windsurf |
| .github/copilot-instructions.md | Copilot |
| .amazonq/rules/*.md | Amazon Q |
| CONVENTIONS.md | Aider |
Instructions are merged in priority order and injected as the system prompt (unless you provide an explicit systemPrompt).
License
MIT
