Cosmo Docs

Getting Started with Cosmo

What happens on first login, the welcome modal, and how to set up your brand kit.

When you sign in to a new Cosmo organization for the first time, you'll see the Welcome Modal followed by four guided setup steps. This page explains what each step does and where the relevant settings live once the modal is dismissed.

Welcome Modal

The welcome modal appears once per user per organization — the first time you log in to that org on the desktop app. It will not appear again on subsequent logins, after signing out and back in, or on other devices.

It contains:

  • A founders' note from Rahul & Gaurav
  • A four-item capability grid showing what Cosmo can do
  • Four suggested Start here steps (described below)
  • A Get started button and a dismiss link

What triggers it

The "already seen" state lives on the membership row in the database — OrgMember.welcomeSeenAt. Immediately after auth resolves, the desktop reads GET /api/v1/auth/onboarding-state and opens the modal only when that timestamp is unset. Dismissing it (via "Get started", "I'll explore on my own", or the close button) posts /api/v1/auth/welcome-seen, which stamps the row.

The flag is stored per user per org: every teammate who joins an org sees the founder note the first time, and because it hangs off the membership, the modal re-appears when the same user later joins a different org.

Because the state is server-side, it survives things that clear local data:

  • Logging out and back in. Logout deliberately wipes all local app data (cosmo-data and renderer localStorage), so a device-local flag would re-show the modal on the next sign-in.
  • A reinstall or a new machine. The flag travels with the account, not the install.

Two caches sit in front of the database read, and neither can re-show a dismissed modal:

  • StoredAuth.welcomeSeen, populated from the auth deep link, answers for the modal when the app starts offline.
  • UserProfile.welcomeModalSeenAt (a cloud-synced orgId → ISO timestamp map) is retained for users who dismissed the modal before the database column existed. When that map — or a completed onboarding — shows the modal was already seen, the desktop hides it and back-fills welcomeSeenAt so the inference is only ever made once.

If the server can't be reached and there is no cached value, the modal stays hidden rather than risking a repeat; it opens on a later launch if the user genuinely hasn't seen it.

Onboarding chat

The onboarding conversation is gated on OrgMember.onboardingCompleted, written by /api/v1/auth/onboarding-complete when the chat finishes or the user clicks Skip setup. That write is awaited and retried once — losing it would onboard the user a second time, since the local copy of the flag is deleted by the logout wipe.

An in-progress onboarding chat is pointed to by UserProfile.onboardingSessionId, which is cloud-synced. A user who signs out mid-onboarding and returns resumes that conversation instead of being greeted again in a new session.

Setup Checklist

The Setup Checklist is a dismissable card at the top of the Hub's Dashboard tab that tracks the same four onboarding steps as the Welcome Modal's "Start here" list, but stays visible (and keeps ticking off items) across the whole life of a new org — not just the first login. Its header reads "Get set up" (with a live N/M count of applicable items) until everything is checked off, at which point it switches to the one-time completion message described under Dismissal.

It shows up to four steps, in this order:

StepScopeComplete when
Upload your brand kitOrg-wideThe org's brand kit (OrgOnboarding.brandKit) has a logo or at least one brand color set, or the org has a logo set from Clerk's "Create organization" screen (Organization.logoUrl) — both mean "the org has a logo," even though only an explicit Brand Kit upload writes to brandKit.logos
Connect an integrationPer memberThis member (MCPConfig.createdBy) has connected at least one MCP connector with status CONNECTED, or one hosted LOCAL (Atlassian, Slack, and other REMOTE_OAUTH connectors store their OAuth token on-device rather than in MCPConfig.credentials, so the server-side status field never flips to CONNECTED for them — hosting: LOCAL is the real signal)
Create your first workspacePer member, with a shared-workspace exceptionThis member (Workspace.createdBy) has created a real (non-seeded) workspace, or this member actually has access to a real shared workspace someone else created — via team membership or an explicit share grant, the same access rules the Workspaces list itself uses. Auto-provisioned workspaces (Workspace.seeded) never count for anyone — see below. A shared workspace existing somewhere in the org is not enough on its own — a member who was never added to that team and never had anything shared with them still needs their own workspace
Invite a teammateOrg-wide, admin-onlyThe org has more than one member, or at least one pending invite. This row is omitted entirely (not shown, not counted toward the 4-item total) for MEMBER/VIEWER roles — inviting is an OWNER/ADMIN-only action (see POST /org/invite), so it isn't an applicable step for a regular member

Why per-member for two items: a brand-new member who joins an org that's already fully set up still needs to personally connect a connector and create a workspace — inheriting a teammate's already-connected integration doesn't check that item for them (a shared workspace is the one exception, since it's usable org-wide). This is why a new member can see a checklist with two items still unchecked even when an existing admin's checklist reads 100% complete — and conversely, why an OWNER/ADMIN sees 4 items where a MEMBER sees only 3.

