Nanobot Config Schema: A Complete Guide to the Pydantic-Based Configuration System
The nanobot config schema is a hierarchical, type-safe configuration system defined in nanobot/config/schema.py that uses Pydantic BaseSettings to enable environment variable overrides via the NANOBOT_ prefix while supporting dynamic LLM provider registration.
The nanobot config schema serves as the single source of truth for all application settings in the HKUDS/nanobot repository. Built on Pydantic, it provides runtime type validation, automatic serialization, and flexible configuration loading from JSON files, YAML, or environment variables.
Core Architecture and File Structure
The entire schema is centralized in [nanobot/config/schema.py](https://github.com/HKUDS/nanobot/blob/main/nanobot/config/schema.py). All configuration classes inherit from a lightweight Base wrapper around Pydantic's BaseModel or directly from BaseSettings, enabling sophisticated validation and environment variable mapping.
The root configuration is handled by the Config class (line 404), which aggregates multiple specialized sub-configurations into a unified object. This design uses Pydantic's model_config to establish automatic environment variable mapping:
model_config = ConfigDict(
env_prefix="NANOBOT_",
env_nested_delimiter="__"
)
This configuration allows any nested field to be overridden using double-underscore notation (e.g., NANOBOT_AGENTS__DEFAULTS__TEMPERATURE=0.7).
Top-Level Configuration Sections
The nanobot config schema is organized into distinct logical domains, each managed by dedicated Pydantic models.
Agents and Model Presets
The AgentsConfig class (line 78) controls default agent behavior through AgentDefaults (line 19) and supports reusable parameter sets via ModelPresetConfig (line 99). Users can define custom presets that specify model names, providers, and inference parameters.
The agents.defaults section can reference a preset by name, falling back to an implicit "default" preset derived from the AgentDefaults fields through the resolve_default_preset method.
Channel and Transcription Settings
ChannelsConfig (line 22) manages per-channel streaming and retry options, while TranscriptionConfig (line 41) handles global audio-transcription parameters. These sections isolate media-processing concerns from agent logic.
LLM Provider Configuration
ProvidersConfig (line 26) is one of the most dynamic sections of the nanobot config schema. It declares built-in providers (OpenAI, Anthropic, Azure, Bedrock) as explicit fields while allowing arbitrary extra fields via model_config = ConfigDict(extra="allow").
Custom providers are automatically converted to ProviderConfig objects through the convert_extra_providers mechanism. The BedrockProviderConfig subclass handles AWS-specific authentication requirements.
API and Gateway Settings
ApiConfig (line 17) configures the internal OpenAI-compatible HTTP API server, including host, port, and authentication settings. GatewayConfig (line 37) manages the gateway process networking and heartbeat handling.
MCP Server and Tool Configuration
MCPServerConfig (line 46) defines external tool servers using stdio, HTTP, or SSE transports. ToolsConfig (line 67) provides fine-grained enable/disable flags for built-in tools (web, exec, filesystem) and enforces workspace restrictions through path validation.
Legacy Services
HeartbeatConfig (line 9) and DreamConfig handle background maintenance tasks. The dream configuration specifically encapsulates memory-compaction behavior, optionally using cron expressions for scheduling.
Environment Variable Overrides
The nanobot config schema leverages Pydantic's BaseSettings to enable complete configuration through environment variables. The system automatically maps variables using the NANOBOT_ prefix and double-underscore nesting:
# Override a value via environment variable
# export NANOBOT_AGENTS__DEFAULTS__TEMPERATURE=0.7
cfg = Config()
print(cfg.agents.defaults.temperature) # → 0.7
# Load the configuration (defaults + optional user file)
from nanobot.config.schema import Config
cfg = Config() # reads ~/.nanobot/config.json if present
print(cfg.agents.defaults.model) # → "anthropic/claude-opus-4-5"
print(cfg.providers.openai.api_key) # → None (masked in __repr__)
Dynamic Provider Resolution
The schema provides utility methods for runtime provider management. The get_provider method retrieves configuration for a specific model name:
# Retrieve the provider config for a given model name
provider_cfg = cfg.get_provider(model="gpt-4")
print(provider_cfg.api_base) # → "https://api.openai.com/v1"
The resolve_preset method converts named presets into fully resolved ModelPresetConfig objects:
# Resolve a named model preset
preset = cfg.resolve_preset("my-gpt-4")
print(preset.model, preset.provider) # → "gpt-4", "openai"
Validation Hooks and Constraints
The nanobot config schema implements rigorous validation through Pydantic's @field_validator and @model_validator decorators. These enforce constraints including:
- Valid timezone strings for scheduling configurations
- Reserved preset name restrictions
- Provider-type compatibility checks
- Workspace path accessibility for tool configurations
Summary
- The nanobot config schema is defined in
nanobot/config/schema.pyusing Pydantic models for type safety and validation. - Environment variables override configuration using the
NANOBOT_prefix and__delimiter for nested fields. - ProvidersConfig supports both built-in LLM providers and dynamic custom providers through
extra="allow". - ModelPresetConfig enables reusable agent parameter sets resolvable via
resolve_preset(). - Validation occurs through Pydantic validators ensuring timezone correctness, provider compatibility, and tool workspace restrictions.
Frequently Asked Questions
How do I override nested configuration values using environment variables?
Use the NANOBOT_ prefix followed by uppercase section names and field names separated by double underscores. For example, to set the default temperature, use NANOBOT_AGENTS__DEFAULTS__TEMPERATURE=0.7. The schema's BaseSettings configuration automatically maps these environment variables to the nested Pydantic model structure.
Can I add custom LLM providers not defined in the schema?
Yes. The ProvidersConfig class uses model_config = ConfigDict(extra="allow"), which permits arbitrary additional fields. When you add a custom provider block to your configuration file or environment variables, the convert_extra_providers method automatically validates and converts it into a ProviderConfig object, making it available to the agent system immediately.
Where are model presets defined and how are they resolved?
Model presets are defined within AgentsConfig as dictionaries of ModelPresetConfig objects. The resolve_preset() method on the root Config class looks up presets by name. If no preset is specified for an agent, the system falls back to resolve_default_preset(), which constructs a preset from the AgentDefaults fields, ensuring every agent has valid model parameters.
What validation occurs when loading the configuration?
The schema enforces multiple constraints through Pydantic validators: timezone strings must be valid IANA identifiers, preset names cannot use reserved keywords, provider configurations must match their declared types (e.g., BedrockProviderConfig for AWS), and filesystem tool paths must reside within allowed workspaces. These validations run automatically when instantiating Config().
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →