* fix: type safety, defensive defaults, and unbounded retry prevention
QueryEngine.ts:
- Import PERMISSION_MODES runtime constant and validate permissionMode
before casting in submitMessage — invalid mode strings fall back to
'default' instead of crashing with ReferenceError: PERMISSION_MODES is
not defined (fixes the runtime gap from the original PR)
- Use splice(0, length, ...messages) instead of length=0 + push() for
atomic array replacement in snip replay, so concurrent readers of
getMessages() never observe an empty state
withRetry.ts:
- Cap persistent retry loop at 100 attempts via PERSISTENT_RETRY_MAX_ATTEMPTS
constant — prevents unbounded retry (~8 hours max with exponential backoff
and 6-hour reset cap) when the unattended retry path is enabled
autoCompact.ts:
- Add MIN_AUTOCOMPACT_FAILURE_COOLDOWN_MS = 10_000 floor for
OPENCLAUDE_AUTOCOMPACT_FAILURE_COOLDOWN_MS override — prevents
misconfiguration from effectively disabling the circuit breaker
autoCompact.test.ts:
- Update test override from 5000 to 15000 to respect the new 10s minimum floor
- Add test case verifying values below the floor (5000, 9999) are rejected
and that the floor value (10000) is accepted
- Update circuit breaker retry-time expectation from 111_000 to 121_000
to account for the new 15s cooldown override
* test: enable UNATTENDED_RETRY feature in bun test scripts
The new persistent retry cap test in withRetry.test.ts needs the real
UNATTENDED_RETRY feature gate to fire, which requires passing
--feature=UNATTENDED_RETRY on the bun test command line. Enable it
in the standard test, test:full, test:coverage, and test:provider
scripts so the test sees the production gate behavior.
* test: cover persistent retry cap driven through real gate
Add a regression test that proves the persistent retry path stops
after PERSISTENT_MAX_ATTEMPTS=100 retryable 429s by driving the real
isPersistentRetryEnabled() gate (no test override seam). Also:
- Switch makeError to the new APIError() constructor so the test
errors match the real wire shape and exercise the production
canRetry/shouldRetry branches
- Add CLAUDE_CODE_UNATTENDED_RETRY to the envKeys clear list so the
gate isn't poisoned by leaked state from a prior test
- Mock src/utils/sleep.js in importFreshWithRetryModule so the
exponential-backoff delays don't slow the suite down
* test: defensively clear leaked env vars in client.test.ts
The 4 failing tests in CI (first-party Anthropic fetch wrapper, env-only
MiniMax routing, OPENAI_MODEL preservation, OpenAI shim options) all sit
at the top of the file and are sensitive to leaked env vars from prior
test files in the same process. Extend the beforeEach, afterEach, and
inline cleanup to clear OPENAI_AUTH_HEADER, OPENAI_AUTH_SCHEME,
OPENAI_AUTH_HEADER_VALUE, MIMO_API_KEY, VENICE_API_KEY, and
NVIDIA_API_KEY alongside the existing vars, and add ANTHROPIC_API_KEY /
ANTHROPIC_AUTH_TOKEN / ANTHROPIC_MODEL to the first test's inline
cleanup so it does not rely solely on the global beforeEach when run
in isolation.
* test: isolate countMcpToolTokens tests from mcp.ts env-var side effect
src/entrypoints/mcp.ts sets CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=true as
a top-level side effect on import. mcp.test.ts imports that file, so the
env var is leaked into the rest of the test process. In
analyzeContext.mcp.test.ts the kill switch forces getToolSearchMode() to
'standard', which makes isToolSearchEnabled() return false, so the
'keeps deferred MCP schemas excluded' test sees isDeferred=false and
returns mcpToolTokens=1000 instead of 0.
Clear the kill switch and ENABLE_TOOL_SEARCH in beforeEach (restoring
the original values in afterEach) so the test observes the production
default of tool search enabled regardless of test ordering.
* fix: validate against EXTERNAL_PERMISSION_MODES; confine persistent retry override to test-only module var
QueryEngine.ts:
- Switch SDK init permissionMode validation from the internal
PERMISSION_MODES set to EXTERNAL_PERMISSION_MODES. The internal
set can include the classifier-only 'auto' mode that is not a
valid wire value for the SDK system/init payload, so emitting
it would produce an unsupported configuration.
withRetry.ts:
- Rename PERSISTENT_RETRY_MAX_ATTEMPTS to PERSISTENT_MAX_ATTEMPTS
to match the convention of the other PERSISTENT_* constants and
re-export it as _PERSISTENT_MAX_ATTEMPTS_FOR_TEST for unit-test
assertion of the cap value (no runtime override seam).
- Hoist isPersistentRetryEnabled() into a local
persistentRetryEnabled const at the top of withRetry() so all
call sites see a consistent snapshot within a single retry
chain.
- Thread persistentRetryEnabled through shouldRetry() so its
branch is decided once per chain rather than re-reading the
feature flag and env var on every attempt.
* feat: emit telemetry when persistent retry cap is reached
* fix: surface changelog cache-write failures in migration
- Only swallow EEXIST (file already exists) errors in migrateChangelogFromConfig
- Rethrow all other write failures (permissions, disk full, etc.)
- Log migration errors instead of silently ignoring them
- This ensures migration failures are surfaced and will retry on next startup
* fix: split mkdir and writeFile in changelog migration
- Ensure mkdir runs before writeFile try/catch
- Only suppress EEXIST from writeFile, not mkdir
- Prevents EEXIST from mkdir incorrectly counting as successful write
* fix: stop overriding getGlobalConfig in user.test.ts mock
* Fix leftover conflict marker in QueryEngine.ts
* fix: remove stale retry guard and handle mkdir EEXIST
- Remove duplicate shouldRetry() call without persistentRetryEnabled arg in withRetry.ts
- Wrap mkdir in try-catch to handle EEXIST on Windows/Bun readonly folders in releaseNotes.ts
* test: don't restore OPENAI auth header env vars in afterEach
These vars were being restored from originalEnv which captures polluted values
from prior test files in the full suite. Removing the restoreEnv calls keeps
them cleared between tests, fixing 'Could not resolve authentication method'
failures in CI smoke-and-tests.
* fix: remove duplicate OPENAI_AUTH_* keys in originalEnv (TS1117)
* fix: restore OPENAI auth header snapshot and move MCP lock to top-level
- client.test.ts: restore OPENAI_AUTH_HEADER/SCHEME/HEADER_VALUE in afterEach
so the file doesn't permanently clear those globals in its worker
- analyzeContext.mcp.test.ts: move acquireSharedMutationLock/release to the
top-level beforeEach/afterEach so all env mutations in this file happen
while the shared mutation lock is held
* fix: use splice for atomic array replacement in snip replay
Restores the atomic array replacement using splice(0, length, ...messages)
instead of length=0 + push(...) that was claimed in commit 4d54d5d but
lost during merge. This ensures concurrent readers of getMessages() never
observe an empty mutableMessages array during snip replay, matching the
compact_boundary behavior.
* ci: add UNATTENDED_RETRY feature flag to release workflow test command
The persistent retry cap test requires the UNATTENDED_RETRY feature flag
to be enabled. The release workflow was running 'bun test --max-concurrency=1'
without the feature flag, causing the test to fail on the release path.
This aligns the release workflow with the package.json test scripts which
all include --feature=UNATTENDED_RETRY.
* fix: clear auth env vars in shared setup; add telemetry at persistent retry cap
- Remove duplicate OPENAI_AUTH_HEADER/SCHEME/VALUE deletes from
clearEnvForMiniMaxOnlyTest() (shared beforeEach already clears them)
- Clarify persistent retry cap comment: the ~8h estimate only applies to
the exponential-backoff path; the reset-delay path (up to
PERSISTENT_RESET_CAP_MS / 6h per attempt) can take far longer
- Telemetry event at retry cap already present from prior commit
* fix: make persistent retry cap test pass without --feature=UNATTENDED_RETRY
Updated test to account for feature flag behavior in retry logic.
* fix: normalize REPL bridge permissionMode against EXTERNAL_PERMISSION_MODES
* fix: export isPersistentRetryEnabled for test-side feature-gate assertion
* fix: use isPersistentRetryEnabled() as real feature gate in retry cap test
Refactor withRetry test to include isPersistentRetryEnabled check and update expected calls logic.
* fix: restore missing retryableRateLimit declaration in persistent retry test
Refactor runRetries function for clarity.
OpenClaude
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.
OpenClaude is also mirrored to GitLawb: gitlawb.com/node/repos/z6MkqDnb/openclaude
Quick Start | Setup Guides | Providers | Source Build | VS Code Extension | Sponsors | Community
Sponsors
|
|
|
|
|
| GitLawb | Bankr.bot | Atomic Chat | Xiaomi MiMo | Atlas Cloud |
Star History
Why OpenClaude
- Use one CLI across cloud APIs and local model backends
- Save provider profiles inside the app with
/provider - Run with OpenAI-compatible services, Gemini, GitHub Models, Codex OAuth, Codex, Ollama, Atomic Chat, and other supported providers
- Keep coding-agent workflows in one place: bash, file tools, grep, glob, agents, tasks, MCP, and web tools
- Use the bundled VS Code extension for launch integration and theme support
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
/providerfor guided provider setup and saved profiles - run
/onboard-githubfor GitHub Models onboarding
Note: OpenClaude does not automatically load project
.envfiles. We recommend using the/providercommand for setup, which saves provider profiles and credentials in.openclaude-profile.json. If you prefer environment variables, export them explicitly or runopenclaude --provider-env-file .envfor provider/setup variables. Export runtime/debug knobs from your shell or launcher.
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, with CLAUDE_CONFIG_DIR still supported as the
legacy fallback. Session names can be reused after older sessions reach a
terminal state; use the session ID to inspect older logs with the same name.
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.
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
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 and defaults to glm-5.2 |
| 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 |
| 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 (43 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 |
| 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
- 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
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
- 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-*andgoogle/gemini-3.1-flash-lite-previewwith/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/v4withglm-5.2by default. Useglm-5.2?reasoning=highfor enhanced reasoning,glm-5.2?reasoning=xhighto request Z.AIreasoning_effort=max, orglm-5.2?thinking=disabledfor faster direct answers. - Xiaomi MiMo uses
api-keyheader auth on the direct OpenAI-compatible route and currently does not support/usagereporting in OpenClaude
GitHub Copilot sub-agent optimization
When CLAUDE_CODE_USE_GITHUB=1, OpenClaude serializes sub-agent execution to reduce GitHub Copilot Premium Request consumption. Default behavior is GITHUB_COPILOT_MAX_SUBAGENTS=1 (synchronous, one sub-agent at a time). Tuning vars (all optional):
| Var | Effect |
|---|---|
| GITHUB_COPILOT_MAX_SUBAGENTS=0 | Suppress sub-agents entirely (sub-agents throw an error). |
| GITHUB_COPILOT_MAX_SUBAGENTS=1 | Force synchronous execution. Default. |
| GITHUB_COPILOT_MAX_SUBAGENTS=2..10 | Parsed/clamped but not enforced differently from =1 (any positive cap = synchronous). |
| GITHUB_COPILOT_ALLOW_SUBAGENTS=1 | Re-enable parallel/background sub-agents, overriding the cap. |
| GITHUB_COPILOT_FORCE_SYNC_SUBAGENTS=1 | Force synchronous execution regardless of cap. |
| GITHUB_COPILOT_OPTIMIZATION_DISABLED=1 | Disable all of the above; sub-agents run as before this feature. |
The is_async field reported in the tengu_agent_tool_selected event and the agent metadata now reflects the final execution mode (i.e., false when synchronous is forced). See .env.example for the full descriptions.
For best results, use models with strong tool/function calling support.
Agent Routing
OpenClaude can route different agents to different models through settings-based routing. This is useful for cost optimization or splitting work by model strength.
Add to ~/.openclaude.json:
{
"agentModels": {
"deepseek-v4-flash": {
"base_url": "https://api.deepseek.com/v1",
"api_key": "sk-your-key"
},
"zai-default": {
"model": "glm-5.2",
"base_url": "https://api.z.ai/api/coding/paas/v4",
"api_key": "sk-your-key"
},
"gpt-4o": {
"base_url": "https://api.openai.com/v1",
"api_key": "sk-your-key"
}
},
"agentRouting": {
"Explore": "deepseek-v4-flash",
"Plan": "gpt-4o",
"general-purpose": "gpt-4o",
"frontend-dev": "zai-default",
"default": "gpt-4o"
}
}
When no routing match is found, the global provider remains the fallback.
agentRouting values and explicit Agent tool model overrides match keys in agentModels. By default, that key is also the model string sent to the provider. Set agentModels.<key>.model when you want a local route key such as zai-default to call a different provider model name such as glm-5.2.
Note:
/providerchanges the global/parent provider for your current session.agentModelsandagentRoutingare specifically for configuring per-agent provider overrides while keeping the parent session unchanged.
Note:
api_keyvalues insettings.jsonare stored in plaintext. Keep this file private and do not commit it to version control.
Model-only routes (same provider): Omit base_url and api_key to run an agent on a different model using your current provider's endpoint and key — no credential duplication:
{
"agentModels": {
"mini": { "model": "gpt-5-mini" }
},
"agentRouting": {
"verification": "mini"
}
}
Built-in agents are routable by their type name. Useful keys: verification (the read-only auditor that runs before completion), Explore, and Plan. For example, "agentRouting": { "verification": "mini" } runs the verifier on gpt-5-mini while your main session stays on its model. Absent any entry, the verifier inherits the main-loop model.
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:
WebSearchcan use Firecrawl's search API while DuckDuckGo remains the default free path for non-Claude modelsWebFetchuses 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 be run as a headless gRPC service, allowing you to integrate its agentic capabilities (tools, bash, file editing) into other applications, CI/CD pipelines, or custom user interfaces. The server uses bidirectional streaming to send real-time text chunks, tool calls, and request permissions for sensitive commands.
1. Start the gRPC Server
Start the core engine as a gRPC service on localhost:50051:
npm run dev:grpc
Configuration
| Variable | Default | Description |
|---|---|---|
GRPC_PORT |
50051 |
Port the gRPC server listens on |
GRPC_HOST |
localhost |
Bind address. Use 0.0.0.0 to expose on all interfaces (not recommended without authentication) |
2. Run the Test CLI Client
We provide a lightweight CLI client that communicates exclusively over gRPC. It acts just like the main interactive CLI, rendering colors, streaming tokens, and prompting you for tool permissions (y/n) via the gRPC action_required event.
In a separate terminal, run:
npm run dev:grpc:cli
Note: The gRPC definitions are located in src/proto/openclaude.proto. You can use this file to generate clients in Python, Go, Rust, or any other language.
Source Build And Local 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
Helpful commands:
bun run devbun testbun run test:coveragebun run security:pr-scan -- --base origin/mainbun run smokebun run doctor:runtimebun run verify:privacy- focused
bun test ...runs for the areas you touch
Testing And Coverage
OpenClaude uses Bun's built-in test runner for unit tests.
Run the full unit suite:
bun test
Generate unit test coverage:
bun run test:coverage
Open the visual coverage report:
open coverage/index.html
If you already have coverage/lcov.info and only want to rebuild the UI:
bun run test:coverage:ui
Use focused test runs when you only touch one area:
bun run test:providerbun run test:provider-recommendationbun test path/to/file.test.ts
Recommended contributor validation before opening a PR:
bun run buildbun run smokebun run test:coveragefor broader unit coverage when your change affects shared runtime or provider logic- focused
bun test ...runs for the files and flows you changed
Coverage output is written to coverage/lcov.info, and OpenClaude also generates a git-activity-style heatmap at coverage/index.html.
Repository Structure
src/- core CLI/runtimescripts/- build, verification, and maintenance scriptsdocs/- setup, contributor, and project documentationpython/- standalone Python helpers and their testsvscode-extension/openclaude-vscode/- VS Code extension.github/- repo automation, templates, and CI configurationbin/- 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
- Use GitHub Discussions for Q&A, ideas, and community conversation
- Use GitHub Issues for confirmed bugs and actionable feature work
- Join the Discord to chat with the community in real time
- Follow @gitlawb on X for updates and announcements
Contributing
Contributions are welcome.
For larger changes, open an issue first so the scope is clear before implementation. Helpful validation commands include:
bun run buildbun run test:coveragebun run smoke- focused
bun test ...runs for files and flows you changed
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.