Completed items show a checkmark but keep their normal text styling (no strikethrough) — only the accent color and check icon indicate completion.

Real state, not a client flag

Item completion is computed server-side on each Hub load (GET /api/v1/setup-checklist), from the same Postgres/blob state the rest of the app reads — never from a locally-set flag. That means a fresh login on a different device shows exactly the same checklist state.

While the app is open, the Hub refetches checklist state automatically:

  • Whenever a workspace or team changes — creating a workspace ticks off that item live.
  • Whenever you return to the Hub from Settings — connecting an integration or uploading a brand kit both live in Settings, which fully unmounts the Hub while open, so returning remounts it and refetches.
  • Whenever the app window regains focus — inviting a teammate happens entirely in the web app (there's no invite UI in the desktop app), so it's the only signal available for a change made outside the app: switching back to the desktop app after sending an invite in the browser ticks off "Invite a teammate" without needing to sign out and back in.

Dismissal

Clicking the close (×) button hides the checklist immediately. Dismissal is stored on UserProfile.setupChecklistDismissedAt — a map of orgId → ISO timestamp, cloud-synced via SyncManager the same way UserProfile.welcomeModalSeenAt is (see Welcome Modal). It is:

  • Per user — dismissing it doesn't hide it for the rest of the org
  • Per org — keyed by orgId, so it re-appears if the user joins a different org
  • Persistent across restarts and reinstalls — synced via SyncManager, so it survives app restart and login from another device

Known limitation: unlike the Welcome Modal's dismissal (which moved to a DB column, OrgMember.welcomeSeenAt, specifically so it survives the logout wipe — see Welcome Modal), checklist dismissal still lives only on the cloud-synced UserProfile blob. The push is fire-and-forget and not retried, and logout wipes local app data — so a dismissal that hasn't finished syncing to the server before logout can be lost, occasionally re-showing the checklist once after a sign-out/sign-in.

If every applicable item completes, the card swaps its header for a one-time "🎉 You're all set up!" message (with every applicable item shown checked) for COMPLETION_AUTO_DISMISS_MS (4 seconds), then automatically dismisses itself — the same persisted dismissal as clicking the close button, so this celebration is shown exactly once per user per org. Closing it manually during that window dismisses it immediately instead of waiting out the timer.

Known limitation: there's currently no UI to un-dismiss the checklist. Once setupChecklistDismissedAt is set for a user/org (whether by clicking close, or by the auto-dismiss timer firing on a checklist that read as complete), it stays dismissed permanently — even if the underlying item logic changes later and would have produced a different result. To test as a "fresh" user against updated logic, use a brand-new member (or clear that user's local profile / UserProfile.setupChecklistDismissedAt entry for the org).

If an item later regresses after being marked complete (e.g. the org's only connector is removed) — but before the checklist has been dismissed — the checklist reappears/re-updates, since completion is recomputed from live state rather than cached at first completion.

Auto-provisioned workspaces never count toward "Create your first workspace" for anyone, including the org creator: both the personal default workspace every member gets and the shared "{Company} HQ" workspace that onboarding seeds are flagged internally as seeded, and the checklist excludes seeded workspaces regardless of who created them. So the member who created the org sees this item unchecked until they (or a teammate) create a real workspace, or they're given access to one someone else created.

Start Here Steps

Clicking a step row in the modal closes the modal and navigates directly to the relevant section.

StepWhat it does
Connect your integrationsOpens the Integrations section in Customize settings
Add your brand kitOpens the Brand Kit section in Customize settings
Tell Cosmo about your workFocuses the chat input so you can describe your team and context
Create your first artifactFocuses the chat input with a starter prompt: "Draft a one-page proposal for…"

Brand Kit

The Brand Kit view is accessible at any time via Customize → Brand Kit.

Only org owners and admins can upload or replace the logo — members and viewers see a read-only preview with no upload control.

Upload a PNG, SVG, JPG, or WebP logo (max 2 MB). The logo is displayed in a preview card with a checkerboard background to show transparency. Once uploaded, a "Replace logo" button appears.

Logos are stored as assets via onboarding-manager.saveAsset and resolved to a data: URL via resolveAssetUrl (the renderer is always loaded over http://, so a file:// URL would never load). The asset reference is saved in OrgOnboarding.brandKit.logos.

If no logo has been uploaded here yet, the Brand Kit falls back to displaying the logo the org used when it was created on the web Create organization form (if one was set). This fallback is display-only — it isn't copied into brandKit.logos — so the first manual upload always takes over permanently.

Brand Colors

Three color slots are available: Primary, Secondary, and Accent. Each has a color swatch, a hex preview, and an Edit button that opens the browser's native color picker. Colors are saved automatically on change.

Colors are stored in OrgOnboarding.brandKit and used by the AI when generating documents and proposals to match your brand identity.