Setup
How fermix setup configures the daemon on first run and on subsequent reconfiguration, including the browser wizard, terminal wizard, non-interactive flags, and what gets written to FERMIX_HOME.
fermix setup is the one command you run to configure Fermix the first time. It installs and starts the background service (the daemon), then opens the browser setup wizard via a short-lived, single-use /setup?t=... URL at http://127.0.0.1:4030 (default port 4030; override with --port or the PORT environment variable). The browser wizard is the default only when you are running the packaged standalone binary on a host with a display. On a headless host (a machine with no graphical browser, such as a server) or a source build, setup falls back automatically to a terminal prompt sequence; --cli forces that path on any host, and supplying any answer flag (such as --openai-api-key) also runs the terminal path.
What setup does
On first run, fermix setup:
- Installs the OS service unit (the file that tells your operating system how to run Fermix in the background: launchd on macOS, systemd on Linux) and starts the daemon.
- Opens a short-lived one-time
/setup?t=...URL in the default browser (or runs the terminal wizard). - Walks through provider selection, realtime voice, channel onboarding, voice-note transcription, plugin integrations, web search and image-generation (media) backends, sandbox mode (the limits on what files and commands the agent can touch), memory tuning, and personalisation. That is the browser wizard’s full set of groups; the terminal wizard prompts for a narrower set (see answer groups).
- Writes
config.tomland seeds the prompt files and workspace directories underFERMIX_HOME.
Running it again with no arguments is safe and repeatable: the wizard checks what is already answered and only prompts for missing values. It also restores any missing prompt files.
Flags
| Flag | Description |
|---|---|
--web |
Force the browser wizard; cannot be combined with --cli, --terminal, or --no-service. On a headless host it prints an SSH port-forward hint instead of opening a browser |
--cli / --terminal |
Force the terminal wizard even on a graphical host |
--no-service |
Configure without installing or starting the OS service unit |
--no-browser |
Print the setup URL instead of opening it |
--port N |
Port for the web setup page (default 4030) |
--user / --system |
Service scope: per-user (the default) or system-wide |
--rotate-token |
Rotate the durable setup token before minting the launch URL, invalidating any previously issued token |
--print-state |
Print the current readiness report and exit without prompting |
--reconfigure |
Re-run the core prompts even if already answered: provider, model, reasoning effort (how hard the model thinks before answering — asked only for providers that support it), the Codex fast toggle, the realtime enable toggle and its follow-up questions, and the owner user ID of every enabled channel |
--migrate-secrets |
Move any plaintext secrets remaining in config.toml into the OS keyring (your operating system’s secure credential store) |
--import-codex |
Import OpenAI OAuth tokens from an existing Codex CLI install (~/.codex); an interactive setup also offers this automatically when Codex credentials are found and no provider is configured yet |
--skip-probe |
Skip the live provider check that a completed setup normally ends with |
--provider NAME |
Choose the primary provider non-interactively (openai_codex, openai, anthropic, xai, openrouter, mistral, ollama) |
--default-model MODEL |
Set the default model non-interactively |
--reasoning-effort LEVEL |
Set reasoning effort non-interactively (none, low, medium, high, xhigh, max) |
--openai-api-key KEY |
Pass the OpenAI API key non-interactively |
--telegram-bot-token TOKEN |
Pass the Telegram bot token non-interactively |
Every provider secret (--anthropic-api-key, --xai-api-key, --openrouter-api-key, --mistral-api-key, --ollama-base-url) and the per-channel and realtime answers follow the same --<key> <value> pattern. Use these for scripted or container installs where the interactive wizard cannot run; any answer flag switches setup to the terminal path.
What gets written
Setup writes to FERMIX_HOME (default ~/.fermix). Override the location with the FERMIX_HOME environment variable before running setup.
| Path | Purpose |
|---|---|
$FERMIX_HOME/config.toml |
Typed snapshot of all wizard answers |
$FERMIX_HOME/auth.json |
OAuth token store for all providers and plugins |
$FERMIX_HOME/setup-token |
Durable local secret protecting the web setup page (never appears in URLs) |
$FERMIX_HOME/memory.db |
Durable memory database |
$FERMIX_HOME/daemon.sock |
Control socket for the CLI |
$FERMIX_HOME/realtime.sock |
Realtime voice socket |
$FERMIX_HOME/workspace/ |
Default sandbox workspace root |
$FERMIX_HOME/bootstrap/ |
Seeded prompt files (IDENTITY, FERMIX, SOUL, REALTIME) |
$FERMIX_HOME/memory/ |
Seeded memory files (USER.md, MEMORY.md) |
$FERMIX_HOME/skills/ |
Local skill directory |
$FERMIX_HOME/plugins/ |
Installed plugin store |
$FERMIX_HOME/browser/ |
Browser profile for the browser tool |
$FERMIX_HOME/journals/ |
Journal storage |
$FERMIX_HOME/realtime/ |
Realtime voice session data |
$FERMIX_HOME/traces/ |
Structured JSONL trace output |
$FERMIX_HOME/logs/ |
Rotating daemon log |
$FERMIX_HOME/grants/ |
Persisted sandbox path grants |
Answer groups
The wizard collects answers across these groups. All answers are persisted to config.toml; secrets are handed off to the OS keyring (see auth and secrets).
The browser wizard has a tab for every group. The terminal wizard prompts only for Provider, Realtime, Channels, Compaction, Memory, and Personalisation. It can also set Transcription and Media, but only from answer flags (--transcription-backend, --transcription-model, --transcription-api-key, --image-backend, --image-model, --google-api-key); there are no web-search, plugin, or sandbox flags, so those three groups are configured from the browser wizard or by editing config.toml.
| Group | Keys |
|---|---|
| Provider | Provider selection, default_model, reasoning_effort, and the provider’s api_key (e.g. openai_api_key). The first provider you configure becomes the primary automatically; after that, saving another provider’s settings adds it as a fallback — promoting it is a separate, explicit “Set primary” action (or the --provider answer) |
| Realtime | realtime_enabled, realtime_api_key, realtime_voice, realtime_max_session_minutes, realtime_max_cost_cents, realtime_persist_transcripts, plus two answers only the web wizard sets (they have no CLI flag): realtime_model (gpt-realtime-2.1-mini, gpt-realtime-2.1, gpt-realtime-2) and realtime_reasoning_effort (minimal, low, medium, high, xhigh — the realtime vocabulary has no none or max; default low) |
| Channels | Per-channel bot_token, signing_secret, owner_user_id, app_secret, and related fields |
| Transcription | transcription_backend (openai/xai/deepgram), transcription_model (the model list is per-backend; switching backend snaps the model to that backend’s default — the SpaceXAI (xai) backend is modelless and carries no model), and transcription_api_key (stored under the selected backend’s key slot). OpenAI and SpaceXAI reuse the chat-provider key when no transcription key is set, but only where that provider is itself configured with an API key — a SpaceXAI Grok subscription/OAuth token is not accepted for speech-to-text; Deepgram always needs its own key. Also settable non-interactively with --transcription-backend, --transcription-model, and --transcription-api-key |
| Plugins | Integration install and auth (OAuth connect or static api_key); managed from the web Plugins page or the fermix plugins CLI rather than typed answer keys. The Plugins page also hosts the Computer Use card (experimental, off by default; see tool reference) |
| Search | web_search_backend plus the chosen backend’s key (brave_api_key, exa_api_key, tavily_api_key, parallel_api_key, perplexity_api_key, firecrawl_api_key); the default DuckDuckGo backend needs no key |
| Media | image_backend, image_model, and the image API key (google_api_key for the Google backend; OpenAI and xAI reuse the chat provider key). image_backend also accepts openai_codex (“OpenAI Codex (ChatGPT)”), which runs on a connected ChatGPT/Codex login instead of an image API key — billed to that subscription. It is opt-in and fails loudly if the login is missing or not entitled; it never silently falls back to another backend |
| Sandbox | sandbox_mode (strict/standard/open), the command profile (bare/assistant/extended), and the environment-variable passthrough allowlist |
| Compaction (summarizing old messages to free up space when a conversation gets long) | compaction_threshold |
| Memory (how often background memory review runs) | review_interval_hours (blank keeps the 24-hour default) |
| Personalisation | bot_name (the assistant’s own name — persists to [fermix_core.agent].name, the source of truth that seeds IDENTITY.md; blank keeps the current name fermix), user_name, timezone, communication_style |
Config precedence
Runtime configuration resolves in this order, later entries winning:
- Compile-time defaults (
config/config.exs) - Persisted setup state (
config.toml) - Environment variable overrides applied at boot (
config/runtime.exs)
See configuration for the full config.toml reference.
Secret storage
Secrets in config.toml are stored as the placeholder value @keyring (a marker that means “the real value lives in the keyring, not in this file”). When saving, the wizard auto-stores plaintext secrets to the OS keyring when a writer is available (macOS security, or the Linux Secret Service via secret-tool; account fermix, service fermix:<ENV>). Without a writer, unchanged plaintext is kept with a warning and only new secrets fail.
The optional [fermix_core] profile key (default general) namespaces keyring entries so two installs on the same host do not overwrite each other’s secrets. Set it before running fermix setup: secrets are written under the profile in effect at save time, and changing the profile on a populated install orphans the old entries.
If a key is still plaintext after initial setup, the wizard prints a warning. Run fermix setup --migrate-secrets to move it to the keyring.
See auth and secrets for the full keyring configuration.
Boot report
After saving, setup checks whether a daemon restart is required for the changes to take effect. A provider change, for example, requires a restart because the agent reads those settings once at startup. How the restart happens depends on which wizard you used:
- Web wizard: when a saved change needs a restart, an “Apply & restart” button appears on the save notice and on the Doctor tab. Clicking it restarts the daemon from the page.
- Terminal wizard: once setup is complete, it finishes by installing (or reconciling) and restarting the OS service itself, printing
Fermix is running (user service).— no separate restart step is needed. If service activation is skipped (--no-service, or a non-packaged build), it prints the manual steps instead.
To restart the daemon manually at any time, run fermix restart.
When setup is complete, the terminal wizard also ends with a live check against the chosen provider (auth probe: <provider>/<model> responded in Nms), so a bad key or rejected token surfaces immediately rather than on your first message. --skip-probe skips it. If a Codex OAuth token is rejected, setup offers to re-run the ChatGPT login on the spot.
Web wizard
The wizard runs as a web form at http://127.0.0.1:4030. It uses the same answer keys and the same validation logic as the terminal wizard. The setup page is protected so only a local session can open it: the fermix setup command is the only thing that mints the short-lived, single-use /setup?t=... launch URL (valid for 15 minutes, consumed on first open). The status dashboard links to a bare /setup, which is refused without a valid token, so a visitor to the dashboard cannot open the wizard — even on a network-exposed daemon. The long-lived setup token is never placed in a URL. Use the web wizard for initial setup when a browser is available, or return to it later to update specific groups.
The wizard is organized into tabs: Provider, Realtime, Channels, Transcription, Plugins, Search, Media, Sandbox, Memory, Personalization, and Doctor.
The Provider tab renders one card per provider (Primary, Fallback, or Not configured). Picking a card loads that provider into the configuration form. Saving configures that provider: the first provider you configure becomes primary automatically; after that, a newly saved provider joins the fallback chain, and a configured non-primary card shows a “Set primary” button that flips the primary flag without re-entering credentials. Each provider offers an OAuth-vs-api_key picker where both are supported (xAI and Anthropic). A provider connected via OAuth whose stored token has gone stale (for example after long disuse) shows a “Reconnect needed” badge instead of “Connected”. The primary provider’s pane also carries a Sub-agent model dropdown — the model delegated sub-agent workers run on, defaulting to “Same as main model”. It lists only the primary provider’s models (sub-agents run on the primary provider unless subagent_provider is set in [fermix_core.routing]); a leftover pin from a different provider shows as “Same as main model” and self-heals on the next save. Provider changes require a daemon restart to take effect.
The Plugins tab mirrors the plugin catalog (install, enable, and connect integrations — see plugins) and also hosts the Computer Use card. Computer use is experimental and off by default: enabling it downloads the native computer-use helper (a checksum-verified binary; Apple Silicon Macs and Linux x86_64 only) and flips the feature flag, which applies on the next daemon restart.
The Doctor tab runs final checks: readiness, provider and channel probes, an “Auth tokens” line that flags stored OAuth tokens needing reconnection (Reconnect needed: <names>), and a Computer use section that probes the helper’s Screen Recording and input-control permissions — on macOS, a Grant macOS permissions button appears when a grant is missing, raising the system prompts up front instead of on the first screenshot.
Reconfiguring
To revisit provider and model choices after initial setup:
fermix setup --reconfigure
For non-interactive reconfiguration, combine --reconfigure with inline flags:
fermix setup --reconfigure --openai-api-key sk-...
The terminal wizard restarts the OS service itself when it finishes, so reconfigured values normally apply immediately. If you need to restart manually (for example after editing config.toml by hand), run:
fermix restart
Headless and container installs
On hosts with no browser, setup detects the headless environment and runs the terminal wizard automatically. To use the web wizard from a headless host anyway (for example a server you reach over SSH), pass --web: setup starts the service, prints the launch URL, and shows an SSH port-forward hint (ssh -L 4030:127.0.0.1:4030 user@host) so you can open the page from your own machine.
To suppress interactive prompts entirely, supply all required values as flags:
fermix setup --cli --no-browser \
--openai-api-key "$OPENAI_API_KEY" \
--telegram-bot-token "$TELEGRAM_BOT_TOKEN"
For container deployments that inject secrets through environment variables, skip the wizard entirely and rely on runtime env overrides (see the environment variable table in configuration).
Idempotency
fermix setup with no flags is safe to run at any time. It seeds only what is missing and does not overwrite answers already in config.toml. After a package-manager upgrade (brew upgrade fermix), re-running fermix setup reconciles the OS service unit if the new binary would write a different one, so the running daemon picks up path or template changes without a manual fermix service install.
Related pages
- Installation: Homebrew and source-build instructions.
- Configuration: Full
config.tomlkey reference and environment variables. - Auth and secrets: Keyring integration,
@keyringsentinel, and secret migration. - Channels: Per-channel token and owner configuration.
- Providers and models: Provider selection, fallback chains, and model pinning.