---
title: Missions hub (pick a guided job and an AI does it for you)
---

# Missions Hub

## What it is

The **Missions hub** is a permanent, chat-first home for Omniscio's guided "do-it-for-me" **missions** — pick one and an AI does the whole task for you in a normal chat session, driving Omniscio's built-in tools (CLI endpoints). It is a **sidebar integration** (`__missions__`) nested under **Prompt Tools**, reachable from its sidebar row OR the **Missions** toolbar button, and is SEPARATE from the onboarding mission surfaces (the empty-state upsell + the old mission picker) that were retired 2026-08-26 behind `MISSION_UPSELL_SURFACES_ENABLED = false`. Missions are the same [MISSION_REGISTRY](/src/shared/missions/registry.ts) entries onboarding pre-spawn already uses; the hub is a new *front door* to launch them on demand.

## Where to find it

### UI surface

- **A sidebar row under Prompt Tools** (Rocket icon) opens the gallery ([MissionsView.tsx](/src/renderer/src/features/missions/MissionsView.tsx)) as a PANEL in the main area — the hubs sidebar stays visible. It is the **Clean Room shape**, NOT `panelOwnsLayout`: the hub HOSTS the sessions its cards launch, so desktop Pane 2 is the standard SessionsSidebar listing past missions, and `mobilePrefersPanel` with no `sidebarComponent`/`panelOwnsLayout` makes the gallery ride the mobile session list's landing slot (`isMobileLandingOverSessions`) rather than replacing it. A `shouldYieldToSessionChat` on `displayedSessionInActiveProject` hands the pane to the mission chat once one is displayed. `panelOwnsLayout: true` was correct only while each card launched into the user’s ACTIVE project (the flag literally declares "a project with no sessions at all"); left on after the hub became the spawn target it makes `computeOverlayKey` return `'missions'` unconditionally and the gallery covers the chat the user just started — the Workflows split-view defect.
- **The "Missions" toolbar button** (Sparkles) opens the same panel — it is a STATIC toolbar item retargeted to `setCurrentView('dashboard')` + `activateVirtualProject(MISSIONS_PROJECT_ID)` (the arij / file-converter idiom). Keeping it static is deliberate: a static `TOOLBAR_ITEMS` entry SUPPRESSES the derived `integration:missions` button, which both preserves an existing `pinnedToolbarItems` entry of `'missions'` (no settings migration) and prevents a duplicate second button. For the same reason its active-highlight uses `isMissionsActive` (computed in `App.tsx` from `activeProjectFolderPath`, like `isArijActive`), NOT `activeIntegrationToolbarId` — that id never resolves for a suppressed derived button, so the highlight would silently never fire.
- **Start launches the mission as a chat session** the user lands in (the existing `launchSession(source=missionId)` path). `launchSession` already moves the active project to the launched session and selects it, so the panel needs no navigate-away callback — the view takes NO props. No bespoke per-mission UI — the interface IS the chat.
- **A mission always spawns IN THIS HUB**, never in whatever project the user was standing in. `__missions__` is in `SPAWNABLE_VIRTUAL_PROJECT_SENTINELS` with a `MANAGED_WORKDIR_SUBDIRS` row (`<userData>/missions-agent`), so the hub hosts the sessions its own cards launch. All three launch sites resolve the `__missions__` row: the gallery, the in-session nudge picker ([SessionPanel.tsx](/src/renderer/src/features/sessions/SessionPanel.tsx)), and the inbox trickle card's "Run it" ([mission-launch-plan.ts](/src/renderer/src/features/alerts/mission-launch-plan.ts)). Previously each picked an ambient target — the active project, `session.projectId`, or "the first spawnable project" — so one mission landed somewhere different every time and guided personal errands opened sessions inside unrelated code repos. If the `__missions__` row has not hydrated yet, Start is DISABLED and the inbox plan returns `error`; neither falls back to another project. **Onboarding's `first-mission` is the one exception** — it deliberately runs in the project the user just created in [ProjectStep.tsx](/src/renderer/src/features/onboarding/steps/ProjectStep.tsx), which is the point of that step.
- The gallery lists `visibleMissionsForPlatform(settings, envEnabled, platform)` — the feature-gated visible set INTERSECTED with the host platform, so a Linux-absent or unreleased mission (e.g. the gated `build-chrome-extension`) never leaks in. An empty state shows when none apply.
- **Mobile:** declared `mobile: { status: 'ready' }` in the ui-registry — as a sidebar integration it is reachable from the mobile sidebar like its siblings, and the gallery is a simple card list.

## How it behaves

### The missions

Data-driven from [MISSION_REGISTRY](/src/shared/missions/registry.ts). Each mission is `promptAsset`-backed (a bundled markdown template under `resources/missions/<id>/`) OR `superPromptId`-backed (a bundled Super Prompt). The hub launches them **immediately** (the model runs the prompt on turn 1); onboarding pre-spawn launches a subset **deferred** (parked on a `<first_response>` opener) — see [onboarding.md](../../.claude/memory/onboarding.md).

