# Setup Wizard Design **Date:** 2026-02-10 **Status:** Draft ## Overview Interactive setup wizard for Flynn. Two entry points: 1. **Auto-trigger** — `flynn start` detects no config, offers to run the wizard 2. **Explicit** — `flynn setup` command, re-runnable for reconfiguration Philosophy: minimal-first to get running fast, then menu-driven for advanced config. ## First-Run Flow When `flynn start` detects no config at `~/.config/flynn/config.yaml`: ``` No configuration found. Would you like to run the setup wizard? [Y/n] ``` Sequential steps: 1. **Welcome** — One-liner: "Let's get Flynn running. This takes about 2 minutes." 2. **Model provider** — Pick from top tier (Anthropic/OpenAI/Ollama), or "More providers" for second tier (Gemini, OpenRouter, xAI, Bedrock, GitHub Models). Prompt for API key (or host for Ollama). Configured as `default` tier. Optionally configure `fast` tier with cheaper model from same provider. 3. **Channel** — Suggest WebChat (zero external setup). Offer Telegram/Discord, or "More channels" for Slack/WhatsApp. Prompt for required fields only. 4. **Write config** — Generate `~/.config/flynn/config.yaml`, print path, show summary. 5. **Offer to start** — "Start Flynn now? [Y/n]" 6. **Offer more** — If declined: "Configure more features? [Y/n]" drops into the menu. ## Menu-Driven Reconfiguration Entry: `flynn setup` with existing config, or "configure more" after first-run. ``` Flynn Setup — Current Configuration Models: anthropic (default tier) Channels: webchat, telegram Memory: keyword search (no embeddings) Automation: none Security: default (no sandbox) Gateway: port 3777, no auth What would you like to configure? 1. Model Providers 2. Channels 3. Memory 4. Automation 5. Security 6. Gateway 0. Done — save and exit > ``` Each section: show current state, offer add/change/remove, return to menu. On "Done": write config, offer restart (if daemon running) or start. Config is buffered in memory; only written to disk on "Done". Ctrl+C exits cleanly with no partial writes. ## Provider Setup Flows ### Top Tier **Anthropic:** ``` API key: sk-ant-•••••• Model [claude-sonnet-4-20250514]: ``` **OpenAI:** ``` API key: sk-•••••• Model [gpt-4.1]: ``` **Ollama:** ``` Host [http://localhost:11434]: Model [llama3.3]: ``` ### Second Tier OpenRouter, xAI, Gemini, Bedrock, GitHub Models — same pattern (API key + model with defaults). OpenRouter and xAI reuse OpenAI-compatible flow with different base URLs. ### Tier Assignment First provider → `default` tier. Then: ``` Configure a fast tier for compaction/delegation? [y/N] ``` If yes, suggest cheaper model from same provider (e.g., claude-haiku-4-5-20251001, gpt-4.1-mini, smaller Ollama model). `complex` and `local` tiers skipped — power-user YAML territory. ## Channel Setup Flows **WebChat** (recommended, zero setup): ``` Gateway port [3777]: ✓ WebChat enabled — visit http://localhost:3777 after starting ``` **Telegram:** ``` Bot token (from @BotFather): 123456:ABC-•••••• Allowed chat IDs (comma-separated): 12345678, -100987654 ``` **Discord:** ``` Bot token: MTIz•••••• Allowed guild IDs (comma-separated, or * for all): 123456789 ``` **Slack:** ``` Bot token (xoxb-...): xoxb-•••••• App token (xapp-...): xapp-•••••• Allowed channel IDs (comma-separated, or * for all): C0123ABC ``` **WhatsApp:** ``` ⚠ WhatsApp requires QR code authentication on first connect. It will appear in the terminal when Flynn starts. Allowed phone numbers (comma-separated, or * for all): 61412345678 ``` Input validation: Telegram tokens match `\d+:.+`, Slack tokens start with `xoxb-`/`xapp-`. Invalid input re-prompts. After each channel: "Add another channel? [y/N]" ## Menu Section Flows ### Memory ``` Enable vector search for semantic memory? [y/N] Embedding provider: 1. OpenAI (recommended) 2. Gemini 3. Ollama (local) 4. Voyage AI API key [reuse from model provider? Y/n]: ``` Smart default: reuse API key if same provider already configured for models. ### Automation ``` Enable cron scheduler? [y/N] Enable webhook receiver? [y/N] Enable Gmail watcher? [y/N] ``` Webhooks prompt for shared secret. Gmail prompts for OAuth credentials path. Cron jobs configured in YAML later. ### Security ``` Enable Docker sandboxing? [y/N] Enable DM pairing for unknown senders? [y/N] Tool policy profile [full]: (minimal/messaging/coding/full) ``` ### Gateway ``` Port [3777]: Set auth token? [y/N] Enable Tailscale Serve? [y/N] Enable gateway lock (single client)? [y/N] ``` ## File Structure ``` src/cli/setup.ts — Command registration + main orchestrator src/cli/setup/ prompts.ts — Readline helpers (ask, choose, confirm, password) providers.ts — Model provider setup flows channels.ts — Channel setup flows memory.ts — Memory/embeddings setup automation.ts — Cron, webhooks, Gmail setup security.ts — Tool policy, sandbox, pairing, hooks gateway.ts — Port, auth, Tailscale, lock summary.ts — Config summary renderer ``` ## Dependencies - **readline** — Node built-in, same as minimal TUI - **yaml** — Round-trip YAML parsing to preserve comments when editing existing configs No `inquirer` or `prompts` packages. ## Prompt Helpers (prompts.ts) - `ask(question, default?)` — Free text input - `choose(question, options[])` — Numbered list, return selection - `confirm(question, default?)` — Y/n boolean - `password(question)` — Hidden input for API keys ## Config I/O Strategy - Load existing YAML with `yaml` package (round-trip, preserves comments) - Buffer all changes in memory - Write only on "Done" or end of first-run flow - Preserve `${ENV_VAR}` references in existing configs — don't resolve them - `mkdir -p ~/.config/flynn` if directory doesn't exist ## Secrets Handling Secrets (API keys, bot tokens) entered inline and stored as plaintext in `config.yaml`. Users can manually replace with `${ENV_VAR}` references later. The wizard's job is to minimize time-to-working-config. ## Integration with Existing Systems - **`flynn start`** — Check for config, offer wizard if missing. After wizard, proceed to start. - **`flynn doctor`** — Validates the config the wizard produces. Wizard does not test API connectivity. - **`flynn setup`** — New command, re-runnable. With existing config: straight to menu. Clean separation: wizard produces config, doctor validates it. ## Testing Strategy - Unit tests for prompt helpers (`ask`, `choose`, `confirm`) - Unit tests for config generation — given answers, assert correct YAML structure - Unit tests for input validation (token formats, port ranges) - Integration test: mock readline, run full first-run flow, assert valid config ## Edge Cases - Config directory missing → `mkdir -p` before writing - Ctrl+C during wizard → clean exit, no partial config - Existing config with `${VAR}` references → preserve them - Re-running setup → load current values as defaults, don't overwrite untouched fields - Invalid input → re-prompt with explanation, never crash ## Explicitly Out of Scope - Config migration between versions - Undo/rollback - Config backup (user has git) - Network validation of API keys (that's `flynn doctor`) - `complex` and `local` model tier configuration - Zhipu, Llama.cpp provider setup (niche, manual YAML)