Nanobot Dynamic Configuration Loading: Runtime Config Management Explained

Nanobot implements a hot-reloading configuration system using Pydantic models, environment variable overrides, and file-system watchers to enable real-time updates without restarting the agent.

Nanobot's configuration system provides type-safe, runtime-reloading capabilities through a modular Python architecture. The HKUDS/nanobot repository implements this via four specialized modules that handle schema validation, path resolution, loading orchestration, and file watching. This design allows developers to modify settings dynamically while maintaining strict validation and environment-based secret management.

Configuration Architecture Overview

The dynamic configuration system spans four core modules in nanobot/config/. Each component handles a specific aspect of the loading lifecycle, from schema definition to runtime monitoring.

Configuration Schema (nanobot/config/schema.py)

The Config class in nanobot/config/schema.py defines the Pydantic-based data model that describes every configurable option. Inheriting from Pydantic's BaseSettings, this schema enables automatic environment variable overrides for any field defined in the model.

The schema uses camelCase aliases to ensure seamless JSON compatibility while maintaining Pythonic snake_case attribute access. It provides default values and validation for complex nested structures, including provider credentials, logging levels, and tool limits.

Path Resolution (nanobot/config/paths.py)

nanobot/config/paths.py centralizes filesystem location management across platforms. It resolves platform-specific directories using XDG standards on Linux and AppData on Windows, guaranteeing that required directories exist before first use.

This module computes the location of ~/.nanobot/config.json and other runtime directories, abstracting cross-platform differences behind a consistent API.

Loading Orchestration (nanobot/config/loader.py)

The nanobot/config/loader.py module orchestrates the configuration discovery and instantiation process. The load() function discovers the user's config file, merges JSON contents with schema defaults, and initiates the file watcher.

Key behaviors include:

  • Discovery: Locates ~/.nanobot/config.json or respects the NANOBOT_CONFIG environment variable for custom paths
  • Merging: Parses JSON into a validated Config instance, applying defaults for missing keys
  • Dynamic Reload: Triggers reload() callbacks when the watcher detects file changes, propagating new values to provider factories and logging subsystems

File System Watching (nanobot/config/watcher.py)

nanobot/config/watcher.py implements the hot-reloading mechanism using the watchdog library. It monitors the configuration file for modifications and emits debounced change events to prevent excessive reloads during rapid edits.

When the watcher detects a change, it invokes loader.reload(), which recreates the Config instance and updates the running bot's settings without requiring a restart.

How Dynamic Reloading Works

Nanobot achieves zero-downtime configurability through a structured loading flow that activates at startup and continues monitoring throughout the application lifecycle.

  1. Application startup calls nanobot.config.loader.load(), which resolves the config file location via paths.py
  2. JSON parsing converts the file contents into a Config object using the Pydantic schema
  3. Validation runs automatically, filling missing fields with defaults and type-checking all values
  4. Watcher initialization starts the file-system monitor in a background thread
  5. Runtime updates trigger when config.json changes, invoking loader.reload() to refresh the configuration instance
  6. Propagation distributes new values to dependent subsystems, including provider factories, loggers, and tool limit handlers

Environment Variable Integration

Because the Config model inherits from Pydantic's BaseSettings, any environment variable matching a field name automatically overrides the corresponding JSON configuration. This dual-source approach enables secure secret management through environment injection while keeping general settings in readable files.

For example, setting NANOBOT_LOG_LEVEL=DEBUG overrides the log_level field in config.json, and NANOBOT_PROVIDERS__OPENAI__API_KEY can inject API credentials without storing them in the configuration file.

Practical Implementation Examples

The following patterns demonstrate common interactions with Nanobot's configuration system:


# Load configuration automatically with validation

from nanobot.config.loader import load

config = load()               # Returns a validated Config instance

print(config.log_level)       # → "INFO" (default or user-provided)

Access nested provider settings safely through the typed schema:


# Access nested provider configuration

openai_cfg = config.providers.openai
print(openai_cfg.api_key)     # Resolved from env var or config file

Runtime updates require no additional code. Edit ~/.nanobot/config.json manually, and the background watcher triggers load() automatically:


# No manual reload required - the watcher updates config automatically

# Changes to ~/.nanobot/config.json propagate within seconds

Summary

  • Modular architecture: Four specialized modules (schema.py, paths.py, loader.py, watcher.py) handle distinct configuration concerns
  • Type safety: Pydantic-based validation ensures all configuration values meet schema requirements before application use
  • Hot reloading: File-system watching via watchdog enables real-time configuration updates without process restarts
  • Environment overrides: BaseSettings inheritance allows environment variables to override JSON configuration for secure secret management
  • Cross-platform support: Automatic resolution of XDG and AppData directories ensures consistent behavior across Linux, macOS, and Windows

Frequently Asked Questions

How does Nanobot detect configuration file changes?

Nanobot uses watchdog in nanobot/config/watcher.py to monitor the configuration file for modifications. The watcher emits debounced events when the file changes, triggering loader.reload() to recreate the Config instance with updated values. This process occurs in a background thread without interrupting the main application flow.

Can I override specific configuration values using environment variables?

Yes. Because the configuration model in nanobot/config/schema.py inherits from Pydantic's BaseSettings, any environment variable matching a field name (e.g., NANOBOT_LOG_LEVEL) automatically overrides the corresponding value in config.json. Nested fields use double underscores (e.g., NANOBOT_PROVIDERS__OPENAI__API_KEY) following Pydantic's environment variable naming convention.

Where does Nanobot look for the configuration file by default?

By default, Nanobot resolves the configuration file path using nanobot/config/paths.py, which locates ~/.nanobot/config.json (or platform-specific equivalents like AppData on Windows). You can override this location by setting the NANOBOT_CONFIG environment variable to a custom file path before starting the application.

Is it safe to edit the configuration while Nanobot is running?

Yes. The configuration system is designed for concurrent access during file modifications. The watcher in nanobot/config/watcher.py implements debouncing to handle rapid successive edits, and Pydantic validation ensures that only valid configurations are applied. Invalid JSON or schema violations during a reload will typically fail gracefully, preserving the previous valid configuration.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →