# Configuration Moltis uses a **layered config model** with two files: | File | Owner | Purpose | |------|-------|---------| | `defaults.toml` | **Moltis** | Shipped defaults, regenerated on every startup | | `moltis.toml` | **You** | Your overrides only | On first run, both files are created in `~/.config/moltis/`. Your `moltis.toml` starts nearly empty — only the installation-specific port is set. All other settings inherit from `defaults.toml` automatically. ## Merge Order Settings are resolved in this order (later wins): 1. **Built-in defaults** — compiled into Moltis (`MoltisConfig::default()`) 2. **`defaults.toml`** — Moltis-managed, refreshed on every startup 3. **`moltis.toml`** — your overrides (additive deep merge) 4. **`MOLTIS_*` environment variables** — highest precedence This means you only need to put values in `moltis.toml` that you intentionally want to differ from the shipped defaults. When Moltis upgrades and improves a default, your installation picks it up automatically — unless you've overridden that specific setting. ```admonish tip title="Don't copy defaults into moltis.toml" Copying a built-in default into `moltis.toml` "freezes" it — future built-in improvements for that setting won't apply. The Settings UI shows **Built-in**, **Overridden**, and **Custom** badges so you can see which values are yours and which are inherited. ``` ## Configuration File Location | Platform | Default Path | |----------|--------------| | macOS/Linux | `~/.config/moltis/moltis.toml` | | Custom | Set via `--config-dir` or `MOLTIS_CONFIG_DIR` | The `defaults.toml` file lives in the same directory. Do not edit it — your changes will be overwritten on the next startup. ## Checking Config `moltis config check` validates your override file (`moltis.toml`) against the known config schema. It also checks that Moltis-managed `defaults.toml` exists and can be parsed, but it does not treat `defaults.toml` as user-authored input. New config fields should be added to the Rust config schema and its `Default` implementation. Moltis regenerates `defaults.toml` from those built-in defaults on startup, while `moltis.toml` should contain only values you intentionally override. ## Agent-Readable Docs Moltis packages the documentation as local markdown files when the install format supports external share files, such as `.deb`, `.rpm`, Homebrew, and similar system packages. Agents are pointed at those local files through the system prompt so they can read setup, configuration, channel, and troubleshooting docs without needing web access. Resolution order is `MOLTIS_DOCS_DIR`, the packaged share docs directory (`/docs`), the source checkout docs in development, then an embedded fallback copied to `~/.moltis/docs/moltis/`. Moltis also writes a generated `config-template.md` under `~/.moltis/docs/moltis/` for the current server port and points agents at it separately. ## Basic Settings ```toml [server] port = 13131 # HTTP/WebSocket port bind = "0.0.0.0" # Listen address [identity] name = "Moltis" # Agent display name [tools] agent_timeout_secs = 600 # Agent run timeout (seconds, 0 = no timeout) agent_max_iterations = 25 # Max tool call iterations per run ``` ## LLM Providers Configure providers through the web UI or directly in `moltis.toml`. API keys can be set via environment variables (e.g. `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`) or in the config file. ```toml [providers] offered = ["anthropic", "openai", "gemini"] [providers.anthropic] enabled = true [providers.openai] enabled = true models = ["gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna"] stream_transport = "sse" # "sse", "websocket", or "auto" [providers.gemini] enabled = true models = ["gemini-2.5-flash", "gemini-2.5-pro"] [providers.local-llm] enabled = true models = ["qwen2.5-coder-7b-q4_k_m"] [chat] priority_models = ["gpt-5.6-sol"] ``` See [Providers](providers.md) for the full list of supported providers and configuration options. ## Remote Execution Command execution can stay local, route to a paired node, or use SSH: ```toml [tools.exec] host = "local" # "local", "node", or "ssh" # node = "mac-mini" # default paired node when host = "node" # ssh_target = "deploy@box" # default SSH target when host = "ssh" ``` When `host = "ssh"`, Moltis can work in two modes: - **System OpenSSH**: reuse your existing host aliases, agent forwarding policy, and `~/.ssh/config`. - **Managed targets**: create or import a deploy key in **Settings → SSH**, then bind that key to a named target. Moltis stores the private key in its credential store and encrypts it with the vault whenever the vault is unsealed. Imported keys may be passphrase-protected, Moltis strips the passphrase during import so runtime execution can stay non-interactive. For stricter SSH verification, managed targets also accept a pasted `known_hosts` line from `ssh-keyscan -H host`. The SSH settings page can scan that for you, and saved targets can refresh or clear their stored pin later. When present, Moltis uses that pin instead of your global OpenSSH known-host policy for that target. Managed targets appear in the Nodes page and chat node picker, so users can see where `exec` will run without digging through config. If multiple managed targets exist, the default one is used when `tools.exec.host = "ssh"` and no session-specific route is selected. `moltis doctor` also reports remote-exec inventory, active backend mode, and obvious SSH setup problems from the CLI. `Settings -> Tools` shows the effective tool inventory for the active session and model, including tool-calling support, MCP server state, skills/plugins, and available execution routes. It is session-aware by design, switching the model or disabling MCP for a session changes what appears there. ## Sandbox Configuration Commands run inside isolated containers for security: ```toml [tools.exec.sandbox] mode = "all" # "off", "non-main", or "all" scope = "session" # "command", "session", or "global" workspace_mount = "ro" # "ro", "rw", or "none" # host_data_dir = "/host/path/data" # Optional override if auto-detection cannot resolve the host path home_persistence = "shared" # "off", "session", or "shared" (default: "shared") # shared_home_dir = "/path/to/shared-home" # Optional path for shared mode backend = "auto" # "auto", "docker", or "apple-container" no_network = true # Packages installed in the sandbox image packages = [ "curl", "git", "jq", "tmux", "python3", "python3-pip", "nodejs", "npm", "golang-go", ] ``` If Moltis runs inside Docker and also mounts the host container socket (`/var/run/docker.sock`), Moltis now auto-detects the host path backing `/home/moltis/.moltis` from the parent container's mount table. If that inspection cannot resolve the correct path, set `host_data_dir` explicitly. ```admonish info When you modify the packages list and restart, Moltis automatically rebuilds the sandbox image with a new tag. ``` ## Web Search Configure the built-in `web_search` tool: ```toml [tools.web.search] enabled = true provider = "brave" # "brave" or "perplexity" max_results = 5 # 1-10 timeout_seconds = 30 cache_ttl_minutes = 15 duckduckgo_fallback = false # Default: do not use DuckDuckGo fallback # api_key = "..." # Brave key, or use BRAVE_API_KEY [tools.web.search.perplexity] # api_key = "..." # Or use PERPLEXITY_API_KEY / OPENROUTER_API_KEY # base_url = "..." # Optional override # model = "perplexity/sonar-pro" # Optional override ``` If no search API key is configured: - with `duckduckgo_fallback = false` (default), Moltis returns a clear hint to set `BRAVE_API_KEY` or `PERPLEXITY_API_KEY` - with `duckduckgo_fallback = true`, Moltis attempts DuckDuckGo HTML search, which may hit CAPTCHA/rate limits ## Skills Configure skill discovery and agent-managed personal skills: ```toml [skills] enabled = true auto_load = ["commit"] enable_agent_sidecar_files = false # Opt-in: allow agents to write sidecar text files in personal skills enable_self_improvement = true # System prompt guidance for autonomous skill creation/update ``` `enable_agent_sidecar_files` is disabled by default. When enabled, Moltis registers the `write_skill_files` tool so agents can write supplementary files such as `script.sh`, `Dockerfile`, templates, or `_meta.json` inside `/skills//`. Writes stay confined to that personal skill directory, reject path traversal and symlink escapes, and are recorded in `~/.moltis/logs/security-audit.jsonl`. `enable_self_improvement` (default: true) injects system prompt guidance that encourages the agent to proactively create and update skills after complex tasks (5+ tool calls), tricky error fixes, or non-obvious workflows. The `patch_skill` tool allows surgical find/replace updates without rewriting the entire skill body. ## Default Reasoning Set a default reasoning/thinking effort for model-less and new main sessions: ```toml [chat] reasoning_default = "high" ``` Accepted values are `minimal`, `low`, `medium`, `high`, `xhigh`, and `max`. `extra-high` is also accepted and is saved as the canonical `xhigh` value. `max` is a distinct level above Extra High, not an alias for `xhigh`. Omit `chat.reasoning_default` to keep Off (the existing behavior); `off` is not a config value. An explicit session choice, either Off or a reasoning level, always takes precedence over this default. Support for reasoning and individual levels depends on the selected model and provider. ## Chat Message Queue When a new message arrives while an agent run is already active, Moltis can either replay queued messages one-by-one or merge them into a single follow-up message. ```toml [chat] message_queue_mode = "followup" # Default: one-by-one replay prompt_memory_mode = "live-reload" # Options: # "followup" - Queue each message and run them sequentially # "collect" - Merge queued text and run once after the active run # "live-reload" - Re-read MEMORY.md before each turn # "frozen-at-session-start" - Keep the first MEMORY.md snapshot for the session ``` ## Memory System Long-term memory uses embeddings for semantic search: ```toml [memory] style = "hybrid" # Or "prompt-only", "search-only", "off" agent_write_mode = "hybrid" # Or "prompt-only", "search-only", "off" user_profile_write_mode = "explicit-and-auto" # Or "explicit-only", "off" backend = "builtin" # Or "qmd" provider = "openai" # Or "local", "ollama", "custom" model = "text-embedding-3-small" citations = "auto" # "on", "off", or "auto" llm_reranking = false search_merge_strategy = "rrf" # Or "linear" session_export = "on-new-or-reset" # Or "off" ``` See [Memory Surfaces](memory-surfaces.md) for the boundary between `session_state`, prompt memory, searchable memory, and sandbox persistence. `memory.style` chooses the high-level behavior, while `chat.prompt_memory_mode` only affects prompt-visible `MEMORY.md`. `memory.agent_write_mode` controls where agent-authored writes are allowed to land. `memory.user_profile_write_mode` controls whether Moltis writes the managed `USER.md` surface, and whether browser/channel timezone or location signals may update it silently. `memory.session_export` controls whether session rollover exports are written at all. ## Authentication Authentication is **only required when accessing Moltis from a non-localhost address**. When running on `localhost` or `127.0.0.1`, no authentication is needed by default. When you access Moltis from a network address (e.g., `http://192.168.1.100:13131`), a one-time setup code is printed to the terminal. Use it to set up a password or passkey. ```toml [auth] disabled = false # Set true to disable auth entirely ``` ```admonish warning Only set `disabled = true` if Moltis is running on a trusted private network. Never expose an unauthenticated instance to the internet. ``` ## Hooks Configure lifecycle hooks: ```toml [hooks] [[hooks.hooks]] name = "my-hook" command = "./hooks/my-hook.sh" events = ["BeforeToolCall", "AfterToolCall"] timeout = 5 # Timeout in seconds [hooks.hooks.env] MY_VAR = "value" # Environment variables for the hook ``` See [Hooks](hooks.md) for the full hook system documentation. ## MCP Servers Connect to Model Context Protocol servers: ```toml [mcp] request_timeout_secs = 30 # Default timeout for MCP requests (seconds) [mcp.servers.filesystem] command = "npx" args = ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed"] request_timeout_secs = 90 # Optional override for this server [mcp.servers.github] command = "npx" args = ["-y", "@modelcontextprotocol/server-github"] env = { GITHUB_TOKEN = "ghp_..." } [mcp.servers.remote_api] transport = "sse" url = "https://mcp.example.com/mcp?api_key=$REMOTE_MCP_KEY" headers = { Authorization = "Bearer ${REMOTE_MCP_TOKEN}" } [mcp.servers.remote_http] transport = "streamable-http" url = "https://mcp.example.com/mcp" headers = { Authorization = "Bearer ${API_KEY}" } ``` Remote MCP URLs and headers support `$NAME` or `${NAME}` placeholders. For live remote servers, values resolve from Moltis-managed env overrides, either `[env]` in config or **Settings** → **Environment Variables**. ## Telegram Integration ```toml [channels.telegram.my-bot] token = "123456:ABC..." dm_policy = "allowlist" allowlist = ["123456789"] # Telegram user IDs or usernames (strings) ``` See [Telegram](telegram.md) for full configuration reference and setup instructions. ## Discord Integration ```toml [channels] offered = ["telegram", "discord"] [channels.discord.my-bot] token = "MTIzNDU2Nzg5.example.bot-token" dm_policy = "allowlist" mention_mode = "mention" allowlist = ["your_username"] ``` See [Discord](discord.md) for full configuration reference and setup instructions. ## Slack Integration ```toml [channels] offered = ["slack"] [channels.slack.my-bot] bot_token = "xoxb-..." app_token = "xapp-..." # Optional. Defaults to Slack; set only for Slack-compatible proxies/gateways. api_base_url = "https://slack.com/api" dm_policy = "allowlist" allowlist = ["U123456789"] ``` See [Slack](slack.md) for full configuration reference and setup instructions. ## TLS / HTTPS ```toml [tls] enabled = true cert_path = "~/.config/moltis/cert.pem" key_path = "~/.config/moltis/key.pem" # If custom paths are not set and auto_generate is true, Moltis generates a # local CA and server certificate for localhost/private-network names. Public # VPS IP access should set public_ip; public domains should use a reverse proxy # or custom CA-issued certificates. # public_ip = "203.0.113.10" # Port for the plain-HTTP redirect / CA-download server. # Defaults to the server port + 1 when not set. # http_redirect_port = 13132 # Serve plain HTTP when bound to a loopback address (127.0.0.1, ::1, # localhost). New installs write `true`; configs without the key keep HTTPS. loopback_http = true ``` Override via environment variable: `MOLTIS_TLS__HTTP_REDIRECT_PORT=8080`. ### Loopback over plain HTTP With `loopback_http = true`, a gateway bound to loopback serves `http://localhost:`. Browsers treat that origin as a secure context: passkeys, service workers and `Secure` cookies all work, and there is no certificate to trust. Any non-loopback bind, such as `0.0.0.0` or a LAN IP, still uses HTTPS. Set `loopback_http = false` to keep HTTPS on localhost, for example if you already rely on `https://localhost` bookmarks or passkeys. ### Trusting the local CA When TLS is active with auto-generated certificates and Moltis runs from a terminal on your desktop, it asks once whether to trust its local CA: - **macOS:** the login keychain, which shows a password dialog. - **Linux:** the system store via `sudo update-ca-certificates`. - **Windows:** the user root store. - **Firefox and Chromium:** their NSS databases, when NSS `certutil` is installed. Moltis remembers your answer for that CA in `certs/ca-trust.txt`. Run `moltis trust-ca` at any time to install the CA manually. The CA carries X.509 name constraints that limit it to `localhost`, `*.localhost`, `.local`, loopback, private (RFC 1918), CGNAT and link-local addresses, plus any extra names the server certificate needs, such as `public_ip` or the machine's hostname. A leaked CA key therefore cannot be used to impersonate public websites. The CA is valid for 10 years and is kept when the server certificate renews. A new CA is generated only when the certificate needs a name outside its scope; you then need to trust it again. CA and server private keys are stored with owner-only permissions. ## Opening the Browser on Start ```toml [server] open_browser = "first-run" # "first-run" | "always" | "never" ``` - `first-run` (default) opens the web UI until onboarding is finished. - `always` opens it on every start. - `never` never opens a browser. A browser is opened only when Moltis runs in an interactive terminal on a desktop session: never over SSH, inside a container, in CI, or under a service manager. On Linux, a `DISPLAY` or `WAYLAND_DISPLAY` is also required. The `--open-browser` and `--no-open-browser` flags override this setting for a single run. The `BROWSER` environment variable selects which browser to use. ## Tailscale Integration Expose Moltis over your Tailscale network: ```toml [tailscale] mode = "serve" # "off", "serve", or "funnel" reset_on_exit = true ``` ## Observability ```toml [metrics] enabled = true prometheus_endpoint = true ``` ## Process Environment Variables (`[env]`) The `[env]` section injects variables into the Moltis process at startup. This is useful in Docker deployments where passing individual `-e` flags is inconvenient, or when you want API keys stored in the config file rather than the host environment. ```toml [env] BRAVE_API_KEY = "your-brave-key" OPENROUTER_API_KEY = "sk-or-..." ELEVENLABS_API_KEY = "..." ``` **Precedence**: existing process environment variables are never overwritten. If `BRAVE_API_KEY` is already set via `docker -e` or the host shell, the `[env]` value is skipped. This means `docker -e` always wins. ```admonish info title="Settings UI vs [env]" Environment variables configured through the Settings UI (Settings > Environment) are also injected into the Moltis process at startup. Precedence: host/`docker -e` > config `[env]` > Settings UI. ``` ## Environment Variables All settings can be overridden via environment variables: | Variable | Description | |----------|-------------| | `MOLTIS_CONFIG_DIR` | Configuration directory | | `MOLTIS_DATA_DIR` | Data directory | | `MOLTIS_SERVER__PORT` | Server port override | | `MOLTIS_SERVER__BIND` | Server bind address override | | `MOLTIS_TOOLS__AGENT_TIMEOUT_SECS` | Agent run timeout override | | `MOLTIS_TOOLS__AGENT_MAX_ITERATIONS` | Agent loop iteration cap override | `MOLTIS_FILES_DIR` is different from these startup overrides: Moltis supplies it to local command agents and `exec` as the resolved [Managed Files](managed-files.md) path. Use it instead of assuming `/files`. ## CLI Flags ```bash moltis --config-dir /path/to/config --data-dir /path/to/data ``` ## Complete Example ```toml [server] port = 13131 bind = "0.0.0.0" [identity] name = "Atlas" [tools] agent_timeout_secs = 600 agent_max_iterations = 25 [providers] offered = ["anthropic", "openai", "gemini"] [tools.exec.sandbox] mode = "all" scope = "session" workspace_mount = "ro" home_persistence = "session" # shared_home_dir = "/path/to/shared-home" backend = "auto" no_network = true packages = ["curl", "git", "jq", "python3", "nodejs", "golang-go"] [memory] backend = "builtin" provider = "openai" model = "text-embedding-3-small" [auth] disabled = false [hooks] [[hooks.hooks]] name = "audit-log" command = "./hooks/audit.sh" events = ["BeforeToolCall"] timeout = 5 ```