Skip to content

Configuration

Lingchu Bot separates deployment configuration from online-editable settings. NoneBot resolves deployment fields from OS environment variables, its .env files or global configuration, then model defaults. Lingchu does not add a second dotenv or TOML precedence layer.

Online-editable overrides live in localstore-owned runtime-overrides.toml. Startup neither creates deployment configuration nor installs JSON Schema files; use the CLI explicitly.

Field Type Default Description
superuser_key string 123456789abcdef Superuser authentication key
message_store_enabled boolean true Whether to enable message-store runtime hooks
message_store_retention_days number 30 Number of days to retain message records; 0 disables day-based expiry
message_store_summary_limit number 500 Maximum length for text, data, and result summaries
message_store_record_api_calls boolean true Whether to record platform API call summaries
message_store_cleanup_enabled boolean true Whether to clean expired message records during shutdown
recall_message_default_count number 10 Default count used by the group message recall command
permission_platform_runtime_passthrough boolean | object true Whether platform runtime roles may satisfy command permission grants
command_trigger_overrides object {} Per-command primary trigger and alias overrides keyed by command_key
menu_page_trigger_overrides object {} Menu page command trigger overrides keyed by page id
protected_subject_feature_keys string[] moderation side-effect commands Command keys blocked when their target user is protected by whitelist policy
lingchu_adapter string unset Selects the enabled adapter for each platform (env: LINGCHUAdapter / LINGCHU_ADAPTER)
lingchu_superusers object (optional) omitted UID to platform account mapping for Lingchu SUPERUSERS

Example runtime-overrides.toml:

#:schema ./runtime-overrides.schema.json
permission_platform_runtime_passthrough = true
[command_trigger_overrides.member_mute]
chinese = "禁言"
english = "mute"
[menu_page_trigger_overrides.member-management]
chinese = "成员管理"
english = "member-management"

Manage runtime-overrides.toml through the deployment’s localstore tooling. Move deployment settings to NoneBot environment variables and mutable settings to runtime-overrides.toml manually. Programmatic updates rewrite TOML and do not preserve custom comments or formatting.

Deployment values can be supplied through NoneBot global configuration:

LINGCHUAdapter = "~onebot.v11"

Or in a .env file:

LINGCHUAdapter=~onebot.v11

runtime-overrides.toml owns different fields, so it does not compete with deployment configuration.

The managed LLM runtime owns a separate llm.toml and llm.schema.json in the same localstore configuration directory. The [pydantic-ai] section is required for AI features; deployment-level LLM fields are no longer a fallback source. Legacy [profiles], [router], and [eve] sections are ignored with a deprecation warning.

#:schema ./llm.schema.json
[pydantic-ai]
model = "openai:gpt-5.2"
api_key_env = "LINGCHU_AI_API_KEY"
base_url = "https://api.openai.com/v1"
timeout = 60.0
[mcp]
enabled = false
review_profile = "default"
max_tool_rounds = 5
[mcp.servers.local_docs]
transport = "stdio"
command = "uvx"
args = ["example-mcp-server"]
[observability]
enabled = true

The model field must match ^[\w.-]+:[\w./-]+$; the prefix selects the Pydantic AI provider (for example openai:, anthropic:, google-gla:, google-vertex:). Pydantic AI reads provider credentials from the env var declared by api_key_env at call time, and defer_model_check=True lets the runtime be constructed before that env var is provisioned. The stable LLMRuntime.respond() / stream() interface delegates to pydantic_ai.Agent.run() / run_stream() and never executes tool calls; tool execution is exclusive to the explicit reviewed MCP Agent configured by [mcp].

Capability probes return supported or unknown based on a pure model-string heuristic (openai:, anthropic:, google-gla:, google-vertex: prefixes are supported for web_search). They improve UI and fallback decisions but never veto an explicitly requested call. Configuration reload structurally validates the candidate [pydantic-ai] section before an atomic swap. Credentials remain lazy per profile. A failed reload leaves the active generation untouched; a successful reload closes retired agents and invalidates capability caches.

  • The HTTP egress layer must revalidate DNS results and redirects because static configuration validation does not perform blocking DNS resolution. The [pydantic-ai] section does not perform SSRF validation on base_url; enforce network policy at the deployment egress boundary.
  • Ordinary LLM calls return model tool calls as data and never execute them. MCP execution exists only through the explicit reviewed Agent configured by [mcp] in llm.toml; it requires identity-group preauthorization and delegates the multi-round tool loop to a pydantic_ai.Agent configured with the authorized MCPToolsets. The legacy project-side review step and confirmation flow have been removed. Set enabled = false to disable all MCP discovery and execution.

The Pydantic AI agent stays lazy: importing Lingchu or starting without a usable [pydantic-ai] section does not import provider SDKs. Missing optional dependencies fail only when their provider is first requested and do not stop unrelated bot features.

Lingchu Bot also creates menu.toml in the plugin configuration directory. This file controls menu presentation only.

Editable fields:

  • Page title
  • Feature summary and usage
  • Page, child page, and item order

Code-owned fields are not editable from TOML. The command_key set, menu page command, platform_capability, and implementation availability stay in code so the menu cannot claim a command or adapter capability that does not exist. Use menu_page_trigger_overrides in config.toml to change menu page triggers. If menu.toml references an unknown command_key, Lingchu rejects the file and keeps the code defaults. Unknown page ids are skipped with a warning.

