Files
openfang/docs/configuration.md
iven 92e5def702
Some checks failed
CI / Check / macos-latest (push) Has been cancelled
CI / Check / ubuntu-latest (push) Has been cancelled
CI / Check / windows-latest (push) Has been cancelled
CI / Test / macos-latest (push) Has been cancelled
CI / Test / ubuntu-latest (push) Has been cancelled
CI / Test / windows-latest (push) Has been cancelled
CI / Clippy (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Security Audit (push) Has been cancelled
CI / Secrets Scan (push) Has been cancelled
CI / Install Script Smoke Test (push) Has been cancelled
初始化提交
2026-03-01 16:24:24 +08:00

53 KiB

OpenFang Configuration Reference

Complete reference for config.toml, covering every configurable field in the OpenFang Agent OS.


Table of Contents


Overview

OpenFang reads its configuration from a single TOML file:

~/.openfang/config.toml

On Windows, ~ resolves to C:\Users\<username>. If the home directory cannot be determined, the system temp directory is used as a fallback.

Key behaviors:

  • Every struct in the configuration uses #[serde(default)], which means all fields are optional. Omitted fields receive their documented default values.
  • Channel sections ([channels.telegram], [channels.discord], etc.) are Option<T> -- when absent, the channel adapter is disabled. Including the section header (even empty) enables the adapter with defaults.
  • Secrets are never stored in config.toml directly. Instead, fields like api_key_env and bot_token_env hold the name of an environment variable that contains the actual secret. This prevents accidental exposure in version control.
  • Sensitive fields (api_key, shared_secret) are automatically redacted in debug output and logs.

Minimal Configuration

The simplest working configuration only needs an LLM provider API key set as an environment variable. With no config file at all, OpenFang boots with Anthropic as the default provider:

# ~/.openfang/config.toml
# Minimal: just override the model if you want something other than defaults.
# Set ANTHROPIC_API_KEY in your environment.

[default_model]
provider = "anthropic"
model = "claude-sonnet-4-20250514"
api_key_env = "ANTHROPIC_API_KEY"

Or to use a local Ollama instance with no API key:

[default_model]
provider = "ollama"
model = "llama3.2:latest"
base_url = "http://localhost:11434"
api_key_env = ""

Full Example

# ============================================================
# OpenFang Agent OS -- Complete Configuration Reference
# ============================================================

# --- Top-level fields ---
home_dir = "~/.openfang"             # OpenFang home directory
data_dir = "~/.openfang/data"        # SQLite databases and data files
log_level = "info"                   # trace | debug | info | warn | error
api_listen = "127.0.0.1:50051"      # HTTP/WS API bind address
network_enabled = false              # Enable OFP peer-to-peer network
api_key = ""                         # API Bearer token (empty = unauthenticated)
mode = "default"                     # stable | default | dev
language = "en"                      # Locale for CLI/messages
usage_footer = "full"                # off | tokens | cost | full

# --- Default LLM Provider ---
[default_model]
provider = "anthropic"
model = "claude-sonnet-4-20250514"
api_key_env = "ANTHROPIC_API_KEY"
# base_url = "https://api.anthropic.com"  # Optional override

# --- Fallback Providers ---
[[fallback_providers]]
provider = "ollama"
model = "llama3.2:latest"
api_key_env = ""
# base_url = "http://localhost:11434"  # Uses catalog default if omitted

[[fallback_providers]]
provider = "groq"
model = "llama-3.3-70b-versatile"
api_key_env = "GROQ_API_KEY"

# --- Memory ---
[memory]
# sqlite_path = "~/.openfang/data/openfang.db"  # Auto-resolved if omitted
embedding_model = "all-MiniLM-L6-v2"
consolidation_threshold = 10000
decay_rate = 0.1

# --- Network (OFP Wire Protocol) ---
[network]
listen_addresses = ["/ip4/0.0.0.0/tcp/0"]
bootstrap_peers = []
mdns_enabled = true
max_peers = 50
shared_secret = ""                   # Required when network_enabled = true

# --- Web Tools ---
[web]
search_provider = "auto"             # auto | brave | tavily | perplexity | duckduckgo
cache_ttl_minutes = 15

[web.brave]
api_key_env = "BRAVE_API_KEY"
max_results = 5
country = ""
search_lang = ""
freshness = ""

[web.tavily]
api_key_env = "TAVILY_API_KEY"
search_depth = "basic"               # basic | advanced
max_results = 5
include_answer = true

[web.perplexity]
api_key_env = "PERPLEXITY_API_KEY"
model = "sonar"

[web.fetch]
max_chars = 50000
max_response_bytes = 10485760        # 10 MB
timeout_secs = 30
readability = true

# --- MCP Servers ---
[[mcp_servers]]
name = "filesystem"
timeout_secs = 30
env = []
[mcp_servers.transport]
type = "stdio"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]

[[mcp_servers]]
name = "remote-tools"
timeout_secs = 60
env = ["REMOTE_API_KEY"]
[mcp_servers.transport]
type = "sse"
url = "https://mcp.example.com/events"

# --- A2A Protocol ---
[a2a]
enabled = false
listen_path = "/a2a"

[[a2a.external_agents]]
name = "research-agent"
url = "https://agent.example.com/.well-known/agent.json"

# --- RBAC Users ---
[[users]]
name = "Alice"
role = "owner"                       # owner | admin | user | viewer
api_key_hash = ""
[users.channel_bindings]
telegram = "123456"
discord = "987654321"

[[users]]
name = "Bob"
role = "user"
[users.channel_bindings]
slack = "U0123ABCDEF"

# --- Channel Adapters ---
# (See "Channels" section below for all 40 adapters)

[channels.telegram]
bot_token_env = "TELEGRAM_BOT_TOKEN"
allowed_users = []
# default_agent = "assistant"
poll_interval_secs = 1

[channels.discord]
bot_token_env = "DISCORD_BOT_TOKEN"
allowed_guilds = []
intents = 33280

[channels.slack]
app_token_env = "SLACK_APP_TOKEN"
bot_token_env = "SLACK_BOT_TOKEN"
allowed_channels = []

Section Reference

Top-Level Fields

These fields sit at the root of config.toml (not inside any [section]).

Field Type Default Description
home_dir path ~/.openfang OpenFang home directory. Stores config, agents, skills.
data_dir path ~/.openfang/data Directory for SQLite databases and persistent data.
log_level string "info" Log verbosity. One of: trace, debug, info, warn, error.
api_listen string "127.0.0.1:50051" Bind address for the HTTP/WebSocket/SSE API server.
network_enabled bool false Enable the OFP peer-to-peer network layer.
api_key string "" (empty) API authentication key. When set, all endpoints except /api/health require Authorization: Bearer <key>. Empty means unauthenticated (local development only).
mode string "default" Kernel operating mode. See below.
language string "en" Language/locale code for CLI output and system messages.
usage_footer string "full" Controls usage info appended to responses. See below.

mode values:

Value Behavior
stable Conservative: no auto-updates, pinned models, frozen skill registry. Uses FallbackDriver.
default Balanced: standard operation.
dev Developer: experimental features enabled.

usage_footer values:

Value Behavior
off No usage information shown.
tokens Show token counts only.
cost Show estimated cost only.
full Show both token counts and estimated cost (default).

[default_model]

Configures the primary LLM provider used when agents do not specify their own model.

[default_model]
provider = "anthropic"
model = "claude-sonnet-4-20250514"
api_key_env = "ANTHROPIC_API_KEY"
# base_url = "https://api.anthropic.com"
Field Type Default Description
provider string "anthropic" Provider name. Supported: anthropic, gemini, openai, groq, openrouter, deepseek, together, mistral, fireworks, ollama, vllm, lmstudio, perplexity, cohere, ai21, cerebras, sambanova, huggingface, xai, replicate.
model string "claude-sonnet-4-20250514" Model identifier. Aliases like sonnet, haiku, gpt-4o, gemini-flash are resolved by the model catalog.
api_key_env string "ANTHROPIC_API_KEY" Name of the environment variable holding the API key. The actual key is read from this env var at runtime, never stored in config.
base_url string or null null Override the API base URL. Useful for proxies or self-hosted endpoints. When null, the provider's default URL from the model catalog is used.

[memory]

Configures the SQLite-backed memory substrate, including vector embeddings and memory decay.

[memory]
# sqlite_path = "/custom/path/openfang.db"
embedding_model = "all-MiniLM-L6-v2"
consolidation_threshold = 10000
decay_rate = 0.1
Field Type Default Description
sqlite_path path or null null Explicit path to the SQLite database file. When null, defaults to {data_dir}/openfang.db.
embedding_model string "all-MiniLM-L6-v2" Model name used for generating vector embeddings for semantic memory search.
consolidation_threshold u64 10000 Number of stored memories before automatic consolidation is triggered to merge and prune old entries.
decay_rate f32 0.1 Memory confidence decay rate. 0.0 = no decay (memories never fade), 1.0 = aggressive decay. Values between 0.0 and 1.0.

[network]

Configures the OFP (OpenFang Protocol) peer-to-peer networking layer with HMAC-SHA256 mutual authentication.

[network]
listen_addresses = ["/ip4/0.0.0.0/tcp/0"]
bootstrap_peers = []
mdns_enabled = true
max_peers = 50
shared_secret = "my-cluster-secret"
Field Type Default Description
listen_addresses list of strings ["/ip4/0.0.0.0/tcp/0"] libp2p multiaddresses to listen on. Port 0 means auto-assign.
bootstrap_peers list of strings [] Multiaddresses of bootstrap peers for DHT discovery.
mdns_enabled bool true Enable mDNS for automatic local network peer discovery.
max_peers u32 50 Maximum number of simultaneously connected peers.
shared_secret string "" (empty) Pre-shared secret for OFP HMAC-SHA256 mutual authentication. Required when network_enabled = true. Both sides must use the same secret. Redacted in logs.

[web]

Configures web search and web fetch capabilities used by agent tools.

[web]
search_provider = "auto"
cache_ttl_minutes = 15
Field Type Default Description
search_provider string "auto" Which search engine to use. See values below.
cache_ttl_minutes u64 15 Cache duration for search/fetch results in minutes. 0 = caching disabled.

search_provider values:

Value Description
auto Cascading fallback: tries Tavily, then Brave, then Perplexity, then DuckDuckGo, based on which API keys are available.
brave Brave Search API. Requires BRAVE_API_KEY.
tavily Tavily AI-native search. Requires TAVILY_API_KEY.
perplexity Perplexity AI search. Requires PERPLEXITY_API_KEY.
duckduckgo DuckDuckGo HTML scraping. No API key needed.

[web.brave]

[web.brave]
api_key_env = "BRAVE_API_KEY"
max_results = 5
country = ""
search_lang = ""
freshness = ""
Field Type Default Description
api_key_env string "BRAVE_API_KEY" Environment variable name holding the Brave Search API key.
max_results usize 5 Maximum number of search results to return.
country string "" Country code for localized results (e.g., "US", "GB"). Empty = no filter.
search_lang string "" Language code (e.g., "en", "fr"). Empty = no filter.
freshness string "" Freshness filter. "pd" = past day, "pw" = past week, "pm" = past month. Empty = no filter.

[web.tavily]