- **Clean up my email inbox — `inbox-concierge`** (NEW). The guided Gmail cleanup, run as a chat: it checks `GET /gmail/status`, walks a first-time user through connecting Gmail, then scans with the built-in Email Cleanup engine (`GET /gmail/cleanup/analysis`) and clears the noise one sender at a time — protecting bank / security / people-you-reply-to first, archiving (never deleting) with an auto-archive filter for "make it stop," everything reversible. Prompt: [mission-prompt.md](/resources/missions/inbox-concierge/mission-prompt.md). It is EXCLUDED from onboarding pre-spawn ([onboarding-prespawn.ts](/src/shared/missions/onboarding-prespawn.ts)) — it needs Gmail connected and does its own runtime status-check + scan, so it carries no static opener to park on.
- **Give my projects real icons — `project-icon-stylist`** (NEW). The guided sidebar cleanup, run as a chat: it reads the real project list (`GET /projects`, which now returns `iconPath` + `iconColor`), learns the available vocabulary (`GET /project/icon-options`), proposes an emoji / Lucide / brand-logo mark per project with an optional colour, and applies only what the user approves (`POST /project/:id/icon`). Prompt: [mission-prompt.md](/resources/missions/project-icon-stylist/mission-prompt.md). EXCLUDED from onboarding pre-spawn ([onboarding-prespawn.ts](/src/shared/missions/onboarding-prespawn.ts)) for the same reason as `inbox-concierge` — it must read live state before it has anything to say, so it carries no static opener to park on, and a brand-new account has no projects to style yet.
- Plus the existing registry missions: `first-mission` (Tidy my computer), `unclaimed-money-check`, `find-local-events`, `ai-workflow-integration-planner`, `tool-scout` (ToolScout), and the gated `build-chrome-extension`.

### Email Cleanup panel — retired

The standalone Email Cleanup sidebar panel (`__email_cleanup__`) was RETIRED in favor of the `inbox-concierge` mission: its sidebar row is hidden for everyone (the Dashboard visibility filter), and any stale pointer redirects to the Inbox. The `/gmail/cleanup/*` routes, the cleanup ENGINE, and the in-Gmail ✨ Clean Up button are unchanged — see [email-cleanup.md](email-cleanup.md).

## For agents

### Adding a mission

1. Add an entry to [MISSION_REGISTRY](/src/shared/missions/registry.ts): `id` (= the `launchSession` source), a `telemetryFeature` (a real FEATURE_REGISTRY id), `platforms`, and exactly one of `promptAsset` / `superPromptId`.
2. For a `promptAsset` mission, add `resources/missions/<id>/mission-prompt.md`. Include a `<first_response>` opener ONLY if it should pre-spawn deferred; a hub-only mission that needs runtime work (like `inbox-concierge`) omits it AND is added to `ONBOARDING_PRESPAWN_EXCLUDED_MISSION_IDS`.
3. It appears in the hub automatically (platform + feature filtered). Registry invariants are locked by [mission-registry.test.ts](/tests/unit/shared/mission-registry.test.ts).

### Code references

- Hub view + anchors: [MissionsView.tsx](/src/renderer/src/features/missions/MissionsView.tsx), [MissionsView.ui-anchors.ts](/src/renderer/src/features/missions/MissionsView.ui-anchors.ts)
- Registry + the platform-AND-feature selector: [registry.ts](/src/shared/missions/registry.ts) (`visibleMissionsForPlatform`)
- Launch path (source → composed prompt): [session-create-prompt-assembly.ts](/src/main/services/session/session-create-prompt-assembly.ts), [super-prompt-mission.ts](/src/main/services/session/super-prompt-mission.ts)
- Integration wiring: the sentinel in [virtual-project-ids.ts](/src/shared/virtual-project-ids.ts), the manifest in [missions.ts](/src/shared/integrations/missions.ts), the panel entry in [ui-registry.ts](/src/renderer/src/integrations/ui-registry.ts). The sidebar row is seeded from the registry at startup by [seed-virtual-projects.ts](/src/main/app/startup/seed-virtual-projects.ts) — no DB migration.
- Toolbar wiring: [toolbar-catalog.ts](/src/renderer/src/features/toolbar/toolbar-catalog.ts) + [ToolbarPinnedItem.tsx](/src/renderer/src/features/toolbar/ToolbarPinnedItem.tsx) + [useToolbarActions.ts](/src/renderer/src/app/useToolbarActions.ts) + [AppTitlebar.tsx](/src/renderer/src/app/AppTitlebar.tsx)
- Grouping: [sidebar-category-grouping-contract.md](../../.claude/memory/contracts/sidebar-category-grouping-contract.md) (Prompt Tools membership + the 2026-08-31 conversion ledger entry)
- Onboarding pre-spawn exclusion: [onboarding-prespawn.ts](/src/shared/missions/onboarding-prespawn.ts)

## Related

### See also

- [onboarding.md](../../.claude/memory/onboarding.md) — the missions registry, onboarding pre-spawn, and the retired onboarding mission surfaces
- [email-cleanup.md](email-cleanup.md) — the Gmail cleanup engine (still powering the in-Gmail button + the mission's `/gmail/cleanup/*` calls)
- [INDEX.md](INDEX.md)

