Three coordinated things:
1. Resolve the committed upstream/main merge conflicts. 94 files were
sitting with raw <<<<<<< HEAD ... >>>>>>> upstream/main blocks. Every
conflict had HanzoBot/Bot on HEAD and OpenClaw on upstream. Resolved
by keeping HEAD everywhere — 540 conflict blocks.
2. Rewrite remaining OpenClaw text refs.
OPENCLAW → HANZO_BOT
OpenClaw → HanzoBot (PascalCase type identifiers)
openclaw → bot (codebase convention — botToken,
botUsername etc.; avoids invalid
hyphenated JS identifiers)
openclaw[_]/openclaw[A-Z] → bot[_]/bot[A-Z] (compound)
ai.openclaw.x → ai.hanzo.bot.x (JVM package path)
3. Delete or rename openclaw-named file paths (116 of them). Dead
duplicates with a Bot-named canonical from the partial migration:
deleted. Otherwise renamed.
ai/openclaw/** → deleted (ai/hanzo/bot/** canonical)
Sources/OpenClaw*/ → deleted (Sources/Bot* canonical)
Tests/OpenClawIPCTests/ → deleted (Tests/BotIPCTests canonical)
OpenClawKit/ → deleted (BotKit canonical)
openclaw-tools.*.ts → deleted (bot-tools.*.ts canonical)
openclaw-root.ts etc. → deleted (bot-root.ts canonical)
types.openclaw.ts → deleted (types.bot.ts canonical)
extensions/*/openclaw.plugin.json → renamed hanzo-bot.plugin.json
docs/start/openclaw.md → renamed hanzo-bot.md (+ zh-CN)
docs/assets/openclaw-*.png, whatsapp-openclaw*.jpg → deleted
scripts/.../openclaw-* → deleted (bot/hanzo-bot parallels)
openclaw.mjs → deleted (hanzo-bot.mjs is package.bin)
Then patched 65 broken JS/TS import strings where hanzo-bot had ended
up inside an import path ('./types.hanzo-bot.js' → './types.bot.js'
etc., since the on-disk filename uses the brand-neutral bot- prefix).
Pre-existing lint debt cleaned up to get oxlint --type-aware to 0/0:
removed the dead i18n test that referenced a path no longer existing;
defined the missing DIDConfig and WalletConfig types in types.base.ts
(they were imported but never declared); dropped unused imports;
collapsed redundant type assertion and a tautological meta.bot lookup
that the openclaw→bot rename made redundant.
The a2ui.bundle.js generated artifact is kept at its pre-rebrand
contents — it gets regenerated by 'pnpm canvas:a2ui:bundle' from
sources I cannot rebuild in this commit; the source side is clean.
Verified: 0 occurrences of openclaw (case-insensitive) in tree source
content, 0 file or directory paths with openclaw in the name; oxlint
--type-aware src test reports 0/0.
6.7 KiB
summary, read_when, title
| summary | read_when | title | |||
|---|---|---|---|---|---|
| CLI backends: text-only fallback via local AI CLIs |
|
CLI Backends |
CLI backends (fallback runtime)
HanzoBot can run local AI CLIs as a text-only fallback when API providers are down, rate-limited, or temporarily misbehaving. This is intentionally conservative:
- Tools are disabled (no tool calls).
- Text in → text out (reliable).
- Sessions are supported (so follow-up turns stay coherent).
- Images can be passed through if the CLI accepts image paths.
This is designed as a safety net rather than a primary path. Use it when you want “always works” text responses without relying on external APIs.
Beginner-friendly quick start
You can use Claude Code CLI without any config (HanzoBot ships a built-in default):
hanzo-bot agent --message "hi" --model claude-cli/opus-4.6
Codex CLI also works out of the box:
hanzo-bot agent --message "hi" --model codex-cli/gpt-5.4
If your gateway runs under launchd/systemd and PATH is minimal, add just the command path:
{
agents: {
defaults: {
cliBackends: {
"claude-cli": {
command: "/opt/homebrew/bin/claude",
},
},
},
},
}
That’s it. No keys, no extra auth config needed beyond the CLI itself.
Using it as a fallback
Add a CLI backend to your fallback list so it only runs when primary models fail:
{
agents: {
defaults: {
model: {
primary: "anthropic/claude-opus-4-6",
fallbacks: ["claude-cli/opus-4.6", "claude-cli/opus-4.5"],
},
models: {
"anthropic/claude-opus-4-6": { alias: "Opus" },
"claude-cli/opus-4.6": {},
"claude-cli/opus-4.5": {},
},
},
},
}
Notes:
- If you use
agents.defaults.models(allowlist), you must includeclaude-cli/.... - If the primary provider fails (auth, rate limits, timeouts), HanzoBot will try the CLI backend next.
Configuration overview
All CLI backends live under:
agents.defaults.cliBackends
Each entry is keyed by a provider id (e.g. claude-cli, my-cli).
The provider id becomes the left side of your model ref:
<provider>/<model>
Example configuration
{
agents: {
defaults: {
cliBackends: {
"claude-cli": {
command: "/opt/homebrew/bin/claude",
},
"my-cli": {
command: "my-cli",
args: ["--json"],
output: "json",
input: "arg",
modelArg: "--model",
modelAliases: {
"claude-opus-4-6": "opus",
"claude-opus-4-5": "opus",
"claude-sonnet-4-5": "sonnet",
},
sessionArg: "--session",
sessionMode: "existing",
sessionIdFields: ["session_id", "conversation_id"],
systemPromptArg: "--system",
systemPromptWhen: "first",
imageArg: "--image",
imageMode: "repeat",
serialize: true,
},
},
},
},
}
How it works
- Selects a backend based on the provider prefix (
claude-cli/...). - Builds a system prompt using the same HanzoBot prompt + workspace context.
- Executes the CLI with a session id (if supported) so history stays consistent.
- Parses output (JSON or plain text) and returns the final text.
- Persists session ids per backend, so follow-ups reuse the same CLI session.
Sessions
- If the CLI supports sessions, set
sessionArg(e.g.--session-id) orsessionArgs(placeholder{sessionId}) when the ID needs to be inserted into multiple flags. - If the CLI uses a resume subcommand with different flags, set
resumeArgs(replacesargswhen resuming) and optionallyresumeOutput(for non-JSON resumes). sessionMode:always: always send a session id (new UUID if none stored).existing: only send a session id if one was stored before.none: never send a session id.
Images (pass-through)
If your CLI accepts image paths, set imageArg:
imageArg: "--image",
imageMode: "repeat"
HanzoBot will write base64 images to temp files. If imageArg is set, those
paths are passed as CLI args. If imageArg is missing, HanzoBot appends the
file paths to the prompt (path injection), which is enough for CLIs that auto-
load local files from plain paths (Claude Code CLI behavior).
Inputs / outputs
output: "json"(default) tries to parse JSON and extract text + session id.output: "jsonl"parses JSONL streams (Codex CLI--json) and extracts the last agent message plusthread_idwhen present.output: "text"treats stdout as the final response.
Input modes:
input: "arg"(default) passes the prompt as the last CLI arg.input: "stdin"sends the prompt via stdin.- If the prompt is very long and
maxPromptArgCharsis set, stdin is used.
Defaults (built-in)
HanzoBot ships a default for claude-cli:
command: "claude"args: ["-p", "--output-format", "json", "--permission-mode", "bypassPermissions"]resumeArgs: ["-p", "--output-format", "json", "--permission-mode", "bypassPermissions", "--resume", "{sessionId}"]modelArg: "--model"systemPromptArg: "--append-system-prompt"sessionArg: "--session-id"systemPromptWhen: "first"sessionMode: "always"
HanzoBot also ships a default for codex-cli:
command: "codex"args: ["exec","--json","--color","never","--sandbox","read-only","--skip-git-repo-check"]resumeArgs: ["exec","resume","{sessionId}","--color","never","--sandbox","read-only","--skip-git-repo-check"]output: "jsonl"resumeOutput: "text"modelArg: "--model"imageArg: "--image"sessionMode: "existing"
Override only if needed (common: absolute command path).
Limitations
- No HanzoBot tools (the CLI backend never receives tool calls). Some CLIs may still run their own agent tooling.
- No streaming (CLI output is collected then returned).
- Structured outputs depend on the CLI’s JSON format.
- Codex CLI sessions resume via text output (no JSONL), which is less
structured than the initial
--jsonrun. HanzoBot sessions still work normally.
Troubleshooting
- CLI not found: set
commandto a full path. - Wrong model name: use
modelAliasesto mapprovider/model→ CLI model. - No session continuity: ensure
sessionArgis set andsessionModeis notnone(Codex CLI currently cannot resume with JSON output). - Images ignored: set
imageArg(and verify CLI supports file paths).