[web.tavily]
api_key_env = "TAVILY_API_KEY"
search_depth = "basic"
max_results = 5
include_answer = true
Field Type Default Description
api_key_env string "TAVILY_API_KEY" Environment variable name holding the Tavily API key.
search_depth string "basic" Search depth: "basic" for fast results, "advanced" for deeper analysis.
max_results usize 5 Maximum number of search results to return.
include_answer bool true Whether to include Tavily's AI-generated answer summary in results.

[web.perplexity]

[web.perplexity]
api_key_env = "PERPLEXITY_API_KEY"
model = "sonar"
Field Type Default Description
api_key_env string "PERPLEXITY_API_KEY" Environment variable name holding the Perplexity API key.
model string "sonar" Perplexity model to use for search queries.

[web.fetch]

[web.fetch]
max_chars = 50000
max_response_bytes = 10485760
timeout_secs = 30
readability = true
Field Type Default Description
max_chars usize 50000 Maximum characters returned in fetched content. Content exceeding this is truncated.
max_response_bytes usize 10485760 (10 MB) Maximum HTTP response body size in bytes.
timeout_secs u64 30 HTTP request timeout in seconds.
readability bool true Enable HTML-to-Markdown readability extraction. When true, fetched HTML is converted to clean Markdown.

[channels]

All 40 channel adapters are configured under [channels.<name>]. Each channel is Option<T> -- omitting the section disables the adapter entirely. Including the section header (even empty) enables it with default values.

Every channel config includes a default_agent field (optional agent name to route messages to) and an overrides sub-table (see Channel Overrides).

[channels.telegram]

[channels.telegram]
bot_token_env = "TELEGRAM_BOT_TOKEN"
allowed_users = []
# default_agent = "assistant"
poll_interval_secs = 1
Field Type Default Description
bot_token_env string "TELEGRAM_BOT_TOKEN" Env var holding the Telegram Bot API token.
allowed_users list of i64 [] Telegram user IDs allowed to interact. Empty = allow all.
default_agent string or null null Agent name to route messages to.
poll_interval_secs u64 1 Long-polling interval in seconds.

[channels.discord]

[channels.discord]
bot_token_env = "DISCORD_BOT_TOKEN"
allowed_guilds = []
# default_agent = "assistant"
intents = 33280
Field Type Default Description
bot_token_env string "DISCORD_BOT_TOKEN" Env var holding the Discord bot token.
allowed_guilds list of u64 [] Guild (server) IDs allowed. Empty = allow all.
default_agent string or null null Agent name to route messages to.
intents u64 33280 Gateway intents bitmask. Default = GUILD_MESSAGES | MESSAGE_CONTENT.

[channels.slack]

[channels.slack]
app_token_env = "SLACK_APP_TOKEN"
bot_token_env = "SLACK_BOT_TOKEN"
allowed_channels = []
Field Type Default Description
app_token_env string "SLACK_APP_TOKEN" Env var holding the Slack app-level token (xapp-) for Socket Mode.
bot_token_env string "SLACK_BOT_TOKEN" Env var holding the Slack bot token (xoxb-) for REST API.
allowed_channels list of strings [] Channel IDs allowed. Empty = allow all.
default_agent string or null null Agent name to route messages to.

[channels.whatsapp]

[channels.whatsapp]
access_token_env = "WHATSAPP_ACCESS_TOKEN"
verify_token_env = "WHATSAPP_VERIFY_TOKEN"
phone_number_id = ""
webhook_port = 8443
allowed_users = []
Field Type Default Description
access_token_env string "WHATSAPP_ACCESS_TOKEN" Env var holding the WhatsApp Cloud API access token.
verify_token_env string "WHATSAPP_VERIFY_TOKEN" Env var holding the webhook verification token.
phone_number_id string "" WhatsApp Business phone number ID.
webhook_port u16 8443 Port to listen for incoming webhook callbacks.
allowed_users list of strings [] Phone numbers allowed. Empty = allow all.
default_agent string or null null Agent name to route messages to.

[channels.signal]

[channels.signal]
api_url = "http://localhost:8080"
phone_number = ""
allowed_users = []
Field Type Default Description
api_url string "http://localhost:8080" URL of the signal-cli REST API.
phone_number string "" Registered phone number for the bot.
allowed_users list of strings [] Allowed phone numbers. Empty = allow all.
default_agent string or null null Agent name to route messages to.

[channels.matrix]

[channels.matrix]
homeserver_url = "https://matrix.org"
user_id = "@openfang:matrix.org"
access_token_env = "MATRIX_ACCESS_TOKEN"
allowed_rooms = []
Field Type Default Description
homeserver_url string "https://matrix.org" Matrix homeserver URL.
user_id string "" Bot user ID (e.g., "@openfang:matrix.org").
access_token_env string "MATRIX_ACCESS_TOKEN" Env var holding the Matrix access token.
allowed_rooms list of strings [] Room IDs to listen in. Empty = all joined rooms.
default_agent string or null null Agent name to route messages to.

[channels.email]

[channels.email]
imap_host = "imap.gmail.com"
imap_port = 993
smtp_host = "smtp.gmail.com"
smtp_port = 587
username = "bot@example.com"
password_env = "EMAIL_PASSWORD"
poll_interval_secs = 30
folders = ["INBOX"]
allowed_senders = []
Field Type Default Description
imap_host string "" IMAP server hostname.
imap_port u16 993 IMAP server port (993 for TLS).
smtp_host string "" SMTP server hostname.
smtp_port u16 587 SMTP server port (587 for STARTTLS).
username string "" Email address for both IMAP and SMTP.
password_env string "EMAIL_PASSWORD" Env var holding the email password or app password.
poll_interval_secs u64 30 IMAP polling interval in seconds.
folders list of strings ["INBOX"] IMAP folders to monitor.
allowed_senders list of strings [] Only process emails from these senders. Empty = all.
default_agent string or null null Agent name to route messages to.

[channels.teams]

