Variation 8-2: Command Center Merged View Specification
Overview
A VS Code sidebar extension view with three tabs (Bolts, Specs, Overview) that displays project state derived from parsed markdown frontmatter. The UI is a pure representation of a centralized metadata state object - it does not perform parsing or state management.
Architecture Principle
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ File System │────>│ Metadata Store │────>│ UI Components │
│ (*.md files) │ │ (Single Source) │ │ (Read-only) │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│ │ │
File Watcher State Object Renders State
Parses YAML Emits Changes Subscribes to
Frontmatter State Updates
**Key Principles:**
- UI components are pure renderers - they receive state and render it
- All data transformations happen in the metadata store layer
- File parsing is isolated - changing parser doesn't affect UI
- UI can be swapped without touching data layer
---
Metadata State Object
Root State Structure
interface SpecsMDState {
// Current workspace context
workspace: {
name: string;
path: string;
memoryBankPath: string;
};
// Parsed artifacts indexed by ID
intents: Map<string, Intent>;
units: Map<string, Unit>;
stories: Map<string, Story>;
bolts: Map<string, Bolt>;
standards: Map<string, Standard>;
// Computed/derived state (cached, updated on change)
computed: {
currentIntent: Intent | null;
activeBolt: Bolt | null;
pendingBolts: Bolt[];
completedBolts: Bolt[];
activityFeed: ActivityEvent[];
overallProgress: ProgressMetrics;
};
// UI state (separate from data state)
ui: {
activeTab: 'bolts' | 'specs' | 'overview';
expandedIntents: Set<string>;
expandedUnits: Set<string>;
expandedBolts: Set<string>;
activityFilter: 'all' | 'stage' | 'bolt';
specsFilter: 'all' | 'active' | 'complete' | 'pending';
activitySectionHeight: number;
};
}
Core Entity Types
interface Intent {
id: string; // e.g., "011-vscode-extension"
name: string;
description?: string;
filePath: string;
// Relationships
unitIds: string[];
// Timestamps from frontmatter
created?: Date;
updated?: Date;
// Computed
status: 'pending' | 'active' | 'complete';
progress: number; // 0-100
}
interface Unit {
id: string; // e.g., "sidebar-provider"
name: string;
description?: string;
filePath: string;
// Relationships
intentId: string;
storyIds: string[];
// Timestamps
created?: Date;
updated?: Date;
// Computed
status: 'pending' | 'active' | 'complete';
progress: number;
}
interface Story {
id: string; // e.g., "001-tree-view"
name: string;
description?: string;
filePath: string;
// Relationships
unitId: string;
boltId?: string; // Associated bolt if any
// Status from frontmatter
status: 'pending' | 'active' | 'complete';
// Timestamps
created?: Date;
started?: Date;
completed?: Date;
}
interface Bolt {
id: string; // e.g., "bolt-sidebar-ui-1"
name: string;
description?: string;
filePath: string;
// Type determines stage pipeline
type: 'DDD' | 'Simple';
// Relationships
intentId: string;
unitId?: string;
storyIds: string[];
// Dependencies (from frontmatter)
requiresBolts: string[]; // Bolt IDs this bolt depends on
enablesBolts: string[]; // Bolt IDs that depend on this bolt
// Stage tracking
stages: BoltStages;
stagesCompleted: StageCompletion[];
// Status
status: 'pending' | 'active' | 'complete' | 'blocked';
// Timestamps from frontmatter
created?: Date;
started?: Date;
completed?: Date;
// Computed
progress: number;
currentStage: string;
isBlocked: boolean; // true if any requiresBolts are not complete
blockedBy: string[]; // IDs of incomplete required bolts
unblocksCount: number; // Number of bolts this enables (for prioritization)
}
interface BoltStages {
// DDD Bolt stages
model?: StageStatus;
design?: StageStatus;
adr?: StageStatus;
implement?: StageStatus;
test?: StageStatus;
// Simple Bolt stages
plan?: StageStatus;
}
type StageStatus = 'pending' | 'active' | 'complete' | 'skipped';
interface StageCompletion {
name: string;
completed: Date;
}
interface Standard {
id: string;
name: string;
category: 'tech-stack' | 'coding-standards' | 'system-architecture';
filePath: string;
updated?: Date;
}
Derived Types
interface ActivityEvent {
id: string;
type: 'bolt-created' | 'bolt-start' | 'bolt-complete' | 'stage-complete';
timestamp: Date;
// Display
icon: string;
iconClass: string;
text: string; // e.g., "Completed <strong>model</strong> stage"
// References
targetId: string; // Bolt ID
targetName: string; // Bolt name
tag: 'bolt' | 'stage';
}
interface ProgressMetrics {
totalIntents: number;
totalUnits: number;
totalStories: number;
totalBolts: number;
completedStories: number;
completedBolts: number;
overallPercent: number;
}
---
UI Component Specification
Tab Structure
┌─────────────────────────────────────────┐
│ SpecsMD [↻] [⚙] │ Header
├─────────────────────────────────────────┤
│ ⚡ Bolts │ 📋 Specs │ 📊 Overview │ Tabs
├─────────────────────────────────────────┤
│ │
│ [Tab Content Area] │ Content
│ │
├─────────────────────────────────────────┤
│ [ Dark ] [ Light ] │ Theme Toggle
└─────────────────────────────────────────┘
Bolts Tab Layout
┌─────────────────────────────────────────┐
│ CURRENT INTENT │
│ 011-vscode-extension │
│ ● 1 Active Bolts ○ 1 Queued ✓ 3 Done │
├─────────────────────────────────────────┤
│ 🎯 CURRENT FOCUS │
│ ┌─────────────────────────────────────┐ │
│ │ bolt-sidebar-ui-1 [In Progress]│ │ Expandable Card
│ │ DDD Bolt | Design Stage │ │
│ ├─────────────────────────────────────┤ │
│ │ [Progress Ring] Stage: Design │ │ Expanded Content
│ │ 40% 2 of 5 complete │ │
│ │ │ │
│ │ [M]──[D]──[A]──[I]──[T] │ │ Stage Pipeline
│ │ ✓ ● ○ ○ ○ │ │
│ │ │ │
│ │ Stories (1/3) │ │
│ │ ☑ Create sidebar layout │ │
│ │ ☐ Design tree view │ │
│ │ ☐ Implement expand/collapse │ │
│ │ │ │
│ │ [Continue] [Files] │ │
│ └─────────────────────────────────────┘ │
├─────────────────────────────────────────┤
│ UP NEXT 2 bolts │
│ ┌─────────────────────────────────────┐ │
│ │ 1 │ bolt-webview-panel-1 [M][D]... │ │ Queue Items
│ │ 2 │ bolt-command-palette [P][I][T] │ │
│ └─────────────────────────────────────┘ │
├═══════════════════════════════════════──┤ Resize Handle (draggable)
│ 🕐 RECENT ACTIVITY [All][S][B] │
│ ┌─────────────────────────────────────┐ │
│ │ ✓ Completed model stage 2h ago │ │ Activity Feed
│ │ bolt-sidebar-ui-1 STAGE │ │ (derived from
│ │ │ │ frontmatter dates)
│ │ ▶ Started bolt-sidebar-ui-1 3h ago │ │
│ │ bolt-sidebar-ui-1 BOLT │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────┘
Specs Tab Layout
┌─────────────────────────────────────────┐
│ Filter: [All Status ▼] │
├─────────────────────────────────────────┤
│ ▼ 📋 011-vscode-extension [75%] │ Intent (expandable)
│ ├─ ▼ ● sidebar-provider 2/3 │ Unit (expandable)
│ │ ├─ ✓ 001-tree-view │ Stories
│ │ ├─ ● 002-expand-collapse │
│ │ └─ ○ 003-file-icons │
│ └─ ▼ ✓ artifact-parser 3/3 │
│ ├─ ✓ 001-parse-frontmatter │
│ ├─ ✓ 002-extract-status │
│ └─ ✓ 003-validate-schema │
└─────────────────────────────────────────┘
Overview Tab Layout
┌─────────────────────────────────────────┐
│ OVERALL PROGRESS │
│ [████████████░░░░░░░░░░░░░░░░░░] 64% │
│ │
│ ┌─────────┐ ┌─────────┐ │
│ │ 64% │ │ 5/8 │ │
│ │Complete │ │ Stories │ │
│ └─────────┘ └─────────┘ │
│ ┌─────────┐ ┌─────────┐ │
│ │ 3/5 │ │ 1 │ │
│ │ Bolts │ │ Intents │ │
│ └─────────┘ └─────────┘ │
├─────────────────────────────────────────┤
│ INTENTS │
│ ┌─────────────────────────────────────┐ │
│ │ 📋 011-vscode-extension 75% │ │
│ │ 2 units | 6 stories │ │
│ └─────────────────────────────────────┘ │
├─────────────────────────────────────────┤
│ ACTIVE BOLTS │
│ ┌─────────────────────────────────────┐ │
│ │ ⚡ bolt-sidebar-ui-1 40% │ │
│ │ DDD | design stage │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────┘
---
State Derivation Logic
Activity Feed Builder
The activity feed is derived from bolt timestamps, not a separate log:
function buildActivityFeed(bolts: Map<string, Bolt>): ActivityEvent[] {
const events: ActivityEvent[] = [];
for (const bolt of bolts.values()) {
// Bolt created event
if (bolt.created) {
events.push({
id: `${bolt.id}-created`,
type: 'bolt-created',
timestamp: bolt.created,
icon: '+',
iconClass: 'bolt-created',
text: `Created <strong>${bolt.name}</strong>`,
targetId: bolt.id,
targetName: bolt.name,
tag: 'bolt'
});
}
// Bolt started event
if (bolt.started) {
events.push({
id: `${bolt.id}-started`,
type: 'bolt-start',
timestamp: bolt.started,
icon: '▶',
iconClass: 'bolt-start',
text: `Started <strong>${bolt.name}</strong>`,
targetId: bolt.id,
targetName: bolt.name,
tag: 'bolt'
});
}
// Stage completion events
for (const stage of bolt.stagesCompleted) {
events.push({
id: `${bolt.id}-${stage.name}-complete`,
type: 'stage-complete',
timestamp: stage.completed,
icon: '✓',
iconClass: 'stage-complete',
text: `Completed <strong>${stage.name}</strong> stage`,
targetId: bolt.id,
targetName: bolt.name,
tag: 'stage'
});
}
// Bolt completed event
if (bolt.completed) {
events.push({
id: `${bolt.id}-completed`,
type: 'bolt-complete',
timestamp: bolt.completed,
icon: '✔',
iconClass: 'bolt-complete',
text: `Completed <strong>${bolt.name}</strong>`,
targetId: bolt.id,
targetName: bolt.name,
tag: 'bolt'
});
}
}
// Sort by timestamp descending (most recent first)
return events.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
}
Up Next Queue
Pending bolts ordered by dependency graph - unblocked bolts first, prioritized by how many downstream bolts they enable:
/**
* Determines if a bolt is blocked by checking if all required bolts are complete
*/
function isBoltBlocked(bolt: Bolt, bolts: Map<string, Bolt>): boolean {
if (!bolt.requiresBolts || bolt.requiresBolts.length === 0) {
return false; // No dependencies = not blocked
}
return bolt.requiresBolts.some(requiredId => {
const requiredBolt = bolts.get(requiredId);
return !requiredBolt || requiredBolt.status !== 'complete';
});
}
/**
* Gets the list of bolt IDs that are blocking this bolt
*/
function getBlockingBolts(bolt: Bolt, bolts: Map<string, Bolt>): string[] {
if (!bolt.requiresBolts) return [];
return bolt.requiresBolts.filter(requiredId => {
const requiredBolt = bolts.get(requiredId);
return !requiredBolt || requiredBolt.status !== 'complete';
});
}
/**
* Counts how many pending bolts this bolt would unblock when completed
*/
function countUnblocks(boltId: string, bolts: Map<string, Bolt>): number {
return Array.from(bolts.values()).filter(b =>
b.status === 'pending' &&
b.requiresBolts?.includes(boltId)
).length;
}
/**
* Gets pending bolts ordered by dependency priority:
* 1. Unblocked bolts come first (all requiresBolts are complete)
* 2. Among unblocked, prioritize by unblocksCount (enables more work)
* 3. Blocked bolts come last, showing what's blocking them
*/
function getUpNextBolts(bolts: Map<string, Bolt>): Bolt[] {
const pendingBolts = Array.from(bolts.values())
.filter(b => b.status === 'pending')
.map(bolt => ({
...bolt,
isBlocked: isBoltBlocked(bolt, bolts),
blockedBy: getBlockingBolts(bolt, bolts),
unblocksCount: countUnblocks(bolt.id, bolts)
}));
return pendingBolts.sort((a, b) => {
// Unblocked bolts come first
if (a.isBlocked !== b.isBlocked) {
return a.isBlocked ? 1 : -1;
}
// Among unblocked, prioritize by how many bolts they enable
if (!a.isBlocked && !b.isBlocked) {
return b.unblocksCount - a.unblocksCount;
}
// Among blocked, sort by fewest blockers (closest to being unblocked)
return a.blockedBy.length - b.blockedBy.length;
});
}
Dependency Visualization
In the UI, blocked bolts show their blockers:
UP NEXT 3 bolts
┌─────────────────────────────────────────────┐
│ 1 │ bolt-webview-panel-1 [M][D][A][I][T]│ Ready (unblocked)
│ │ Enables: 2 bolts │
├─────────────────────────────────────────────┤
│ 2 │ bolt-command-palette [P][I][T] │ Ready (unblocked)
│ │ No dependencies │
├─────────────────────────────────────────────┤
│ 🔒│ bolt-sidebar-provider [M][D][A][I][T]│ Blocked
│ │ Waiting: bolt-artifact-parser-1 │
└─────────────────────────────────────────────┘
Progress Calculation
function calculateProgress(entity: { stories: Story[] }): number {
const total = entity.stories.length;
if (total === 0) return 0;
const completed = entity.stories.filter(s => s.status === 'complete').length;
return Math.round((completed / total) * 100);
}
function calculateBoltProgress(bolt: Bolt): number {
const stages = Object.values(bolt.stages);
const total = stages.length;
if (total === 0) return 0;
const completed = stages.filter(s => s === 'complete').length;
return Math.round((completed / total) * 100);
}
---
Frontmatter Schema
Bolt Frontmatter
---
id: bolt-sidebar-ui-1
name: Sidebar UI Implementation
type: DDD
intent: 011-vscode-extension
unit: sidebar-provider
status: active
# Dependencies
requires_bolts:
- bolt-artifact-parser-1 # Must be complete before this bolt can start
enables_bolts:
- bolt-sidebar-provider-1 # Will be unblocked when this bolt completes
# Timestamps (ISO 8601)
created: 2025-12-26T09:00:00Z
started: 2025-12-26T10:00:00Z
completed: null
# Stage tracking
stages:
model: complete
design: active
adr: pending
implement: pending
test: pending
stagesCompleted:
- name: model
completed: 2025-12-26T10:30:00Z
# Associated stories
stories:
- 001-create-sidebar-layout
- 002-design-tree-view
- 003-implement-expand-collapse
---
Story Frontmatter
---
id: 001-tree-view
name: Tree View Implementation
unit: sidebar-provider
status: complete
created: 2025-12-25T14:00:00Z
started: 2025-12-25T14:30:00Z
completed: 2025-12-25T16:00:00Z
---
---
Implementation Notes
State Update Flow
- File watcher detects change in `memory-bank/**/*.md`
- Parser reads and parses affected file's frontmatter
- Metadata store updates relevant entity in state
- Computed properties are recalculated (activity feed, progress, etc.)
- State change event emitted
- UI components re-render with new state
UI Subscription Pattern
// UI subscribes to state changes
stateStore.subscribe((state: SpecsMDState) => {
// Re-render affected components
renderBoltsTab(state);
renderSpecsTab(state);
renderOverviewTab(state);
});
// UI actions dispatch to store
function onBoltClick(boltId: string) {
stateStore.dispatch({ type: 'EXPAND_BOLT', payload: boltId });
}
Separation Boundaries
| Layer | Responsibility | Does NOT do | |-------|----------------|-------------| | File Watcher | Detect file changes, debounce | Parse content | | Parser | Extract frontmatter, validate schema | Store state | | State Store | Manage state, compute derived values | Render UI | | UI Components | Render state, handle user input | Parse files, compute data |
---
Visual Design Tokens
/* Status Colors */
--status-complete: #22c55e; /* Green */
--status-active: #f97316; /* Orange */
--status-pending: #6b7280; /* Gray */
--status-blocked: #ef4444; /* Red */
--status-info: #3b82f6; /* Blue */
/* Accent */
--accent-primary: #f97316; /* Orange - brand color */
/* Stage Pipeline Icons */
DDD: M (Model) → D (Design) → A (ADR) → I (Implement) → T (Test)
Simple: P (Plan) → I (Implement) → T (Test)
---
File References
- **HTML Mockup**: `variation-8-2.html`
- **Activity Timeline Variant**: `variation-8a-command-center-timeline.html`