Problem
senpi/omo has no first-run onboarding flow. A brand-new user launches into a welcome header + an empty prompt, and everything after that is manual and error-driven:
- Auth is
/login, discovered only via the "No models available. Use /login ..." error text (packages/coding-agent/src/core/auth-guidance.ts:6-20).
- Model selection is
/model, also discovered via error guidance (auth-guidance.ts:19-20).
- senpi has a first-time setup dialog (theme + analytics only), but
shouldRunFirstTimeSetup() hard-gates it to the official Pi distribution (@earendil-works/pi-coding-agent, app name pi, config dir .pi) plus PI_EXPERIMENTAL=1 — so senpi/omo distributions never see it (packages/coding-agent/src/cli/startup-ui.ts:113-128, dialog at src/modes/interactive/components/first-time-setup.ts:31-117).
- The omo layer's existing "onboarding" is a conversational tour skill, not setup:
omo/packages/omo-senpi/src/components/onboarding/component.ts:23-65 injects a hidden bootstrap message that makes the agent read skills/onboarding/SKILL.md (6-lane tour). It configures no provider, no model, no auth — and it has a chicken-and-egg problem: the tour itself needs a working provider+model to run, which is exactly what a first-run user doesn't have.
omo setup (omo-native launcher) can detect/import sibling harness credentials (omo/packages/omo-native/bin/lib/setup-detect.js:99-137, setup-import.js:202-218) but only when the user explicitly types it; first launch just prints a one-line stderr hint (launcher.js:131-132,155-156).
Reference: how oh-my-pi does it (can1357/oh-my-pi @ v18.0.0, 96f4280976)
oh-my-pi ships a versioned, fullscreen TUI setup wizard worth copying structurally:
- Trigger: cold launch compares persisted
setupVersion against CURRENT_SETUP_VERSION (=2) and lazy-loads the wizard when stale (src/main.ts:525-531, src/modes/setup-version.ts:22). Explicit re-run via omp setup forces it (src/commands/setup.ts:30,57; non-TTY exits 1).
- Scenes, in order (
src/modes/setup-wizard/index.ts:17-23): providers (OAuth sign-in + web-search tabs) → default model (ModelBrowser) → glyph mode (nerd/unicode/ascii) → composer shape (minVersion: 2) → theme (live preview). Each scene has a minVersion, so upgrades replay only new scenes — the wizard doubles as upgrade onboarding.
- UX: fullscreen overlay with animated splash (2.6s) → 420ms cross-dissolve → scenes → "Setup saved" outro (
wizard-overlay.ts); Esc skips a scene; arrow/enter/mouse supported.
- Gates (
index.ts:39-63): never runs on non-TTY, on session resume, with OMP_SKIP_SETUP=1, or with startup.setupWizard: false.
- Persistence: global
config.yml + project .omp/config.yml for model roles; OAuth tokens in the agent DB; markSetupWizardComplete() writes setupVersion (index.ts:65-70).
- Notable: no telemetry-consent scene; no non-interactive wizard.
Why this issue lives in senpi (not omo)
The wizard needs engine-level surfaces: pre-interactive TUI dialogs, the /login OAuth/API-key flows, the model selector, theme + shareAnalytics settings, and the existing (Pi-gated) first-time-setup.ts scaffolding. All of that is senpi runtime code. The omo plugin layer only gets extension events (session_start etc.) and can't render a wizard before the first prompt. omo-side work (credential import scene, tour chaining) hangs off an extension hook proposed below and can be a follow-up in oh-my-openagent.
Proposal
A. Gating & trigger
- Add
setupVersion to settings.json schema; introduce CURRENT_SETUP_VERSION = 1.
- On interactive cold launch, run the wizard when: TTY && not resuming && not
--print/-p && setupVersion < CURRENT_SETUP_VERSION && SENPI_SKIP_SETUP unset && startup.setupWizard !== false.
- Generalize
shouldRunFirstTimeSetup() (startup-ui.ts:113-128): drop the official-Pi-distribution hard gate and the PI_EXPERIMENTAL requirement; make it branding-aware so pi/senpi/omo distributions all qualify (keep custom-agent-dir exclusion).
- Explicit re-run:
senpi --setup (and/or a /setup slash command). Non-TTY invocation exits 1 with a clear message, mirroring omp setup.
B. Scenes (v1)
- Provider sign-in — reuse the
/login flows (OAuth + API-key paste). Show already-detected credentials; Esc to skip. auth-guidance.ts messages should then point at the wizard too.
- Default model — reuse the
/model selector; persist the default role.
- Theme — lift the existing dark/light step from
first-time-setup.ts.
- Analytics opt-in — keep the existing
shareAnalytics question.
Each scene carries a minVersion (oh-my-pi pattern) so future scenes replay for upgraders without re-running everything.
C. Extension hook (the omo integration point)
- Let extensions contribute wizard scenes and/or a post-setup hook.
- omo-senpi then: (a) contributes a "found credentials from Claude Code/opencode/... — import?" scene reusing omo-native
setup-detect.js/setup-import.js logic, and (b) chains the existing conversational onboarding tour after wizard completion, so omo-onboarding:bootstrap fires only once a working provider+model exists. Ordering contract: wizard → auth+model guaranteed → tour.
D. Persistence
settings.json: setupVersion, theme, shareAnalytics, default model role. Credentials stay in the existing auth store. No new config files.
Acceptance criteria
Out of scope / follow-ups
- oh-my-openagent side: the credential-import scene + tour-chaining component work (file there once the senpi hook shape lands).
- Glyph/composer-style appearance scenes beyond theme — add later via
minVersion bumps.
- Non-interactive/headless setup wizard (oh-my-pi doesn't have one either).
Problem
senpi/omo has no first-run onboarding flow. A brand-new user launches into a welcome header + an empty prompt, and everything after that is manual and error-driven:
/login, discovered only via the "No models available. Use /login ..." error text (packages/coding-agent/src/core/auth-guidance.ts:6-20)./model, also discovered via error guidance (auth-guidance.ts:19-20).shouldRunFirstTimeSetup()hard-gates it to the official Pi distribution (@earendil-works/pi-coding-agent, app namepi, config dir.pi) plusPI_EXPERIMENTAL=1— so senpi/omo distributions never see it (packages/coding-agent/src/cli/startup-ui.ts:113-128, dialog atsrc/modes/interactive/components/first-time-setup.ts:31-117).omo/packages/omo-senpi/src/components/onboarding/component.ts:23-65injects a hidden bootstrap message that makes the agent readskills/onboarding/SKILL.md(6-lane tour). It configures no provider, no model, no auth — and it has a chicken-and-egg problem: the tour itself needs a working provider+model to run, which is exactly what a first-run user doesn't have.omo setup(omo-native launcher) can detect/import sibling harness credentials (omo/packages/omo-native/bin/lib/setup-detect.js:99-137,setup-import.js:202-218) but only when the user explicitly types it; first launch just prints a one-line stderr hint (launcher.js:131-132,155-156).Reference: how oh-my-pi does it (can1357/oh-my-pi @ v18.0.0, 96f4280976)
oh-my-pi ships a versioned, fullscreen TUI setup wizard worth copying structurally:
setupVersionagainstCURRENT_SETUP_VERSION(=2) and lazy-loads the wizard when stale (src/main.ts:525-531,src/modes/setup-version.ts:22). Explicit re-run viaomp setupforces it (src/commands/setup.ts:30,57; non-TTY exits 1).src/modes/setup-wizard/index.ts:17-23): providers (OAuth sign-in + web-search tabs) → default model (ModelBrowser) → glyph mode (nerd/unicode/ascii) → composer shape (minVersion: 2) → theme (live preview). Each scene has aminVersion, so upgrades replay only new scenes — the wizard doubles as upgrade onboarding.wizard-overlay.ts); Esc skips a scene; arrow/enter/mouse supported.index.ts:39-63): never runs on non-TTY, on session resume, withOMP_SKIP_SETUP=1, or withstartup.setupWizard: false.config.yml+ project.omp/config.ymlfor model roles; OAuth tokens in the agent DB;markSetupWizardComplete()writessetupVersion(index.ts:65-70).Why this issue lives in senpi (not omo)
The wizard needs engine-level surfaces: pre-interactive TUI dialogs, the
/loginOAuth/API-key flows, the model selector, theme +shareAnalyticssettings, and the existing (Pi-gated)first-time-setup.tsscaffolding. All of that is senpi runtime code. The omo plugin layer only gets extension events (session_startetc.) and can't render a wizard before the first prompt. omo-side work (credential import scene, tour chaining) hangs off an extension hook proposed below and can be a follow-up in oh-my-openagent.Proposal
A. Gating & trigger
setupVersiontosettings.jsonschema; introduceCURRENT_SETUP_VERSION = 1.--print/-p&&setupVersion < CURRENT_SETUP_VERSION&&SENPI_SKIP_SETUPunset &&startup.setupWizard !== false.shouldRunFirstTimeSetup()(startup-ui.ts:113-128): drop the official-Pi-distribution hard gate and thePI_EXPERIMENTALrequirement; make it branding-aware so pi/senpi/omo distributions all qualify (keep custom-agent-dir exclusion).senpi --setup(and/or a/setupslash command). Non-TTY invocation exits 1 with a clear message, mirroringomp setup.B. Scenes (v1)
/loginflows (OAuth + API-key paste). Show already-detected credentials; Esc to skip.auth-guidance.tsmessages should then point at the wizard too./modelselector; persist the default role.first-time-setup.ts.shareAnalyticsquestion.Each scene carries a
minVersion(oh-my-pi pattern) so future scenes replay for upgraders without re-running everything.C. Extension hook (the omo integration point)
setup-detect.js/setup-import.jslogic, and (b) chains the existing conversational onboarding tour after wizard completion, soomo-onboarding:bootstrapfires only once a working provider+model exists. Ordering contract: wizard → auth+model guaranteed → tour.D. Persistence
settings.json:setupVersion,theme,shareAnalytics, default model role. Credentials stay in the existing auth store. No new config files.Acceptance criteria
settings.json, no auth), interactive launch: wizard runs before the first prompt; completing it leaves a working provider + default model.-p/--print), non-TTY, session resume,SENPI_SKIP_SETUP=1, orstartup.setupWizard: false./loginguidance intact.CURRENT_SETUP_VERSIONreplays only scenes with a higherminVersionfor existing users.senpi --setupforces a full re-run; non-TTY exits 1.setup-wizard.test.tscoverage: scene selection/version gating, persistence, skip paths;first-time-setupcomponent tests updated.Out of scope / follow-ups
minVersionbumps.