Skip to content

Route map

The app shell (ControlCenterLayout) wraps every in-workspace route via a ShellRoute. Every in-shell destination is workspace-prefixed — /workspaces/:workspaceId/… — and the workspace id in the URL is the single source of truth for the active workspace. Only the pre-context surfaces have no prefix: /splash, /onboarding, /signed-out and the bare /workspaces picker, all full-screen and outside the shell.

The gate is complete when at least one forge is connected for the signed-in user and at least one workspace exists.

A missing credential and a missing setup are different screens, and the discriminator is users.onboarding_finished_at read off the caller’s own identity.me — never “workspaces exist”, which is wrong the moment someone is invited into a workspace they never created. With no forge connected, an account that has onboarded goes to /signed-out to re-authenticate; one that has not goes to /onboarding. While the flag is still unknown the guard holds the splash rather than guessing, because it never redirects back out of onboarding.

Path Screen
/splash Startup splash that resolves the onboarding gate
/onboarding API keys plus first-workspace setup
/signed-out Re-authenticate: the same forge-connections card Settings renders, with no step bar and no continue button — the router leaves on its own once a forge reports in
/workspaces Workspace list and picker
/workspaces/:workspaceId Redirects to /workspaces/:workspaceId/inbox

Paths below omit the /workspaces/:workspaceId prefix.

Path Query params Screen
/inbox Unified inbox: PRs classified by review lifecycle plus non-PR work blocking the operator. The post-guard landing route; a bare /workspaces/:workspaceId redirects here
/spaces Space surface, no space selected
/spaces/:spaceId ?m=<messageId>, ?tab=<key> One space; m deep-links to a message and is consumed once on open
/tickets Ticket board
/tickets/:ticketId Ticket master-detail
/projects/:projectId Project overview
/pull-requests PR list
/pull-requests/compose ?space=<spaceId> Compose a new pull request; space names the space whose isolated worktree supplies the branch
/pull-requests/:owner/:repo/:prNumber ?tab=<key> PR detail with diff viewer
/pipelines Pipeline run list
/pipelines/run ?templateId=<id> Manual run launcher
/pipelines/:runId Pipeline run detail (step timeline)
/plans Plan Studio hub: active plans, plan documents, playbooks
/plans/:kind/:id Plan Studio for one plan; kind is orchestration or document
/meetings Meetings list
/meetings/record Live meeting recording screen
/meetings/:meetingId Meeting detail: notes, transcript, action items, decisions
/calendar Calendar: month, week and agenda views
/calendar/:eventId Calendar event detail (sibling route; shares the calendar page key)
/newsfeed Newsfeed list
/newsfeed/article/:articleId Article reader
/observability Observability hub: live Agent Hub plus cost, usage, quota and behaviour analytics. Defaults to the Agent Hub tab
/users/:login GitHub user profile
/api-keys API key management. No navigation entry point — reachable only by URL
/settings/… Settings screens (below)

Conversations and threads have no route of their own — a thread is a conversation inside /spaces/:spaceId, opened as an editor tab rather than addressed by URL.

There is no /dashboard route and no dashboard screen. The analytics surface is /observability, reached from the sidebar footer.

There is no “Plans” sidebar item. Plan Studio opens as an editor tab from the plan’s row in the conversation that produced it; /plans and /plans/:kind/:id are deep links.

/observability and /pull-requests/compose have no entry in the route-title or breadcrumb registries, so both show the bare app name in the window title and no breadcrumb trail.

/settings redirects to /settings/you/profile. The sidebar’s settings button navigates to /settings/you/appearance instead, so the two entry points land on different pages. Cmd/Ctrl + , goes to /settings and therefore to the profile page.

Settings paths are namespaced by scopeyou/, workspace/, server/ — because the segment states who a change affects. Two paths predate the namespacing and are not scoped in the URL: /settings/memory and /settings/pipelines.

Path Screen
/settings/you/profile Profile and identity (the settings landing)
/settings/you/appearance Theme, language, typography, editor theme
/settings/you/notifications Per-event toggles, quiet hours
/settings/you/keybindings Keyboard shortcut reference (read-only)
/settings/you/devices Paired phones and remote control
/settings/you/audio Soundscape and audio output
/settings/you/newsfeed Feed management: sources, refresh, read state
Path Screen
/settings/workspace/general Name, logo, secret globs, review concurrency, branch naming, sync health, chat bridges, danger zone
/settings/workspace/members Roster, invites, audit trail
/settings/workspace/agents Registered agent identities
/settings/workspace/repositories Repositories registered in this workspace
/settings/workspace/skills Skill configuration
/settings/memory Workspace memory: facts, policies, knowledge graph
/settings/workspace/permissions Agent permissions: guardrail matrix and what-if probe
/settings/pipelines Pipeline templates
/settings/pipelines/:templateId Pipeline template editor (drag-and-drop canvas)
Path Screen
/settings/server/connection Connection and status
/settings/server/sso Single sign-on (SAML, OIDC, SCIM provisioning)
/settings/server/providers Model providers and adapters
/settings/server/mcp Built-in and external MCP servers
/settings/server/rigs Enclosures: what this host can boot, base images, custom images, running machines
/settings/server/voice Voice and meeting models (ASR, diarization)
/settings/server/diagnostics Diagnostics and privacy: sandboxing, embedding, sync engine, logging, crash reporting
/settings/server/sandbox Sandbox exec grants: commands an agent asked to run and you allowed
/settings/server/backup Backup and restore: install snapshots, per-workspace export, import and delete
/settings/server/about About and updates

kSettingsNav in lib/features/settings/settings_nav.dart is the single source of truth for this list; a test asserts every registered /settings/ route appears there exactly once.

Concern File
Router lib/router/app_router.dart
Route builders lib/router/routes.dart
Auth guards lib/router/guards.dart
Onboarding gate lib/features/auth/providers/onboarding_providers.dart
Settings navigation lib/features/settings/settings_nav.dart