aidaemon 0.9.13

A personal AI agent that runs as a background daemon, accessible via Telegram, Slack, or Discord, with tool use, MCP integration, and persistent memory
Documentation
# aidaemon configuration
#
# Secrets resolution order:
#   1. "keychain"    → reads from OS credential store (macOS Keychain, etc.)
#   2. "${ENV_VAR}"  → reads from environment variable (for Docker/CI)
#   3. "plain-value" → used as-is (not recommended for production)
#
# The setup wizard stores secrets in the OS keychain automatically.
# Set AIDAEMON_NO_KEYCHAIN=1 to use env-file-backed secrets instead of OS keychain.
# Optional: set AIDAEMON_ENV_FILE=/absolute/path/.env to choose the env file path.
# In no-keychain mode, secret updates (including OAuth token refresh rotation) are written to that env file.

[provider]
# Provider type: openai_compatible, google_genai, or anthropic
api_key = "keychain"
# api_key = "${AIDAEMON_API_KEY}"
base_url = "https://openrouter.ai/api/v1"
# Optional: Cloudflare AI Gateway authenticated mode
# gateway_token = "keychain"
# # gateway_token = "${AIDAEMON_GATEWAY_TOKEN}"
#
# Moonshot OpenAI-compatible base URL:
# base_url = "https://api.moonshot.ai/v1"
#
# MiniMax OpenAI-compatible base URL:
# base_url = "https://api.minimax.io/v1"
#
# Cloudflare AI Gateway base URL format:
# base_url = "https://gateway.ai.cloudflare.com/v1/<ACCOUNT_ID>/<GATEWAY_ID>/compat"

[provider.models]
primary = "openai/gpt-4o"
fast = "openai/gpt-4o-mini"
smart = "anthropic/claude-sonnet-4"

[telegram]
bot_token = "keychain"
# bot_token = "${TELOXIDE_TOKEN}"
allowed_user_ids = [123456789]
# Optional webhook mode for lower delivery latency in production.
# Long polling remains the default unless explicitly enabled.
# Multi-bot note: if multiple bots enable webhooks on one aidaemon instance,
# each bot needs a unique `listen_addr` (port).
# [telegram.webhook]
# enabled = false
# public_url = "https://bot.example.com"
# listen_addr = "0.0.0.0:8443"
# # Optional custom path (defaults to "/telegram/{bot_username}").
# # path = "/telegram"
# # Optional 1..100, Telegram defaults to 40.
# # max_connections = 40
# # Optional: clear queued Telegram updates when setting the webhook.
# # drop_pending_updates = false

# Global webhook defaults for ALL Telegram bots (config-based and dynamic).
# When enabled, any bot without an explicit [webhook] section with enabled = true
# will auto-derive webhook settings from these defaults at startup.
# Per-bot [telegram.webhook] with enabled = true always takes precedence.
# [telegram_webhook_defaults]
# enabled = false
# base_domain = "bots.example.com"   # Each bot gets <slug>.bots.example.com
# port_start = 8443                  # First auto-assigned port; increments for each bot
# max_connections = 40               # Telegram max_connections (1..100)
# drop_pending_updates = false       # Clear queued updates when setting webhook
# bind_local_only = true             # true → 127.0.0.1, false → 0.0.0.0

[state]
db_path = "aidaemon.db"
working_memory_cap = 50
# consolidation_interval_hours = 6  # How often to run memory consolidation (extract durable facts from conversations)
# encryption_key = "keychain"       # Optional override; default startup uses AIDAEMON_ENCRYPTION_KEY from .env
# encryption_key = "${AIDAEMON_ENCRYPTION_KEY}"

[terminal]
# Set to ["*"] to allow all commands (only if you trust the LLM fully)
allowed_prefixes = ["ls", "cat", "head", "tail", "echo", "date", "whoami", "pwd", "find", "wc", "grep", "tree", "file", "stat", "uname", "df", "du", "ps", "which", "env", "printenv"]
# Telegram /terminal Mini App URL (must be HTTPS).
# Runtime override: AIDAEMON_TERMINAL_WEB_APP_URL
web_app_url = "https://terminal.aidaemon.ai"
# Enable local terminal bridge websocket worker.
# Runtime override: AIDAEMON_TERMINAL_BRIDGE_ENABLED
bridge_enabled = true
# Rust bridge endpoint for local daemon <-> broker websocket (must be WSS).
# Runtime override: AIDAEMON_TERMINAL_BROKER_URL
daemon_ws_url = "wss://terminal.aidaemon.ai/v1/ws/daemon"
# Optional static daemon connector token.
# If unset, aidaemon auto-mints short-lived connector tokens using your Telegram bot secret proof.
# Runtime override: AIDAEMON_TERMINAL_DAEMON_TOKEN
# daemon_connect_token = "keychain"
# Optional insecure fallback: if true, static daemon_connect_token is used when secure minting fails.
# Default false (recommended). Runtime override: AIDAEMON_TERMINAL_ALLOW_STATIC_FALLBACK
# allow_static_token_fallback = false
# Optional explicit Telegram user ID; defaults to first telegram owner.
# Runtime override: AIDAEMON_TERMINAL_USER_ID
# daemon_user_id = 123456789
# Optional overrides for bridge device id / shell.
# daemon_device_id = "macbook-pro"
# daemon_shell = "/bin/zsh"

