docs: add setup wizard design

Interactive setup wizard with two entry points: auto-trigger on
first run (no config detected) and explicit `flynn setup` command.
Minimal-first flow for quick start, menu-driven for reconfiguration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
William Valentin
2026-02-10 09:14:45 -08:00
parent bab3f26ef6
commit 6b426a1e52
@@ -0,0 +1,248 @@
# 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)