Menu

#326 feat(setup): port "A · Rail" first-run wizard with on-device model picker

closed
nobody
None
2026-06-23
2026-06-23
Anonymous
No

Originally created by: Akarsh-Hegde

Ports the "A · Rail" direction of the Meridian Setup design into the real first-run wizard. Re-skins the working flow (no behaviour rebuild): live commands drive it, the design supplies presentation, retokenized onto the product palette (amber, not the mock's orange) so the wizard matches the dashboard it hands off to.

Scope

UI (ui/app/setup/, split to stay under the 500-line rule): Welcome → Permissions → Local intelligence → Integrations → Completion, in a centered 948×628 card.

  • Permissions: the three real required cards incl. Input Monitoring (the design omitted it; the in-process capture pipeline needs it). The design's Notifications / Launch-at-login toggles are dropped — no backend.
  • Integrations: Jira + Trello use the real start_oauth / get_oauth_status flow; Linear/GitHub/Asana render explicitly disabled, never wired to error.
  • globals.css: adds --pop-shadow + mer-spin / mer-pop.

Deep model step — a real, working 3-tier picker:

  • Tiers map to real checkpoints (Qwen3.5-4B / Qwen3.5-9B-OptiQ / phi-4) with honest model identity, not fictional names.
  • Live hardware-spec panel + a memory gauge sized against detected RAM.
  • Prefetch only fires on an explicit Download with the preference written first, so the "Ready" badge can't mislabel which model loaded.

Backend

  • meridian-core settings + ui/lib/settings.ts: new llm_model_preference.
  • run_task_linker_mlx._resolve_model_id honours that preference (degrades via llm_selector when it can't fit the Metal budget).
  • New tray commands: detect_system_specs, set_model_preference, get_model_preference.
  • tray.rs widens the setup window 560×660 → 980×660 for the Rail shell.

Verified

Tray build + clippy clean · meridian-core test passes · cargo fmt --check clean · Python compiles · UI build + TypeScript passes · /setup in the static export · headless render check of Welcome + the Deep Model step. Full pre-push suite (incl. cargo test, UI build, security audit) passed on push.

Known limitation

The MLX server resolves its model id once per process. Fresh-install (shipping) ordering is correct; on a dev machine where the server is already running with a different model cached, changing the pick won't hot-swap until the server restarts (no reload command today).

🤖 Generated with Claude Code

Related

Tickets: #330
Tickets: #347

Discussion

  • Anonymous

    Anonymous - 2026-06-23

    Originally posted by: Akarsh-Hegde

    Code review (high effort) — self-review + 2 independent finder agents

    Reviewed the diff across 8 angles (correctness, removed-behavior, cross-file, reuse/simplification/efficiency, altitude, conventions). Backend is clean — the df/system_profiler/sysctl parsing, the settings round-trip, and the Python model resolver all degrade gracefully (the one latent note: _resolve_model_id's min_ram fallback would mis-size a model absent from llm_selector._MODELS, but all three wizard-offered checkpoints are in the catalog, so it's unreachable from the UI).

    Found 6 issues in the React wizard (4 correctness/UX + 2 cleanup), left inline — all now fixed in b24031b:

    1. Failed prefetch permanently bricked the Download button (prefetchStarted never reset). ✅
    2. No pending state between Download-click and server-running (re-clickable button, no spinner). ✅
    3. OAuth connecting row spun forever — no deadline (old TasksView had 180s). ✅
    4. OAuth poll spammed setErr every 2s / clobbered the other provider. ✅
    5. Dead APPS export (dock map from the dropped fake desktop). ✅
    6. OAUTH_PROVIDERS duplicated INTEGRATIONS.oauth. ✅

    Two intentional behavior changes were reviewed and accepted, not flagged as bugs: explicit Download replacing the old eager auto-prefetch (the wantModel commit gate that keeps the "Ready" badge truthful; model still lazy-loads on first classify), and the split of mark_setup_complete + window-close into Finish → Completion → Open (no first-run-loop risk — the flag is written on Finish).

     
  • Anonymous

    Anonymous - 2026-06-23

    Ticket changed by: Akarsh-Hegde

    • status: open --> closed
     

Log in to post a comment.