[channels.teams]
app_id = ""
app_password_env = "TEAMS_APP_PASSWORD"
webhook_port = 3978
allowed_tenants = []
Field Type Default Description
app_id string "" Azure Bot App ID.
app_password_env string "TEAMS_APP_PASSWORD" Env var holding the Azure Bot Framework app password.
webhook_port u16 3978 Port for the Bot Framework incoming webhook.
allowed_tenants list of strings [] Azure AD tenant IDs allowed. Empty = allow all.
default_agent string or null null Agent name to route messages to.

[channels.mattermost]

[channels.mattermost]
server_url = "https://mattermost.example.com"
token_env = "MATTERMOST_TOKEN"
allowed_channels = []
Field Type Default Description
server_url string "" Mattermost server URL.
token_env string "MATTERMOST_TOKEN" Env var holding the Mattermost bot token.
allowed_channels list of strings [] Channel IDs to listen in. Empty = all.
default_agent string or null null Agent name to route messages to.

[channels.irc]

[channels.irc]
server = "irc.libera.chat"
port = 6667
nick = "openfang"
# password_env = "IRC_PASSWORD"
channels = ["#openfang"]
use_tls = false
Field Type Default Description
server string "irc.libera.chat" IRC server hostname.
port u16 6667 IRC server port.
nick string "openfang" Bot nickname.
password_env string or null null Env var holding the server password (optional).
channels list of strings [] IRC channels to join (e.g., ["#openfang", "#general"]).
use_tls bool false Use TLS for the connection.
default_agent string or null null Agent name to route messages to.

[channels.google_chat]

[channels.google_chat]
service_account_env = "GOOGLE_CHAT_SERVICE_ACCOUNT"
space_ids = []
webhook_port = 8444
Field Type Default Description
service_account_env string "GOOGLE_CHAT_SERVICE_ACCOUNT" Env var holding the service account JSON key.
space_ids list of strings [] Google Chat space IDs to listen in.
webhook_port u16 8444 Port for the incoming webhook.
default_agent string or null null Agent name to route messages to.

[channels.twitch]

