Anyclaude Sdk
FreeNot checkedStandalone, browser-compatible SDK providing Claude Code agent capabilities (tools, tool loop, multi-turn, MCP, sub-agents, sessions) against any OpenAI/Anthrop
About
Standalone, browser-compatible SDK providing Claude Code agent capabilities (tools, tool loop, multi-turn, MCP, sub-agents, sessions) against any OpenAI/Anthropic-compatible LLM endpoint. Runs in the browser (WebContainer), Node, and Bun — no backend requ
README
npm version anyclaude-react license docs live demo
Claude Code agent capabilities — tools, the tool loop, multi-turn conversations, MCP, sub-agents, multi-agent teams, sessions — against any OpenAI- or Anthropic-compatible LLM endpoint, running in the browser (WebContainer), Node, and Bun. No backend required, no OAuth, no native binaries.
Live demo: a full IDE running in your browser · Docs: anyclaude-docs.puter.site · React UI kit: anyclaude-react
It exposes the same query() async-generator interface and the same SDKMessage
envelope as @anthropic-ai/claude-agent-sdk, so code written against the official
SDK can iterate our output unchanged.
Multi-agent teams go beyond one agent: a coordinator delegates board tasks to
worker sub-agents in parallel, you can dispatch a message to a running worker
and have it land on its next tool round (push delivery, like the message queue),
supervise them live with background dispatch, and even run agents in separate
Web Workers or browser tabs that share one mailbox via BroadcastChannelMailbox.
See Teams & sub-agents.
Install
npm install anyclaude-sdk @webcontainer/api
@webcontainer/api is an optional peer dependency — only needed if you use
WebContainerWorkspace. You can supply your own FileSystem/CommandExecutor.
Quick start
import { WebContainer } from '@webcontainer/api'
import {
query,
WebContainerWorkspace,
createOpenAIClient,
ALL_CLAUDE_CODE_TOOLS,
} from 'anyclaude-sdk'
// 1. Boot a WebContainer and wrap it as a workspace.
const wc = await WebContainer.boot()
const workspace = new WebContainerWorkspace(wc)
// 2. Point at any OpenAI-compatible endpoint.
const llm = createOpenAIClient({
apiKey: import.meta.env.VITE_OPENAI_API_KEY,
baseUrl: 'https://api.openai.com/v1', // or Groq, Together, OpenRouter, local…
model: 'gpt-4o',
})
// 3. Run the agent — same shape as the official SDK.
for await (const msg of query({ prompt: 'List the files and summarize the project', workspace, llm })) {
if (msg.type === 'assistant') {
for (const block of msg.message.content) {
if (block.type === 'text') console.log(block.text)
}
} else if (msg.type === 'result' && msg.subtype === 'success') {
console.log('Done:', msg.result)
}
}
MCP servers (external + in-process)
Connect external MCP servers or define in-process tools. Because browsers block
direct cross-origin MCP fetches (CORS), pass a mcpProxy for remote servers:
import { createSdkMcpServer, tool } from 'anyclaude-sdk'
const calc = createSdkMcpServer({
name: 'calc',
tools: [tool('add', 'Add two numbers',
{ type: 'object', properties: { a: { type: 'number' }, b: { type: 'number' } }, required: ['a', 'b'] },
(args) => ({ content: [{ type: 'text', text: String(args.a + args.b) }] }))],
})
query({
prompt, workspace, llm,
mcpServers: {
calc, // in-process, no network
docs: { type: 'http', url: 'https://mcp.example.com' }, // remote
},
// Route remote MCP through a CORS proxy (function, `{url}`/`{rawUrl}` template, or bare prefix):
mcpProxy: 'https://my-proxy.example/?url={url}',
})
Remote tools are exposed as mcp__<server>__<tool>.
Providers
Three transport clients, all implementing the same LLMClient interface:
import { createOpenAIClient, createAnthropicClient, createResponsesClient } from 'anyclaude-sdk'
// OpenAI-compatible Chat Completions (OpenAI, Groq, Together, OpenRouter, xAI, Kilo, local…)
const a = createOpenAIClient({ apiKey, baseUrl: 'https://api.x.ai/v1', model: 'grok-build-0.1' })
// Anthropic Messages API
const b = createAnthropicClient({ apiKey, model: 'claude-sonnet-4-6' })
// OpenAI Responses API (POST /v1/responses)
const c = createResponsesClient({ apiKey, model: 'gpt-4o' })
All three normalize tool calls, streaming, and usage to the same StreamResult,
and include a fallback parser for models that emit tool calls as inline text.
Multi-turn / interactive sessions
Use a PromptStream to push user turns over time:
import { query, PromptStream } from 'anyclaude-sdk'
const prompts = new PromptStream()
const session = query({ prompt: prompts, workspace, llm, model: 'gpt-4o' })
prompts.push('Create a hello.txt with a greeting')
// …later, based on UI input:
prompts.push('Now translate it to French')
prompts.end() // close the conversation
for await (const msg of session) {
// render msg…
}
Tools
ALL_CLAUDE_CODE_TOOLS includes:
| Tool | Purpose |
|---|---|
bash |
Run shell commands via jsh (2>&1//dev/null redirects are stripped) |
read_file |
Read text (numbered lines, offset/limit), images (auto-downsampled base64), PDFs (document block), and notebooks (.ipynb cells + outputs); binary files are rejected with guidance |
write_file |
Write a file, creating parent dirs |
edit_file |
Exact-match string replace (requires a prior read) |
multi_edit |
Apply a sequence of edits to one file atomically |
notebook_edit |
Replace/insert/delete cells in a .ipynb |
delete_file |
Remove a file/dir |
glob |
Find files by glob pattern (**, *, ?) |
grep |
Regex search across files |
list_files |
List a directory |
todo_write |
Track a multi-step task list across turns |
web_fetch |
Fetch a URL → clean Markdown via the Jina Reader (CORS-free, JS-rendered) |
web_search |
Web search via Jina + DuckDuckGo HTML; returns top-N title/URL/snippet |
File reading: images, PDFs, notebooks
read_file dispatches by file type. Image and PDF bytes are forwarded to the
model automatically as a follow-up user turn (Anthropic gets native
image/document blocks; OpenAI-compatible endpoints get image_url/file
parts), so the model can actually see the file, not just a text summary.
Tune the caps via limits:
query({ prompt, workspace, llm, limits: { maxTokens: 25000, maxImageBytes: 3_750_000, maxPdfPages: 20 } })
Pass a subset, or your own Tool[], via tools::
import { readFile, writeFile, editFile } from 'anyclaude-sdk'
query({ prompt, workspace, llm, tools: [readFile, writeFile, editFile] })
Slash commands
A user turn beginning with / is intercepted. Built-ins: /help, /clear,
/compact [focus] (summarizes history to free context), /tools, /cost,
/model. Define your own prompt-template commands:
import { query, promptCommand } from 'anyclaude-sdk'
query({
prompt: promptStream, workspace, llm,
commands: [promptCommand('review', 'Review the diff', 'Review this code and list issues: $ARGUMENTS')],
})
// user types: /review src/app.ts
Background tasks
Enable with background: true to run sub-agents or long work off the critical
path. The task tool gains run_in_background (returns a task id immediately),
and task_list / task_output / task_stop tools let the agent poll them.
Optional off-main-thread execution via a Comlink worker harness
(exposeBackgroundWorker / wrapWorker); the in-thread manager works without it.
query({ prompt, workspace, llm, agents: {}, background: true })
Agents in separate Web Workers
Two halves: Comlink for main→worker control (wrapWorker / exposeBackgroundWorker,
above), and BroadcastChannelMailbox so agents in different workers gossip
mailbox-style. It's a drop-in Mailbox, so the existing team tools
(send_message / dispatch_tasks) work unchanged across workers:
import { BroadcastChannelMailbox } from 'anyclaude-sdk'
// inside each Web Worker / tab / worker_thread, same channel name:
const mailbox = new BroadcastChannelMailbox({ channelName: 'team', origin: 'planner' })
query({ prompt, workspace, llm, team: true, mailbox })
// messages sent by one worker land in the addressed agent's inbox in another.
Uses the global BroadcastChannel by default. For durable cross-tab delivery
(IndexedDB/localStorage fallbacks, older browsers, Node) use the one-call helper
— it's backed by the bundled broadcast-channel
package, lazy-imported so it stays out of bundles that don't use it:
const mailbox = await BroadcastChannelMailbox.crossTab({ channelName: 'team', origin: 'planner' })
query({ prompt, workspace, llm, team: true, mailbox })
Push delivery to a running agent. Messages addressed to an agent are
auto-injected into its transcript at the next turn boundary — same model as the
message queue, but from the shared mailbox. So a coordinator (or peer, or another
worker) can redirect a running sub-agent mid-task and it lands on the
sub-agent's next tool round, no polling tool needed. dispatch_tasks names each
worker worker:<taskId> so you can target a specific one:
mailbox.send('coordinator', 'worker:task_1', 'while you work: also add logging')
// worker:task_1 sees "[Team messages] - from coordinator: ..." on its next step.
On by default with team: true; opt out via query({ deliverTeamMessages: false }).
Pluggable backends
You aren't tied to WebContainer. A Sandbox is just a FileSystem plus a
CommandExecutor, and you can mix and match.
Any sandbox provider
Adapters wrap each provider's client structurally (no hard dependency on their SDKs — install only the one you use):
import { E2BSandbox, VercelSandbox, DaytonaSandbox, CloudflareSandbox } from 'anyclaude-sdk'
// e.g. E2B
import { Sandbox } from 'e2b'
const sbx = await Sandbox.create()
const workspace = new E2BSandbox(sbx)
query({ prompt, workspace, llm })
Supported: WebContainer, E2B, Vercel Sandbox, Daytona,
Cloudflare Sandbox, and LocalSandbox (real OS). All implement the same
Sandbox interface.
Local real-OS sandbox (Node)
Run the agent directly against the host machine's filesystem and shell — like Claude Code — with automatic platform detection (Windows / macOS / Linux):
import { LocalSandbox, createAnthropicClient, query } from 'anyclaude-sdk'
const workspace = new LocalSandbox({ cwd: '/path/to/project' }) // defaults to process.cwd()
const llm = createAnthropicClient({ baseUrl, model: 'claude-sonnet-4-6', apiKey })
for await (const msg of query({ prompt: 'add a CLI flag and run the tests', workspace, llm })) { /* … */ }
The agent's working directory is taken from the sandbox automatically. See
examples/local-agent.mjs for a runnable headless demo. On Windows it uses
cmd.exe; elsewhere $SHELL//bin/sh (override via shell/shellArgs).
Persistent, full Linux-style filesystem (no server)
For a durable local filesystem in the browser, use a DB-backed FS and seed a
standard Linux tree. DexieFileSystem (IndexedDB) is the recommended default
— persistent across reloads, indexed for fast readdir/glob, with metadata
(mode, mtime, symlinks):
import {
DexieFileSystem, OpfsFileSystem, seedLinuxTree, composeWorkspace, NoopCommandExecutor,
} from 'anyclaude-sdk'
const fs = new DexieFileSystem('my-project-fs') // or: new OpfsFileSystem()
await seedLinuxTree(fs) // /bin /etc /home/user /tmp /usr …
// File-only agent (no shell):
const workspace = composeWorkspace(fs, new NoopCommandExecutor(), '/home/user')
// …or pair a persistent FS with a remote shell:
// const workspace = composeWorkspace(fs, new E2BSandbox(sbx), '/home/user')
OpfsFileSystem (Origin Private File System) is offered alongside Dexie for
large-binary / native-handle scenarios; use OpfsFileSystem.isSupported() to
feature-detect.
A MemoryFileSystem also ships for tests:
import { MemoryFileSystem, NoopCommandExecutor, composeWorkspace } from 'anyclaude-sdk'
const fs = new MemoryFileSystem()
await fs.writeFile('/app/index.ts', 'export const x = 1')
const workspace = composeWorkspace(fs, new NoopCommandExecutor())
Skills (programmatic)
Declare reusable prompt-skills inline — each becomes a /name slash command and is invokable by the agent through the skill tool. $ARGUMENTS is substituted at call time:
import { query, defineSkill } from 'anyclaude-sdk'
query({
prompt, workspace, llm,
skills: [
defineSkill({
name: 'changelog',
description: 'Summarize git changes into a changelog entry',
instructions: 'Write a concise changelog entry for: $ARGUMENTS',
argumentHint: '<since>',
}),
],
})
You can also pass plain Skill objects, or skills: true to load .claude/skills/*.md from the workspace.
Serverless & the "survivor"
Run query() in a serverless function and stream SDKMessages to the browser. For runs longer than the platform's time cap, checkpoint at a turn boundary and continue transparently in a fresh invocation:
// pause near the deadline, persist to the store, emit a `paused` message
query({ prompt, workspace, llm, sessionStore, maxDurationMs: 20_000 })
// later — resume + continue the tool loop with NO new user message
query({ workspace, llm, sessionStore, resume: true, continueRun: true })
Pluggable SessionStore adapters (all implement SessionStoreLike): SessionStore (IndexedDB), MemorySessionStore, KVSessionStore (Vercel KV / Upstash), RedisSessionStore, PostgresSessionStore (Neon / pg / postgres.js), SupabaseSessionStore.
Client-side tools — server brain, browser hands
Declare tools the host executes — e.g. run bash in the user's browser WebContainer while the agent loop runs on your server. The run pauses with a client_tool_request; the client executes it and you resume with the result:
import { WORKSPACE_TOOL_NAMES } from 'anyclaude-sdk'
query({ prompt, llm, workspace, sessionId, clientTools: WORKSPACE_TOOL_NAMES }) // → emits client_tool_request + pauses
query({ llm, workspace, sessionId, resume: true, continueRun: true, clientToolResults }) // → continues
On the browser side, anyclaude-react turns those into a ready executor map backed by any workspace — a WebContainer (real shell + files), the user's IndexedDB (DexieFileSystem), OPFS, or memory:
import { createWebContainerClientTools, createWorkspaceClientTools } from 'anyclaude-react'
useAgent({ endpoint: '/api/agent', clientTools: createWebContainerClientTools(wc) }) // files + bash
useAgent({ endpoint: '/api/agent', clientTools: createWorkspaceClientTools(new DexieFileSystem('my-db')) }) // IndexedDB
Interactive — ask_user_question
Provide onAskUser and the agent gains an ask_user_question tool to put a multiple-choice decision to the user:
query({ prompt, workspace, llm, onAskUser: async ({ question, options }) => pickOne(question, options) })
Hiding your prompt from the browser (projection)
The agent loop runs server-side, so your system prompt, tool instructions, and retrieved context live in the server→LLM request and never reach the browser. To also strip sensitive artifacts (reasoning, raw tool output / RAG, model identity) from the streamed messages, wrap the stream — a pure, opt-in output transform:
import { projectMessages } from 'anyclaude-sdk'
for await (const m of projectMessages(query({ /* ... */ }), { preset: 'public' }))
res.write(JSON.stringify(m) + '\n')
paused and client_tool_request control messages are always preserved. (Note: anything that runs in the browser — createAgentClient mode — necessarily exposes its request; use the server/endpoint path when the prompt is proprietary.)
React UI kit — anyclaude-react
npm install anyclaude-react
useAgent() plus restylable components — chat (AgentChat, ChatPanel, Transcript, MarkdownMessage, Composer, Working, ToolCall) and an IDE set (Terminal, FileExplorer, CodeEditor, AskUser). createAgentClient / createEndpointClient auto-stitch paused continuations and run clientTools in the browser.
Run Claude Code against any model — anyclaude-sdk/anthropic-endpoint
Stand up an Anthropic Messages API-compatible endpoint backed by any OpenAI-compatible model, so Claude Code itself (or any Anthropic-Messages client) runs against DeepSeek / Qwen / GLM / Kimi / local Ollama. Unlike a naive proxy, inline tool-call dialects are recovered into proper tool_use blocks, so tool use actually works on cheap models.
import { createOpenAIClient } from 'anyclaude-sdk/llm'
import { anthropicToChat, anthropicSSE } from 'anyclaude-sdk/anthropic-endpoint'
const llm = createOpenAIClient({ baseUrl: 'https://api.deepseek.com/v1', model: 'deepseek-chat', apiKey })
// POST /v1/messages:
for await (const evt of anthropicSSE(llm, anthropicToChat(body), { model: 'deepseek-chat' })) res.write(evt)
// then: ANTHROPIC_BASE_URL=http://localhost:8787 claude
Runnable: examples/claude-code-router.
Reliable tool use on cheap / open models
Frontier models emit clean native function-calls; cheaper ones often don't. Three layers (in anyclaude-sdk/llm) close the gap: tool-call dialects (parseToolCalls — xml-function / hermes / json-fence), auto-detected model profiles (profileForModel — qwen/deepseek/moonshot/zhipu/mistral/llama), and self-healing argument repair (query({ repairToolCalls }), on by default — validates args and feeds the model a corrective tool_result instead of running with garbage). Prove it on your endpoints with scripts/compat-matrix.mjs → COMPATIBILITY.md.
Scaffold an in-browser AI IDE
npm create anyclaude-app@latest my-app # template: bolt — WebContainer + chat + live preview, no backend
The bolt template wires useWebContainerPreview({ wc }) (boot a dev server → live preview URL) + a browser-side query() + the IDE components. See anyclaude-react.
Token efficiency — deferred tools
Keep a large pool of rarely-used tools out of the per-turn payload (big savings on weak/uncached models) while staying discoverable + callable. Mark them deferred; tool_search indexes them and the loop arms a tool (sends its schema on subsequent turns) once search surfaces it — then it executes normally.
query({ prompt, workspace, llm,
extraTools: [deploy, ...integrationTools], // e.g. 35 integration tools
deferredTools: ['stripe_charge', 'supabase_query', /* … the niche ones */],
})
// or per-tool: defineTool({ name, description, parameters, run, defer: true })
Only the lean core + tool_search are sent each turn; the model searches when it needs a niche tool, the SDK arms it, and the call goes through. Register 35, send ~10.
Agent-loop tuning (cheap / lightweight / fast)
Opt-in knobs for token cost and latency — especially on weak / uncached models:
query({
prompt, workspace, llm,
systemPromptPreset: 'lean', // ~70% shorter built-in prompt — saved every turn on uncached models
keepToolResults: 6, // context editing: stub tool_results older than the last 6 (caps transcript growth)
parallelToolExecution: true, // run a turn's read-only tool calls concurrently (~2× faster on multi-read turns)
deferredTools: [/* niche tools */], // keep rarely-used tools out of the payload until tool_search arms them
})
// custom read tool opting into parallelism:
defineTool({ name: 'get_logs', description: '…', parameters, run, parallelSafe: true })
Mutating tools / bash / delegated client tools always execute serially; keepToolResults and parallelToolExecution preserve correctness, just trim cost/latency.
Other niceties
- Live compaction marker —
autoCompactemits acompact_boundarywithstatus: 'start'before summarizing (for a live "compacting…" shimmer) andstatus: 'end'after withpost_tokens. - Cancel a queued message —
MessageQueue.push()returns a stable id;remove(id)cancels a single pending message (per-pill ✕ in a UI). - BYO LLM client — reuse the SDK's wire codec:
toOpenAIMessages,consumeSSE, and the LLM types fromanyclaude-sdk/llm(no bare-root import in browser bundles).
Examples & live demo
Runnable Vite projects in examples/: browser-ide (WebContainer IDE — real shell + Node in the tab), browser-chat, claude-code-router, vercel-kv-survivor, vercel-supabase-survivor, vercel-indexeddb-survivor, vercel-clienttools (server brain / browser hands). Try the live demo.
API
query(options): AsyncGenerator<SDKMessage>— main entry.prompt: string | AsyncIterable<SDKUserMessage>workspace: FileSystem & CommandExecutorllm: LLMClienttools?,extraTools?,allowedTools?/disallowedTools?,deferredTools?(lazy-load),model?,systemPrompt?/appendSystemPrompt?,maxTurns?(default 50),cwd?,abortController?- serverless:
sessionStore?,resume?,maxDurationMs?,continueRun? - client tools:
clientTools?,clientToolResults?; interactive:onAskUser? - also:
mcpServers?,agents?,commands?,hooks?,background?,team?,memory?,permissionMode?/canUseTool?,messageQueue?
createOpenAIClient/createAnthropicClient/createResponsesClientWebContainerWorkspace,MemoryFileSystem,NoopCommandExecutor,LocalSandbox,composeWorkspacedefineTool(custom tools),projectMessages(server-side stream redaction)ALL_CLAUDE_CODE_TOOLS, individual tools,toolDefs,toolByName- browser-clean subpaths:
anyclaude-sdk/{query,loop,llm,fs,workspace,tools,session,memory,compact,permissions,skills,queue,prompt,anthropic-endpoint,telemetry} anyclaude-sdk/llm:parseToolCalls+ dialects,profileForModel(model profiles),validateToolArguments(repair),toOpenAIMessages/consumeSSE(BYO-client codec)anyclaude-sdk/anthropic-endpoint:anthropicToChat,anthropicSSE,streamResultToAnthropicMessage(Claude-Code router)runToolLoop(/loop),compactWithWindow(/compact),track/telemetryEnabled(/telemetry)- All
SDK*message types,ContentBlockParam,LLMClient,ToolDef,SessionStoreLike, etc.
Differences from the official SDK
| Feature | Official SDK | anyclaude-sdk |
|---|---|---|
| Auth | OAuth token | None required |
| Backend | claude.ai API | Any OpenAI/Anthropic endpoint |
| Runtime | Node only | Browser, Node, Bun |
| File ops | Native filesystem | Pluggable (WebContainer / Memory / IndexedDB / local) |
| Commands | Native shell | jsh (WebContainer) / local / client-side tools |
| MCP / slash commands / background tasks / sub-agents | Built-in | Built-in |
| Serverless survivor + prompt projection | — | Built-in |
Telemetry
The SDK emits anonymous, opt-out usage telemetry (SDK version, runtime, a coarse model-family bucket, and which features are used) — never code, prompts, repo identity, paths, or keys. It sends to an aggregate-only collector (a Puter Worker; source in examples/telemetry-collector). Disable with ANYCLAUDE_TELEMETRY=0, DO_NOT_TRACK=1, or query({ disableTelemetry: true }); repoint with ANYCLAUDE_TELEMETRY_URL (or set it to '' to send nowhere). Full disclosure: TELEMETRY.md.
License
MIT
Install Anyclaude Sdk in Claude Desktop, Claude Code & Cursor
unyly install anyclaude-sdkInstalls into Claude Desktop, Claude Code, Cursor & VS Code — handles npx, uvx and build-from-source repos for you.
First time? Get the CLI: curl -fsSL https://unyly.org/install | sh
Or configure manually
Run in your terminal:
claude mcp add anyclaude-sdk -- npx -y anyclaude-sdkFAQ
Is Anyclaude Sdk MCP free?
Yes, Anyclaude Sdk MCP is free — one-click install via Unyly at no cost.
Does Anyclaude Sdk need an API key?
No, Anyclaude Sdk runs without API keys or environment variables.
Is Anyclaude Sdk hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install Anyclaude Sdk in Claude Desktop, Claude Code or Cursor?
Open Anyclaude Sdk on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
GitHub
PRs, issues, code search, CI status
by GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
by mcpdotdirectCompare Anyclaude Sdk with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All development MCPs
