feat(onboarding): minimalistic guided first-agent wizard - #1371
Conversation
A fresh self-hoster who opens the web UI now gets a guided path to first value instead of an empty dashboard. The wizard asks one question — "what do you want your first agent to do?" — maps the intent to a starter template, and deploys a tailored, ready-to-chat agent in a couple of clicks. Design: teach by doing, not by reading. No mandatory tour. The one hard setup gate (Claude auth) is surfaced as a non-blocking hint linking to Settings → Integrations; everything else is deferred just-in-time. - components/OnboardingWizard.vue: purpose picker → POST /api/agents → "Open chat". Verifies mapped local templates exist (scout/sage/scribe), falls back to a blank Claude Code agent so deploy never 404s. - views/Dashboard.vue: auto-opens once on a fresh, empty install (dismissal remembered in localStorage); empty-state "Get started" button re-opens it. - routers/settings.py: feature-flags gains claude_auth_configured (bool; anthropic key in DB/env OR any subscription) so the wizard's setup hint reflects reality. Cached in stores/sessions.js. - Remove orphaned OnboardingChecklist.vue / useOnboarding.js (dead code built on the removed Process Engine). - docs: onboarding-wizard flow spec + follow-up build issues. Related to Abilityai/trinity-enterprise#52 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lets a user re-run onboarding (and QA preview it on a non-empty fleet) without deleting agents. Bypasses the empty-fleet gate and prior dismissal. Related to Abilityai/trinity-enterprise#52 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per review: the wizard shouldn't be a parallel deploy button. It now guides the user through the REAL UI and carries them to the credential the agent needs. - Step 'create' delegates to the actual CreateAgentModal (template prefilled from the chosen purpose) instead of calling createAgent itself — the user clicks the real create button. - Step 'credential' leads to connecting a Claude subscription (Settings -> Integrations -> Claude Subscriptions), with step-by-step 'claude setup-token' guidance; if Claude is already connected it confirms and offers 'Open chat' instead. Related to Abilityai/trinity-enterprise#52 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two wiring bugs made the wizard vanish on create with no guidance: - Dashboard wired @deployed to closeOnboarding, unmounting the wizard the moment the agent was created. Now @deployed refreshes the fleet (so the new agent shows without a page reload) and leaves the wizard open to advance to its credential step. - CreateAgentModal emits 'created' then 'close'; onModalClose reset the step back to the picker. Now it only resets on a real cancel (still on the create step), so the post-create 'close' no longer clobbers the credential step. Related to Abilityai/trinity-enterprise#52 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The wizard backdrop was z-40, one tier below the app's modal/dropdown layer (z-50), so header chrome like the time-range control showed through the dim overlay instead of being grayed out. Bump to z-50 to match SystemViewEditor / the build-info modal. Related to Abilityai/trinity-enterprise#52 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
z-50 alone didn't dim the header time-range control — the wizard was nested in the Dashboard's layout, confining its stacking. Teleport the overlay to <body> so it renders in the document's top stacking context and the dim backdrop covers everything behind it, every mode. Related to Abilityai/trinity-enterprise#52 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…sters Self-hosters get the onboarding wizard automatically on a fresh, empty install, but the relaunch link wasn't documented anywhere. Add a 'Guided Onboarding (First Run)' section to the Quick Start (auto-open behavior + http://localhost/?onboarding=1 relaunch, with the 'log in first' caveat), and a pointer from Setup so it's discoverable right after install. Related to Abilityai/trinity-enterprise#52 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
trinity-system is present on every install and is included in the network store's agents list, so 'agents.length === 0' was never true and the wizard would never auto-open on a genuinely fresh install. Gate on the count of non-system agents instead. Related to Abilityai/trinity-enterprise#52 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…enly A decisive click-through test confirmed the backdrop already covers the timeline time-ruler (clicking it dismisses the wizard; elementsFromPoint returns the backdrop) — it was never a stacking bug. The ruler just has a white background, so at 70% opacity it read as a light-gray band that looked 'not grayed' next to darker UI. Bumping to 85% dims white rows closer to everything else. Related to Abilityai/trinity-enterprise#52 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| /> | ||
|
|
||
| <!-- intro + credential: the wizard's own guidance card --> | ||
| <div v-else class="fixed inset-0 z-50 overflow-y-auto"> |
There was a problem hiding this comment.
[medium] Modal a11y gap. This overlay has no role="dialog"/aria-modal="true", no focus trap, no Escape-to-close, and no body scroll-lock. The repo just standardized exactly these for ChannelConfigDialog (#19: "focus mgmt, trap, scroll lock"), so this regresses against that bar. At minimum: add role="dialog" aria-modal="true" + an aria-labelledby pointing at the <h2>, an Escape @keydown, and focus the first control on open. Reusing the existing dialog pattern/composable would keep it consistent.
There was a problem hiding this comment.
Fixed in 872afe0 — added role=dialog/aria-modal/aria-labelledby, Escape-to-close, a Tab focus trap, focus-on-open, and body scroll-lock.
| # Anthropic key exists (DB or env) OR any Claude subscription is | ||
| # registered. Non-sensitive: a boolean, never the key itself. | ||
| "claude_auth_configured": bool(settings_service.get_anthropic_api_key()) | ||
| or bool(db.list_subscriptions()), |
There was a problem hiding this comment.
[low-med] Hot-path full table read. /api/settings/feature-flags is fetched on nearly every page load (NavBar, Dashboard, AgentDetail). When no Anthropic key is set, this calls db.list_subscriptions() — materializing every subscription row (decrypting credentials in SubscriptionWithAgents? at least full hydration) just to test existence. Prefer a cheap COUNT(*) > 0 / EXISTS helper (e.g. db.has_any_subscription()). The or short-circuits when a key exists, so this only bites key-less installs — which is exactly the onboarding state this flag targets, so it will be hit.
There was a problem hiding this comment.
Fixed in 872afe0 — added db.has_any_subscription() (COUNT existence check); the flag now uses it instead of bool(db.list_subscriptions()), so no rows are materialized/decrypted on this hot path.
| // Confirm mapped local templates exist; fall back to blank so the prefilled | ||
| // CreateAgentModal never points at a missing template. | ||
| try { | ||
| const r = await axios.get('/api/templates', { headers: authStore.authHeader }) |
There was a problem hiding this comment.
[low] Duplicate templates fetch. The wizard fetches /api/templates here only to downgrade a missing local template to blank, and then CreateAgentModal fetches /api/templates again on its own mount in the create step — two round-trips for the same data within one flow. Minor; acceptable if you prefer the isolation, but worth a note. The fallback also mutates p.template in place on the ref array, which works but is a little surprising.
There was a problem hiding this comment.
Fixed in 872afe0 — dropped the wizard's /api/templates fetch; the missing-template→blank fallback now lives in CreateAgentModal (which already fetches), so the create flow makes one request.
…p fetch) - a11y (medium): OnboardingWizard now has role=dialog/aria-modal/ aria-labelledby, Escape-to-close, a Tab focus trap, focus-on-open, and body scroll-lock. Matches the modal-a11y bar set in #19. - perf (low-med): /api/settings/feature-flags no longer materializes every subscription row to compute claude_auth_configured. New db.has_any_subscription() does a COUNT existence check; replaces bool(db.list_subscriptions()). - cleanup (low): drop the wizard's duplicate /api/templates fetch. The missing-template->blank fallback now lives in CreateAgentModal (the component that already fetches templates), so the create flow makes one request instead of two. Related to Abilityai/trinity-enterprise#52 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
vybe
left a comment
There was a problem hiding this comment.
Validated via /validate-pr: backend flag is boolean-only (no key leak) with a parameterized COUNT existence check; frontend reuses the real CreateAgentModal (no cloned API path, Invariant #7) and safely net-removes dead OnboardingChecklist/useOnboarding (green build confirms no remaining importers). All 18 required checks green. Non-blocking follow-ups: cross-tracker trinity-enterprise#52 needs a manual status-in-dev bump; feature-flows.md index not updated for the new flow doc.


What
Gives a fresh self-hoster a guided path to first value instead of an empty dashboard. The wizard asks one question — "what do you want your first agent to do?" — maps the intent to a starter template, and deploys a tailored, ready-to-chat agent in a couple of clicks.
This is the first slice of the trinity-enterprise#52 onboarding epic: a single, self-contained PR that lets a person start their own AI agent in minutes with guidance. Subsequent slices (mandatory Claude-auth setup gate, ambient checklist, JIT GitHub PAT) spin off from the spec.
Design
scout/sage/scribe) or a blank Claude Code agent.localStorage.Changes
Frontend
components/OnboardingWizard.vue— purpose picker →POST /api/agents→ "Open chat" (/agents/:name?tab=chat). Verifies mapped templates exist against/api/templates; missing → blank-agent fallback so deploy never 404s.views/Dashboard.vue— mounts the wizard, auto-opens viamaybeAutoOpenOnboarding()(gated on!isFleetLoading && agents.length === 0 && !dismissed); empty-state "Get started" button re-opens it.stores/sessions.js— cachesclaudeAuthConfiguredfrom feature-flags.Backend
routers/settings.py—GET /api/settings/feature-flagsgainsclaude_auth_configured=bool(anthropic_api_key)(DB or env) or any registered subscription. A boolean only; never the key itself.Removed
OnboardingChecklist.vue+useOnboarding.js(orphaned, modeled on the removed Process Engine — mounted nowhere, linked to non-existent/processes/*routes).Docs
docs/memory/feature-flows/onboarding-wizard.md— flow spec + follow-up build issues.Test
GET /api/settings/feature-flags→claude_auth_configured: trueon this dev instance.OnboardingWizard.vuetransforms without errors via the dev server.?tab=integrationsresolves to the Integrations tab.Related to Abilityai/trinity-enterprise#52
🤖 Generated with Claude Code