0xfandom c3930ca5ad fix(mcp): resolve server names by own-property, not the prototype chain (#1983)
* fix(mcp): resolve server names by own-property, not the prototype chain

getMcpConfigByName and the mcp remove handler look names up in plain
object maps built from JSON config with a bare servers[name] truthiness
check. Reserved names ('constructor', '__proto__', 'toString', …) resolve
to inherited Object.prototype members, which are truthy, so:

- `mcp get constructor` skips the not-found guard, prints a fabricated
  record, and hands the Object constructor to the health check;
- `mcp remove constructor` reports the reserved name as present in
  multiple scopes and prompts to pick one instead of "No MCP server found".

The same leak reaches runAgent and the print handlers, which all route
through getMcpConfigByName. Gate every lookup on Object.hasOwn so only
real, own-property server names resolve.

* test(mcp): restore project mcpServers in afterEach for isolation

Save and restore getCurrentProjectConfig().mcpServers the same way the
global config is handled, rather than hardcoding undefined, so the test
never leaks state into suites that share the in-memory test config.

* fix(mcp): cover the remaining prototype-name mutation and doctor paths

The own-property gate only covered unscoped removal and getMcpConfigByName.
The scoped paths still used bare lookups:

- removeMcpConfig's project/user/local existence checks accepted inherited
  members, so 'mcp remove constructor -s user' reported a successful removal
  while leaving the configuration untouched;
- addMcpConfig's already-exists checks rejected valid 'mcp add constructor';
- doctor's servers[name] and activeServers[name] fabricated definitions for
  prototype names.

Gate all of them on Object.hasOwn. Also reject the name '__proto__' at add
time: it passes the character check but assigning it on a plain object hits
the prototype setter instead of creating an own property, so the server
would be reported as added and silently vanish.

Restore NODE_ENV in the test teardown alongside the config state.

* fix(mcp): report a reserved __proto__ entry in file config

A hand-authored .mcp.json can contain a server named "__proto__": JSON.parse
gives it a real own key, but it cannot be copied onto a plain object, so the
schema's rebuild dropped it before validation ever ran. The entry simply did
not exist and nothing said why, and with own-property lookups the scoped
removal path now correctly reports it as absent -- so there was no way to
learn the name was the problem.

Detect it on the raw parsed config and surface a fatal validation error
naming the entry, matching the rejection addMcpConfig already performs for
the same name. The rest of the file still parses.

* test(mcp): serialize the proto-name suite on the shared mutation lock

The suite swaps NODE_ENV and the process-wide global and project MCP
configurations without holding sharedMutationLock, so bun can run it
alongside another state-mutating file: that file observes the injected
realserver/locallyreal fixtures, or its own updates are overwritten when
this teardown restores its snapshots.

Acquire the lock in setup and release it from a finally in teardown, the
same shape officialRegistry.test.ts uses.

Also cover the reserved __proto__ entry arriving from parsed file config.

* fix(mcp): reserve constructor alongside __proto__

With own-property lookups in place, `mcp add constructor` persists an entry
the config schema then rejects -- and it rejects the whole mcpServers
object, so the newly added server is unusable and every other server in that
scope stops loading with it.

Refuse the name at add, and name it at file ingress: the only diagnostic
before was a generic "does not adhere to schema" against `mcpServers`, which
does not say which entry is at fault. The scan runs ahead of the schema
parse because that path returns early. `__proto__` and `constructor` are the
only two names that fail a write/read round trip -- toString,
hasOwnProperty, valueOf and the rest all persist and read back correctly.

* fix(mcp): reject a config with a reserved server name outright

parseMcpConfig flagged a fatal reserved name but, for __proto__, still returned
a usable partial config because zod's rebuild silently drops the key and the
schema parse succeeds. Callers that branch on the config -- the --mcp-config
ingress in main.tsx -- then took the partial config and discarded the error,
starting with the bad entry quietly gone. Return config: null whenever a fatal
reserved-name error is present, matching the constructor path where the schema
already fails, so the invalid input is rejected at every consumer.

* fix(mcp): keep reserved-name findings visible in all-server doctor output

doctorAllServers builds server reports only for names that survived parsing or
are active, and attaches server-keyed findings to those. A fatal reserved-name
error is keyed by a name that never survives parsing, so its finding was built
into no report and dropped -- mcp doctor --config-only read clean while the
invalid config was present. Surface any finding whose server has no report as a
global finding.

* fix(mcp): do not mutate a fatally poisoned project .mcp.json

A reserved server name (`__proto__`/`constructor`) now fails the whole
parse and returns config: null, so getProjectMcpConfigsFromCwd reports an
empty map even though valid siblings remain on disk. Project-scope add
rebuilt the file from that empty snapshot and wrote only the new server,
silently dropping every sibling; project-scope remove reported a valid
sibling as "not found". Refuse to mutate the file when it fails to parse,
naming the offending entry, instead of treating the empty map as truth.

* fix(mcp): surface reserved-name errors in single-server doctor output

doctorServer set report.findings to only the global findings and never
applied the orphan fold doctorAllServers uses, so a fatal reserved-name
error in a poisoned scope was dropped when the requested target lived in
another scope -- exit 0 with the real fault hidden. Promote findings for
names other than the reported one, and skip the state.not_found branch
when a validation finding already explains the requested name so the
report no longer carries two blocking findings with contradictory text.

* fix(mcp): honor the fatal-parse contract across every scope

The config:null contract was only enforced on project-scope .mcp.json.
Extend it so a fatally poisoned scope is never silently mutated:

- Re-check the project snapshot immediately before the write rebuild, not
  only at the existence check -- the file can go fatal in between, and
  rebuilding from the resulting empty map would drop valid siblings.
- Refuse user/local add and remove when that scope parses to config:null,
  so the CLI no longer reports success for a scope that then loads nothing
  (or mutates a sibling in a raw map that stays unloadable).
- Gate enterprise exclusive control on the managed file's presence, not on
  a successful parse, so a poisoned managed-mcp.json can't silently drop
  the policy lock and let user/project servers take over.

Generalize the guard to assertMcpScopeWritable(errors, scopeLabel).

* test(mcp): pin allowedSettingSources so the local-scope guard is hermetic

getMcpConfigsByScope() returns an empty writability-error list when a scope's
setting source is disabled, and allowedSettingSources is a process-wide global
other suites mutate. In bun's file order a suite that leaves localSettings
disabled (e.g. one exercising --setting-sources) would make the 'fatally
poisoned local scope' case skip its guard, so addMcpConfig(...'local') resolved
instead of rejecting -- the intermittent CI failure at config.protoName.test.ts.
Pin the full source set in beforeEach and restore it in afterEach, matching the
NODE_ENV and MCP-config snapshotting this suite already does.

* fix(mcp): guard scope mutations on raw parse errors, not the source filter

assertMcpScopeWritable read errors from getMcpConfigsByScope()/
getProjectMcpConfigsFromCwd(), which suppress errors to an empty list when a
scope's setting source is disabled. addMcpConfig/removeMcpConfig still mutate
the raw mcpServers maps, so under a narrowed --setting-sources set a fatally
poisoned scope could be written or deleted (clobbering valid siblings) while the
CLI reported success. Add getScopeMutationErrors(), which parses each scope's
raw source directly, and route every write guard through it.

* fix(mcp): detect unscoped-remove membership from parsed scope views

Unscoped `mcp remove` read local/user membership from the raw
getCurrentProjectConfig()/getGlobalConfig() maps while project used the parsed
view. A fatally poisoned local/user scope has no loadable servers yet still
holds the raw entry, so the handler listed the server as living there and then
removeMcpConfig refused with 'Cannot modify … config'. Read all three scopes
through getMcpConfigsByScope() so detection matches what is actually removable.

* fix(mcp): read the raw project scope for mutations, not the source view

getScopeMutationErrors only covered the write guard's errors; the project
existence check and .mcp.json rebuild still read servers from the
source-gated getProjectMcpConfigsFromCwd(). With projectSettings excluded from
--setting-sources that returned an empty map, so an add rebuilt the file
without the valid siblings and a remove mis-reported the server as absent.
Drop the source gate from getProjectMcpConfigsFromCwd() (a mutation-only read)
so it always sees the real file, and fold the project write guards back onto
its returned errors. Regression covers add/remove with projectSettings off.

* test(mcp): re-pin the poisoned local fixture atomically per mutation

The local-scope poison regressions flaked under the full parallel suite:
sharedMutationLock serializes other lock holders but not every writer of the
process-wide test project config or NODE_ENV, so a stray async task from another
suite could clobber the fixture during an await gap between the setup and the
assertion. addMcpConfig/removeMcpConfig reach their scope guard with no awaited
work in between, so re-establishing NODE_ENV, the enabled sources, and the
poisoned config synchronously immediately before each mutation (pinPoisonedLocalScope)
keeps the guard's read atomic regardless of what ran during earlier awaits.

* fix(mcp): surface managed-mcp.json parse errors in enterprise mode

Enterprise exclusive mode engages on the managed file's presence, so a
malformed or reserved-name managed-mcp.json fail-closes every other MCP source.
getClaudeCodeMcpConfigs returned errors: [] for that branch, and
getSettingsWithAllErrors aggregated only user/project/local, so startup and the
MCP UI saw an empty server list with no diagnosable reason. Propagate the
enterprise scope's parse errors as generic-error PluginErrors from the exclusive
branch and include the enterprise scope in the settings error aggregation.

* fix(mcp): detect unscoped-remove membership source-filter-independent

Reading membership from getMcpConfigsByScope applied the --setting-sources load
filter, so an unscoped `mcp remove foo` reported "No MCP server found" for a
clean user/local/project entry that removeMcpConfig(foo, scope) still mutates
when that source is narrowed out. Read each scope the same way removeMcpConfig
resolves existence -- the raw getCurrentProjectConfig()/getGlobalConfig() maps
and getProjectMcpConfigsFromCwd() -- still own-property gated so inherited
members are not treated as present.

* fix(mcp): surface managed-mcp.json errors in headless startup

The headless (-p) MCP consumer destructured only servers from the
config promise and discarded errors. A fatal managed-mcp.json
fail-closes every file-based MCP source, so scripted users saw an empty
server list with no diagnostic — indistinguishable from an intentionally
empty configuration. Emit the config errors on stderr in non-interactive
sessions (interactive already surfaces them via the MCP error UI).

* fix(mcp): enforce enterprise-exclusive boundary in named lookups

getMcpConfigByName() gated plugin-only mode but not the enterprise-
exclusive policy. A present managed-mcp.json takes exclusive, fail-closed
control of MCP (its mere presence engages the policy, even when the file
is malformed), and getClaudeCodeMcpConfigs() drops every non-enterprise
source accordingly — but the named lookup fell through to the user/
project/local maps. A user with a locally configured server plus an
invalid managed file could therefore still resolve that server by name
via 'mcp get <server>' (checkMcpServerHealth) or an agent definition's
named-server reference (runAgent), bypassing the intended policy.

Return only an enterprise-owned entry (or null) whenever
doesEnterpriseMcpConfigExist() is true, before consulting other scopes,
mirroring the boundary getClaudeCodeMcpConfigs() already enforces.
2026-09-21 09:04:37 +08:00
2026-04-30 18:22:01 +08:00
2026-04-30 18:22:01 +08:00
2026-04-03 09:40:17 +08:00

OpenClaude — Open terminal for any LLM

Gitlawb%2Fopenclaude | Trendshift Gitlawb%2Fopenclaude | Trendshift Gitlawb%2Fopenclaude | Trendshift

OpenClaude is an open-source coding-agent CLI for cloud and local model providers.

Use OpenAI-compatible APIs, Gemini, GitHub Models, Codex OAuth, Codex, Ollama, Atomic Chat, and other supported backends while keeping one terminal-first workflow: prompts, tools, agents, MCP, slash commands, and streaming output.

PR Checks Release npm downloads Discussions Discord X Security Policy License

OpenClaude is also mirrored to GitLawb: gitlawb.com/node/repos/z6MkqDnb/openclaude

Quick Start | Setup Guides | Providers | Development | VS Code Extension | Partners | Community

Partners

GitLawb logo Bankr.bot logo Atomic Chat logo Xiaomi MiMo logo Atlas Cloud logo
GitLawb Bankr.bot Atomic Chat Xiaomi MiMo Atlas Cloud
AI/ML API logo Novita AI logo ApiSmart logo Concentrate logo Exa logo
AI/ML API Novita AI ApiSmart Concentrate Exa

Why OpenClaude

  • One CLI across cloud APIs and local model backends — no per-provider tooling
  • Guided provider setup and saved profiles with /provider
  • Coding-agent workflows in one place: bash, file tools, grep, glob, agents, tasks, MCP, and web tools
  • A bundled VS Code extension for launch integration and theme support
  • A pixel-art hero companion who fires an arrow every time you press Enter (really — see Meet your buddy)

Quick Start

Install

OpenClaude requires Node.js >=22.0.0 for npm installs and runtime. Bun is only needed for source builds and local development.

npm install -g @gitlawb/openclaude@latest

If you're on Arch Linux, you can install OpenClaude from the community-maintained AUR package:

paru -S openclaude

If the install later reports ripgrep not found, install ripgrep system-wide and confirm rg --version works in the same terminal before starting OpenClaude.

Verify / troubleshoot installed version:

openclaude --version
npm view @gitlawb/openclaude dist-tags
npm install -g @gitlawb/openclaude@latest

Start

openclaude

Inside OpenClaude:

  • run /provider for guided provider setup and saved profiles
  • run /onboard-github for GitHub Models onboarding

Note: OpenClaude does not automatically load project .env files. We recommend using the /provider command for setup, which saves provider profiles and credentials in .openclaude-profile.json. If you prefer environment variables, export them explicitly or run openclaude --provider-env-file .env for provider/setup variables. Export runtime/debug knobs from your shell or launcher.

Resume or fork a conversation

Resume an existing conversation by session ID, or continue the most recent conversation in the current directory:

openclaude --resume <session-id>
openclaude --continue

Add --fork-session to branch the conversation history into a new session ID instead of reusing the original transcript:

openclaude --resume <session-id> --fork-session
openclaude --continue --fork-session

Forking is conversation branching only. It does not create filesystem isolation, copy your working tree, or create a git worktree branch.

Background sessions

Run long non-interactive prompts detached from the current terminal:

openclaude --bg "fix failing tests"
openclaude --bg --name auth-refactor "refactor auth middleware"
openclaude ps
openclaude logs auth-refactor
openclaude logs auth-refactor -f
openclaude kill auth-refactor

Background sessions are local child processes. OpenClaude does not start a daemon or network service, and permission/provider/model/settings flags are passed to the child process the same way they are for a foreground --print run. Session metadata and logs are stored under the resolved OpenClaude config directory, usually ~/.openclaude/bg-sessions/; OPENCLAUDE_CONFIG_DIR can point OpenClaude somewhere else. CLAUDE_CONFIG_DIR is ignored for OpenClaude background-session storage. Session names can be reused after older sessions reach a terminal state; use the session ID to inspect older logs with the same name. A naturally finished session is recorded as exited when its process returns zero and failed when it returns nonzero or handles a termination signal. stale remains the conservative result when the process disappears without an observed outcome; an explicit successful openclaude kill is recorded as killed, and killed takes precedence over a natural exited or failed outcome for the same process. Terminal outcomes are stored separately under bg-sessions/terminal/; deleting that directory makes finished sessions fall back to liveness-derived status. OpenClaude does not infer POSIX signal names on Windows. Unobservable force termination, host crashes, and power loss remain stale on every platform.

openclaude attach <id-or-name> currently reports the matching session and points to openclaude logs <id> -f; full terminal reattach is not implemented for local background sessions yet.

OpenClaude config cutover

OpenClaude stores its own config under ~/.openclaude and ~/.openclaude.json by default. It does not read ~/.claude, project .claude/ directories, or CLAUDE_CONFIG_DIR; new users can start with an empty OpenClaude config and do not need Claude Code installed.

If you previously used OpenClaude with .claude paths, migrate intentionally: copy only the settings, commands, agents, skills, scheduled tasks, or other files you personally created for OpenClaude into the matching .openclaude location. Do not blanket-copy .claude, and do not copy Claude Code credentials or auth files. For provider authentication, prefer running OpenClaude's provider setup again or exporting provider-specific environment variables.

Fastest OpenAI setup

macOS / Linux:

export CLAUDE_CODE_USE_OPENAI=1
export OPENAI_API_KEY=sk-your-key-here
export OPENAI_MODEL=gpt-4o

openclaude

Windows PowerShell:

$env:CLAUDE_CODE_USE_OPENAI="1"
$env:OPENAI_API_KEY="sk-your-key-here"
$env:OPENAI_MODEL="gpt-4o"

openclaude

Fastest local Ollama setup

macOS / Linux:

export CLAUDE_CODE_USE_OPENAI=1
export OPENAI_BASE_URL=http://localhost:11434/v1
export OPENAI_MODEL=qwen2.5-coder:7b

openclaude

Windows PowerShell:

$env:CLAUDE_CODE_USE_OPENAI="1"
$env:OPENAI_BASE_URL="http://localhost:11434/v1"
$env:OPENAI_MODEL="qwen2.5-coder:7b"

openclaude

For Ollama, OpenClaude uses Ollama's native chat API and requests a 32768-token context window on each chat request so same-session history is not silently truncated by Ollama's OpenAI-compatible shim. Set OPENCLAUDE_OLLAMA_NUM_CTX or OLLAMA_CONTEXT_LENGTH if you need a different request-level context size. See Advanced Setup for verification with ollama ps.

Setup Guides

Beginner-friendly guides:

Advanced and source-build guides:

Supported Providers

Provider Setup Path Notes
OpenAI-compatible /provider or env vars Works with OpenAI, OpenRouter, DeepSeek, Groq, Mistral, LM Studio, and other compatible /v1 servers
Z.AI GLM Coding Plan /provider or OpenAI-compatible env vars Uses OPENAI_API_KEY at https://api.z.ai/api/coding/paas/v4, defaults to glm-5.2, and offers the vision-capable glm-5.3-flash option
AI/ML API /provider or AIMLAPI_API_KEY (setup guide) Uses https://api.aimlapi.com/v1, auto-detects the OpenAI-compatible route from AIMLAPI_API_KEY, sends OpenClaude attribution headers, and discovers chat-capable models from the public /models catalog
Concentrate /provider or CONCENTRATE_API_KEY Unified OpenAI-compatible gateway at https://api.concentrate.ai/v1; defaults to deepseek-v4-flash and auto-discovers the chat model catalog
LLMTR /provider or OpenAI-compatible env vars Multi-model gateway at https://llmtr.com/v1; /provider and --provider llmtr default to deepseek/deepseek-v4-flash, while raw env setup must set OPENAI_BASE_URL=https://llmtr.com/v1 and OPENAI_MODEL; accepts LLMTR_API_KEY or OPENAI_API_KEY after the route is selected and discovers tool-capable Chat Completions models from the public catalog
Command Code /provider or OpenAI-compatible env vars Hybrid OpenAI-compatible gateway at https://api.commandcode.ai/provider/v1; /provider and --provider commandcode default to deepseek/deepseek-v4-flash, while raw env setup must set OPENAI_BASE_URL=https://api.commandcode.ai/provider/v1 and OPENAI_MODEL; requires CMD_API_KEY, COMMANDCODE_API_KEY, or the official COMMAND_CODE_API_KEY after the route is selected and discovers Chat Completions models from the public catalog. Claude models are unsupported by this Chat Completions integration
ApiSmart /provider or APISMART_API_KEY Uses https://gw.apismart.ai/v1, defaults to DEEPSEEK_V4_FLASH, and supports optional APISMART_MODEL plus authenticated model discovery
Hicap /provider or OpenAI-compatible env vars Uses api-key auth, discovers models from unauthenticated /models, and supports Responses mode for gpt- models
Fireworks AI /provider or env vars First-class provider with 276 curated models (DeepSeek, Qwen, Llama, Gemma, and more); uses FIREWORKS_API_KEY
LongCat /provider or env vars Meituan LongCat OpenAI-compatible API at https://api.longcat.chat/openai/v1; uses LONGCAT_API_KEY and defaults to LongCat-2.0
ClinePass /provider or env vars AI model gateway with usage limits (5hr, weekly, monthly); uses CLINE_API_KEY at https://api.cline.bot/api/v1
Gemini /provider or env vars Supports API key only
GitHub Models /onboard-github Interactive onboarding with saved credentials
Codex OAuth /provider Opens ChatGPT sign-in in your browser and stores Codex credentials securely
Codex /provider Uses existing Codex CLI auth, OpenClaude secure storage, or env credentials
Gitlawb Opengateway Startup default, /provider, or env vars Smart gateway at https://opengateway.gitlawb.com/v1; requires an API key from https://gitlawb.com/opengateway/keys and routes Xiaomi MiMo and GMI Cloud partner models by OPENAI_MODEL
OpenCode Zen /provider or env vars Pay-as-you-go AI gateway (48 models); uses OPENCODE_API_KEY via https://opencode.ai/zen/v1; shared key with OpenCode Go
OpenCode Go /provider or env vars $10/mo subscription for open models (13 models); uses OPENCODE_API_KEY via https://opencode.ai/zen/go/v1; shared key with OpenCode Zen
Xiaomi MiMo /provider or env vars OpenAI-compatible API at https://mimo.mi.com; uses MIMO_API_KEY and defaults to mimo-v2.5-pro
NEAR AI /provider or env vars Unified gateway (Claude, GPT, Gemini + TEE open models); uses NEARAI_API_KEY at https://cloud-api.near.ai/v1
Cloudflare Workers AI /provider or env vars OpenAI-compatible API at https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/ai/v1; uses CLOUDFLARE_API_TOKEN. Replace <ACCOUNT_ID> with your Cloudflare account id.
Ollama /provider or env vars Local inference with no API key
Atomic Chat /provider, env vars, or bun run dev:atomic-chat Local Model Provider; auto-detects loaded models
Bedrock / Vertex / Foundry env vars Anthropic-family cloud routes; Vertex is for Claude on Vertex AI, not arbitrary Model Garden models

What Works

  • Tool-driven coding workflows: Bash, file read/write/edit, grep, glob, agents, tasks, MCP, and slash commands
  • Streaming responses: Real-time token output and tool progress
  • Tool calling: Multi-step tool loops with model calls, tool execution, and follow-up responses
  • Images: URL and base64 image inputs for providers that support vision. Paste from the clipboard with Ctrl+V (Alt+V on Windows). 1080p/4K screenshots still attach. If processing fails and the image is over the 5MB payload limit or the 8000px API edge, the prompt shows that error instead of "No image found". For Anthropic requests containing more than 20 images (including retained conversation history and tool results), local images must fit within 2000×2000 pixels. On Amazon Bedrock and Google Cloud Vertex AI, document blocks also count toward that 20-block threshold. OpenClaude attempts to resize them before sending; if processing cannot produce a compliant image, it reports an actionable error rather than silently dropping attachments. Resize the affected images or start a new conversation with fewer images (or documents on those partners).
  • Provider profiles: Guided setup plus saved user-level provider profile support
  • Local and remote model backends: Cloud APIs, local servers, and Apple Silicon local inference
  • Codebase intelligence (repo map): Structural map of the repository ranked by PageRank importance, auto-injected into context when the REPO_MAP flag is enabled or the REPO_MAP environment variable is set. Inspect with /repomap (2048-token default). See docs/repo-map.md for details.
  • A companion with signature moves: A truecolor pixel-art hero who lives beside your prompt and reacts when you work. See below.

Meet Your Buddy

Run /buddy to hatch a companion — a truecolor pixel-art hero who stands beside your prompt, idles, blinks, and fires their signature move every time you submit a message:

/buddy                  hatch (first run) or pet your companion
/buddy set robinhood    the green archer — arrow shot on every Enter
/buddy set kaio         gold-haired warrior — charges a full-width energy wave
/buddy set strawhat     stretchy punch that snaps back
/buddy set merlin       twinkling sparkle stream
/buddy set kage         spinning shuriken
/buddy set ember        dragon fire with a real heat gradient
/buddy set corsair      cannonball with smoke trail
/buddy name Robin       rename your companion
/buddy set random       back to your rolled hero

Companions respect prefersReducedMotion, degrade gracefully to line art in low-color terminals, and can be silenced with /buddy mute. Requires a terminal at least 100 columns wide for the full sprite.

Provider Notes

OpenClaude supports multiple providers, but behavior is not identical across all of them.

  • Anthropic-specific features may not exist on other providers
  • Tool quality depends heavily on the selected model
  • Smaller local models can struggle with long multi-step tool flows
  • Some providers impose lower output caps than the CLI defaults, and OpenClaude adapts where possible
  • AI/ML API uses the OpenAI-compatible route, defaults to gpt-4o, and only surfaces chat-capable models from its public catalog
  • Gitlawb Opengateway is the fresh-install startup default and requires an API key from https://gitlawb.com/opengateway/keys. It uses one OpenAI-compatible base URL; switch between mimo-* and google/gemini-3.1-flash-lite-preview with /model, and do not pin the base URL to /v1/xiaomi-mimo.
  • Z.AI GLM Coding Plan uses https://api.z.ai/api/coding/paas/v4 with glm-5.2 by default. On that direct route, GLM-5.3-Flash is selectable as glm-5.3-flash and accepts image input. Its OpenClaude effort choices are low, high, and xhigh, with xhigh requesting Z.AI max; GLM-5.3 and the existing GLM-5.2 query controls remain supported. These capabilities are not claimed for gateways that happen to carry the same model name.
  • Xiaomi MiMo uses api-key header auth on the direct OpenAI-compatible route and currently does not support /usage reporting in OpenClaude
  • GitHub Copilot serializes sub-agent execution by default to reduce Premium Request consumption — see Agent Routing and Step Limits for tuning

For best results, use models with strong tool/function calling support.

Agents

Route different agents to different models (cost optimization, splitting work by model strength), cap sub-agent tool steps with maxSteps, and tune GitHub Copilot sub-agent behavior. Configured via settings, agent frontmatter, and environment variables:

  • per-agent provider/model overrides via agentModels + agentRouting in ~/.openclaude/settings.json
  • model-only routes that reuse your current provider's credentials
  • built-in agents (Explore and Plan [feature-gated], verification [feature-gated: requires VERIFICATION_AGENT + tengu_hive_evidence], code-reviewer [requires diff inline]) routable by type name

See Agent Routing and Step Limits for the full guide.

Web Search and Fetch

By default, WebSearch works on non-Anthropic models using DuckDuckGo. This gives GPT-4o, DeepSeek, Gemini, Ollama, and other OpenAI-compatible providers a free web search path out of the box.

Note: DuckDuckGo fallback works by scraping search results and may be rate-limited, blocked, or subject to DuckDuckGo's Terms of Service. If you want a more reliable supported option, configure Firecrawl.

For Anthropic-native backends and Codex responses, OpenClaude keeps the native provider web search behavior.

WebFetch works, but its basic HTTP plus HTML-to-markdown path can still fail on JavaScript-rendered sites or sites that block plain HTTP requests.

Set a Firecrawl API key if you want Firecrawl-powered search/fetch behavior:

export FIRECRAWL_API_KEY=your-key-here

With Firecrawl enabled:

  • WebSearch can use Firecrawl's search API while DuckDuckGo remains the default free path for non-Claude models
  • WebFetch uses Firecrawl's scrape endpoint instead of raw HTTP, handling JS-rendered pages correctly

Free tier at firecrawl.dev includes 500 credits. The key is optional.

Headless gRPC Server

OpenClaude can run as a headless gRPC service with bidirectional streaming — integrate its agentic capabilities into other applications, CI/CD pipelines, or custom UIs. Start it with npm run dev:grpc; a test CLI client ships with the repo. See Headless gRPC Server for configuration and client generation from src/proto/openclaude.proto.

Development

Use Node.js >=22.0.0 and Bun 1.3.13 or newer for source builds.

bun install
bun run build
node dist/cli.mjs

Day-to-day commands:

  • bun run dev — build and launch from source
  • bun test — full unit suite (Bun's built-in runner)
  • bun test path/to/file.test.ts — focused runs for the areas you touch
  • bun run test:coverage — coverage to coverage/lcov.info plus a visual report at coverage/index.html (bun run test:coverage:ui rebuilds just the UI)
  • bun run smoke — smoke checks
  • bun run doctor:runtime, bun run verify:privacy; for PR intent scanning, use the fresh-upstream, explicit-ref workflow in the local pre-push validation contract

Focused suites: bun run test:provider, bun run test:provider-recommendation.

To benchmark the launcher module compile cache, build the CLI and run:

bun run build
bun run benchmark:startup

The benchmark requires Node >=22.8.0, where the compile-cache API was added; the built OpenClaude launcher continues to support the declared Node >=22.0.0 runtime range.

The benchmark defaults to 30 separate-process warm runs and 10 isolated empty-cache runs. It reports the median, IQR, MAD, first cache-populating run, first warm-up, Node/OS/CPU details, bundle size, and commit. Direct bundle timings are included only as a secondary diagnostic; the full launcher result is the decision signal. Use bun run benchmark:startup -- --warm-runs 40 --cold-runs 10 to request a larger sample set. The benchmark records results without enforcing a timing threshold in CI.

OpenClaude leaves Node's standard compile-cache controls authoritative. Set NODE_DISABLE_COMPILE_CACHE=1 to disable the optimization, including for V8 coverage runs that require uncached compilation.

Before opening or updating a PR, run the authoritative local pre-push validation contract. The commands below are useful for narrow iteration, but they do not replace that required preflight:

  • bun run build
  • bun run smoke
  • bun run test:coverage when your change affects shared runtime or provider logic
  • focused bun test ... runs for the files and flows you changed

Repository Structure

  • src/ - core CLI/runtime
  • scripts/ - build, verification, and maintenance scripts
  • docs/ - setup, contributor, and project documentation
  • vscode-extension/openclaude-vscode/ - VS Code extension
  • .github/ - repo automation, templates, and CI configuration
  • bin/ - CLI launcher entrypoints

VS Code Extension

The repo includes a VS Code extension in vscode-extension/openclaude-vscode for OpenClaude launch integration, provider-aware Control Center, in-editor chat, theme support, and optional Microsoft Foundry / Azure OpenAI configuration (endpoint, API version, deployment, API key via Secret Storage) injected into launched terminals. See that folder's README.

Security

If you believe you found a security issue, see SECURITY.md.

Community

Contributing

Contributions are welcome. For larger changes, open an issue first so the scope is clear before implementation. See Development for the build, test, and pre-PR validation commands.

Disclaimer

OpenClaude is an independent community project and is not affiliated with, endorsed by, or sponsored by Anthropic.

OpenClaude originated from the Claude Code codebase and has since been substantially modified to support multiple providers and open use. "Claude" and "Claude Code" are trademarks of Anthropic PBC. See LICENSE for details.

License

MIT for OpenClaude contributors' modifications; the derived Claude Code remains Anthropic's. See more.

S
Description
runs anywhere. uses anything
Readme
94 MiB
Languages
TypeScript 98.9%
JavaScript 0.8%
Astro 0.2%