# Understanding the Nanobot Config File Format: A Complete Guide to Pydantic-Based Configuration

> Master the nanobot config file format with this guide. Learn how Pydantic models handle agents, providers, channels, and tools, with environment variable support and validation.

- Repository: [✨Data Intelligence Lab@HKU✨/nanobot](https://github.com/HKUDS/nanobot)
- Tags: tutorial
- Published: 2026-07-22

---

**Nanobot uses a single JSON configuration file located at `~/.nanobot/config.json` that is parsed into a hierarchy of Pydantic models defined in [`nanobot/config/schema.py`](https://github.com/HKUDS/nanobot/blob/main/nanobot/config/schema.py), supporting environment variable overrides and validation for agents, providers, channels, and tools.**

The HKUDS/nanobot project relies on a declarative configuration system to manage its multi-agent runtime, transcription services, and LLM provider integrations. Understanding the nanobot config file format is essential for customizing agent behavior, adding custom providers, and enforcing security policies. This guide examines the schema definitions, validation logic, and runtime loading mechanisms that power nanobot's flexible configuration system.

## Root Configuration Structure

The entry point for all configuration is the `Config` class in [`nanobot/config/schema.py`](https://github.com/HKUDS/nanobot/blob/main/nanobot/config/schema.py), which inherits from Pydantic's `BaseSettings` to enable environment variable integration.

```python
class Config(BaseSettings):
    agents: AgentsConfig = Field(default_factory=AgentsConfig)
    channels: ChannelsConfig = Field(default_factory=ChannelsConfig)
    transcription: TranscriptionConfig = Field(default_factory=TranscriptionConfig)
    providers: ProvidersConfig = Field(default_factory=ProvidersConfig)
    api: ApiConfig = Field(default_factory=ApiConfig)
    gateway: GatewayConfig = Field(default_factory=GatewayConfig)
    tools: ToolsConfig = Field(default_factory=ToolsConfig)
    model_presets: dict[str, ModelPresetConfig] = Field(
        default_factory=dict,
        validation_alias=AliasChoices("modelPresets", "model_presets"),
        serialization_alias="modelPresets",
    )

```

Each attribute represents a subsystem configuration with default factories that lazily instantiate nested models. Because the class extends `BaseSettings`, environment variables prefixed with `NANOBOT_` automatically override JSON values, enabling dynamic configuration without file modifications.

## Agent and Model Configuration

Agent behavior is controlled through a nested hierarchy of configuration models that define defaults and reusable presets.

### AgentsConfig and AgentDefaults

The `AgentsConfig` class holds the default agent configuration through its `defaults: AgentDefaults` field. The `AgentDefaults` model specifies core runtime parameters including:

- **`workspace`** – The working directory for agent file operations
- **`model_preset`** – Reference to a named preset configuration
- **`model`** – Direct model specification (e.g., "gpt-4", "claude-3-opus")
- **`provider`** – Target LLM provider identifier
- **`max_tool_iterations`** – Safety limit for recursive tool calls
- **`timezone`** – IANA timezone string for temporal operations
- **`unified_session`** – Boolean for session persistence across interactions

### Model Preset Resolution

Named model presets are defined in `model_presets` as dictionaries mapping strings to `ModelPresetConfig` objects. Each preset encapsulates `model`, `provider`, `max_tokens`, `temperature`, and `reasoning_effort` parameters.

The resolution logic resides in `Config.resolve_default_preset()` and `Config.resolve_preset(name)`, which build a complete `ModelPresetConfig` by merging named presets with implicit defaults (source lines 38-45 in [`nanobot/config/schema.py`](https://github.com/HKUDS/nanobot/blob/main/nanobot/config/schema.py)). This allows users to define quick-switch profiles for different tasks while maintaining fallback values.

## Provider Configuration

LLM provider settings are managed through `ProvidersConfig`, which enumerates supported providers while allowing arbitrary custom providers via extra fields.

### ProviderConfig Schema

Every provider, whether built-in or custom, uses the `ProviderConfig` base model:

```python
class ProviderConfig(Base):
    api_key: str | None = Field(default=None, repr=False)
    api_base: str | None = None
    api_type: Literal["auto", "chat_completions", "responses"] = "auto"
    extra_headers: dict[str, str] | None = None
    extra_body: dict[Any, Any] | None = None
    extra_query: dict[str, str] | None = None
    proxy: str | None = None
    thinking_style: str | None = None

```

Critical validation rules apply to these fields. The `api_key` field uses `repr=False` to prevent accidental exposure in logs. The `api_type` parameter is restricted to `"auto"` for all providers except OpenAI, enforced by `_validate_api_type_scope()` (source lines 98-106). Custom providers defined in the JSON file are automatically converted to `ProviderConfig` instances via `convert_extra_providers()` (source lines 80-93).

### Provider Matching Algorithm

At runtime, nanobot selects providers using `Config._match_provider()`, which implements a sophisticated matching algorithm (source lines 64-131). The method evaluates model name prefixes, explicit provider declarations, keyword matches, and finally falls back to any provider with a configured `api_key`. This enables zero-configuration operation when only one provider has authentication credentials.

## Channel, Tool, and Auxiliary Settings

Beyond agents and providers, the nanobot config file format supports granular control over communication channels and tool execution.

### ChannelsConfig

`ChannelsConfig` manages per-chat-application behavior, controlling streaming output, tool-hint display visibility, and retry limits (source lines 22-38). These settings allow fine-tuning of the user experience across different messaging platforms.

### ToolsConfig

The `ToolsConfig` class aggregates settings for all built-in tools including web search, code execution, filesystem access, and image generation. Notable security flags include:

- **`restrict_to_workspace`** – Boolean enforcing that all file operations remain within the designated workspace directory
- **`webui_allow_local_service_access`** – Permission flag allowing the WebUI to connect to localhost services

Tool classes are lazily imported via `_lazy_default()` to prevent circular import issues during configuration loading.

### Auxiliary Subsystems

Additional configuration sections include:

- **`TranscriptionConfig`** – Audio transcription service parameters and defaults
- **`ApiConfig`** – OpenAI-compatible HTTP API server settings (host, port, optional API key)
- **`GatewayConfig`** – Nanobot gateway server options including heartbeat intervals
- **`HeartbeatConfig`** – Periodic housekeeping job scheduling (now cron-based)

Each follows the consistent Pydantic pattern of typed fields with validation constraints and sensible defaults.

## Validation, Aliases, and Environment Overrides

The nanobot config file format supports flexible input handling through Pydantic's validation and alias systems.

### Field Aliases

The `AliasChoices` mechanism allows multiple JSON key formats for the same field. For example, `model_presets` accepts both `"modelPresets"` (camelCase) and `"model_presets"` (snake_case) during validation, while serializing exclusively to `"modelPresets"` for consistency.

### Environment Variable Override

Because `Config` extends `BaseSettings`, environment variables prefixed with `NANOBOT_` override file values. Nested fields use double underscores as delimiters:

```bash
export NANOBOT_AGENTS__DEFAULTS__WORKSPACE="/tmp/custom-workspace"
export NANOBOT_API__PORT=9100

```

### Field Validators

Custom validators enforce domain constraints. For instance, the `timezone` field validates against known IANA timezone databases (source lines 66-75), preventing runtime errors from invalid locale strings.

## Loading and Runtime Behavior

Configuration persistence and hot-reloading are handled by dedicated modules in the `nanobot/config/` package.

### Configuration Loading Pipeline

The `nanobot.config.loader` module handles the initialization sequence:

1. Locates the configuration file at `~/.nanobot/config.json` (or creates defaults if missing)
2. Parses JSON content through the Pydantic `Config` model
3. Applies environment variable overrides
4. Returns a validated configuration instance

If the configuration file is absent, nanobot uses default values and prompts the user to run `nanobot onboard` for initial setup.

### File Watching and Hot Reload

The `nanobot.config.watcher` module monitors the configuration file for changes during runtime. When modifications are detected, the watcher triggers a configuration reload without requiring process restart, enabling dynamic adjustment of agent parameters and provider credentials.

### Path Resolution

Utility functions in `nanobot.config.paths` provide cross-platform resolution of configuration directories, workspace locations, and related filesystem paths, ensuring consistent behavior across operating systems.

## Practical Configuration Examples

### Reading Configuration Programmatically

Access the parsed configuration in Python to inspect runtime settings:

```python
from nanobot.config.schema import Config

# Load from default location with environment overrides

cfg = Config()

# Access workspace path

print("Workspace:", cfg.agents.defaults.workspace)

# Resolve a named model preset

preset = cfg.resolve_preset(name="primary")
print(f"Using model: {preset.model} via provider: {preset.provider}")

```

### Adding a Custom Provider

Extend nanobot with proprietary or self-hosted LLM endpoints by adding custom provider definitions:

```json
{
  "providers": {
    "mycorp": {
      "apiKey": "sk-custom-key",
      "apiBase": "https://api.internal.corp.com/v1",
      "thinkingStyle": "detailed"
    }
  },
  "modelPresets": {
    "corp-default": {
      "model": "mycorp/gpt-4",
      "provider": "mycorp",
      "max_tokens": 8192,
      "temperature": 0.2
    }
  }
}

```

### Enforcing Workspace Security

Programmatically restrict tools to the workspace directory:

```python
from nanobot.config.schema import Config
import json
from pathlib import Path

cfg = Config()
cfg.tools.restrict_to_workspace = True

# Persist changes

config_path = Path("~/.nanobot/config.json").expanduser()
config_path.write_text(
    json.dumps(cfg.model_dump(mode="json"), indent=2)
)

```

### Environment-Based Port Configuration

Override the gateway server port without modifying the configuration file:

```bash
export NANOBOT_GATEWAY__PORT=8080
nanobot gateway

```

## Summary

- The nanobot config file format uses a single JSON file at `~/.nanobot/config.json` parsed by Pydantic models in [`nanobot/config/schema.py`](https://github.com/HKUDS/nanobot/blob/main/nanobot/config/schema.py).
- The root `Config` class extends `BaseSettings`, enabling environment variable overrides with the `NANOBOT_` prefix.
- Agent behavior is configured through `AgentsConfig` and `AgentDefaults`, with `ModelPresetConfig` enabling reusable model parameter sets.
- Provider configuration supports both built-in services and custom endpoints via `ProvidersConfig` and the extensible `ProviderConfig` base class.
- The `_match_provider()` method implements intelligent provider selection based on model names, prefixes, and available API keys.
- Security features include `restrict_to_workspace` for filesystem isolation and `repr=False` for API key protection.
- Configuration changes are detected at runtime by `nanobot.config.watcher`, enabling hot-reloading without service interruption.

## Frequently Asked Questions

### Where is the nanobot configuration file located?

The default location is `~/.nanobot/config.json` on Unix-like systems, resolved through the `nanobot.config.paths` module. If the file does not exist, nanobot initializes with default values and prompts you to run `nanobot onboard` to generate the initial configuration.

### How do I override configuration values using environment variables?

Set environment variables prefixed with `NANOBOT_` using double underscores to denote nested fields. For example, `NANOBOT_AGENTS__DEFAULTS__MODEL` overrides the default agent model, while `NANOBOT_PROVIDERS__OPENAI__API_KEY` sets the OpenAI API key without storing it in the JSON file.

### Can I add custom LLM providers not included in the default schema?

Yes, the `ProvidersConfig` class accepts extra fields that are automatically converted to `ProviderConfig` instances via `convert_extra_providers()`. Simply add a new key to the `providers` object in your JSON file with `apiKey`, `apiBase`, and other standard fields, then reference it in your `modelPresets` or agent defaults.

### What validation occurs when loading the configuration?

Pydantic validates all fields against their type annotations, with additional custom validators enforcing business logic such as IANA timezone validation for the `timezone` field and API type restrictions enforced by `_validate_api_type_scope()`. Invalid configurations raise validation errors with detailed messages indicating the problematic field and accepted values.