# Optional path alias roots for relative "projects/..." requests.
# Precedence for scoped path resolution:
# 1) explicit absolute/anchored paths
# 2) existing relative paths in current working directory
# 3) alias roots below
# [path_aliases]
# projects = ["~/projects"]

[daemon]
health_port = 8080

# [daemon.queue_policy]
# # Capacity (bounded channels).
# approval_capacity = 16
# media_capacity = 16
# trigger_event_capacity = 64
#
# # Depth thresholds as queue fill ratios (0.0-1.0).
# warning_ratio = 0.75
# overload_ratio = 0.90
#
# # Overload handling.
# # Lane-specific overload and fairness settings.
# [daemon.queue_policy.lanes.approval]
# adaptive_shedding = true
# fair_sessions = true
# fair_session_window_secs = 60
# fair_max_events_per_session = 4
#
# [daemon.queue_policy.lanes.media]
# adaptive_shedding = true
# fair_sessions = true
# fair_session_window_secs = 60
# fair_max_events_per_session = 4
#
# [daemon.queue_policy.lanes.trigger]
# adaptive_shedding = true
# fair_sessions = true
# fair_session_window_secs = 60
# fair_max_events_per_session = 4
#
# # Legacy shared knobs (still accepted; applied to all lanes when lane settings are default).
# # adaptive_shedding = true
# # fair_trigger_sessions = true
# # fair_trigger_session_window_secs = 60
# # fair_trigger_max_events_per_session = 4

# [skills]
# enabled = true
# dir = "skills"    # relative to config.toml location

# [browser]
# enabled = true
# headless = true
# screenshot_width = 1280
# screenshot_height = 720
# # Use an existing Chrome profile to inherit cookies/sessions (e.g. Cloudflare, GitHub, AWS)
# user_data_dir = "~/Library/Application Support/Google/Chrome"
# profile = "Default"    # or "Profile 1", "Profile 2", etc.

# [triggers.email]
# host = "imap.gmail.com"
# port = 993
# username = "you@gmail.com"
# password = "keychain"
# # password = "${AIDAEMON_EMAIL_PASSWORD}"
# folder = "INBOX"

# [search]
# backend = "brave"
# api_key = "keychain"
# # api_key = "${AIDAEMON_SEARCH_API_KEY}"

# [subagents]
# enabled = true
# max_depth = 3            # max nesting levels for sub-agents
# max_iterations = 10      # agentic loop iterations per sub-agent
# max_response_chars = 8000
# timeout_secs = 300       # 5 minute timeout per sub-agent

# [cli_agents]
# enabled = true
# timeout_secs = 600           # default timeout per invocation
# max_output_chars = 16000     # max output before truncation
# # If cli_agent action=run omits "tool", aidaemon auto-picks:
# # claude -> gemini -> codex -> copilot -> aider (first installed)
#
# # Pre-configured tools (auto-discovered on startup via `which`)
# # Override or add your own:
# [cli_agents.tools.claude]
# command = "claude"
# args = ["-p", "--output-format", "json"]
#
# [cli_agents.tools.gemini]
# command = "gemini"
# args = ["--sandbox=false", "--yolo", "--output-format", "json"]
#
# [cli_agents.tools.codex]
# command = "codex"
# args = ["exec", "--json", "--dangerously-bypass-approvals-and-sandbox"]

# [mcp.filesystem]
# command = "npx"
# args = ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]

# [policy]
# All policy features are enabled by default. Uncomment to override.
# policy_shadow_mode = true          # log policy shadow comparisons and rollout diagnostics
# policy_enforce = true              # enforce policy context budget cap (vs model max only)
# tool_filter_enforce = true         # risk-based tool filtering
# uncertainty_clarify_enforce = true  # ask for clarification on ambiguous requests
# context_refresh_enforce = true      # mid-loop context budget refresh
# learning_evidence_gate_enforce = true  # stricter evidence thresholds for auto-learning
# autotune_shadow = true             # log auto-tune adjustments
# autotune_enforce = true            # apply auto-tune adjustments
# uncertainty_clarify_threshold = 0.55
#
# [policy.write_consistency]
# # Guardrail thresholds for dual-write drift checks.
# max_abs_global_delta = 3
# max_session_mismatch_count = 0
# max_stale_task_starts = 0
# max_missing_message_id_events = 0

[diagnostics]
enabled = true
record_decision_points = true
max_events = 200
include_raw_tool_args = false