agent-wrapper-sdk
v0.1.0
Published
TypeScript wrapper around @anthropic-ai/claude-agent-sdk with progressive disclosure API
Maintainers
Readme
agent-wrapper-sdk
A TypeScript wrapper around @anthropic-ai/claude-agent-sdk that provides a progressive disclosure API — start with a one-liner, scale to full expert control.
import { agent } from "agent-wrapper-sdk";
const result = await agent("Review this codebase for security issues");
if (result.ok) {
console.log(result.result);
}Why?
The official claude-agent-sdk is powerful but low-level. This wrapper adds:
- Progressive disclosure — 4 levels from zero-config to full control
- Fluent builder —
Agent.builder().model("opus").tools([...]).run("prompt") - Result pattern — typed
{ ok: true, result } | { ok: false, error }, never throws - Tool tiers — classify tools as
observe/confirm/dangerous - Hook middleware — composable
HookChainwith presets for logging, security, audit - Skill system — multi-format parser (Claude Code, Cursor, Amp, Codex, YAML, JSON, Markdown, Raw)
- Session management — create, resume, fork conversations via
SessionHandle - Subagent factory — scoped child agents with capability restrictions
- Store interface — persist sessions and events (in-memory or file-based)
- 100% SDK coverage — every feature accessible, with escape hatches to raw SDK
Installation
# Bun (recommended)
bun add agent-wrapper-sdk @anthropic-ai/claude-agent-sdk
# npm
npm install agent-wrapper-sdk @anthropic-ai/claude-agent-sdk
# pnpm
pnpm add agent-wrapper-sdk @anthropic-ai/claude-agent-sdk
@anthropic-ai/claude-agent-sdkis a peer dependency — you must install it alongside this package.
Set your API key:
export ANTHROPIC_API_KEY=sk-ant-...
# Or use OAuth token:
export CLAUDE_CODE_OAUTH_TOKEN=...Quick Start
Level 1: One-liner
import { agent } from "agent-wrapper-sdk";
const result = await agent("What files are in this directory?");
if (result.ok) {
console.log(result.result);
console.log(`Cost: $${result.usage.cost}`);
}Level 2: Builder Pattern
import { Agent } from "agent-wrapper-sdk";
const result = await Agent.builder()
.model("sonnet")
.tools(["Read", "Glob", "Grep"])
.permission("acceptEdits")
.maxTurns(10)
.run("Analyze the project architecture");Level 3: Custom Tools & Hooks
import { Agent, defineTool, logging } from "agent-wrapper-sdk";
import { z } from "zod";
const weatherTool = defineTool({
name: "get_weather",
description: "Get weather for a city",
schema: z.object({ city: z.string() }),
handler: async ({ city }) => ({
content: [{ type: "text", text: `Weather in ${city}: 25°C, sunny` }],
}),
tier: "observe",
});
const result = await Agent.builder()
.model("opus")
.addTool(weatherTool)
.use(logging())
.run("What's the weather in Bangkok?");Level 4: Full Power
import { Agent, HookChain, logging, tierBased, InMemoryStore } from "agent-wrapper-sdk";
const store = new InMemoryStore();
const hooks = new HookChain();
hooks.merge(logging());
hooks.merge(tierBased());
const agent = Agent.builder()
.model("opus")
.systemPrompt("You are a senior code reviewer.")
.tools(["Read", "Write", "Edit", "Glob", "Grep"])
.allowedTools(["Read", "Glob", "Grep"])
.disallowedTools(["Bash"])
.permission("acceptEdits")
.use(hooks)
.thinking({ type: "enabled", budgetTokens: 10000 })
.maxTurns(30)
.maxBudget(2.0)
.sandbox({ network: { allowedDomains: ["api.github.com"] } })
.fileCheckpointing(true)
.store(store)
.build();
// Streaming
for await (const event of agent.stream("Review all files in src/")) {
if (event.type === "text") {
process.stdout.write(event.text);
}
}Core Concepts
Result Pattern
Every execution returns an AgentResult<T> — a discriminated union that never throws:
type AgentResult<T> = AgentSuccess<T> | AgentFailure;
// AgentSuccess: ok=true, result, sessionId, usage, duration, durationApi, turns,
// structuredOutput?, stopReason, permissionDenials, modelUsage
// AgentFailure: ok=false, error (typed), partialResult?, sessionId?, usage,
// duration, permissionDenialsError types are exhaustive:
type AgentError =
| { type: "max_turns"; turns: number; limit: number; errors: string[] }
| { type: "max_budget"; spent: number; limit: number; errors: string[] }
| { type: "execution_error"; errors: string[] }
| { type: "auth_failed"; message: string }
| { type: "billing_error"; message: string }
| { type: "rate_limit"; retryAfter?: number }
| { type: "invalid_request"; message: string }
| { type: "server_error"; message: string }
| { type: "max_output_tokens"; message: string }
| { type: "interrupted" }
| { type: "aborted" }
| { type: "unknown"; message: string }Model Shortcuts
Use convenient aliases instead of full model names:
| Shortcut | Resolves To |
|----------|-------------|
| "opus" | claude-opus-4-6 |
| "sonnet" | claude-sonnet-4-6 |
| "haiku" | claude-haiku-4-5 |
Or pass any full model string directly.
Tool Tiers
Tools are classified by risk level for automatic permission management:
| Tier | Risk | Examples | Default Behavior |
|------|------|----------|-----------------|
| observe | Safe, read-only | Read, Glob, Grep, WebSearch | Auto-allow |
| confirm | Side-effects | Write, Edit, NotebookEdit | Ask user |
| dangerous | Destructive | Bash | Deny by default |
import { defineTool } from "agent-wrapper-sdk";
const myTool = defineTool({
name: "deploy",
description: "Deploy the app",
tier: "dangerous",
schema: z.object({ env: z.enum(["staging", "production"]) }),
handler: async ({ env }) => { /* ... */ },
});Modules
The package provides 14 importable modules via sub-path exports:
Tools — agent-wrapper-sdk/tools
Define, register, and manage custom tools with type-safe Zod schemas.
import { defineTool, ToolRegistry, DEFAULT_TOOL_TIERS } from "agent-wrapper-sdk/tools";
const registry = new ToolRegistry();
registry.register(myTool);
console.log(registry.names()); // ["my-tool"]
console.log(registry.size); // 1
console.log(registry.has("my-tool")); // trueEvents — agent-wrapper-sdk/events
25+ typed events with monotonic sequence envelopes.
import { TypedEventBus, EnvelopeFactory } from "agent-wrapper-sdk/events";
const bus = new TypedEventBus();
bus.on("text", (event) => process.stdout.write(event.text));
bus.on("tool_start", (event) => console.log(`Tool: ${event.toolName}`));
bus.on("done", (event) => console.log(`Done: ${event.totalTurns} turns`));
bus.once("error", (event) => console.error(event.error));
console.log(bus.listenerCount("text")); // 1
bus.clear();
const envelope = new EnvelopeFactory("session-id");
const env = envelope.next(); // { id, seq, timestamp, sessionId }Event types: text, text_delta, thinking, thinking_delta, tool_start, tool_end, tool_progress, tool_input_delta, tool_use_summary, turn_complete, done, error, session_init, status, auth_status, compacted, files_persisted, task_started, task_progress, task_completed, hook_started, hook_progress, hook_response, rate_limit, prompt_suggestion, raw
Hooks — agent-wrapper-sdk/hooks
Middleware chain for intercepting 18 agent lifecycle events.
import { HookChain, logging, tierBased, auditLog, allowAll } from "agent-wrapper-sdk/hooks";
const hooks = new HookChain();
hooks.merge(logging()); // Console log all tool usage
hooks.merge(tierBased()); // Allow/deny based on tool tiers
// Custom hook handler
hooks.add("PreToolUse", async (input) => {
console.log(`Tool: ${input.toolName}`);
return { decision: "allow" };
});
// Use with builder
Agent.builder().use(hooks).build();Hook events: PreToolUse, PostToolUse, PostToolUseFailure, Notification, UserPromptSubmit, SessionStart, SessionEnd, Stop, SubagentStart, SubagentStop, PreCompact, PermissionRequest, Setup, TeammateIdle, TaskCompleted, ConfigChange, WorktreeCreate, WorktreeRemove
Built-in presets:
logging()— Console log all tool usage (Pre+PostToolUse)tierBased()— Route Bash to confirm tierallowAll()— Bypass all permission checksauditLog(path)— Write tool usage audit trail to JSONL file
Permissions — agent-wrapper-sdk/permissions
Fine-grained tool access control.
import { TierPolicy, PermissionManager } from "agent-wrapper-sdk/permissions";
// TierPolicy presets
const policy = TierPolicy.default(); // observe=allow, confirm=ask, dangerous=deny
const lax = TierPolicy.permissive(); // everything allowed
const tight = TierPolicy.strict(); // only observe allowed
// PermissionManager with block/allow sets
const manager = new PermissionManager({
mode: "default",
allowedTools: new Set(["Read", "Glob", "Grep"]),
blockedTools: new Set(["Bash"]),
});
manager.check("Read"); // → "allow"
manager.check("Bash"); // → "deny" (blocked has priority)
manager.check("Write"); // → "ask" (falls through to tier policy)Sessions — agent-wrapper-sdk/sessions
Multi-turn conversations with SessionHandle.
import { Agent, SessionHandle } from "agent-wrapper-sdk";
const agent = Agent.builder()
.model("sonnet")
.permission("acceptEdits")
.maxTurns(5)
.build();
const handle = new SessionHandle(agent);
await handle.run("Analyze this codebase");
await handle.continue("Now refactor the auth module");
await handle.continue("Add tests for the changes");
console.log(handle.sessionId); // UUID from first runSkills — agent-wrapper-sdk/skills
Load and parse skill definitions from 8 different formats.
import { SkillParser, SkillLoader, codingStandards, testing, securityReview } from "agent-wrapper-sdk/skills";
// Parse any format — auto-detected
const skill = SkillParser.parse("# TypeScript Expert\nSpecializes in TS.\n## Rules\n...");
const jsonSkill = SkillParser.parse('{"name":"test","instructions":"..."}');
const detected = SkillParser.detectFormat(content); // → "json" | "yaml" | "claude-code" | ...
// Load from filesystem
const loaded = await SkillLoader.fromDir("./skills/deploy");
const all = await SkillLoader.discover("./skills"); // All subdirs
// Built-in presets
const coding = codingStandards(); // TypeScript best practices
const tests = testing(); // Testing guidelines
const security = securityReview(); // Security checklistSupported formats: Claude Code (# headings), Cursor (.cursorrules), Amp, Codex, YAML, Markdown (with frontmatter), JSON, Raw text
Subagents — agent-wrapper-sdk/subagents
Create scoped child agents with capability restrictions.
import { SubagentFactory, explorer, reviewer, coder, researcher } from "agent-wrapper-sdk/subagents";
// Factory (instance methods)
const factory = new SubagentFactory();
const readOnly = factory.readOnly({ description: "Reader", prompt: "Read code", model: "haiku" });
const full = factory.fullAccess({ description: "Writer", prompt: "Write code", model: "sonnet" });
const scoped = factory.scoped({
description: "Scoped worker",
prompt: "Work in scope",
model: "haiku",
tools: ["Read", "Grep"],
disallowedTools: ["Bash"],
});
// Presets — ready-to-use configs
const exp = explorer(); // Fast, read-only exploration
const rev = reviewer(); // Code review specialist
const cod = coder(); // Full write access
const res = researcher(); // Research specialist
// Use with builder
Agent.builder()
.subagent("explorer", explorer())
.subagent("reviewer", reviewer())
.build();Sandbox — agent-wrapper-sdk/sandbox
Configure network and filesystem restrictions.
import { sandboxStrict, sandboxPermissive, sandboxNetworkOnly } from "agent-wrapper-sdk";
const s = sandboxStrict(); // No bash, no unsandboxed, managed network only
const p = sandboxPermissive(); // Full access, all allowed
const n = sandboxNetworkOnly(["api.github.com"]); // Only specific domains
// Full custom config
const custom = {
enabled: true,
autoAllowBash: false,
network: {
allowedDomains: ["api.github.com"],
allowManagedDomainsOnly: false,
allowLocalBinding: true,
},
filesystem: {
allowWrite: ["/tmp"],
denyWrite: ["/etc"],
denyRead: ["/root/.ssh"],
},
};MCP — agent-wrapper-sdk/mcp
Manage Model Context Protocol servers — 5 transport types supported.
Agent.builder()
.mcp("fs", { command: "npx", args: ["-y", "@modelcontextprotocol/server-filesystem", "."] }) // stdio
.mcp("api", { type: "sse", url: "http://localhost:3001/sse" }) // SSE
.mcp("http", { type: "http", url: "http://localhost:3002/mcp" }) // HTTP streamable
.mcp("proxy", { type: "claude_ai_proxy" }) // Claude.ai proxy
.build();
// Runtime control
await agent.reconnectMcp("fs");
await agent.toggleMcp("api", false);
await agent.setMcpServers({ /* new config */ });
const status = await agent.mcpStatus();Output — agent-wrapper-sdk/output
Get structured, typed responses via Zod schemas or raw JSON Schema.
import { Agent, resolveOutputFormat } from "agent-wrapper-sdk";
import { z } from "zod";
// Zod schema (auto-converted to JSON Schema)
const schema = z.object({ summary: z.string(), score: z.number() });
const result = await Agent.builder()
.model("sonnet")
.outputFormat(schema) // Accepts Zod directly
.run("Analyze code quality");
if (result.ok && result.structuredOutput) {
const data = result.structuredOutput as z.infer<typeof schema>;
console.log(data.summary, data.score);
}Stores — agent-wrapper-sdk/stores
Persist sessions and events.
import { InMemoryStore, FileStore } from "agent-wrapper-sdk/stores";
const mem = new InMemoryStore(); // Ephemeral (testing)
const file = new FileStore("/path/to/data"); // JSON + JSONL persistence
// AgentStore interface: saveSession, loadSession, listSessions, deleteSession,
// appendEvent, getEvents
Agent.builder().store(file).build();Presets — agent-wrapper-sdk/presets
Pre-configured agents for common tasks:
import { codeReviewer, researcher, fileProcessor, devops } from "agent-wrapper-sdk/presets";
const review = await codeReviewer("Review src/ for security issues");Builder Reference
The AgentBuilder provides 45+ methods. See the full reference above and CLAUDE.md for details.
| Category | Methods |
|----------|---------|
| Core | model, fallbackModel, cwd, systemPrompt, systemPromptPreset |
| Tools | tools, toolPreset, tool, addTool, toolTier, allowedTools, disallowedTools |
| Permissions | permission, canUseTool, permissionPromptTool, dangerouslySkipPermissions |
| Thinking | thinking, effort |
| Limits | maxTurns, maxBudget |
| Hooks | hook, use |
| Subagents | subagent, mainAgent |
| MCP | mcp, strictMcpConfig |
| Skills | skill, skillInline |
| Sessions | sessionId, persistSession |
| Files | fileCheckpointing |
| Sandbox | sandbox |
| Output | outputFormat |
| Store | store |
| Plugins | plugin |
| Runtime | executable, executableArgs, cliPath, spawnProcess, abortController, extraArgs |
| Debug | debug, debugFile, onStderr |
| Options | promptSuggestions, includePartialMessages, settingSources, additionalDirectories, env, betas |
| Execute | build, run, stream |
Agent Methods
// Execution
agent.run<T>(prompt) // → Promise<AgentResult<T>>
agent.stream(prompt) // → AsyncGenerator<AgentEvent>
agent.step(prompt) // → Promise<TurnOutcome>
// Session
agent.continue<T>(prompt) // Continue current session
agent.resume<T>(sessionId, prompt) // Resume a past session
agent.fork<T>(sessionId, prompt) // Fork from a session
agent.resumeAt<T>(sessionId, messageId, prompt)
// Runtime control
agent.interrupt() // Stop execution
agent.close() // Clean up
agent.setPermissionMode(mode) // Change permissions
agent.setModel(model) // Change model
agent.stopTask(taskId) // Stop a task
// Introspection
agent.skills() // → SkillInfo[]
agent.models() // Available models
agent.mcpStatus() // MCP server status
agent.accountInfo() // Account info
// File management
agent.rewindFiles(messageId, opts?) // Revert file changes
// MCP management
agent.reconnectMcp(name)
agent.toggleMcp(name, enabled)
agent.setMcpServers(servers)
// Escape hatches
agent.toSdkOptions() // Raw SDK Options
agent.getQueryInstance() // Raw SDK QueryRequirements
- Node.js >= 18.0.0 or Bun >= 1.0.0
- TypeScript >= 5.7.0 (for development)
@anthropic-ai/claude-agent-sdk>= 0.2.0 (peer dependency)ANTHROPIC_API_KEYorCLAUDE_CODE_OAUTH_TOKENenvironment variable
Contributing
See CLAUDE.md for detailed development guidelines, architecture, and coding standards.
git clone https://github.com/piyanggoon/agent-wrapper-sdk.git
cd agent-wrapper-sdk
bun install && bun test # 106+ testsLicense
Credits
Built by @piyanggoon. Wraps @anthropic-ai/claude-agent-sdk by Anthropic.
