Config Models¶
::: src.config
Overview¶
All configuration is defined as Pydantic v2 BaseModel subclasses and loaded from a single config.yaml file. Environment variable expansion (${VAR}) is supported throughout all string values.
Source file: src/config.py
load_config(path="config.yaml") -> AppConfig¶
Load and validate configuration from a YAML file.
def load_config(path: str = "config.yaml") -> AppConfig:
"""Load and validate config from YAML file."""
config_path = Path(path)
if not config_path.exists():
raise FileNotFoundError(f"Config file not found: {path}")
with open(config_path) as f:
raw = yaml.safe_load(f)
expanded = _walk_expand(raw or {})
return AppConfig.model_validate(expanded)
| Parameter | Type | Default | Description |
|---|---|---|---|
path |
str |
"config.yaml" |
Path to the YAML configuration file |
Returns: Validated AppConfig instance.
Raises: FileNotFoundError if the config file does not exist; pydantic.ValidationError on invalid config.
Process:
- Read YAML file via
yaml.safe_load() - Recursively expand
${VAR}patterns withos.environ.get(var, "") - Validate via
AppConfig.model_validate()
AppConfig¶
Top-level configuration model. All sections are optional and default to their respective model defaults.
class AppConfig(BaseModel):
agent: AgentConfig = Field(default_factory=AgentConfig)
provider: ProviderConfig = Field(default_factory=ProviderConfig)
channels: ChannelsConfig = Field(default_factory=ChannelsConfig)
scheduler: SchedulerConfig = Field(default_factory=SchedulerConfig)
mcp_servers: dict[str, dict[str, Any]] = Field(default_factory=dict)
skills: SkillsConfig = Field(default_factory=SkillsConfig)
web: WebConfig = Field(default_factory=WebConfig)
transcription: TranscriptionConfig = Field(default_factory=TranscriptionConfig)
gateway: GatewayConfig = Field(default_factory=GatewayConfig)
claude_code: ClaudeCodeConfig = Field(default_factory=ClaudeCodeConfig)
logging: LoggingConfig = Field(default_factory=LoggingConfig)
| Field | Type | Default | Description |
|---|---|---|---|
agent |
AgentConfig |
AgentConfig() |
Agent workspace and iteration settings |
provider |
ProviderConfig |
ProviderConfig() |
LLM provider configuration |
channels |
ChannelsConfig |
ChannelsConfig() |
Channel adapters |
scheduler |
SchedulerConfig |
SchedulerConfig() |
Task scheduler settings |
mcp_servers |
dict[str, dict[str, Any]] |
{} |
MCP server configurations (passed to MultiServerMCPClient) |
skills |
SkillsConfig |
SkillsConfig() |
Skill loading configuration |
web |
WebConfig |
WebConfig() |
Web tools configuration |
transcription |
TranscriptionConfig |
TranscriptionConfig() |
Voice transcription settings |
gateway |
GatewayConfig |
GatewayConfig() |
Host gateway configuration |
claude_code |
ClaudeCodeConfig |
ClaudeCodeConfig() |
Claude Code bridge settings |
logging |
LoggingConfig |
LoggingConfig() |
Logging level |
AgentConfig¶
Agent workspace and execution settings.
class AgentConfig(BaseModel):
workspace: str = "./workspace"
data_dir: str = "./data"
max_tool_iterations: int = 20
| Field | Type | Default | Description |
|---|---|---|---|
workspace |
str |
"./workspace" |
Root directory for agent file operations |
data_dir |
str |
"./data" |
Directory for runtime data (checkpoints, sessions, tasks) |
max_tool_iterations |
int |
20 |
Maximum tool call iterations per agent invocation |
ProviderConfig¶
LLM provider configuration.
class ProviderConfig(BaseModel):
name: str = "anthropic"
model: str = "claude-sonnet-4-6"
api_key: Optional[str] = None
temperature: Optional[float] = None
max_tokens: Optional[int] = None
base_url: Optional[str] = None
| Field | Type | Default | Validator | Description |
|---|---|---|---|---|
name |
str |
"anthropic" |
-- | Provider name (e.g. "anthropic", "openai", "google-genai") |
model |
str |
"claude-sonnet-4-6" |
-- | Model identifier |
api_key |
Optional[str] |
None |
Empty string to None |
API key for the provider |
temperature |
Optional[float] |
None |
Must be 0.0--2.0 | Sampling temperature |
max_tokens |
Optional[int] |
None |
-- | Maximum output tokens |
base_url |
Optional[str] |
None |
Empty string to None |
Custom API base URL |
Validators:
api_key,base_url: empty strings are converted toNonetemperature: must be between 0.0 and 2.0 (inclusive) if set
TelegramChannelConfig¶
Telegram channel settings.
class TelegramChannelConfig(BaseModel):
enabled: bool = False
token: str = ""
trigger: str = "@Ciana"
allowed_users: list[str] = Field(default_factory=list)
| Field | Type | Default | Validator | Description |
|---|---|---|---|---|
enabled |
bool |
False |
-- | Enable Telegram channel |
token |
str |
"" |
-- | Telegram bot token |
trigger |
str |
"@Ciana" |
-- | Prefix required in group chats to trigger the bot |
allowed_users |
list[str] |
[] |
Coerces items to str |
User IDs allowed to use the bot (empty = allow all) |
Validators:
allowed_users: all items are coerced tostr(handles integer user IDs in YAML)
ChannelsConfig¶
Container for all channel configurations.
class ChannelsConfig(BaseModel):
telegram: TelegramChannelConfig = Field(default_factory=TelegramChannelConfig)
| Field | Type | Default | Description |
|---|---|---|---|
telegram |
TelegramChannelConfig |
TelegramChannelConfig() |
Telegram channel config |
SchedulerConfig¶
Task scheduler settings.
class SchedulerConfig(BaseModel):
enabled: bool = False
poll_interval: int = 60
data_file: str = "./data/scheduled_tasks.json"
| Field | Type | Default | Validator | Description |
|---|---|---|---|---|
enabled |
bool |
False |
-- | Enable the scheduler |
poll_interval |
int |
60 |
Must be >= 1 | Seconds between scheduler polls |
data_file |
str |
"./data/scheduled_tasks.json" |
-- | Path to the tasks JSON file |
SkillsConfig¶
Skill loading settings.
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
True |
Enable skill loading |
directory |
str |
"skills" |
Virtual path relative to workspace |
WebConfig¶
Web tools configuration.
| Field | Type | Default | Validator | Description |
|---|---|---|---|---|
brave_api_key |
Optional[str] |
None |
Empty string to None |
Brave Search API key (enables Brave; None = DuckDuckGo fallback) |
fetch_timeout |
int |
30 |
-- | HTTP timeout for web_fetch in seconds |
TranscriptionConfig¶
Voice message transcription settings.
class TranscriptionConfig(BaseModel):
enabled: bool = False
provider: str = "groq"
model: str = "whisper-large-v3-turbo"
api_key: Optional[str] = None
base_url: Optional[str] = None
timeout: int = 30
| Field | Type | Default | Validator | Description |
|---|---|---|---|---|
enabled |
bool |
False |
-- | Enable voice transcription |
provider |
str |
"groq" |
Must be "groq" or "openai" |
Transcription provider |
model |
str |
"whisper-large-v3-turbo" |
-- | Whisper model identifier |
api_key |
Optional[str] |
None |
Empty string to None |
Provider API key |
base_url |
Optional[str] |
None |
Empty string to None |
Custom API base URL |
timeout |
int |
30 |
-- | Transcription timeout in seconds |
BridgeDefinition¶
Per-bridge security configuration for the gateway.
class BridgeDefinition(BaseModel):
allowed_commands: list[str] = Field(default_factory=list)
allowed_cwd: list[str] = Field(default_factory=list)
| Field | Type | Default | Description |
|---|---|---|---|
allowed_commands |
list[str] |
[] |
Command basenames allowed for this bridge |
allowed_cwd |
list[str] |
[] |
Filesystem paths the bridge can use as working directories |
GatewayConfig¶
Host gateway settings.
class GatewayConfig(BaseModel):
enabled: bool = False
url: Optional[str] = None
token: Optional[str] = None
port: int = 9842
default_timeout: int = 30
bridges: dict[str, BridgeDefinition] = Field(default_factory=dict)
| Field | Type | Default | Validator | Description |
|---|---|---|---|---|
enabled |
bool |
False |
-- | Enable gateway integration |
url |
Optional[str] |
None |
Empty string to None |
Gateway URL (e.g. "http://host.docker.internal:9842") |
token |
Optional[str] |
None |
Empty string to None |
Bearer token for authentication |
port |
int |
9842 |
-- | Port the gateway server listens on |
default_timeout |
int |
30 |
-- | Default subprocess timeout in seconds |
bridges |
dict[str, BridgeDefinition] |
{} |
-- | Per-bridge command and cwd allowlists |
Example config.yaml:
gateway:
enabled: true
url: "http://host.docker.internal:9842"
token: "${GATEWAY_TOKEN}"
port: 9842
default_timeout: 30
bridges:
claude-code:
allowed_commands: [claude]
allowed_cwd: ["~/Projects", "~/Documents"]
apple-notes:
allowed_commands: [memo]
ClaudeCodeConfig¶
Claude Code bridge settings.
class ClaudeCodeConfig(BaseModel):
enabled: bool = False
bridge_url: Optional[str] = None
bridge_token: Optional[str] = None
projects_dir: str = "~/.claude/projects"
permission_mode: Optional[str] = None
timeout: int = 0
claude_path: str = "claude"
state_file: str = "data/cc_user_states.json"
| Field | Type | Default | Validator | Description |
|---|---|---|---|---|
enabled |
bool |
False |
-- | Enable Claude Code bridge |
bridge_url |
Optional[str] |
None |
Empty string to None |
Gateway URL override (falls back to gateway.url) |
bridge_token |
Optional[str] |
None |
Empty string to None |
Auth token override (falls back to gateway.token) |
projects_dir |
str |
"~/.claude/projects" |
-- | Path to Claude Code projects directory |
permission_mode |
Optional[str] |
None |
Empty string to None |
Claude Code --permission-mode flag value |
timeout |
int |
0 |
-- | Command timeout in seconds (0 = no limit) |
claude_path |
str |
"claude" |
-- | Path to claude CLI binary |
state_file |
str |
"data/cc_user_states.json" |
-- | Path for persisting per-user session state |
LoggingConfig¶
Logging settings.
| Field | Type | Default | Validator | Description |
|---|---|---|---|---|
level |
str |
"INFO" |
Must be one of DEBUG, INFO, WARNING, ERROR, CRITICAL; auto-uppercased |
Python logging level |