[channels.twitch]
oauth_token_env = "TWITCH_OAUTH_TOKEN"
channels = ["mychannel"]
nick = "openfang"
Field Type Default Description
oauth_token_env string "TWITCH_OAUTH_TOKEN" Env var holding the Twitch OAuth token.
channels list of strings [] Twitch channels to join (without # prefix).
nick string "openfang" Bot nickname in Twitch chat.
default_agent string or null null Agent name to route messages to.

[channels.rocketchat]

[channels.rocketchat]
server_url = "https://rocketchat.example.com"
token_env = "ROCKETCHAT_TOKEN"
user_id = ""
allowed_channels = []
Field Type Default Description
server_url string "" Rocket.Chat server URL.
token_env string "ROCKETCHAT_TOKEN" Env var holding the Rocket.Chat auth token.
user_id string "" Bot user ID.
allowed_channels list of strings [] Channel IDs to listen in. Empty = all.
default_agent string or null null Agent name to route messages to.

[channels.zulip]

[channels.zulip]
server_url = "https://zulip.example.com"
bot_email = "bot@zulip.example.com"
api_key_env = "ZULIP_API_KEY"
streams = []
Field Type Default Description
server_url string "" Zulip server URL.
bot_email string "" Bot email address registered in Zulip.
api_key_env string "ZULIP_API_KEY" Env var holding the Zulip API key.
streams list of strings [] Stream names to listen in. Empty = all.
default_agent string or null null Agent name to route messages to.

[channels.xmpp]

[channels.xmpp]
jid = "bot@jabber.org"
password_env = "XMPP_PASSWORD"
server = ""
port = 5222
rooms = []
Field Type Default Description
jid string "" XMPP JID (e.g., "bot@jabber.org").
password_env string "XMPP_PASSWORD" Env var holding the XMPP password.
server string "" XMPP server hostname. Defaults to the JID domain if empty.
port u16 5222 XMPP server port.
rooms list of strings [] MUC (multi-user chat) rooms to join.
default_agent string or null null Agent name to route messages to.

[channels.line]

[channels.line]
channel_secret_env = "LINE_CHANNEL_SECRET"
access_token_env = "LINE_CHANNEL_ACCESS_TOKEN"
webhook_port = 8450
Field Type Default Description
channel_secret_env string "LINE_CHANNEL_SECRET" Env var holding the LINE channel secret.
access_token_env string "LINE_CHANNEL_ACCESS_TOKEN" Env var holding the LINE channel access token.
webhook_port u16 8450 Port for the incoming webhook.
default_agent string or null null Agent name to route messages to.

[channels.viber]

[channels.viber]
auth_token_env = "VIBER_AUTH_TOKEN"
webhook_url = ""
webhook_port = 8451
Field Type Default Description
auth_token_env string "VIBER_AUTH_TOKEN" Env var holding the Viber Bot auth token.
webhook_url string "" Public URL for the Viber webhook endpoint.
webhook_port u16 8451 Port for the incoming webhook.
default_agent string or null null Agent name to route messages to.

[channels.messenger]

[channels.messenger]
page_token_env = "MESSENGER_PAGE_TOKEN"
verify_token_env = "MESSENGER_VERIFY_TOKEN"
webhook_port = 8452
Field Type Default Description
page_token_env string "MESSENGER_PAGE_TOKEN" Env var holding the Facebook page access token.
verify_token_env string "MESSENGER_VERIFY_TOKEN" Env var holding the webhook verify token.
webhook_port u16 8452 Port for the incoming webhook.
default_agent string or null null Agent name to route messages to.

[channels.reddit]

[channels.reddit]
client_id = ""
client_secret_env = "REDDIT_CLIENT_SECRET"
username = ""
password_env = "REDDIT_PASSWORD"
subreddits = []
Field Type Default Description
client_id string "" Reddit app client ID.
client_secret_env string "REDDIT_CLIENT_SECRET" Env var holding the Reddit client secret.
username string "" Reddit bot username.
password_env string "REDDIT_PASSWORD" Env var holding the Reddit bot password.
subreddits list of strings [] Subreddit names to monitor.
default_agent string or null null Agent name to route messages to.

[channels.mastodon]

[channels.mastodon]
instance_url = "https://mastodon.social"
access_token_env = "MASTODON_ACCESS_TOKEN"
Field Type Default Description
instance_url string "" Mastodon instance URL (e.g., "https://mastodon.social").
access_token_env string "MASTODON_ACCESS_TOKEN" Env var holding the Mastodon access token.
default_agent string or null null Agent name to route messages to.

[channels.bluesky]

[channels.bluesky]
identifier = "mybot.bsky.social"
app_password_env = "BLUESKY_APP_PASSWORD"
service_url = "https://bsky.social"
Field Type Default Description
identifier string "" Bluesky handle or DID.
app_password_env string "BLUESKY_APP_PASSWORD" Env var holding the Bluesky app password.
service_url string "https://bsky.social" PDS (Personal Data Server) URL.
default_agent string or null null Agent name to route messages to.

[channels.feishu]

[channels.feishu]
app_id = ""
app_secret_env = "FEISHU_APP_SECRET"
webhook_port = 8453
Field Type Default Description
app_id string "" Feishu/Lark app ID.
app_secret_env string "FEISHU_APP_SECRET" Env var holding the Feishu app secret.
webhook_port u16 8453 Port for the incoming webhook.
default_agent string or null null Agent name to route messages to.

[channels.revolt]

[channels.revolt]
bot_token_env = "REVOLT_BOT_TOKEN"
api_url = "https://api.revolt.chat"
Field Type Default Description
bot_token_env string "REVOLT_BOT_TOKEN" Env var holding the Revolt bot token.
api_url string "https://api.revolt.chat" Revolt API base URL.
default_agent string or null null Agent name to route messages to.

[channels.nextcloud]

[channels.nextcloud]
server_url = "https://nextcloud.example.com"
token_env = "NEXTCLOUD_TOKEN"
allowed_rooms = []
Field Type Default Description
server_url string "" Nextcloud server URL.
token_env string "NEXTCLOUD_TOKEN" Env var holding the Nextcloud Talk auth token.
allowed_rooms list of strings [] Room tokens to listen in. Empty = all.
default_agent string or null null Agent name to route messages to.

[channels.guilded]

[channels.guilded]
bot_token_env = "GUILDED_BOT_TOKEN"
server_ids = []
Field Type Default Description
bot_token_env string "GUILDED_BOT_TOKEN" Env var holding the Guilded bot token.
server_ids list of strings [] Server IDs to listen in. Empty = all.
default_agent string or null null Agent name to route messages to.

[channels.keybase]

[channels.keybase]
username = ""
paperkey_env = "KEYBASE_PAPERKEY"
allowed_teams = []
Field Type Default Description
username string "" Keybase username.
paperkey_env string "KEYBASE_PAPERKEY" Env var holding the Keybase paper key.
allowed_teams list of strings [] Team names to listen in. Empty = all DMs.
default_agent string or null null Agent name to route messages to.

[channels.threema]

[channels.threema]
threema_id = ""
secret_env = "THREEMA_SECRET"
webhook_port = 8454
Field Type Default Description
threema_id string "" Threema Gateway ID.
secret_env string "THREEMA_SECRET" Env var holding the Threema API secret.
webhook_port u16 8454 Port for the incoming webhook.
default_agent string or null null Agent name to route messages to.

[channels.nostr]

[channels.nostr]
private_key_env = "NOSTR_PRIVATE_KEY"
relays = ["wss://relay.damus.io"]
Field Type Default Description
private_key_env string "NOSTR_PRIVATE_KEY" Env var holding the Nostr private key (nsec or hex format).
relays list of strings ["wss://relay.damus.io"] Nostr relay WebSocket URLs to connect to.
default_agent string or null null Agent name to route messages to.

[channels.webex]

[channels.webex]
bot_token_env = "WEBEX_BOT_TOKEN"
allowed_rooms = []
Field Type Default Description
bot_token_env string "WEBEX_BOT_TOKEN" Env var holding the Webex bot token.
allowed_rooms list of strings [] Room IDs to listen in. Empty = all.
default_agent string or null null Agent name to route messages to.

[channels.pumble]

[channels.pumble]
bot_token_env = "PUMBLE_BOT_TOKEN"
webhook_port = 8455
Field Type Default Description
bot_token_env string "PUMBLE_BOT_TOKEN" Env var holding the Pumble bot token.
webhook_port u16 8455 Port for the incoming webhook.
default_agent string or null null Agent name to route messages to.

[channels.flock]

[channels.flock]
bot_token_env = "FLOCK_BOT_TOKEN"
webhook_port = 8456
Field Type Default Description
bot_token_env string "FLOCK_BOT_TOKEN" Env var holding the Flock bot token.
webhook_port u16 8456 Port for the incoming webhook.
default_agent string or null null Agent name to route messages to.

[channels.twist]

[channels.twist]
token_env = "TWIST_TOKEN"
workspace_id = ""
allowed_channels = []
Field Type Default Description
token_env string "TWIST_TOKEN" Env var holding the Twist API token.
workspace_id string "" Twist workspace ID.
allowed_channels list of strings [] Channel IDs to listen in. Empty = all.
default_agent string or null null Agent name to route messages to.

[channels.mumble]

[channels.mumble]
host = "mumble.example.com"
port = 64738
username = "openfang"
password_env = "MUMBLE_PASSWORD"
channel = ""
Field Type Default Description
host string "" Mumble server hostname.
port u16 64738 Mumble server port.
username string "openfang" Bot username in Mumble.
password_env string "MUMBLE_PASSWORD" Env var holding the Mumble server password.
channel string "" Mumble channel to join.
default_agent string or null null Agent name to route messages to.

[channels.dingtalk]

[channels.dingtalk]
access_token_env = "DINGTALK_ACCESS_TOKEN"
secret_env = "DINGTALK_SECRET"
webhook_port = 8457
Field Type Default Description
access_token_env string "DINGTALK_ACCESS_TOKEN" Env var holding the DingTalk webhook access token.
secret_env string "DINGTALK_SECRET" Env var holding the DingTalk signing secret.
webhook_port u16 8457 Port for the incoming webhook.
default_agent string or null null Agent name to route messages to.

[channels.discourse]

[channels.discourse]
base_url = "https://forum.example.com"
api_key_env = "DISCOURSE_API_KEY"
api_username = "system"
categories = []
Field Type Default Description
base_url string "" Discourse forum base URL.
api_key_env string "DISCOURSE_API_KEY" Env var holding the Discourse API key.
api_username string "system" Discourse API username.
categories list of strings [] Category slugs to monitor.
default_agent string or null null Agent name to route messages to.

[channels.gitter]

[channels.gitter]
token_env = "GITTER_TOKEN"
room_id = ""
Field Type Default Description
token_env string "GITTER_TOKEN" Env var holding the Gitter auth token.
room_id string "" Gitter room ID to listen in.
default_agent string or null null Agent name to route messages to.

[channels.ntfy]

[channels.ntfy]
server_url = "https://ntfy.sh"
topic = "my-agent-topic"
token_env = "NTFY_TOKEN"
Field Type Default Description
server_url string "https://ntfy.sh" ntfy server URL. Can be self-hosted.
topic string "" Topic to subscribe/publish to.
token_env string "NTFY_TOKEN" Env var holding the auth token. Optional for public topics.
default_agent string or null null Agent name to route messages to.

[channels.gotify]

[channels.gotify]
server_url = "https://gotify.example.com"
app_token_env = "GOTIFY_APP_TOKEN"
client_token_env = "GOTIFY_CLIENT_TOKEN"
Field Type Default Description
server_url string "" Gotify server URL.
app_token_env string "GOTIFY_APP_TOKEN" Env var holding the Gotify app token (for sending messages).
client_token_env string "GOTIFY_CLIENT_TOKEN" Env var holding the Gotify client token (for receiving messages via WebSocket).
default_agent string or null null Agent name to route messages to.

[channels.webhook]

[channels.webhook]
secret_env = "WEBHOOK_SECRET"
listen_port = 8460
# callback_url = "https://example.com/webhook"
Field Type Default Description
secret_env string "WEBHOOK_SECRET" Env var holding the HMAC signing secret for verifying incoming webhooks.
listen_port u16 8460 Port to listen for incoming webhook requests.
callback_url string or null null URL to POST outgoing messages to.
default_agent string or null null Agent name to route messages to.

[channels.linkedin]

[channels.linkedin]
access_token_env = "LINKEDIN_ACCESS_TOKEN"
organization_id = ""
Field Type Default Description
access_token_env string "LINKEDIN_ACCESS_TOKEN" Env var holding the LinkedIn OAuth2 access token.
organization_id string "" LinkedIn organization ID for messaging.
default_agent string or null null Agent name to route messages to.

[[mcp_servers]]

MCP (Model Context Protocol) server connections provide external tool integration. Each entry is a separate [[mcp_servers]] array element.

[[mcp_servers]]
name = "filesystem"
timeout_secs = 30
env = []

[mcp_servers.transport]
type = "stdio"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/docs"]
[[mcp_servers]]
name = "remote-api"
timeout_secs = 60
env = ["GITHUB_PERSONAL_ACCESS_TOKEN"]

[mcp_servers.transport]
type = "sse"
url = "https://mcp.example.com/sse"
Field Type Default Description
name string required Display name for this MCP server. Tools are namespaced as mcp_{name}_{tool}.
timeout_secs u64 30 Request timeout in seconds.
env list of strings [] Environment variable names to pass through to the subprocess (stdio transport only).

Transport variants (tagged union on type):

type Fields Description
stdio command (string), args (list of strings, default []) Spawn a subprocess, communicate via JSON-RPC over stdin/stdout.
sse url (string) Connect to an HTTP Server-Sent Events endpoint.

[a2a]

Agent-to-Agent protocol configuration, enabling inter-agent communication across OpenFang instances.

[a2a]
enabled = true
listen_path = "/a2a"

[[a2a.external_agents]]
name = "research-agent"
url = "https://agent.example.com/.well-known/agent.json"

[[a2a.external_agents]]
name = "code-reviewer"
url = "https://reviewer.example.com/.well-known/agent.json"
Field Type Default Description
enabled bool false Whether A2A protocol is enabled.
listen_path string "/a2a" URL path prefix for A2A endpoints.
external_agents list of objects [] External A2A agents to discover and interact with.

external_agents entries:

Field Type Description
name string Display name for the external agent.
url string Agent card endpoint URL (typically /.well-known/agent.json).

[[fallback_providers]]

Fallback provider chain. When the primary LLM provider ([default_model]) fails, these are tried in order.

[[fallback_providers]]
provider = "ollama"
model = "llama3.2:latest"
api_key_env = ""
# base_url = "http://localhost:11434"

[[fallback_providers]]
provider = "groq"
model = "llama-3.3-70b-versatile"
api_key_env = "GROQ_API_KEY"
Field Type Default Description
provider string "" Provider name (e.g., "ollama", "groq", "openai").
model string "" Model identifier for this provider.
api_key_env string "" Env var name for the API key. Empty for local providers (ollama, vllm, lmstudio).
base_url string or null null Base URL override. Uses catalog default if null.

[[users]]

RBAC multi-user configuration. Users can be assigned roles and bound to channel platform identities.

[[users]]
name = "Alice"
role = "owner"
api_key_hash = "sha256_hash_of_api_key"

[users.channel_bindings]
telegram = "123456"
discord = "987654321"
slack = "U0ABCDEFG"
Field Type Default Description
name string required User display name.
role string "user" User role in the RBAC hierarchy.
channel_bindings map of string to string {} Maps channel platform names to platform-specific user IDs, binding this user identity across channels.
api_key_hash string or null null SHA256 hash of the user's personal API key for authenticated API access.

Role hierarchy (highest to lowest privilege):

Role Description
owner Full administrative access. Can manage all agents, users, and configuration.
admin Can manage agents and most settings. Cannot modify owner accounts.
user Can interact with agents. Limited management capabilities.
viewer Read-only access. Can view agent responses but cannot send messages.

Channel Overrides

Every channel adapter supports an [channels.<name>.overrides] sub-table that customizes agent behavior per-channel.

[channels.telegram.overrides]
model = "claude-haiku-4-5-20251001"
system_prompt = "You are a concise Telegram assistant."
dm_policy = "respond"
group_policy = "mention_only"
rate_limit_per_user = 10
threading = true
output_format = "telegram_html"
usage_footer = "tokens"
Field Type Default Description
model string or null null Model override for this channel. Uses the agent's default model when null.
system_prompt string or null null System prompt override for this channel.
dm_policy string "respond" How the bot handles direct messages. See below.
group_policy string "mention_only" How the bot handles group messages. See below.
rate_limit_per_user u32 0 Maximum messages per user per minute. 0 = unlimited.
threading bool false Enable thread replies (where supported by the platform).
output_format string or null null Override output formatting. See below.
usage_footer string or null null Override usage footer mode for this channel. Values: off, tokens, cost, full.

dm_policy values:

Value Description
respond Respond to all direct messages (default).
allowed_only Only respond to DMs from users in the allowed list.
ignore Ignore all direct messages.

group_policy values:

Value Description
all Respond to all messages in group chats.
mention_only Only respond when the bot is @mentioned (default).
commands_only Only respond to slash commands.
ignore Ignore all group messages.

output_format values:

Value Description
markdown Standard Markdown (default).
telegram_html Telegram HTML subset (<b>, <i>, <code>, etc.).
slack_mrkdwn Slack mrkdwn format (*bold*, _italic_, `code`).
plain_text No formatting markup.

Environment Variables

Complete table of all environment variables referenced by the configuration. None of these are read by the config file itself -- they are read at runtime by the kernel and channel adapters.

LLM Provider Keys

Variable Used By Description
ANTHROPIC_API_KEY [default_model] Anthropic API key (Claude models).
GEMINI_API_KEY Gemini driver Google Gemini API key. Alias: GOOGLE_API_KEY.
OPENAI_API_KEY OpenAI-compat driver OpenAI API key.
GROQ_API_KEY Groq provider Groq API key (fast Llama inference).
DEEPSEEK_API_KEY DeepSeek provider DeepSeek API key.
PERPLEXITY_API_KEY Perplexity provider / web search Perplexity API key.
OPENROUTER_API_KEY OpenRouter provider OpenRouter API key.
TOGETHER_API_KEY Together AI provider Together AI API key.
MISTRAL_API_KEY Mistral provider Mistral AI API key.
FIREWORKS_API_KEY Fireworks provider Fireworks AI API key.
COHERE_API_KEY Cohere provider Cohere API key.
AI21_API_KEY AI21 provider AI21 Labs API key.
CEREBRAS_API_KEY Cerebras provider Cerebras API key.
SAMBANOVA_API_KEY SambaNova provider SambaNova API key.
HUGGINGFACE_API_KEY Hugging Face provider Hugging Face Inference API key.
XAI_API_KEY xAI provider xAI (Grok) API key.
REPLICATE_API_KEY Replicate provider Replicate API key.

Web Search Keys

Variable Used By Description
BRAVE_API_KEY [web.brave] Brave Search API key.
TAVILY_API_KEY [web.tavily] Tavily Search API key.
PERPLEXITY_API_KEY [web.perplexity] Perplexity Search API key (shared with LLM provider).

Channel Tokens

Variable Channel Description
TELEGRAM_BOT_TOKEN Telegram Bot API token from @BotFather.
DISCORD_BOT_TOKEN Discord Discord bot token.
SLACK_APP_TOKEN Slack Slack app-level token (xapp-) for Socket Mode.
SLACK_BOT_TOKEN Slack Slack bot token (xoxb-) for REST API.
WHATSAPP_ACCESS_TOKEN WhatsApp WhatsApp Cloud API access token.
WHATSAPP_VERIFY_TOKEN WhatsApp Webhook verification token.
MATRIX_ACCESS_TOKEN Matrix Matrix homeserver access token.
EMAIL_PASSWORD Email Email account password or app password.
TEAMS_APP_PASSWORD Teams Azure Bot Framework app password.
MATTERMOST_TOKEN Mattermost Mattermost bot token.
TWITCH_OAUTH_TOKEN Twitch Twitch OAuth token.
ROCKETCHAT_TOKEN Rocket.Chat Rocket.Chat auth token.
ZULIP_API_KEY Zulip Zulip bot API key.
XMPP_PASSWORD XMPP XMPP account password.
GOOGLE_CHAT_SERVICE_ACCOUNT Google Chat Service account JSON key.
LINE_CHANNEL_SECRET LINE LINE channel secret.
LINE_CHANNEL_ACCESS_TOKEN LINE LINE channel access token.
VIBER_AUTH_TOKEN Viber Viber Bot auth token.
MESSENGER_PAGE_TOKEN Messenger Facebook page access token.
MESSENGER_VERIFY_TOKEN Messenger Webhook verification token.
REDDIT_CLIENT_SECRET Reddit Reddit app client secret.
REDDIT_PASSWORD Reddit Reddit bot account password.
MASTODON_ACCESS_TOKEN Mastodon Mastodon access token.
BLUESKY_APP_PASSWORD Bluesky Bluesky app password.
FEISHU_APP_SECRET Feishu Feishu/Lark app secret.
REVOLT_BOT_TOKEN Revolt Revolt bot token.
NEXTCLOUD_TOKEN Nextcloud Nextcloud Talk auth token.
GUILDED_BOT_TOKEN Guilded Guilded bot token.
KEYBASE_PAPERKEY Keybase Keybase paper key.
THREEMA_SECRET Threema Threema Gateway API secret.
NOSTR_PRIVATE_KEY Nostr Nostr private key (nsec or hex).
WEBEX_BOT_TOKEN Webex Webex bot token.
PUMBLE_BOT_TOKEN Pumble Pumble bot token.
FLOCK_BOT_TOKEN Flock Flock bot token.
TWIST_TOKEN Twist Twist API token.
MUMBLE_PASSWORD Mumble Mumble server password.
DINGTALK_ACCESS_TOKEN DingTalk DingTalk webhook access token.
DINGTALK_SECRET DingTalk DingTalk signing secret.
DISCOURSE_API_KEY Discourse Discourse API key.
GITTER_TOKEN Gitter Gitter auth token.
NTFY_TOKEN ntfy ntfy auth token (optional for public topics).
GOTIFY_APP_TOKEN Gotify Gotify app token (sending).
GOTIFY_CLIENT_TOKEN Gotify Gotify client token (receiving).
WEBHOOK_SECRET Webhook HMAC signing secret for webhook verification.
LINKEDIN_ACCESS_TOKEN LinkedIn LinkedIn OAuth2 access token.

Validation

KernelConfig::validate() runs at boot time and returns a list of warnings (non-fatal). The kernel still starts, but logs each warning.

What is validated

For every enabled channel (i.e., its config section is present in the TOML), the validator checks that the corresponding environment variable(s) are set and non-empty:

Channel Env vars checked
Telegram bot_token_env
Discord bot_token_env
Slack app_token_env, bot_token_env (both checked)
WhatsApp access_token_env
Matrix access_token_env
Email password_env
Teams app_password_env
Mattermost token_env
Zulip api_key_env
Twitch oauth_token_env
Rocket.Chat token_env
Google Chat service_account_env
XMPP password_env
LINE access_token_env
Viber auth_token_env
Messenger page_token_env
Reddit client_secret_env
Mastodon access_token_env
Bluesky app_password_env
Feishu app_secret_env
Revolt bot_token_env
Nextcloud token_env
Guilded bot_token_env
Keybase paperkey_env
Threema secret_env
Nostr private_key_env
Webex bot_token_env
Pumble bot_token_env
Flock bot_token_env
Twist token_env
Mumble password_env
DingTalk access_token_env
Discourse api_key_env
Gitter token_env
ntfy token_env (only if token_env is non-empty; public topics are OK without auth)
Gotify app_token_env
Webhook secret_env
LinkedIn access_token_env

For web search providers, the validator checks:

Provider Env var checked
brave web.brave.api_key_env
tavily web.tavily.api_key_env
perplexity web.perplexity.api_key_env
duckduckgo (no check -- no API key needed)
auto (no check -- cascading fallback handles missing keys)

What is NOT validated

  • The api_key_env in [default_model] is not checked by validate(). Missing LLM keys cause errors at runtime when the driver is first used.
  • The shared_secret in [network] is not validated against network_enabled. If networking is enabled with an empty secret, authentication will fail at connection time.
  • MCP server configurations are not validated at config load time. Connection errors surface during the background MCP connect phase.
  • Agent manifests have their own separate validation.

Some subsystems have their own configuration that is not part of config.toml but is worth noting:

Session Compaction (runtime)

Configured internally via CompactionConfig (not currently exposed in config.toml):

Field Default Description
threshold 80 Compact when session message count exceeds this.
keep_recent 20 Number of recent messages preserved verbatim after compaction.
max_summary_tokens 1024 Maximum tokens for the LLM summary of compacted messages.

WASM Sandbox (runtime)

Configured internally via SandboxConfig (not currently exposed in config.toml):

Field Default Description
fuel_limit 1000000 Maximum CPU instruction budget. 0 = unlimited.
max_memory_bytes 16777216 (16 MB) Maximum WASM linear memory.
timeout_secs null (30s fallback) Wall-clock timeout for epoch-based interruption.

Model Routing (per-agent manifest)

Configured in agent manifests via ModelRoutingConfig:

Field Default Description
simple_model "claude-haiku-4-5-20251001" Model for simple queries.
medium_model "claude-sonnet-4-20250514" Model for medium-complexity queries.
complex_model "claude-sonnet-4-20250514" Model for complex queries.
simple_threshold 100 Token count below which a query is classified as simple.
complex_threshold 500 Token count above which a query is classified as complex.

Autonomous Guardrails (per-agent manifest)

Configured in agent manifests via AutonomousConfig:

Field Default Description
quiet_hours null Cron expression for quiet hours (agent pauses during this window).
max_iterations 50 Maximum tool-use iterations per invocation.
max_restarts 10 Maximum automatic restarts before permanent stop.
heartbeat_interval_secs 30 Seconds between heartbeat health checks.
heartbeat_channel null Channel to send heartbeat status to (e.g., "telegram").