docs: make onboarding friendlier for beginners (#4177)

* docs: make onboarding friendlier for beginners

* docs: build clearer documentation paths

Maintainer edit: turn the onboarding follow-up into a layered docs structure for first-time setup, provider selection, troubleshooting, CLI reference, and source-level architecture. This keeps quick start focused while giving advanced users precise reference paths.

* docs: render architecture flow with mermaid

Maintainer edit: replace the ASCII architecture sketch with a GitHub-rendered Mermaid flowchart so the core runtime path is easier to scan in the PR and README docs.

* docs: recommend model presets for model config

Maintainer edit: make named modelPresets the primary model configuration path and expand fallback preset examples so string fallbacks are clearly preset names, not raw model IDs.

* docs: document api base urls and langfuse setup

Maintainer edit: explain when users need apiBase/base URL in quick start and provider docs, and add Langfuse tracing setup with troubleshooting links.

* docs: use python module pip consistently

Maintainer edit: keep install commands tied to the active Python interpreter by using python -m pip in the Azure optional dependency notes too.

* docs: add non-technical getting started path

Maintainer edit: add a wizard-first guide for users without terminal or JSON background, including a text TUI menu example and links from the main docs entrypoints.

* docs: avoid hard-wrapped prose in user docs

Maintainer edit: unwrap ordinary prose across user-facing documentation while preserving markdown structure, code blocks, tables, lists, and prompt/template files.

* docs: keep desktop list continuations nested

Maintainer edit: preserve list nesting after unwrapping prose in the desktop WebUI sync guide.

* docs: add one-command installer

Maintainer edit: add auditable macOS/Linux and Windows install scripts that install nanobot-ai and start the onboarding wizard, then document the commands in the main onboarding entrypoints.

* docs: add installer dry run mode

Maintainer edit: add --dry-run to the one-command installer scripts so users can preview Python detection, install source, pip command, and wizard behavior without changing their environment.

* docs: clean installer error output

Maintainer edit: make PowerShell installer failures print a concise Error: message instead of Write-Error call-site details.

* docs: add provider setup cookbook

Maintainer edit: add pasteable provider recipes for common hosted, local, fallback, runtime switching, and Langfuse setups, then link the cookbook from onboarding and troubleshooting entrypoints.

* docs: address review feedback

* docs: clarify reader paths

* docs: explain terminal basics for beginners

* docs: clarify wizard navigation

* docs: avoid duplicate onboarding steps

* docs: add setup status check

* docs: explain status output

* docs: remove provider recommendation wording

* docs: explain status diagnostics

* docs: reduce hard-wrapped guidance

* docs: migrate config examples to presets

* docs: clarify python command fallbacks

* docs: improve installer failure recovery

* docs: expand install troubleshooting

* docs: cover installer download failures

* docs: put stable install paths first

* docs: add bundled webui quick path

* docs: clarify provider-neutral setup

* docs: clarify gateway setup for chat surfaces

* docs: improve docs navigation paths

* docs: add configuration quick jump

* docs: clarify provider secret variables

* chore: request PR review acknowledgement

Empty commit: please read the PR review comments and reply on the PR to confirm that you have received them.

This commit intentionally changes no files; it exists only to notify the remote Codex run so it can end its active goal.

* docs: add README start here guide

* docs: avoid provider recommendation wording

* docs: guide next steps after first reply

* docs: explain merging JSON snippets

* docs: add CLI command chooser

* docs: add configuration task map

* docs: add deployment readiness guide

* docs: simplify WebUI entry paths

* docs: add provider recipe chooser

* docs: fix provider factual references

Update OpenRouter and LongCat model examples, align Bedrock guidance, and make fallback snippets schema-valid.

Also correct group policy wording and image-generation provider lists to match the current code.

* fix: keep PowerShell installer from closing caller shell

* docs: mention self-guided configuration
This commit is contained in:
chengyongru
2026-06-10 00:36:22 +08:00
committed by GitHub
parent 56ce18167e
commit 4a58b83acc
31 changed files with 3491 additions and 454 deletions
+362 -130
View File
@@ -2,10 +2,53 @@
Config file: `~/.nanobot/config.json`
This is the full reference. If this is your first install, start with [`quick-start.md`](./quick-start.md). If you are trying to choose a model or fix provider/model matching, use [`providers.md`](./providers.md) first and come back here for exact fields and advanced options.
The JSON examples below are usually partial snippets to merge into your existing config, not full replacement files. For the mental model behind config, workspace, gateway, channels, sessions, tools, and memory, see [`concepts.md`](./concepts.md).
The generated `config.json` uses camelCase keys such as `apiKey` and `intervalS`. snake_case keys are also accepted for compatibility, but the docs prefer camelCase because that is what nanobot writes back to disk.
For setup and runtime failures, follow the diagnosis order in [`troubleshooting.md`](./troubleshooting.md) before changing multiple config areas at once.
> [!NOTE]
> If your config file is older than the current schema, you can refresh it without overwriting your existing values:
> run `nanobot onboard`, then answer `N` when asked whether to overwrite the config.
> nanobot will merge in missing default fields and keep your current settings.
> If your config file is older than the current schema, you can refresh it without overwriting your existing values: run `nanobot onboard`, then answer `N` when asked whether to overwrite the config. nanobot will merge in missing default fields and keep your current settings.
## Quick Jump
| Need | Section |
|---|---|
| Keep secrets out of `config.json` | [Environment Variables for Secrets](#environment-variables-for-secrets) |
| Trace model calls | [Langfuse Observability](#langfuse-observability) |
| Configure credentials and endpoints | [Providers](#providers) |
| Name and switch model choices | [Model Presets](#model-presets) |
| Add fallback chains | [Model Fallbacks](#model-fallbacks) |
| Configure voice transcription | [Transcription Settings](#transcription-settings) |
| Tune channel defaults | [Channel Settings](#channel-settings) |
| Configure web search and fetch | [Web Tools](#web-tools) |
| Enable image generation | [Image Generation](#image-generation) |
| Add MCP servers | [MCP](#mcp-model-context-protocol) |
| Review shell, workspace, and SSRF controls | [Security](#security) |
| Control access and pairing | [Pairing](#pairing) |
| Tune gateway jobs, sessions, and tools | [Gateway Heartbeat](#gateway-heartbeat), [Auto Compact](#auto-compact), [Unified Session](#unified-session), [Tool Hint Max Length](#tool-hint-max-length) |
## Where to Edit First
If you are not sure where a setting belongs, start from the task you are trying to complete. Most changes touch one config section and one verification command.
| Task | First keys to check | Verify with | Deep dive |
|---|---|---|---|
| Make the first model reply work | `providers.<name>.apiKey`, optional `providers.<name>.apiBase`, `modelPresets.<preset>`, `agents.defaults.modelPreset` | `nanobot status`, then `nanobot agent -m "Hello!"` | [Providers](#providers), [Model Presets](#model-presets) |
| Add fallback models | `modelPresets.<fallback>`, `agents.defaults.fallbackModels` | `nanobot status`, then a normal agent run | [Model Fallbacks](#model-fallbacks) |
| Keep secrets out of the config file | `${ENV_VAR}` placeholders inside any string value | Start nanobot from the same environment that sets the variable | [Environment Variables for Secrets](#environment-variables-for-secrets) |
| Open the bundled WebUI | `channels.websocket.enabled`, optional `channels.websocket.port`, `channels.websocket.tokenIssueSecret` | `nanobot gateway`, then open `http://127.0.0.1:8765` | [Channel Settings](#channel-settings), [WebSocket docs](./websocket.md) |
| Connect one chat app | `channels.<channel>.enabled`, channel credentials, `channels.<channel>.allowFrom` | `nanobot channels status`, then `nanobot gateway --verbose` | [Channel Settings](#channel-settings), [Chat Apps](./chat-apps.md) |
| Enable voice transcription | `transcription.enabled`, `transcription.provider`, matching `providers.<name>.apiKey` | Send or upload a short voice message through a configured surface | [Transcription Settings](#transcription-settings) |
| Enable web search or fetch | `tools.web.search.*`, `tools.web.fetch.*`, optional `tools.ssrfWhitelist` | Ask a question that requires current web information, then inspect logs if needed | [Web Tools](#web-tools), [Security](#security) |
| Enable image generation | `tools.imageGeneration.enabled`, `tools.imageGeneration.provider`, `tools.imageGeneration.model`, matching provider credentials | Enable Image Generation in the WebUI and send one image request | [Image Generation](#image-generation) |
| Add external tools through MCP | `tools.mcpServers.<name>` | Start `nanobot gateway --verbose` and check startup/tool logs | [MCP](#mcp-model-context-protocol) |
| Tighten tool and network safety | `tools.restrictToWorkspace`, `tools.exec.sandbox`, `tools.ssrfWhitelist`, `channels.*.allowFrom` | Run the same workflow through the channel or CLI you plan to expose | [Security](#security), [Pairing](#pairing) |
| Run multiple isolated bots | separate `--config` and `--workspace` paths, plus distinct `gateway.port` or channel ports when processes run together | Start each process with explicit paths and run `nanobot status` for the default instance only | [Multiple Instances](./multiple-instances.md), [CLI Reference](./cli-reference.md) |
| Observe model calls | `LANGFUSE_SECRET_KEY`, `LANGFUSE_PUBLIC_KEY`, `LANGFUSE_BASE_URL` environment variables | Run one model call, then check the matching Langfuse project | [Langfuse Observability](#langfuse-observability) |
## Environment Variables for Secrets
@@ -116,14 +159,46 @@ ANTHROPIC_API_KEY="$(pass show api/anthropic)" nanobot agent
ANTHROPIC_API_KEY="$(bw get password api/anthropic)" nanobot agent
```
## Langfuse Observability
nanobot can trace OpenAI-compatible provider calls through Langfuse's OpenAI SDK wrapper. This is configured with environment variables, not `config.json`.
Install the optional package in the same Python environment that runs nanobot:
```bash
python -m pip install langfuse
```
Set Langfuse credentials before starting `nanobot agent`, `nanobot gateway`, or `nanobot serve`:
```bash
export LANGFUSE_SECRET_KEY="sk-lf-..."
export LANGFUSE_PUBLIC_KEY="pk-lf-..."
export LANGFUSE_BASE_URL="https://cloud.langfuse.com"
```
For PowerShell:
```powershell
$env:LANGFUSE_SECRET_KEY = "sk-lf-..."
$env:LANGFUSE_PUBLIC_KEY = "pk-lf-..."
$env:LANGFUSE_BASE_URL = "https://cloud.langfuse.com"
```
When `LANGFUSE_SECRET_KEY` is set and the `langfuse` package is installed, nanobot uses `langfuse.openai.AsyncOpenAI` for OpenAI-compatible providers so model requests are sent to Langfuse in the background. If the secret key is set but `langfuse` is missing, nanobot logs a warning and falls back to the regular OpenAI client.
Use the Langfuse region or self-hosted URL that matches your project. The [Langfuse OpenAI SDK docs](https://langfuse.com/integrations/model-providers/openai-py) use `LANGFUSE_BASE_URL` for cloud regions and self-hosted instances.
Tracing covers the providers that go through nanobot's OpenAI-compatible client path. Native providers that do not use that client may not produce Langfuse OpenAI-wrapper traces.
## Providers
> [!TIP]
> - **Voice transcription**: Voice messages and WebUI/desktop microphone input use the shared top-level `transcription` settings. By default Groq Whisper is used; set `transcription.provider` to `"openai"` for OpenAI Whisper, `"openrouter"` for OpenRouter speech-to-text models, `"xiaomi_mimo"` for Xiaomi MiMo ASR, or `"assemblyai"` for AssemblyAI. API keys still live in the matching `providers.<provider>` config.
> - **Voice transcription**: Voice messages and WebUI/desktop microphone input use the shared top-level `transcription` settings. The default `transcription.provider` value is `"groq"`; set it to `"openai"` for OpenAI Whisper, `"openrouter"` for OpenRouter speech-to-text models, `"xiaomi_mimo"` for Xiaomi MiMo ASR, or `"assemblyai"` for AssemblyAI. API keys still live in the matching `providers.<provider>` config.
> - **MiniMax Coding Plan**: Exclusive discount links for the nanobot community: [Overseas](https://platform.minimax.io/subscribe/coding-plan?code=9txpdXw04g&source=link) · [Mainland China](https://platform.minimaxi.com/subscribe/token-plan?code=GILTJpMTqZ&source=link)
> - **MiniMax (Mainland China)**: If your API key is from MiniMax's mainland China platform (minimaxi.com), set `"apiBase": "https://api.minimaxi.com/v1"` in your minimax provider config.
> - **MiniMax thinking mode**: Use `providers.minimaxAnthropic` when you want `reasoningEffort` / thinking mode. MiniMax exposes that capability through its Anthropic-compatible endpoint, so nanobot keeps it as a separate provider instead of guessing MiniMax-specific thinking parameters on the generic OpenAI-compatible `minimax` endpoint. It uses the same `MINIMAX_API_KEY`. Default Anthropic-compatible base URL: `https://api.minimax.io/anthropic`; for mainland China use `https://api.minimaxi.com/anthropic`.
> - **VolcEngine / BytePlus Coding Plan**: Use dedicated providers `volcengineCodingPlan` or `byteplusCodingPlan` instead of the pay-per-use `volcengine` / `byteplus` providers.
> - **MiniMax thinking mode**: `providers.minimaxAnthropic` is the config block for `reasoningEffort` / thinking mode. MiniMax exposes that capability through its Anthropic-compatible endpoint, so nanobot keeps it as a separate provider instead of guessing MiniMax-specific thinking parameters on the generic OpenAI-compatible `minimax` endpoint. It uses the same `MINIMAX_API_KEY`. Default Anthropic-compatible base URL: `https://api.minimax.io/anthropic`; for mainland China use `https://api.minimaxi.com/anthropic`.
> - **VolcEngine / BytePlus Coding Plan**: Subscription endpoints are configured through dedicated providers `volcengineCodingPlan` or `byteplusCodingPlan`, separate from the pay-per-use `volcengine` / `byteplus` providers.
> - **Zhipu Coding Plan**: If you're on Zhipu's coding plan, set `"apiBase": "https://open.bigmodel.cn/api/coding/paas/v4"` in your zhipu provider config.
> - **Alibaba Cloud BaiLian**: If you're using Alibaba Cloud BaiLian's OpenAI-compatible endpoint, set `"apiBase": "https://dashscope.aliyuncs.com/compatible-mode/v1"` in your dashscope provider config.
> - **StepFun Step Plan**: If you're on StepFun's Step Plan subscription, set `"apiBase": "https://api.stepfun.com/step_plan/v1"` in your stepfun provider config. Supported models include `step-3.5-flash`, `step-3.5-flash-2603`, and `step-router-v1`.
@@ -134,11 +209,13 @@ ANTHROPIC_API_KEY="$(bw get password api/anthropic)" nanobot agent
| Provider | Purpose | Get API Key |
|----------|---------|-------------|
| `custom` | Any OpenAI-compatible endpoint | — |
| `openrouter` | LLM (recommended, access to all models) + Voice transcription (STT models) | [openrouter.ai](https://openrouter.ai) |
| `openrouter` | LLM gateway for hosted model families + Voice transcription (STT models) | [openrouter.ai](https://openrouter.ai) |
| `huggingface` | LLM (Hugging Face Inference Providers) | [huggingface.co/settings/tokens](https://huggingface.co/settings/tokens) |
| `skywork` | LLM (Skywork / APIFree API gateway) | [apifree.ai](https://www.apifree.ai) |
| `volcengine` | LLM (VolcEngine, pay-per-use) | [Coding Plan](https://www.volcengine.com/activity/codingplan?utm_campaign=nanobot&utm_content=nanobot&utm_medium=devrel&utm_source=OWO&utm_term=nanobot) · [volcengine.com](https://www.volcengine.com) |
| `volcengine_coding_plan` | LLM (VolcEngine Coding Plan subscription endpoint) | [volcengine.com](https://www.volcengine.com/activity/codingplan?utm_campaign=nanobot&utm_content=nanobot&utm_medium=devrel&utm_source=OWO&utm_term=nanobot) |
| `byteplus` | LLM (VolcEngine international, pay-per-use) | [Coding Plan](https://www.byteplus.com/en/activity/codingplan?utm_campaign=nanobot&utm_content=nanobot&utm_medium=devrel&utm_source=OWO&utm_term=nanobot) · [byteplus.com](https://www.byteplus.com) |
| `byteplus_coding_plan` | LLM (BytePlus Coding Plan subscription endpoint) | [byteplus.com](https://www.byteplus.com/en/activity/codingplan?utm_campaign=nanobot&utm_content=nanobot&utm_medium=devrel&utm_source=OWO&utm_term=nanobot) |
| `anthropic` | LLM (Claude direct) | [console.anthropic.com](https://console.anthropic.com) |
| `azure_openai` | LLM (Azure OpenAI) | [portal.azure.com](https://portal.azure.com) |
| `bedrock` | LLM (AWS Bedrock Converse, Claude/Nova/Llama/etc.) | [aws.amazon.com/bedrock](https://aws.amazon.com/bedrock/) |
@@ -155,7 +232,7 @@ ANTHROPIC_API_KEY="$(bw get password api/anthropic)" nanobot agent
| `dashscope` | LLM (Qwen) | [dashscope.console.aliyun.com](https://dashscope.console.aliyun.com) |
| `moonshot` | LLM (Moonshot/Kimi) | [platform.moonshot.cn](https://platform.moonshot.cn) |
| `zhipu` | LLM (Zhipu GLM) | [open.bigmodel.cn](https://open.bigmodel.cn) |
| `mimo` | LLM (MiMo) | [platform.xiaomimimo.com](https://platform.xiaomimimo.com) |
| `xiaomi_mimo` | LLM (MiMo) | [platform.xiaomimimo.com](https://platform.xiaomimimo.com) |
| `longcat` | LLM (LongCat) | [longcat.chat](https://longcat.chat/platform/docs/zh/) |
| `ant_ling` | LLM (Ant Ling / 蚂蚁百灵) | [developer.ant-ling.com](https://developer.ant-ling.com/en/docs/api-reference/openai/) |
| `ollama` | LLM (local, Ollama) | — |
@@ -165,6 +242,7 @@ ANTHROPIC_API_KEY="$(bw get password api/anthropic)" nanobot agent
| `stepfun` | LLM (Step Fun/阶跃星辰) | [platform.stepfun.com](https://platform.stepfun.com) |
| `ovms` | LLM (local, OpenVINO Model Server) | [docs.openvino.ai](https://docs.openvino.ai/2026/model-server/ovms_docs_llm_quickstart.html) |
| `vllm` | LLM (local, any OpenAI-compatible server) | — |
| `nvidia` | LLM (NVIDIA NIM) | [build.nvidia.com](https://build.nvidia.com/) |
| `openai_codex` | LLM (Codex, OAuth) | `nanobot provider login openai-codex` |
| `github_copilot` | LLM (GitHub Copilot, OAuth) | `nanobot provider login github-copilot` |
| `qianfan` | LLM (Baidu Qianfan) | [cloud.baidu.com](https://cloud.baidu.com/doc/qianfan/s/Hmh4suq26) |
@@ -221,11 +299,16 @@ The `azure_openai` provider talks to your Azure OpenAI resource via the OpenAI *
"apiBase": "https://my-resource.openai.azure.com"
}
},
"agents": {
"defaults": {
"modelPresets": {
"azure": {
"provider": "azure_openai",
"model": "my-gpt-5-deployment"
}
},
"agents": {
"defaults": {
"modelPreset": "azure"
}
}
}
```
@@ -241,11 +324,16 @@ Omit `apiKey` (or leave it empty / unset). The provider falls back to [`DefaultA
"apiBase": "https://my-resource.openai.azure.com"
}
},
"agents": {
"defaults": {
"modelPresets": {
"azure": {
"provider": "azure_openai",
"model": "my-gpt-5-deployment"
}
},
"agents": {
"defaults": {
"modelPreset": "azure"
}
}
}
```
@@ -253,7 +341,7 @@ Omit `apiKey` (or leave it empty / unset). The provider falls back to [`DefaultA
Install the optional dependency:
```bash
pip install 'nanobot-ai[azure]'
python -m pip install 'nanobot-ai[azure]'
```
`DefaultAzureCredential` walks this chain in order and uses the first identity that succeeds:
@@ -268,15 +356,14 @@ pip install 'nanobot-ai[azure]'
The identity that ends up signing the request **must be assigned the `Cognitive Services OpenAI User` RBAC role** (or higher) on the Azure OpenAI resource. Without that role you will see `401`/`403` errors at the first request.
> `apiBase` remains mandatory in both modes — it's your Azure resource endpoint and cannot be inferred. If neither `apiKey` is set nor `azure-identity` is installed, the provider raises a clear error pointing you at `pip install 'nanobot-ai[azure]'`.
> `apiBase` remains mandatory in both modes — it's your Azure resource endpoint and cannot be inferred. If neither `apiKey` is set nor `azure-identity` is installed, the provider raises a clear error pointing you at `python -m pip install 'nanobot-ai[azure]'`.
</details>
<details>
<summary><b>Skywork / APIFree</b></summary>
Skywork uses APIFree's OpenAI-compatible Agent API endpoint. Configure the provider
once, then use Skywork model IDs such as `skywork-ai/skyclaw-v1`.
Skywork uses APIFree's OpenAI-compatible Agent API endpoint. Configure the provider once, then use Skywork model IDs such as `skywork-ai/skyclaw-v1`.
```json
{
@@ -286,19 +373,23 @@ once, then use Skywork model IDs such as `skywork-ai/skyclaw-v1`.
"apiBase": "https://api.apifree.ai/agent/v1"
}
},
"agents": {
"defaults": {
"modelPresets": {
"skywork": {
"provider": "skywork",
"model": "skywork-ai/skyclaw-v1",
"maxTokens": 32768,
"contextWindowTokens": 131072
}
},
"agents": {
"defaults": {
"modelPreset": "skywork"
}
}
}
```
You can also reference `${APIFREE_API_KEY}` in `apiKey` if that is how your
environment names the credential.
You can also reference `${APIFREE_API_KEY}` in `apiKey` if that is how your environment names the credential.
</details>
@@ -344,12 +435,17 @@ For a non-Anthropic model such as Amazon Nova:
"region": "us-east-1"
}
},
"agents": {
"defaults": {
"modelPresets": {
"bedrockNova": {
"provider": "bedrock",
"model": "bedrock/amazon.nova-lite-v1:0",
"reasoningEffort": null
}
},
"agents": {
"defaults": {
"modelPreset": "bedrockNova"
}
}
}
```
@@ -364,12 +460,17 @@ With a Bedrock API key:
"apiKey": "${AWS_BEARER_TOKEN_BEDROCK}"
}
},
"agents": {
"defaults": {
"modelPresets": {
"bedrockNova": {
"provider": "bedrock",
"model": "bedrock/amazon.nova-lite-v1:0",
"reasoningEffort": null
}
},
"agents": {
"defaults": {
"modelPreset": "bedrockNova"
}
}
}
```
@@ -384,11 +485,16 @@ With a named AWS profile:
"profile": "my-bedrock-profile"
}
},
"agents": {
"defaults": {
"modelPresets": {
"bedrockNova": {
"provider": "bedrock",
"model": "bedrock/amazon.nova-lite-v1:0"
}
},
"agents": {
"defaults": {
"modelPreset": "bedrockNova"
}
}
}
```
@@ -402,13 +508,18 @@ With a named AWS profile:
"region": "us-east-1"
}
},
"agents": {
"defaults": {
"modelPresets": {
"bedrockClaude": {
"provider": "bedrock",
"model": "bedrock/global.anthropic.claude-opus-4-7",
"reasoningEffort": "medium",
"maxTokens": 8192
}
},
"agents": {
"defaults": {
"modelPreset": "bedrockClaude"
}
}
}
```
@@ -483,8 +594,7 @@ nanobot agent -m "Reply with one short sentence."
<details>
<summary><b>OpenAI Codex (OAuth)</b></summary>
Codex uses OAuth instead of API keys. Requires a ChatGPT Plus or Pro account.
No `providers.openaiCodex` block is needed in `config.json`; `nanobot provider login` stores the OAuth session outside config.
Codex uses OAuth instead of API keys. Requires a ChatGPT Plus or Pro account. No `providers.openaiCodex` block is needed in `config.json`; `nanobot provider login` stores the OAuth session outside config.
**1. Login:**
```bash
@@ -494,9 +604,15 @@ nanobot provider login openai-codex
**2. Set model** (merge into `~/.nanobot/config.json`):
```json
{
"modelPresets": {
"codex": {
"provider": "openai_codex",
"model": "openai-codex/gpt-5.1-codex"
}
},
"agents": {
"defaults": {
"model": "openai-codex/gpt-5.1-codex"
"modelPreset": "codex"
}
}
}
@@ -521,8 +637,7 @@ nanobot agent -c ~/.nanobot-telegram/config.json -w /tmp/nanobot-telegram-test -
<details>
<summary><b>GitHub Copilot (OAuth)</b></summary>
GitHub Copilot uses OAuth instead of API keys. Requires a [GitHub account with a plan](https://github.com/features/copilot/plans) configured.
No `providers.githubCopilot` block is needed in `config.json`; `nanobot provider login` stores the OAuth session outside config.
GitHub Copilot uses OAuth instead of API keys. Requires a [GitHub account with a plan](https://github.com/features/copilot/plans) configured. No `providers.githubCopilot` block is needed in `config.json`; `nanobot provider login` stores the OAuth session outside config.
**1. Login:**
```bash
@@ -532,9 +647,15 @@ nanobot provider login github-copilot
**2. Set model** (merge into `~/.nanobot/config.json`):
```json
{
"modelPresets": {
"copilot": {
"provider": "github_copilot",
"model": "github-copilot/gpt-4.1"
}
},
"agents": {
"defaults": {
"model": "github-copilot/gpt-4.1"
"modelPreset": "copilot"
}
}
}
@@ -558,9 +679,7 @@ nanobot agent -c ~/.nanobot-telegram/config.json -w /tmp/nanobot-telegram-test -
<details>
<summary><b>LongCat (OpenAI-compatible)</b></summary>
LongCat is available through nanobot's built-in OpenAI-compatible provider flow.
The default API base already points to `https://api.longcat.chat/openai/v1`, so you
usually only need to set `apiKey`.
LongCat is available through nanobot's built-in OpenAI-compatible provider flow. The default API base already points to `https://api.longcat.chat/openai/v1`, so you usually only need to set `apiKey`.
```json
{
@@ -569,29 +688,32 @@ usually only need to set `apiKey`.
"apiKey": "${LONGCAT_API_KEY}"
}
},
"modelPresets": {
"longcat": {
"provider": "longcat",
"model": "LongCat-2.0-Preview",
"maxTokens": 8192,
"contextWindowTokens": 1048576
}
},
"agents": {
"defaults": {
"provider": "longcat",
"model": "LongCat-Flash-Chat"
"modelPreset": "longcat"
}
}
}
```
Official model names include `LongCat-Flash-Chat`, `LongCat-Flash-Thinking`,
`LongCat-Flash-Thinking-2601`, and `LongCat-Flash-Lite`.
Current LongCat API docs list `LongCat-2.0-Preview` as the supported model. The older `LongCat-Flash-*` models were retired by LongCat on 2026-05-29.
</details>
<details>
<summary><b>Xiaomi MiMo</b></summary>
Xiaomi MiMo models are automatically detected by the `xiaomi_mimo` provider when
the model name contains `mimo`. The default API base is
`https://api.xiaomimimo.com/v1`.
Xiaomi MiMo models are automatically detected by the `xiaomi_mimo` provider when the model name contains `mimo`. The default API base is `https://api.xiaomimimo.com/v1`.
> **Token Plan**: If you're using MiMo's token plan, override `apiBase` with the
> dedicated endpoint:
> **Token Plan**: If you're using MiMo's token plan, override `apiBase` with the dedicated endpoint:
>
> ```json
> {
@@ -601,27 +723,28 @@ the model name contains `mimo`. The default API base is
> "apiBase": "https://token-plan-sgp.xiaomimimo.com/v1"
> }
> },
> "modelPresets": {
> "mimo": {
> "provider": "xiaomi_mimo",
> "model": "xiaomi/mimo-v2.5-pro"
> }
> },
> "agents": {
> "defaults": {
> "model": "xiaomi/mimo-v2.5-pro"
> "modelPreset": "mimo"
> }
> }
> }
> ```
>
> No need to set `provider` explicitly — the model name contains `mimo`, which
> auto-matches to the `xiaomi_mimo` provider spec. Use an API key from the MiMo
> token plan console and check the MiMo platform for the latest supported model
> names.
> Use the model ID and API key from the MiMo token plan console, and check the MiMo platform for the latest supported model names.
</details>
<details>
<summary><b>StepFun Step Plan (subscription)</b></summary>
Step Plan is StepFun's subscription-based service for high-frequency AI developers.
If you're on a Step Plan subscription, override `apiBase` in the existing `stepfun`
provider config to point to the dedicated Step Plan endpoint.
Step Plan is StepFun's subscription-based service for high-frequency AI developers. If you're on a Step Plan subscription, override `apiBase` in the existing `stepfun` provider config to point to the dedicated Step Plan endpoint.
```json
{
@@ -631,26 +754,28 @@ provider config to point to the dedicated Step Plan endpoint.
"apiBase": "https://api.stepfun.com/step_plan/v1"
}
},
"agents": {
"defaults": {
"modelPresets": {
"stepfun": {
"provider": "stepfun",
"model": "step-3.5-flash"
}
},
"agents": {
"defaults": {
"modelPreset": "stepfun"
}
}
}
```
Supported models include `step-3.5-flash`, `step-3.5-flash-2603`, and
`step-router-v1`.
Supported models include `step-3.5-flash`, `step-3.5-flash-2603`, and `step-router-v1`.
</details>
<details>
<summary><b>Ant Ling (OpenAI-compatible)</b></summary>
Ant Ling is available through nanobot's built-in OpenAI-compatible provider flow.
The default API base points to `https://api.ant-ling.com/v1`, so you usually
only need to set `apiKey`.
Ant Ling is available through nanobot's built-in OpenAI-compatible provider flow. The default API base points to `https://api.ant-ling.com/v1`, so you usually only need to set `apiKey`.
```json
{
@@ -659,17 +784,21 @@ only need to set `apiKey`.
"apiKey": "${ANT_LING_API_KEY}"
}
},
"agents": {
"defaults": {
"modelPresets": {
"antLing": {
"provider": "ant_ling",
"model": "Ling-2.6-flash"
}
},
"agents": {
"defaults": {
"modelPreset": "antLing"
}
}
}
```
Official OpenAI-compatible model names include `Ling-2.6-1T`,
`Ling-2.6-flash`, `Ling-2.5-1T`, `Ling-1T`, `Ring-2.5-1T`, and `Ring-1T`.
Official OpenAI-compatible model names include `Ling-2.6-1T`, `Ling-2.6-flash`, `Ling-2.5-1T`, `Ling-1T`, `Ring-2.5-1T`, and `Ring-1T`.
</details>
@@ -686,9 +815,15 @@ Connects directly to any OpenAI-compatible endpoint — llama.cpp, Together AI,
"apiBase": "https://api.your-provider.com/v1"
}
},
"modelPresets": {
"custom": {
"provider": "custom",
"model": "your-model-name"
}
},
"agents": {
"defaults": {
"model": "your-model-name"
"modelPreset": "custom"
}
}
}
@@ -698,7 +833,7 @@ Connects directly to any OpenAI-compatible endpoint — llama.cpp, Together AI,
>
> `custom` is the right choice for providers that expose an OpenAI-compatible **chat completions** API. It does **not** force third-party endpoints onto the OpenAI/Azure **Responses API**.
>
> If your proxy or gateway is specifically Responses-API-compatible, use the `azure_openai` provider shape instead and point `apiBase` at that endpoint:
> If your proxy or gateway is specifically Responses-API-compatible, configure the `azure_openai` provider shape and point `apiBase` at that endpoint:
>
> ```json
> {
@@ -709,11 +844,16 @@ Connects directly to any OpenAI-compatible endpoint — llama.cpp, Together AI,
> "defaultModel": "your-model-name"
> }
> },
> "agents": {
> "defaults": {
> "modelPresets": {
> "responsesProxy": {
> "provider": "azure_openai",
> "model": "your-model-name"
> }
> },
> "agents": {
> "defaults": {
> "modelPreset": "responsesProxy"
> }
> }
> }
> ```
@@ -761,16 +901,21 @@ ollama run llama3.2
"apiBase": "http://localhost:11434"
}
},
"agents": {
"defaults": {
"modelPresets": {
"ollama": {
"provider": "ollama",
"model": "llama3.2"
}
},
"agents": {
"defaults": {
"modelPreset": "ollama"
}
}
}
```
> `provider: "auto"` also works when `providers.ollama.apiBase` is configured, but setting `"provider": "ollama"` is the clearest option.
> `provider: "auto"` also works when `providers.ollama.apiBase` is configured, but pinning `"provider": "ollama"` inside the preset is the clearest option.
</details>
@@ -794,17 +939,21 @@ ollama run llama3.2
"apiBase": "http://localhost:1234/v1"
}
},
"agents": {
"defaults": {
"modelPresets": {
"lmStudio": {
"provider": "lm_studio",
"model": "local-model"
}
},
"agents": {
"defaults": {
"modelPreset": "lmStudio"
}
}
}
```
> **Note:** Set `apiKey` to `null` for LM Studio since it runs locally and doesn't require authentication. The model name should match what's shown in the LM Studio UI.
> `provider: "auto"` also works when `providers.lm_studio.apiBase` is configured, but setting `"provider": "lm_studio"` is the clearest option.
> **Note:** Set `apiKey` to `null` for LM Studio since it runs locally and doesn't require authentication. The model name should match what's shown in the LM Studio UI. `provider: "auto"` also works when `providers.lm_studio.apiBase` is configured, but pinning `"provider": "lm_studio"` inside the preset is the clearest option.
</details>
@@ -812,7 +961,7 @@ ollama run llama3.2
<details>
<summary><b>Atomic Chat (local)</b></summary>
[Atomic Chat](https://atomic.chat/) is a local-first desktop app that exposes an **OpenAI-compatible** HTTP API (default `http://localhost:1337/v1`). Use it when you want to run nanobot against a model on your own machine instead of a hosted API provider.
[Atomic Chat](https://atomic.chat/) is a local-first desktop app that exposes an **OpenAI-compatible** HTTP API (default `http://localhost:1337/v1`). This setup applies when you want to run nanobot against a model on your own machine instead of a hosted API provider.
**1. Start Atomic Chat**
@@ -830,18 +979,23 @@ ollama run llama3.2
"apiBase": "http://localhost:1337/v1"
}
},
"agents": {
"defaults": {
"modelPresets": {
"atomic": {
"provider": "atomic_chat",
"model": "qwen3-32b"
}
},
"agents": {
"defaults": {
"modelPreset": "atomic"
}
}
}
```
> **Note:** Replace `qwen3-32b` with the model ID from Atomic Chat. Set `apiKey` to `null` if your Atomic Chat server does not require a key. If it does, set `apiKey` (or the `ATOMIC_CHAT_API_KEY` environment variable) to the value Atomic Chat expects.
> `provider: "auto"` also works when `providers.atomic_chat.apiBase` is configured, but setting `"provider": "atomic_chat"` is the clearest option.
> `provider: "auto"` also works when `providers.atomic_chat.apiBase` is configured, but pinning `"provider": "atomic_chat"` inside the preset is the clearest option.
</details>
@@ -907,17 +1061,21 @@ docker run -d \
"apiBase": "http://localhost:8000/v3"
}
},
"agents": {
"defaults": {
"modelPresets": {
"ovms": {
"provider": "ovms",
"model": "openai/gpt-oss-20b"
}
},
"agents": {
"defaults": {
"modelPreset": "ovms"
}
}
}
```
> OVMS is a local server — no API key required. Supports tool calling (`--tool_parser gptoss`), reasoning (`--reasoning_parser gptoss`), and streaming.
> See the [official OVMS docs](https://docs.openvino.ai/2026/model-server/ovms_docs_llm_quickstart.html) for more details.
> OVMS is a local server — no API key required. Supports tool calling (`--tool_parser gptoss`), reasoning (`--reasoning_parser gptoss`), and streaming. See the [official OVMS docs](https://docs.openvino.ai/2026/model-server/ovms_docs_llm_quickstart.html) for more details.
</details>
<a id="vllm-local-openai-compatible"></a>
@@ -945,12 +1103,18 @@ vllm serve meta-llama/Llama-3.1-8B-Instruct --port 8000
}
```
*Model:*
*Model preset:*
```json
{
"modelPresets": {
"vllm": {
"provider": "vllm",
"model": "meta-llama/Llama-3.1-8B-Instruct"
}
},
"agents": {
"defaults": {
"model": "meta-llama/Llama-3.1-8B-Instruct"
"modelPreset": "vllm"
}
}
}
@@ -958,31 +1122,34 @@ vllm serve meta-llama/Llama-3.1-8B-Instruct --port 8000
</details>
Contributor notes for adding new providers live in
[`development.md`](./development.md#adding-an-llm-provider).
Contributor notes for adding new providers live in [`development.md`](./development.md#adding-an-llm-provider).
## Model Presets
Model presets let you name a complete model configuration and switch it at runtime with `/model <preset>`.
Model presets let you name a complete model configuration and switch it at runtime with `/model <preset>`. They are the recommended way to configure models because the same names can be reused for startup selection, chat-command switching, and fallback chains.
Existing configs do not need to change. If you do not set `modelPresets` or `agents.defaults.modelPreset`, nanobot keeps using `agents.defaults.*` exactly as before.
Existing configs do not need to change. Direct `agents.defaults.model`, `provider`, `maxTokens`, `contextWindowTokens`, `temperature`, and `reasoningEffort` fields still define the implicit `default` preset. For new configs, prefer top-level `modelPresets` plus `agents.defaults.modelPreset`.
```json
{
"modelPresets": {
"fast": {
"provider": "openrouter",
"model": "anthropic/claude-sonnet-4.5",
"maxTokens": 4096,
"contextWindowTokens": 65536
}
},
"agents": {
"defaults": {
"model": "openai/gpt-4.1",
"provider": "openai",
"maxTokens": 8192,
"contextWindowTokens": 128000,
"temperature": 0.1,
"modelPreset": "fast",
"fallbackModels": ["deep"]
"fallbackModels": ["deep", "localSmall"]
}
},
"modelPresets": {
"fast": {
"model": "openai/gpt-4.1-mini",
"label": "Fast",
"model": "gpt-4.1-mini",
"provider": "openai",
"maxTokens": 4096,
"contextWindowTokens": 128000,
@@ -990,11 +1157,20 @@ Existing configs do not need to change. If you do not set `modelPresets` or `age
"reasoningEffort": "low"
},
"deep": {
"model": "anthropic/claude-opus-4-5",
"label": "Deep",
"model": "claude-opus-4-5",
"provider": "anthropic",
"maxTokens": 8192,
"contextWindowTokens": 200000,
"reasoningEffort": "high"
},
"localSmall": {
"label": "Local Small",
"model": "llama3.2",
"provider": "ollama",
"maxTokens": 4096,
"contextWindowTokens": 32768,
"temperature": 0.2
}
}
}
@@ -1004,6 +1180,7 @@ Existing configs do not need to change. If you do not set `modelPresets` or `age
| Field | Description |
|-------|-------------|
| `label` | Optional display name shown in model lists. |
| `model` | Model name to use for this preset. |
| `provider` | Provider name, or `"auto"` to use provider auto-detection. |
| `maxTokens` | Maximum completion/output tokens. |
@@ -1011,24 +1188,72 @@ Existing configs do not need to change. If you do not set `modelPresets` or `age
| `temperature` | Sampling temperature. |
| `reasoningEffort` | Optional reasoning/thinking setting. Provider support varies. |
`default` is reserved and always means the implicit preset built from `agents.defaults.*`; do not define `modelPresets.default`. Use `/model default` to switch back to `agents.defaults.*`.
`default` is reserved and always means the implicit preset built from direct `agents.defaults.*` fields; do not define `modelPresets.default`. Use `/model default` to switch back to those direct fields in an existing config.
Set `agents.defaults.modelPreset` to choose the startup preset. When `modelPreset` is `null` or omitted, startup uses the implicit `default` preset from direct `agents.defaults.*` fields. Runtime changes made with `/model <preset>` are not written back to `config.json`; they affect future turns until the process restarts or another model/config change replaces them.
### Model Fallbacks
`agents.defaults.fallbackModels` defines an ordered failover chain for the active model configuration. The primary model is still selected by `agents.defaults.modelPreset` (or the implicit default config when no preset is active).
`agents.defaults.fallbackModels` defines an ordered failover chain for the active model configuration. The primary model is still selected by `agents.defaults.modelPreset` or, in older configs, by the implicit `default` preset from direct `agents.defaults.*` fields.
Each fallback candidate can be either:
- A preset name from `modelPresets`, such as `"deep"`. The preset's full model, provider, generation, and context-window config is used.
- A preset name from `modelPresets`, such as `"deep"`. This is the recommended form. The preset's full model, provider, generation, and context-window config is used.
- An inline fallback object with at least `provider` and `model`. Optional `maxTokens`, `contextWindowTokens`, and `temperature` fields inherit from the active primary config when omitted. `reasoningEffort` does not inherit; omit it to leave reasoning off for that fallback, or set it explicitly for models that support reasoning.
Preset fallback chain:
```json
{
"modelPresets": {
"fast": {
"model": "gpt-4.1-mini",
"provider": "openai",
"maxTokens": 4096,
"contextWindowTokens": 128000,
"temperature": 0.2
},
"deep": {
"model": "claude-opus-4-5",
"provider": "anthropic",
"maxTokens": 8192,
"contextWindowTokens": 200000,
"reasoningEffort": "high"
},
"localSmall": {
"model": "llama3.2",
"provider": "ollama",
"maxTokens": 4096,
"contextWindowTokens": 32768
}
},
"agents": {
"defaults": {
"modelPreset": "fast",
"fallbackModels": ["deep", "localSmall"]
}
}
}
```
String entries are preset names, not raw model names. In the example above, `"deep"` means `modelPresets.deep`; nanobot will not interpret it as a provider model ID. Changing a preset updates both `/model <preset>` switching and any fallback chain that references it.
Inline fallback object:
```json
{
"modelPresets": {
"fast": {
"provider": "openrouter",
"model": "anthropic/claude-sonnet-4.5",
"maxTokens": 4096,
"contextWindowTokens": 65536
}
},
"agents": {
"defaults": {
"modelPreset": "fast",
"fallbackModels": [
"deep",
{
"provider": "deepseek",
"model": "deepseek-v4-pro",
@@ -1041,26 +1266,12 @@ Each fallback candidate can be either:
}
```
String entries are preset names, not raw model names. If you want to use a model that is not already a preset, use the inline object form.
Use inline objects only when a fallback is not worth naming as a reusable preset. `fallbackModels` belongs under `agents.defaults`, not inside individual `modelPresets` entries.
Failover only runs when the primary provider returns a retryable model/provider error before any answer text has been streamed. Typical fallback cases include timeouts, connection errors, 5xx server errors, 429 rate limits, overloads, and quota/balance exhaustion. It does not run for malformed requests, authentication/permission errors, content filtering/refusals, or context-length/message-format errors.
If fallback candidates use smaller `contextWindowTokens` values, nanobot builds context using the smallest window in the active chain so every candidate can receive the same prompt.
Set `agents.defaults.modelPreset` to start with a named preset:
```json
{
"agents": {
"defaults": {
"modelPreset": "fast"
}
}
}
```
When `modelPreset` is `null` or omitted, startup uses the implicit `default` preset from `agents.defaults.*`. Runtime changes made with `/model <preset>` are not written back to `config.json`; they affect future turns until the process restarts or another model/config change replaces them.
## Transcription Settings
Audio transcription is a shared capability used by chat-channel voice messages and by WebUI/desktop microphone input. Chat-channel voice messages are transcribed automatically before they enter the agent. WebUI and desktop microphone input is transcribed into the composer first, so you can edit the text before sending.
@@ -1116,8 +1327,7 @@ Transcription credentials are intentionally not stored in `transcription`. Put t
Selecting a transcription provider does not configure credentials by itself. For example, the effective provider may default to Groq for compatibility, but transcription is only usable when `providers.groq.apiKey` or the matching environment-backed config is available. The Settings UI writes only the top-level `transcription` fields.
If you are adding a new transcription provider, see
[`development.md`](./development.md#adding-a-transcription-provider).
If you are adding a new transcription provider, see [`development.md`](./development.md#adding-a-transcription-provider).
## Channel Settings
@@ -1130,7 +1340,9 @@ Global settings that apply to all channels. Configure under the `channels` secti
"sendToolHints": false,
"extractDocumentText": true,
"sendMaxRetries": 3,
"telegram": { ... }
"telegram": {
"enabled": false
}
}
}
```
@@ -1145,8 +1357,7 @@ Global settings that apply to all channels. Configure under the `channels` secti
`channels.transcriptionProvider` and `channels.transcriptionLanguage` are deprecated compatibility fields. They remain as a read-only fallback for older configs, but new configuration should use top-level `transcription.provider` and `transcription.language`.
`sendProgress` and `sendToolHints` can also be overridden per channel. The
global values stay as defaults for channels that do not set their own value:
`sendProgress` and `sendToolHints` can also be overridden per channel. The global values stay as defaults for channels that do not set their own value:
```json
{
@@ -1330,10 +1541,7 @@ You can also set `OLOSTEP_API_KEY` in the environment instead of storing it in c
}
```
You can also set `WEB_SEARCH_API_KEY` for compatibility with the Volcengine web-search skill.
Create the key in the [Volcengine web search console](https://console.volcengine.com/search-infinity/web-search),
then copy it from [API keys](https://console.volcengine.com/search-infinity/api-key).
Volcengine Ark keys are separate and do not work for this search provider.
You can also set `WEB_SEARCH_API_KEY` for compatibility with the Volcengine web-search skill. Create the key in the [Volcengine web search console](https://console.volcengine.com/search-infinity/web-search), then copy it from [API keys](https://console.volcengine.com/search-infinity/api-key). Volcengine Ark keys are separate and do not work for this search provider.
**SearXNG** (self-hosted, no API key needed):
```json
@@ -1572,12 +1780,36 @@ nanobot agent -m "/pairing approve ABCD-EFGH"
```
## Gateway Heartbeat
The gateway can run a protected heartbeat cron job that periodically checks `HEARTBEAT.md` in the active workspace. This is enabled by default when you run `nanobot gateway`.
```json
{
"gateway": {
"heartbeat": {
"enabled": true,
"intervalS": 1800,
"keepRecentMessages": 8
}
}
}
```
If `HEARTBEAT.md` has tasks under `## Active Tasks`, the agent executes them and delivers useful results to the most recently active chat target. If the file has no active tasks, the heartbeat is skipped silently.
The heartbeat job is backed by the same cron service as user-created reminders. It is stored under the active workspace (`<workspace>/cron/jobs.json`) and shows up in `cron(action="list")` as `heartbeat`, but it is system-managed and cannot be removed with the `cron` tool. Disable it through config and restart the gateway if you do not want periodic heartbeat checks.
| Option | Default | Description |
|--------|---------|-------------|
| `gateway.heartbeat.enabled` | `true` | Register the built-in heartbeat cron job on gateway startup. |
| `gateway.heartbeat.intervalS` | `1800` | Seconds between heartbeat checks. |
| `gateway.heartbeat.keepRecentMessages` | `8` | Number of recent heartbeat-session messages to retain after each run. |
## Subagent Concurrency
By default, nanobot only allows one spawned subagent at a time. When the limit is
reached, the `spawn` tool returns an error so the agent can decide to wait or
rearrange its work. This protects local LLM servers from loading multiple KV caches
at once. If your provider can handle more parallel work, raise the limit:
By default, nanobot only allows one spawned subagent at a time. When the limit is reached, the `spawn` tool returns an error so the agent can decide to wait or rearrange its work. This protects local LLM servers from loading multiple KV caches at once. If your provider can handle more parallel work, raise the limit:
```json
{