Skip to main content

Command Center

Command Center is a Next.js web application that provides a real-time operational dashboard for Equabot. It connects to the Equabot gateway and the local orchestration system to display agent status, task priorities, and system health.

Architecture

Browser (PWA)
    |
    v
Command Center (Next.js 16, port 3001)
    |
    +-- /api/chat ----------------+-> Ollama (local, port 11434)    [routingMode=local]
    |                             +-> OpenAI API (direct)            [model contains openai/]
    |                             \-> Equabot Gateway (port 18789)   [default]
    +-- /api/events ---------------> SSE stream for UI refresh signals
    +-- /api/health ---------------> Equabot Gateway (port 18789)
    +-- /api/heartbeat/state ------> Heartbeat status service
    +-- /api/compute --------------> Local system metrics
    +-- /api/models/* -------------> Local model probes + gateway model catalog
    +-- /api/gateway-sessions/* ---> Gateway session inspection
    +-- /api/tasks/stack ----------> GitHub Projects + orchestration stack data
    +-- /api/conversations/* ------> Conversation persistence APIs
    +-- /api/orchestration/* ------> Orchestration state files
    \-- /api/comet/lifecycle ------> Comet-Bridge run lifecycle state sync
Command Center reads orchestration state from local JSON files written by the orchestration system and routes chat messages based on routing mode and model selection.

Key components

ComponentPurpose
StatusDashboardReal-time gateway health, compute metrics, agent summary, and queue counters
AgentMonitorActive/blocked agent list with instruct and respawn actions
PriorityStackScore-ranked task sidebar sourced from GitHub Projects or local stack data
ComputeMonitorFocused compute panel (CPU/RAM/Ollama) with 10-second refresh
OrchestrationTreeHierarchical orchestration/task visualization panel
QuickActionsCategorized command buttons (Tasks, Communication, Analysis, System)

Setup

Prerequisites

  • Node.js 22+
  • Equabot gateway running on port 18789

Environment

Create .env.local:
EQUABOT_GATEWAY_URL=http://localhost:18789
EQUABOT_GATEWAY_TOKEN=your-token-here

# Optional -- only needed for OpenAI direct routing
OPENAI_API_KEY=sk-...

# Optional -- override local Ollama endpoint (default: http://localhost:11434)
OLLAMA_URL=http://localhost:11434

Run

npm install
npm run dev    # Starts on port 3001

API routes

Core routes used by the Command Center UI:
RouteMethodAuthDescription
/api/chatPOSTYesRoutes chat and attachments to Ollama, OpenAI direct, or Equabot gateway
/api/eventsGET (SSE)YesReal-time event stream consumed by useEventStream
/api/healthGETNoGateway health check with latency
/api/heartbeat/stateGETYesHeartbeat state used by StatusDashboard
/api/computeGETYesLocal CPU, RAM, and Ollama metrics
/api/gateway/configGETYesGateway model defaults (primary, fallbacks, provider catalog)
/api/models/statusGETYesAggregated local/gateway model availability
/api/tasks/stackGETYesPriority stack data (GitHub Projects, local, remote, bundled fallback)
/api/conversationsGET/POSTYesConversation collection (list/create)
/api/conversations/[id]GET/PUT/DELETEYesConversation detail operations
/api/conversations/[id]/messagesPOST/DELETEYesConversation message append/clear
/api/orchestration/statusGETYesAggregated agent/queue/blocker status
/api/orchestration/instructPOSTYesSend instruction to a blocked agent
/api/orchestration/respawnPOSTYesRespawn a stuck agent session
/api/orchestration/cleanupPOSTYesDeduplicate and TTL-prune blocked agents
/api/comet/lifecyclePOSTNoComet-Bridge run lifecycle sync (start/update/complete/abort/fail/get)
Additional utility routes: /api/gateway-sessions/*, /api/task-threads, /api/docs/*, /api/threads/*, /api/preferences, /api/report-issue.

Task stack contract

/api/tasks/stack is the canonical normalization adapter. It ingests GitHub Project items (24-field inventory) and produces a unified TaskStackItem payload consumed by all UI surfaces. The response includes a schemaVersion field for observability.
Last verified against source: 2026-02-28
The gh project field-list --format json CLI does not distinguish text, number, and date fields — all report as ProjectV2Field. Only ProjectV2SingleSelectField is identified by type. The update-project-field.py helper infers field type from the value format (numeric values use --number, YYYY-MM-DD patterns use --date, otherwise --text).
Visible fields (17 table columns)
#Field NameField TypeOptions / Details
1TitleTitle (built-in)Issue/item title with link to source repo
2AssigneesAssignees (built-in)GitHub users
3Linked pull requestsLinked PRs (built-in)Auto-linked PRs (draft/open/merged)
4Sub-issues progressSub-issues progress (built-in)Segmented bar; numerical ratio (e.g. 2/5)
5PrioritySingle select (custom)P0 - Critical, P1 - High, P2 - Medium, P3 - Low
6Stack RankNumber (custom)Primary sort key; ascending
7UrgencySingle select (custom)Urgent, High, Normal, Low
8Blocked ByText (custom)Free-text dependency/blocker references
9Equabot SessionText (custom)Equabot session links or IDs
10Comet Browser ThreadText (custom)Comet browser thread references
11Comet Browser SpaceText (custom)Comet browser space references
12Gmail Email ThreadText (custom)Gmail thread links
13Shortwave AppText (custom)Shortwave references
14NotebookLMText (custom)NotebookLM links
15Google Drive FolderText (custom)Google Drive folder URL
16QBO LinkText (custom)QuickBooks Online links
17Google DocText (custom)Google Doc links
Hidden fields (7 — configured but not displayed as columns)
#Field NameField TypeDetails
18StatusSingle select (built-in)Todo, In Progress, Done; used by filter and board grouping
19LabelsLabels (built-in)GitHub issue labels
20MilestoneMilestone (built-in)GitHub milestones
21RepositoryRepository (built-in)Multi-repo source field
22TypeType (built-in)Issue type classification
23ReviewersReviewers (built-in)PR reviewers
24Parent issueParent issue (built-in)Hierarchy parent reference
View configuration (Stack Ranked Priority List)
  • Group by: Priority
  • Sort: Stack Rank ascending (primary), Priority ascending (secondary)
  • Filter: -status:Done
  • Field sum: Count
  • Default repository: Balancing-Rock/command-center-so
Project owner mapping: Two GitHub owners reference “Project #4” with different internal IDs. Orchestration scripts must specify --project-owner explicitly to target the correct project.
OwnerProject #Internal IDDefault in Scripts
ShawnOwen4PVT_kwHOAX66ks4BOENIupdate-project-field.py, sync-project-ranks.py
Balancing-Rock4PVT_kwDOD2hUnc4BPXw1backfill-project4-fields.sh, project-sync.py

Issue ingestion

Issues from 9 connected repositories are automatically added to Project #4 through two mechanisms. The GitHub Team plan limits built-in auto-add workflows to 5 per project; additional repos use a GitHub Actions workflow. Method A — Built-in Project Workflows (5 repos) Configured directly on the project under Settings > Workflows. Each triggers when a new or updated item matches the is:issue filter.
RepositoryWorkflow Name
stacks-ranking-prioritiesAuto-add to project
command-center-soAuto-add: command-center-so
stack-ranked-prioritiesAuto-add: stack-ranked-priorities
Food-Tracking_AppAuto-add: Food-Tracking_App
sscs-qbo-syncAuto-add: sscs-qbo-sync
Method B — GitHub Actions (4 repos) Each repo contains .github/workflows/auto-add-to-project.yml using actions/add-to-project@v1.0.2, authenticated via the ADD_TO_PROJECT_PAT classic PAT (repo + project scopes).
RepositoryTriggerAuth
task-threadsissues: [opened]Org secret (Balancing-Rock)
demo-repositoryissues: [opened]Org secret (Balancing-Rock)
Speed-Reader-Appissues: [opened]Org secret (Balancing-Rock)
EQUAStart/equabotissues: [opened, transferred, reopened]Repo secret (cross-org)
EQUAStart/equabot uses a repo-level secret because GitHub org secrets do not cross org boundaries. The PAT itself is scoped to the user account and covers both orgs. Canonical architecture reference: project-auto-add-flowchart.md

Source priority

The stack adapter tries these sources in order:
  1. GitHub Projects (live data via gh CLI)
  2. Local stack file (for local dev with recent syncs)
  3. Remote compute API (if configured)
  4. Bundled data (static fallback)

Task identity

Tasks use a composite identity with precedence:
  1. projectItemId (GitHub Project item ID — used for project mutations)
  2. githubIssueNumber (cross-repo references)
  3. slug (UI/session alias)

Priority and status authority

GitHub Project fields (Priority, Status, Stack Rank, Urgency) are authoritative. The UI may compute display-only decorations but does not override the normalized values from the API payload.

Blocker convention

The Blocked By text field supports parseable tokens:
PatternExample
#N (same-repo issue)#123
issue:Nissue:456
owner/repo#N (cross-repo)Balancing-Rock/equabot#789
item:PVTI_xxx (project item)item:PVTI_abc123
session:... (session dependency)session:agent:main:task-thread:42
Tokens are comma- or semicolon-separated. Optional annotation text after -- is stripped before parsing.

Session linkage

Sessions are linked to task threads using cascade matching:
  1. Equabot session key (strongest match)
  2. GitHub issue number (extracted from session label)
  3. Slug (legacy fallback)

Runtime mapping

Each project field anchors a specific runtime entity:
System EntityProject FieldsPurpose
Task ThreadTitle, Repository, Type, Parent issueCanonical thread identity and hierarchy
Priority StackPriority, Stack Rank, Urgency, StatusOrdering, triage, and lifecycle
Dependency GraphBlocked By, Sub-issues progressBlockers and aggregate completion
Agent Runtime SessionEquabot SessionPrimary orchestrator/agent context
Browser Subagent ContextComet Browser Thread, Comet Browser SpaceBrowser automation and research context
Conversation ContextGmail Email Thread, Shortwave App, NotebookLMCommunication and knowledge context
Artifact LayerGoogle Drive Folder, Google Doc, QBO LinkPersistent deliverables and finance links
The unified runtime chain is: Task ThreadAgent SessionSubagent ContextConversation SurfacesArtifacts Where:
  • Agent Session is anchored by the Equabot Session field.
  • Subagent Context is anchored by the Comet Browser fields.
  • Conversation Surfaces are anchored by email and research fields (Gmail, Shortwave, NotebookLM).
  • Artifacts are anchored by Drive, Docs, and QBO fields.
This mapping allows different UI layouts (table, board, conversation panel, session monitor) to render the same underlying thread state from one project schema.

Polling and real-time behavior

Command Center uses SSE as the primary mechanism for UI update triggers, with periodic polling as fallback.
Endpoint(s)MechanismIntervalComponent
/api/eventsSSE (primary)ContinuousAgentMonitor, PriorityStack, others
/api/orchestration/statusPoll fallback60sAgentMonitor
/api/tasks/stackPoll15mPriorityStack full data refresh
/api/tasks/stackLocal recalculation60sPriorityStack live score and age updates
/api/computePoll10sComputeMonitor
/api/compute, /api/orchestration/status, /api/health, /api/heartbeat/stateBatched poll30sStatusDashboard

Orchestration integration

Command Center reads these files from the orchestration directory:
FileContents
global-stack.jsonPriority-ranked task list
blocked-agents.jsonBlocked agents and threads
work-queue.jsonActive sessions, completed tasks, stalled items
learnings.jsonlDaily learnings log

Orchestration scripts

These Python scripts in equabot/orchestration/ interact with GitHub Project V2 fields:
ScriptPurposeInvocation
update-project-field.pyUpdate any project field by human-readable namepython3 update-project-field.py <issue_ref> <field_name> <value>
sync-project-ranks.pySync Stack Rank from global-stack.json to projectCron-driven; reads global-stack.json
backfill-project4-fields.shBackfill Priority and Urgency from issue labelsManual; one-time setup
project-sync.pySync project items to Priority Stack cacheCron-driven
verify-sync-chain.pyVerify sync chain integrity across GDrive, local threads, global-stack, GitHub Project #4, and CC APIpython3 verify-sync-chain.py [--issues REF,...] [--json] [--skip-gdrive] [--skip-cc]

update-project-field.py

Unified helper for updating any GitHub Project V2 custom field by human-readable inputs. Resolves all identifiers at runtime via the gh CLI with zero raw GraphQL.
python3 update-project-field.py <issue_ref> <field_name> <value> [--project-owner OWNER] [--project-number N] [--dry-run]
Arguments:
  • issue_ref — Issue URL (https://github.com/owner/repo/issues/N) or shortref (owner/repo#N)
  • field_name — Human-readable project field name (e.g., "Google Drive Folder", "Priority", "Stack Rank")
  • value — Value to set. For single-select fields, use the option name (e.g., "P1 - High")
Flags:
  • --project-owner — GitHub project owner (default: ShawnOwen)
  • --project-number — GitHub project number (default: 4)
  • --dry-run — Resolve all IDs and print the gh project item-edit command without executing
Field type auto-detection: The gh CLI does not expose granular field types for text, number, and date fields (all report as ProjectV2Field). The script infers the correct gh project item-edit flag from the value format:
Value PatternDetected TypeCLI Flag
Has options in field metadataSingle select--single-select-option-id
Matches YYYY-MM-DDDate--date
Valid integer or floatNumber--number
Anything elseText--text
Examples:
# Set a text field
python3 update-project-field.py EQUAStart/equabot#14 "Google Drive Folder" "https://drive.google.com/..."

# Set a number field
python3 update-project-field.py EQUAStart/equabot#14 "Stack Rank" 3

# Set a single-select field
python3 update-project-field.py EQUAStart/equabot#14 "Priority" "P1 - High"

# Dry run with a different project owner
python3 update-project-field.py --dry-run --project-owner Balancing-Rock Balancing-Rock/command-center-so#34 "Priority" "P2 - Medium"
Error handling: Exits non-zero with actionable messages for invalid issue references, issues not in the project, unknown field names (lists available fields), unknown option names (lists valid options), and gh CLI failures.

Tech stack

  • Framework: Next.js 16 (App Router)
  • Language: TypeScript
  • Styling: Tailwind CSS 4
  • Icons: Heroicons
  • Auth: NextAuth.js middleware
  • State: React hooks

Troubleshooting

Turbopack HMR errors

Known Next.js 16 issue (“Module factory not available”). Quick fixes:
  1. Hard-refresh browser (Cmd+Shift+R)
  2. Restart dev server (npm run dev)
  3. Full cache clear (rm -rf .next && npm run dev)
  4. Fallback to webpack (npx next dev --no-turbo)

404 on API routes during development

Usually caused by stale Turbopack cache state. The predev script clears the dev cache before startup to reduce this.