Command Center
The four-tab operator surface for AI transformation — Operations, My Role, Delegate, Transformation — backed by typed system entities (Task, Workstream, Role) and a unified data pipeline.
Overview
The Command Center is the consolidated operator surface for visualizing AI-human work distribution, delegation pipelines, and transformation outcomes. It groups four purpose-built pages under /command-center/ with a shared tab strip, all reading from the same typed entity graph:
- Operations (
/command-center/operations) — Sankey flow of work across workstreams, roles, and delegation states - My Role (
/command-center/my-role) — the current user's workstreams, delegation queue, and readiness trend - Delegate (
/command-center/delegate) — the delegation wizard + candidate queue, scored by readiness - Transformation (
/command-center/transformation) — before/after snapshots, KPI strips, milestone timelines for shareable reporting
This feature unifies four previously-separate top-level routes into a cohesive workspace backed by three system entity types, named platform data sources, and a typed query layer — replacing the previous mix of public.actions-metadata parsing and tenant-local entity types.
Key Concepts
System entity types (platform-wide, tenant_id IS NULL)
Registered in features/entities/system-types/catalog.ts:
| Slug | Purpose | Core fields |
|---|---|---|
task | User-facing work items | description, status, delegation_state, task_type, work_category, measurement fields, readiness_score, guardrails, reversible_until, trial |
workstream | Organizational unit / swimlane | name, status, health, target_agent_share, loaded_hourly_cost, coverage_note, owner_user_id |
role | Human capacity unit | name, seniority, weekly_capacity_hours, description |
Task relations point at Workstream (in_workstream, one) and Role (owned_by_role, one). Per ADR-0004, Task entities are the product surface; public.actions (the action registry) is a parallel primitive and no Action entity type is registered.
Delegation states
The four-state lifecycle that drives the Sankey flow and the delegation wizard:
| State | Meaning |
|---|---|
human_only | No AI participation — baseline |
trialing | AI is running alongside a human reviewer — gathering confidence |
agent_supervised | AI runs first-draft, human approves — hours saved but still gated |
agent_autonomous | AI operates unattended within guardrails — full productivity gain |
Work category — the AI-transition lens
Orthogonal to task_type (which is the issue-tracker classification: task / bug / feature / milestone / question), work_category segments work by its AI-transition profile:
strategic— high-judgment, low-volume (board prep, market theses)operational— recurring, measurable (pipeline reviews, monthly closes)administrative— transactional, high-volume (invoice routing, CRM hygiene)
Measurement — flat fields, one contract
All measurement fields live flat on the Task entity's content (not nested) so the standard entity form builder, filter UI, and CSV I/O work without jsonSchema overrides:
measurement_cadence(daily / weekly / monthly / ad_hoc)measurement_volume_per_period(nonneg)measurement_human_time_per_run(hours, nonneg)measurement_agent_time_per_run(hours, nonneg)measurement_annual_dollar_value(currency, nonneg)
A thin adapter — extractMeasurement() in features/custom/server/work-model/measurement-adapter.ts — bridges flat fields to the nested TaskMeasurement shape that computeAnnualDollarValue() / computeWeeklyHumanHours() / computeWeeklyAgentHours() in features/actions/lib/measurement.ts expect. The arithmetic stays DRY; only the wire format translates.
Readiness score — 0..100 scale
Normalized for UI readability. Computed via computeReadinessScore() in features/custom/server/work-model/readiness.ts from work_category + measurement_cadence + measurement_volume_per_period + measurement_human_time_per_run. The Phase 5 migration converts any legacy 0..1 values to the new scale on write.
How It Works
Data flow
User opens /command-center/operations
→ server component creates Command Center named data sources
→ resolves the workstreams + roles EntityDataSource contracts
→ listWorkstreamsWithCoverage() reads entities[type=workstream]
→ joins task relations for coverage metrics
→ projects typed WorkstreamWithCoverage[] + aggregate counts
→ passes as props to client Sankey componentEvery Command Center page follows the same pattern: server-component SSR creates the named sources from features/custom/server/work-model/data-sources.ts, passes validated EntityDataSource contracts into features/custom/server/work-model/*.ts, then passes typed props to the client block. No client-side work-model fetches — the data is all SSR-hydrated.
Route structure
app/(app)/command-center/
├── layout.tsx # wraps all four tabs with <CommandCenterTabs />
├── operations/
│ ├── page.tsx
│ └── operations-client.tsx
├── my-role/
│ ├── page.tsx
│ └── my-role-content.tsx
├── delegate/
│ ├── page.tsx
│ ├── delegate-client.tsx
│ └── loading.tsx
└── transformation/
├── page.tsx
├── sections.tsx
├── data.ts
└── print-styles.tsxThe tab strip (features/custom/components/command-center/command-center-tabs.tsx) uses usePathname() to handle both bare paths and tenant-scoped URLs (/t/<slug>/command-center/...). The navigation config (features/navigation/defaults.ts) exposes Command Center as an expanded sidebar group (defaultOpen: true, collapsible: true) so the four tabs appear together.
Query layer
All work-model queries live in features/custom/server/work-model/:
| File | Exports |
|---|---|
data-sources.ts | createCommandCenterDataSources(), commandCenterEntitySource(), canonical source IDs |
task-queries.ts | DelegationCandidate, getDelegationQueue() |
workstream-queries.ts | WorkstreamCoverage, WorkstreamWithCoverage, getWorkstreamsWithCoverage() |
role-queries.ts | RoleRecord, RoleInventory, getRoleInventory(), listRolesForUser(), getRoleDelegationShare() |
transformation-queries.ts | TransformationSnapshot, getTransformationSnapshot() |
overnight-queries.ts | OvernightSummary, getOvernightSummary() |
promote.ts | promoteTask() — advances delegation_state and logs the promotion to a session |
readiness.ts | computeReadinessScore(), buildReadinessContext() |
agent-share.ts | TaskDelegationState, DELEGATION_STATE_LABELS |
measurement-adapter.ts | extractMeasurement(), extractDelegationState() — flat→nested bridge |
view-data-source-presets.ts | Registers the canonical sources as reusable view-editor source presets |
The canonical Command Center sources are all entity-native: task, workstream, role, milestone, and contest. Task-oriented queries read from entities with entity_type_slug = 'task' (plus joins to entity_relations for workstream + role). public.actions metadata is no longer parsed at read time.
Those same source definitions are also registered in the workspace-editor
library as Command Center source presets. Standalone views can import tasks,
delegationQueue, workstreams, roles, milestones, and contests from the
Library → Sources tab without copying route-local loader code into platform
views.
API Reference
getDelegationQueue(tenantId, options?) → DelegationCandidate[]
Returns Task entities ranked by readiness score, filtered to delegation_state ∈ {human_only, trialing} by default or by the supplied task EntityDataSource. Each candidate has: taskEntityId, description, work_category, readiness_score (0..100), delegation_state, and measurement (nested TaskMeasurement if all three core fields are present).
promoteTask(supabase, { taskEntityId, targetState }) → { taskEntityId, fromState, toState }
Advances a Task entity's delegation_state forward (human_only → trialing → agent_supervised → agent_autonomous). Writes the state change to entity.content.delegation_state and logs a session event. Idempotent on fromState === toState.
getWorkstreamsWithCoverage(tenantId, options?) → WorkstreamWithCoverage[]
Returns Workstream entities with rolled-up coverage metrics (weekly human hours, weekly agent hours, target agent share, actual agent share). Accepts a workstream EntityDataSource and joins entity_relations for in_workstream task references.
getTransformationSnapshot(tenantId) → TransformationSnapshot
The full Transformation page payload — before/after human hours per workstream, annual dollar value delta, delegation-state distribution, milestone timeline. Used by transformation-kpi-strip, transformation-before-after, transformation-human-agent-chart, transformation-milestone-timeline, transformation-workstream-rollup, transformation-narrative-quote.
Migration
The Phase 5 migration (features/inngest/functions/migrate-todos-to-task-entities.ts) carries the full work-model metadata from public.actions.metadata to the Task entity's content:
- Flat measurement fields map 1:1 from nested
TaskMeasurement readiness_scoreconverts 0..1 → 0..100 when detected as legacy scale- Legacy
content.categorylifts totask_type - Measurement helpers are re-applied via
extractMeasurement()when queried
Index support: supabase/migrations/20260423000000_task_entity_work_model_indexes.sql adds 4 partial expression indexes on entities.content ->> 'field' scoped to entity_type_slug='task' for fast filtering on delegation_state, work_category, measurement_cadence, and readiness_score.
For Agents
Agents can read and write Task entities via the standard entity tools — no command-center-specific tools required:
searchEntities({ typeSlug: "task", filter: { content: { delegation_state: "trialing" } } })updateEntity(id, { content: { delegation_state: "agent_supervised", readiness_score: 85 } })createRelation({ fromEntityId, toEntityId, relationshipType: "in_workstream" })
Heartbeat agents that promote tasks across delegation states should call promoteTask() from features/custom/server/work-model/promote.ts rather than writing content.delegation_state directly — promoteTask logs a session event for the pulse + audit trail.
Design Decisions
Why a unified /command-center/ namespace? Previously, the four pages lived at top-level (/operations, /my-role, /delegate, /transformation) with no visible grouping in the sidebar. Users didn't know they were part of the same workflow. Nesting under /command-center/ with a persistent tab strip makes the pipeline explicit: see the flow (Operations), find your work (My Role), promote candidates (Delegate), review outcomes (Transformation).
Why system entity types for Workstream and Role? Both existed as tenant-local entity types from the PR #829 seed. Making them system types gives platform TypeScript modules (like the work-model queries) a stable type import without requiring every tenant to register their own. The entity-type-access.ts resolver already prefers tenant-local over global, so existing seeded entities keep their entity_type_id intact — the system types are additive, not destructive.
Why flat measurement fields instead of nested? Nested measurement: { cadence, volume_per_period, ... } requires custom form builders, filter UIs, and CSV mappers to understand the jsonSchema nesting. Flat fields work with the stock entity surface for free — and the arithmetic helpers still consume the nested shape via a thin adapter, keeping the math DRY.
Why 0..100 readiness and not 0..1? Users read "85%" more naturally than "0.85". The data migration converts legacy values; all new code uses the 0..100 scale.
Why no Action entity type? Per ADR-0004, public.actions is the action registry (a parallel primitive to entities) — it stores trigger configs, cron schedules, and output contracts. Representing both the work item and the action config as entities would conflate two semantically different primitives. Task entities are for humans to see and manage; public.actions rows are internal automation infrastructure.
Related Modules
- Tasks — the action registry primitive and its trigger/dispatch system
- Sessions — execution records for promoted tasks
- Entity System — how system entity types register and resolve
- Block System — the 12 block components this feature hosts
- ADR-0004 — why Task entity and Action registry are separate
Entity System
The core data primitive of the Sprinter Platform. Every record in the system is an entity, typed by a DB-driven schema, stored in a universal table, and connected through a relationship graph.
Automation Ratio
The scoring engine for the gamification thesis — persistent time-series of agent-vs-human work ownership per tenant, workstream, role, and user.