The optional nested NovelAI subplugin owns this file and its sibling novelai_image.schema.json. Defaults are model nai-diffusion-4-5-full, size 832x1216, 28 steps, scale 5, sampler k_euler_ancestral, and a 120-second timeout. Set token with LINGCHU_NOVELAI_TOKEN in preference to storing it in TOML.

Token authentication is preferred. Username/password login is also supported: set username and provide LINGCHU_NOVELAI_PASSWORD; the subplugin exchanges it for an in-memory token through account_base_url (default https://api.novelai.net). Custom gateways can set base_url and account_base_url independently.

Full image-API defaults also include n_samples (1-8), quality, uc_preset (0-3), noise_schedule, cfg_rescale, dynamic_thresholding, auto_smea, prefer_brownian, vibe_cache_entries, and image_download_max_bytes. The last two bound the in-memory vibe-token cache and chat image downloads.

The prompt pipeline uses the managed default LLM profile for language understanding, translation, and hint extraction. Configure it in llm.toml; all former global or child-specific LLM fallback keys have been removed and are ignored. Native provider web search is no longer available after the Pydantic AI migration.

TIPO prompt expansion is a separate, optional llama.cpp service:

tipo_enabled = true
tipo_base_url = "http://127.0.0.1:8081/v1"
tipo_model = "tipo-500m-ft"
tipo_timeout = 30.0
tipo_max_tokens = 512
tipo_temperature = 0.5
tipo_top_p = 0.95
tipo_top_k = 40

tipo_api_key is optional and is omitted from the generated TOML when unset. Every field can also be supplied with the LINGCHU_NOVELAI_ prefix, for example LINGCHU_NOVELAI_TIPO_BASE_URL. Set tipo_enabled = false to skip TIPO and use the LLM-produced English description and tags directly. A timeout, transport error, or unusable TIPO completion has the same fallback and does not stop image generation. See Deploy TIPO with llama.cpp.

permission_platform_runtime_passthrough controls whether platform-side roles such as QQ group owner/admin/member can satisfy Lingchu permission grants through runtime identity groups. Set it to false to require explicit Lingchu memberships, or use a TOML table such as [permission_platform_runtime_passthrough] with qq = false for platform-specific behavior.

command_trigger_overrides and menu_page_trigger_overrides are loaded before matchers are registered. Primary trigger changes therefore take effect on restart. The override loader rejects duplicate triggers across commands.

Whitelist protection is configured through subject policy APIs and protected_subject_feature_keys. When a protected user is the target of a listed side-effect command, Lingchu blocks that command; protected users may still operate commands they are otherwise allowed to use.

core_version, data_dir, config_dir, cache_dir, and system platform helpers are still provided by the core Config. Paths come from nonebot-plugin-localstore:

Path Purpose
data_dir Data file directory
config_dir Configuration file directory
cache_dir Cache file directory

Runtime translation reads the lingchu_locale NoneBot configuration key. The recommended project-specific key in .env is:

LINGCHU_LOCALE=zh_CN

Available catalogs currently include zh_CN and en_US. Locale names are normalized before use, so en-US and en_US.UTF-8 both become en_US. When the setting is missing, empty, or NoneBot has not been initialized, the default locale is zh_CN.

in_containers comes from global NoneBot configuration. It must be a Boolean value.

LINGCHU_IN_CONTAINERS=true

The repository root currently does not ship a committed local bot.py. Project-level localstore paths are controlled by NoneBot configuration; see .env.example:

LOCALSTORE_USE_CWD=true

This means localstore-related directories prefer the current working directory, which is convenient for local development and debugging.

Lingchu Bot supports per-handle configuration files for granular control of individual command behaviors. Each handle (command) can have its own TOML configuration file that overrides code defaults.

Handle configuration files follow the naming convention <command_key>.toml and are stored in the plugin configuration directory managed by nonebot-plugin-localstore. For example:

  • recall_message.toml — Configuration for the message recall command
  • member_mute.toml — Configuration for the member mute command
  • kick_member.toml — Configuration for the kick member command

All handle configuration files share a common structure validated by handle_config.schema.json:

Field Type Default Description
enabled boolean true Whether this handle is enabled
defaults object {} Handle-specific default values (e.g., default_count for recall_message)
policies object {} Policy configuration for this handle

The defaults object can contain handle-specific fields. For example, recall_message.toml might define a default_count field that sets the default number of messages to recall when the user omits the count parameter.

The HandleConfigManager class provides centralized access to handle configurations:

  • get_config(command_key) — Read configuration for a specific handle
  • update_config(command_key, updates) — Update configuration with partial changes
  • get_all_configs() — Get configurations for all registered handles
  • ensure_config_files() — Create missing configuration files with defaults

The manager automatically:

  • Caches loaded configurations for performance
  • Falls back to registered defaults when files are missing or invalid
  • Validates configurations against JSON Schema before persisting updates

Each handle module must register its default configuration in handle_config_defaults/ using register_handle_defaults(). This ensures:

  1. The handle has a canonical default configuration
  2. HandleConfigManager can validate the command_key
  3. Missing configuration files fall back to known defaults
#:schema ./handle_config.schema.json
enabled = true
[defaults]
default_count = 10
[policies]

This example shows a recall_message.toml file with the standard structure. The defaults.default_count field overrides the code-defined default for the recall command.