* chore(types): add any-usage baseline + lint budget gate (Phase 0)
Phase 0 of a multi-phase plan to reduce explicit `any` usage safely.
No source files modified in this PR.
- Add eslint@9 + @typescript-eslint deps (lint only, no fix rules).
- New minimal flat eslint.config.js enabling only
`@typescript-eslint/no-explicit-any` as warn. Stub plugins registered
for legacy `custom-rules`, `eslint-plugin-n`, and `react-hooks`
references in existing `// eslint-disable` comments so the comments
stay valid (no rule name resolution errors).
- New `scripts/any-usage-report.ts`: walks src/, tests/, scripts/ and
buckets `any` usage into `: any` annotations, `as any` casts,
`[key: ...]: any` index signatures, `// @ts-ignore` directives, and
generic `any` args. Emits `reports/any-usage.{json,md}`. `--check`
mode exits non-zero if the count grows vs the baseline.
- Lock the baseline at 1,031 occurrences across 198 files.
- Add `lint`, `lint:any-budget`, `check:strict` scripts.
- Plan: docs/plans/imperative-hugging-sphinx.md
Verification:
- `bun run typecheck` clean
- `bun run lint` exit 0 (845 warnings, 0 errors)
- `bun run lint:any-budget` ok (current=1031 baseline=1031)
* chore(types): narrow any in 6 small src files (Phase 1, batch 1)
Phase 1 of the plan to reduce `any` usage. Targets only files with
1–2 lint hits where the concrete type is reachable in scope.
- src/services/api/withRetry.ts: isQuotaExhausted signature `any` → `unknown`,
add local structural narrowing for `.message`/`.status` access.
- src/utils/validation.ts: assertFunction predicate signature `any[]`/`any` →
`unknown[]`/`unknown`.
- src/utils/conversationArc.ts: extractTextFromContent — replace `(block: any)`
in filter/map with explicit type predicate narrowing.
- src/utils/optionalRuntimeModule.ts: dynamic-import wrapper returns
`Promise<unknown>` instead of `Promise<any>`.
- src/entrypoints/mcp.ts: tighten block mapping with the existing structural
type already in scope; replace `(finalResult as any).isError` with a
narrow cast.
- src/components/EffortPicker.tsx: drop redundant `: any` on useAppState
selector — the function's generic infers `AppState` for free.
Verification:
- bun run typecheck clean
- bun run lint: 835 warnings (was 845)
- bun run lint:any-budget: 1022 / 1031 baseline (delta -9)
- bun test src/utils/optionalRuntimeModule.test.ts + conversationArc.test.ts:
36 pass / 0 fail
- bun test src/services/api/withRetry.test.ts: 44 pass / 0 fail
* chore(types): narrow any in WebSearchTool + adapters (Phase 1, batch 2)
Phase 1 continues. These are all boundary code (HTTP responses from
external search APIs), so every `any` is at a module boundary per the
plan. Each adapter now types its response with `unknown` + structural
narrowing instead of `any`.
- providers/types.ts: firstMatch/normalizeHit accept `unknown` and narrow
to `Record<string, unknown>` before index access.
- providers/timeout.ts: fetchJsonWithWebSearchTimeout returns
Promise<unknown>.
- providers/{bing,brave,jina,linkup,mojeek,tavily,you,exa,custom}.ts: each
adapter's response data is cast to a minimal shape (`{ results?: unknown }`
etc.), then array elements are narrowed to `Record<string, unknown>` with
`typeof` checks per field.
- WebSearchTool.ts: getCodexSources and extractCodexWebSearchFailure now
take `Record<string, unknown>`; nested `action`/`error`/`result` are
cast locally to `Record<string, unknown>` so `?.field` chains type-check.
Verification:
- bun run typecheck clean
- bun run lint: 805 warnings (was 835, -30)
- bun run lint:any-budget: 992 / 1022 baseline
- bun test src/tools/WebSearchTool: 138 pass / 0 fail across 9 files
* chore(types): narrow any in 6 mid-size src files (Phase 1, batch 3)
Phase 1 continues. Each replacement uses a precise structural cast
(`as { uuid?: string }` etc.) or `unknown` with typeof/Array.isArray
narrows at use sites.
- src/utils/settings/types.ts: zod preprocess callback `any` → `unknown`,
copy via `Record<string, unknown>`.
- src/entrypoints/sdk/v2.ts: initialMessages param/var `any[]` → `Message[]`;
local cast at the boundary with stripChainFields.
- src/entrypoints/sdk/query.ts: msg `.uuid` access uses
`as { uuid?: string }`; `fileHistoryCanRestore` etc. accept `UUID` (from
`crypto`); `mcpServerStatus` accesses `client.error` / `client.config`
directly since the union members already have them.
- src/commands/cache-probe/cache-probe.ts: getField reduce `any` → `unknown`
with typeof guard; catch (err: any) → `err: unknown` with
`err instanceof Error`; mainMakeUsage/mainConvertChunkUsage take `unknown`
and read fields via typeof checks.
- src/services/compact/snipProjection.ts: snipMetadata / uuid accessed via
narrow structural casts, no longer `as any`.
- src/utils/messages.ts: tool_use block destructuring for extra_content uses
`as { extra_content?: unknown; [k: string]: unknown }` instead of
`as any`.
Public SDK surface (entrypoints/sdk.d.ts, entrypoints/sdk/index.ts
SdkMcpToolDefinition<Schema = any>) is intentionally permissive for
consumer ergonomics and is left untouched per the plan's do-not-touch
list.
Verification:
- bun run typecheck clean
- bun run lint: 782 warnings (was 805, -23)
- bun run lint:any-budget: 969 / 992 baseline
- bun test (sdk v2/factories + compact + messages): 91 pass / 0 fail
* fix(types): correct BetaContentBlock cast in messages.ts (Phase 1 fix)
Verifier caught that the `as { [k: string]: unknown; extra_content?: unknown }`
cast on a `BetaToolUseBlock` did not sufficiently overlap (BetaToolUseBlock
lacks an index signature), so the destructured spread of `restBlock`
yielded a malformed union member that failed to assign to BetaContentBlock[].
Fix: cast through `unknown` first, then assert the final return value as
`BetaContentBlock` (the declared element type of the outer `.map`). This
narrows from the prior `as any` while keeping the previous structural
intent (preserve all block fields, optionally inject `extra_content`).
Verification:
- bun run typecheck clean
- bun test src/utils/messages/: 79 pass / 0 fail
* chore(types): narrow any in 5 dense src + 1 script (Phase 1, batch 4)
Each replacement preserves runtime behavior while using concrete types
where reachable and `unknown` with structural narrowing where not.
- src/components/ClaudeMdExternalIncludesDialog.tsx: 4 helper updaters
(acceptProject/User, declineProject/User) take `ProjectConfig` from
`src/utils/config.ts` instead of `any` (matches the
`saveCurrentProjectConfig` updater signature).
- src/components/ProviderManager.tsx: env-clearing objects in
`activateGithubProvider` and the GitHub disable path used
`undefined as any`. The intent is "delete this key on merge" but the
zod schema coerces to string. Replaced with
`undefined as unknown as string` (honest about the lie) and added a
comment explaining intent.
- src/services/compact/snipCompact.ts: introduced a structural
`SnipMessage` type for the public function params. Tests construct
fake messages with `uuid: 'u4'` (not branded UUID), so a strict
`Message[]` would reject them; the structural type accepts both
production messages and test fixtures. `snipCompactIfNeeded` is
generic `<T extends SnipMessage>` so callers get the same shape back.
Internal content blocks use `unknown` + type-predicate narrowing.
- src/query.ts: yield site for the boundary message casts to `Message`
since the value is constructed as a real `Message` in production.
- scripts/grpc-cli.ts: proto descriptor, stream, and message callback
typed as `unknown` / `ClientDuplexStream<unknown, unknown>`. The
dynamic `.proto` payload is cast once at the boundary into a
structural shape so per-field access (`text_chunk.text` etc.) is
tracked explicitly.
- scripts/generate-sdk-types.ts: the JSON-Schema-walking converter
takes `unknown` everywhere and narrows via typeof / Array.isArray at
each access. `Map<unknown, string>` for placeholder identity
comparison, `Set<string | undefined>` no longer used here.
Verification:
- bun run typecheck clean
- bun run lint: 728 warnings (was 782, -54)
- bun run lint:any-budget: 916 / 969 baseline
- bun test src/services/compact: 91 pass / 0 fail
* chore(types): remove 3 eslint-disable no-explicit-any suppressions
Tighten three small call sites where the `any` was used as a lazy
escape hatch and a real type was reachable in scope.
- src/main.tsx: `(global as any).require('inspector')` becomes
`(global as unknown as { require: (s: string) => { url: () => string } })`.
The dynamic require is being phased out, but while it remains the
narrow structural cast documents the shape we actually consume.
- src/ink/reconciler.ts: catch (error: any) → catch (error: unknown);
`error.code === 'ERR_MODULE_NOT_FOUND'` accesses the code via
`(error as { code?: unknown }).code`.
- src/components/wizard/WizardProvider.tsx:
`createContext<WizardContextValue<any> | null>(null)` →
`createContext<WizardContextValue | null>(null)`. The
`WizardContextValue` generic already defaults to
`Record<string, unknown>`, so the `<any>` was redundant; consumers
that need a tighter type can supply it via
`useContext<WizardContextValue<T>>`.
Note: most remaining lint warnings come from file-level
`/* eslint-disable @typescript-eslint/no-explicit-any */` blocks at the
top of do-not-touch files (src/types/{message,utils,tools}.ts,
src/constants/querySource.ts, src/entrypoints/sdk/controlTypes.ts) and
from public SDK surface (src/entrypoints/sdk{,.d.ts,v2.ts}). Both are
intentional per the plan.
Verification:
- bun run typecheck clean
* chore(types): refresh any-usage baseline
* fix(types): address PR review feedback on any-reduction tooling
- Pin eslint to resolved version (9.39.5) so lint warning totals stay
stable across lockfile updates.
- Wire lint:any-budget into the regular `check` gate (was only in
check:strict), so any-usage regressions block PRs.
- any-usage-report: use lstat and skip symlinks so a self-referencing
link under src/tests/scripts can't stall the budget scan.
- any-usage-report --check: exit nonzero when the baseline file is
missing or invalid so the gate can't be silently disabled.
- Remove dangling references to docs/plans/imperative-hugging-sphinx.md
from eslint.config.js and scripts/any-usage-report.ts headers.
- mcp.ts: defensively skip non-object tool-output entries (primitives
/ null) instead of crashing on boundary data.
- messages.ts: realign the mis-indented tool_search-off branch so the
blockExtra + return block reads at the right level.
No budget delta (913 -> 913). Typecheck, lint, budget, and the affected
unit tests all green.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore(types): narrow any in src/grpc/server.ts (5 warnings)
- protoDescriptor cast: replace `as any` with a structural type that only
declares the AgentService shape we actually use.
- handleChat: ServerDuplexStream<any, any> -> <unknown, unknown>; the
clientMessage is narrowed locally where it's read.
- previousMessages: any[] -> Message[] (already imported, already used
as the type of this.sessions).
- catch (err: any) -> catch (err); err.message is now gated behind an
instanceof Error check.
Typecheck, lint, budget, and the 2 grpc unit tests all green.
Lint 728 -> 723 (-5). Budget 913 -> 909 (-4).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore(types): narrow any in src/utils/knowledgeGraph.ts (18 warnings)
Add explicit LegacyEntity / LegacyRelation / LegacySummary / LegacyData
types so the migration path stops round-tripping through `any`.
- LegacySource.data, mergeLegacySources, normalizeLegacyData,
readLegacySqliteStore, SqliteReadResult.data, and doMigration all take
the new LegacyData shape.
- LegacyData.entities is typed `Record<string, LegacyEntity> | LegacyEntity[]`
because older JSON dumps stored entities as an array. normalizeLegacyData
converts the array form to the record form so downstream code can keep
using Object.entries. (Old loop relied on the same `id ?? entryKey`
fallback, so behavior is preserved; verified by all 20 unit tests.)
- SQLite row accessor now returns `Record<string, unknown>` (was `any[]`);
per-row readers narrow `row.id`, `row.attributes`, `row.keywords`,
`row.content` from `unknown` and the existing typeof guards preserve
the previous fail-soft behavior on malformed rows.
Lint 723 -> 705 (-18). Budget 909 -> 894 (-15). All 20 knowledgeGraph
unit tests pass; typecheck clean.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore(types): narrow SDK tool() generic and handler signature (12 warnings)
The public SDK MCP tool() helper previously defaulted its Schema generic
to `any` and typed handler args as `any`. Switch both to `unknown`:
- SdkMcpToolDefinition<Schema = unknown>
- tool<Schema = unknown> with handler (args: Schema, extra: unknown)
- annotations?: any -> ToolAnnotations (imported from MCP SDK types)
This is a strictly tighter API: callers who pass a concrete schema get
the same behavior; callers who relied on implicit any now have to
validate handler args (which they should have been doing anyway).
All 4 SDK MCP tool wiring tests pass; typecheck clean.
Lint 705 -> 695 (-10). Budget 894 -> 884 (-10).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(types): address PR feedback on SDK + grpc type hardening
Apply 4 of 5 CodeRabbit review items (skipped item 5: SDK resume flow
JSONL validation, deferred as larger refactor).
- sdk.d.ts: switch MCP type imports to the package's public
`@modelcontextprotocol/sdk/types.js` subpath (was the internal
dist/esm/types.js path).
- sdk.d.ts: handler return Promise<any> -> Promise<CallToolResult> in
both SdkMcpToolDefinition and the tool() helper, matching the
runtime contract and the sibling declarations in sdk/index.ts and
sdk/v2.ts.
- grpc/server.ts: introduce a local ClientMessage interface (matching
the openclaude.proto oneof payload) and type the duplex-stream
request as ServerDuplexStream<ClientMessage, unknown>. The handler
body was already reading these fields by name; the type now
documents them.
- grpc/server.ts: ServiceDefinition generic was being passed a
ServerDuplexStream, which isn't a valid T (T must be a record
keyed by method name). Switch to ServiceDefinition<{ Chat: never }>
so the call to addService accepts a real implementation-map key.
Typecheck, lint, budget, and the 6 affected unit tests all green.
Lint 695 -> 693 (-2). Budget 884 -> 882 (-2).
* fix(types): address 6 reviewer findings on PR #2208
Six findings (four P2, two P3) from the second review pass.
1. knowledgeGraph legacy array normalization: previously dropped entries
whose `id` was neither string nor number, breaking recovery for
idless array entries. Use the array index as the fallback key so
mergeLegacySources' existing `id ?? entryKey` logic continues to
recover the entry. All 20 unit tests still pass.
2. SDK tool() generic conflated schema descriptor with invocation
value type, breaking the test fixture (and any external consumer)
that declares the handler with a concrete value type. Restore
`args: any` for the handler across the factory, SdkMcpToolDefinition,
and the .d.ts declaration; keep `Schema` as the generic for
inputSchema typing.
3. sdk.d.ts now declares ToolAnnotations and CallToolResult locally
instead of importing from @modelcontextprotocol/sdk, preserving
the optional peer contract. A consumer without MCP installed no
longer gets TS2307 on a no-op SDKSession type import.
4. any-usage-report now strips comments, string literals, and
template-literal contents before applying the annotation regex,
so `// example: any`, `': any'`, and similar non-type occurrences
no longer count. @ts-ignore / @ts-expect-error / @ts-nocheck
directives are preserved for the ignore category. Budget went
from 882 to 776.
5. generate-sdk-types: schemas module cast as Record<string, () => unknown>
was wrong because HOOK_EVENTS is a non-callable; cast as
Record<string, unknown> and narrow per-access. def.getter() and
Reflect.get(schema, 'description') both narrowed to a callable /
object shape before use. Generated output unchanged (diff empty).
6. any-usage-report walk(): readdir failures now propagate instead
of being silently swallowed, so a partial scan cannot publish a
too-low replacement baseline or pass --check.
Typecheck, lint, budget, and 26 affected unit tests all green.
* chore(types): refresh any-usage baseline after upstream rebase
Baseline 776 -> 779. The +3 comes from upstream #2196 (Command Code
gateway) test mocks merged to main after the baseline was recorded:
2x (payload: any) in ProviderManager.test.tsx, 1x 'as any' in
providerProfiles.test.ts. Symptom-level narrowing of another merged
PR's test fixtures is out of scope; re-baseline to the rebased tree.
---------
Co-authored-by: Gravirei <gravirei@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
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 | Development | VS Code Extension | Partners | Community
Partners
|
|
|
|
|
| GitLawb | Bankr.bot | Atomic Chat | Xiaomi MiMo | Atlas Cloud |
|
|
|
|
|
|
| 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
/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.
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:
- Advanced Setup
- Smart Auto-Routing
- Agent Routing and Step Limits
- Headless gRPC Server
- Repo Map (codebase intelligence)
- Skills
- Android Install
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_MAPflag is enabled or theREPO_MAPenvironment 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-*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. On that direct route, GLM-5.3-Flash is selectable asglm-5.3-flashand accepts image input. Its OpenClaude effort choices arelow,high, andxhigh, withxhighrequesting Z.AImax; 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-keyheader auth on the direct OpenAI-compatible route and currently does not support/usagereporting 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+agentRoutingin~/.openclaude/settings.json - model-only routes that reuse your current provider's credentials
- built-in agents (
ExploreandPlan[feature-gated],verification[feature-gated: requiresVERIFICATION_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:
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 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 sourcebun test— full unit suite (Bun's built-in runner)bun test path/to/file.test.ts— focused runs for the areas you touchbun run test:coverage— coverage tocoverage/lcov.infoplus a visual report atcoverage/index.html(bun run test:coverage:uirebuilds just the UI)bun run smoke— smoke checksbun 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 buildbun run smokebun run test:coveragewhen your change affects shared runtime or provider logic- focused
bun test ...runs for the files and flows you changed
Repository Structure
src/- core CLI/runtimescripts/- build, verification, and maintenance scriptsdocs/- setup, contributor, and project documentationvscode-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. 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.
