helixevo 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,15 @@ All notable changes to HelixEvo are documented here.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.6.1] - 2026-03-24
8
+
9
+ ### Added
10
+ - Shared dashboard operator-flow helpers for loop-stage breadcrumbs, contextual surface handoffs, curated release spotlight content, and guide deep-link integration
11
+
12
+ ### Changed
13
+ - Overview, Projects, Research, Co-Evolution, Ontology, and Topology now expose clearer operator breadcrumbs, adjacent control links, and stronger next-step empty-state onboarding
14
+ - Overview release spotlight is now curated through a dedicated helper so post-release guidance stays easy to update and does not silently drift stale
15
+
7
16
  ## [0.6.0] - 2026-03-24
8
17
 
9
18
  ### Added
@@ -6,6 +6,9 @@ import { ConsolePanel } from '@/components/console-panel'
6
6
  import { MetricCard } from '@/components/metric-card'
7
7
  import { PageHero } from '@/components/page-hero'
8
8
  import { SectionFrame } from '@/components/section-frame'
9
+ import { OperatorLoopTrail } from '@/components/operator-loop-trail'
10
+ import { SurfaceJumpLinks } from '@/components/surface-jump-links'
11
+ import { NextStepEmptyState } from '@/components/next-step-empty-state'
9
12
 
10
13
  type RunState = 'idle' | 'running' | 'success' | 'error' | 'stopped'
11
14
  type CommandName = 'evolve' | 'research' | 'generalize'
@@ -283,17 +286,20 @@ export default function CoEvolutionClient({ summary, ontology }: Props) {
283
286
  <span className="badge badge-gray">review threshold {(summary.governance.profile.reviewThreshold * 100).toFixed(0)}%</span>
284
287
  </div>
285
288
  </div>
286
- <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
287
- <button onClick={() => handleRun('research')} disabled={runState === 'running'} className="badge badge-blue" style={{ border: 'none', cursor: 'pointer' }}>Run research</button>
288
- <button onClick={() => handleRun('evolve')} disabled={runState === 'running'} className="badge badge-green" style={{ border: 'none', cursor: 'pointer' }}>Run evolve</button>
289
- <button onClick={() => handleRun('generalize')} disabled={runState === 'running'} className="badge badge-purple" style={{ border: 'none', cursor: 'pointer' }}>Run generalize</button>
290
- <Link href="/ontology" className="badge badge-gray">Open ontology</Link>
291
- <Link href="/topology" className="badge badge-gray">Open topology</Link>
289
+ <div style={{ display: 'grid', gap: 10 }}>
290
+ <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
291
+ <button onClick={() => handleRun('research')} disabled={runState === 'running'} className="badge badge-blue" style={{ border: 'none', cursor: 'pointer' }}>Run research</button>
292
+ <button onClick={() => handleRun('evolve')} disabled={runState === 'running'} className="badge badge-green" style={{ border: 'none', cursor: 'pointer' }}>Run evolve</button>
293
+ <button onClick={() => handleRun('generalize')} disabled={runState === 'running'} className="badge badge-purple" style={{ border: 'none', cursor: 'pointer' }}>Run generalize</button>
294
+ </div>
295
+ <SurfaceJumpLinks surface="coevolution" variant="compact" title="Response handoffs" />
292
296
  </div>
293
297
  </div>
294
298
  }
295
299
  />
296
300
 
301
+ <OperatorLoopTrail surface="coevolution" />
302
+
297
303
  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 16 }}>
298
304
  <MetricCard label="Open pressure" value={summary.pressureLifecycle.open} sublabel={`${summary.pressureLifecycle.highPriorityOpen} high-priority waiting for response`} tone={summary.pressureLifecycle.open > 0 ? 'yellow' : 'green'} icon="!" />
299
305
  <MetricCard label="Promotion-ready motifs" value={summary.pressureMotifs.promotionReady} sublabel={`${summary.pressureMotifs.total} recurring motifs tracked`} tone="purple" icon="⇄" />
@@ -403,10 +409,13 @@ export default function CoEvolutionClient({ summary, ontology }: Props) {
403
409
  </div>
404
410
  </div>
405
411
  )) : (
406
- <div className="empty-state" style={{ padding: 24 }}>
407
- <div className="empty-state-title">No promotion-ready motifs yet</div>
408
- <div className="empty-state-desc">Recurring cross-project demand will appear here once the same pressure region repeats often enough to justify generalization.</div>
409
- </div>
412
+ <NextStepEmptyState
413
+ title="No promotion-ready motifs yet"
414
+ description="Recurring cross-project demand will appear here once the same pressure region repeats often enough to justify generalization instead of one-off local response."
415
+ command="helixevo project-setup <path>"
416
+ pageLink={{ label: 'Open Projects', href: '/projects', tone: 'blue' }}
417
+ guideLink={{ label: 'Guide · Adaptation Loop', anchor: 'loop', tone: 'purple' }}
418
+ />
410
419
  )}
411
420
  </div>
412
421
  </SectionFrame>
@@ -430,10 +439,13 @@ export default function CoEvolutionClient({ summary, ontology }: Props) {
430
439
  <div className="metric-card-sublabel">{lane.resolving} resolving • {lane.exploratory} exploratory • {lane.none} non-resolving</div>
431
440
  </div>
432
441
  )) : (
433
- <div className="empty-state" style={{ gridColumn: '1 / -1', padding: 24 }}>
434
- <div className="empty-state-title">No intervention records yet</div>
435
- <div className="empty-state-desc">Run research, evolve, or generalize to start populating the governed response ledger.</div>
436
- </div>
442
+ <NextStepEmptyState
443
+ title="No intervention records yet"
444
+ description="The governed response ledger will start populating once pressure is routed into live research, evolve, or generalize work."
445
+ command="helixevo evolve"
446
+ pageLink={{ label: 'Open Research', href: '/research', tone: 'blue' }}
447
+ guideLink={{ label: 'Guide · Surface Map', anchor: 'surfaces', tone: 'purple' }}
448
+ />
437
449
  )}
438
450
  </div>
439
451
  </SectionFrame>
@@ -472,10 +484,13 @@ export default function CoEvolutionClient({ summary, ontology }: Props) {
472
484
  </div>
473
485
  </div>
474
486
  )) : (
475
- <div className="empty-state" style={{ padding: 24 }}>
476
- <div className="empty-state-title">No project response hotspots yet</div>
477
- <div className="empty-state-desc">Project-linked pressure will appear here once failures and project analysis produce current demand.</div>
478
- </div>
487
+ <NextStepEmptyState
488
+ title="No project response hotspots yet"
489
+ description="Project-linked pressure will appear here once failures and project analysis produce current demand for the response loop to act on."
490
+ command="helixevo project-setup <path>"
491
+ pageLink={{ label: 'Open Projects', href: '/projects', tone: 'blue' }}
492
+ guideLink={{ label: 'Guide · Quick Start', anchor: 'quickstart', tone: 'purple' }}
493
+ />
479
494
  )}
480
495
  </div>
481
496
  </SectionFrame>
@@ -501,10 +516,13 @@ export default function CoEvolutionClient({ summary, ontology }: Props) {
501
516
  </div>
502
517
  </div>
503
518
  )) : (
504
- <div className="empty-state" style={{ padding: 24 }}>
505
- <div className="empty-state-title">No transfer evidence yet</div>
506
- <div className="empty-state-desc">Once recurring pressure is promoted into reusable generalized skill knowledge, realized transfer evidence will appear here.</div>
507
- </div>
519
+ <NextStepEmptyState
520
+ title="No transfer evidence yet"
521
+ description="Transfer evidence appears after recurring pressure is promoted into reusable generalized knowledge rather than staying trapped in local fixes."
522
+ command="helixevo generalize"
523
+ pageLink={{ label: 'Open Ontology', href: '/ontology', tone: 'green' }}
524
+ guideLink={{ label: 'Guide · Semantic Control', anchor: 'semanticcontrol', tone: 'purple' }}
525
+ />
508
526
  )}
509
527
  </div>
510
528
  </SectionFrame>
@@ -548,10 +566,13 @@ export default function CoEvolutionClient({ summary, ontology }: Props) {
548
566
  </div>
549
567
  </div>
550
568
  )) : (
551
- <div className="empty-state" style={{ padding: 24 }}>
552
- <div className="empty-state-title">No open pressure backlog</div>
553
- <div className="empty-state-desc">Once pressure enters the system, open and in-progress items will be queued here with governed routing recommendations.</div>
554
- </div>
569
+ <NextStepEmptyState
570
+ title="No open pressure backlog"
571
+ description="Open and in-progress pressure will queue here once HelixEvo is observing real demand from projects, failures, or recurring motifs."
572
+ command="helixevo watch --project <name>"
573
+ pageLink={{ label: 'Open Projects', href: '/projects', tone: 'blue' }}
574
+ guideLink={{ label: 'Guide · Adaptation Loop', anchor: 'loop', tone: 'purple' }}
575
+ />
555
576
  )}
556
577
  </div>
557
578
  </SectionFrame>
@@ -578,10 +599,13 @@ export default function CoEvolutionClient({ summary, ontology }: Props) {
578
599
  </div>
579
600
  </div>
580
601
  )) : (
581
- <div className="empty-state" style={{ padding: 24 }}>
582
- <div className="empty-state-title">No response records yet</div>
583
- <div className="empty-state-desc">Command-level intervention records will appear here once the response loop starts operating.</div>
584
- </div>
602
+ <NextStepEmptyState
603
+ title="No response records yet"
604
+ description="Command-level intervention records will appear here once the response loop starts operating across research, evolve, generalize, or manual review."
605
+ command="helixevo research"
606
+ pageLink={{ label: 'Open Ontology', href: '/ontology', tone: 'green' }}
607
+ guideLink={{ label: 'Guide · Surface Map', anchor: 'surfaces', tone: 'purple' }}
608
+ />
585
609
  )}
586
610
  </div>
587
611
  </SectionFrame>
@@ -6,6 +6,9 @@ import { ConsolePanel } from '@/components/console-panel'
6
6
  import { MetricCard } from '@/components/metric-card'
7
7
  import { PageHero } from '@/components/page-hero'
8
8
  import { SectionFrame } from '@/components/section-frame'
9
+ import { OperatorLoopTrail } from '@/components/operator-loop-trail'
10
+ import { SurfaceJumpLinks } from '@/components/surface-jump-links'
11
+ import { NextStepEmptyState } from '@/components/next-step-empty-state'
9
12
  import type { OntologyControlDashboardSummary, OntologyReviewDecisionStatus } from '@/lib/data'
10
13
 
11
14
  type RunState = 'idle' | 'running' | 'success' | 'error'
@@ -86,15 +89,18 @@ export default function OntologyClient({ initialDashboard }: { initialDashboard:
86
89
  <div className="hero-note-title">Kernel + review + semantic adoption</div>
87
90
  <div className="hero-note-copy">Use this surface to move from frontier hypotheses into approved extensions, inspect active semantic consumers, and manage deprecation with operator-visible risk rather than hidden drift.</div>
88
91
  </div>
89
- <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
90
- <button onClick={() => runAction('refresh', {}, 'ontology refresh')} disabled={runState === 'running'} className="badge badge-blue" style={{ border: 'none', cursor: 'pointer' }}>Refresh ontology frontier</button>
91
- <Link href="/coevolution" className="badge badge-gray">Open co-evolution</Link>
92
- <Link href="/topology" className="badge badge-gray">Open topology</Link>
92
+ <div style={{ display: 'grid', gap: 10 }}>
93
+ <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
94
+ <button onClick={() => runAction('refresh', {}, 'ontology refresh')} disabled={runState === 'running'} className="badge badge-blue" style={{ border: 'none', cursor: 'pointer' }}>Refresh ontology frontier</button>
95
+ </div>
96
+ <SurfaceJumpLinks surface="ontology" variant="compact" title="Semantic handoffs" />
93
97
  </div>
94
98
  </div>
95
99
  }
96
100
  />
97
101
 
102
+ <OperatorLoopTrail surface="ontology" />
103
+
98
104
  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 16 }}>
99
105
  <MetricCard label="Kernel concepts" value={dashboard.summary.kernelConcepts} sublabel={`${dashboard.kernel.relationFamilies.length} relation families`} tone="purple" icon="◎" />
100
106
  <MetricCard label="Frontier hypotheses" value={dashboard.summary.frontier} sublabel={`${dashboard.summary.reviewOpen} open • ${dashboard.summary.deferred} deferred`} tone={dashboard.summary.reviewOpen > 0 ? 'yellow' : 'neutral'} icon="◇" />
@@ -198,10 +204,13 @@ export default function OntologyClient({ initialDashboard }: { initialDashboard:
198
204
  </div>
199
205
  </div>
200
206
  )) : (
201
- <div className="empty-state" style={{ padding: 24 }}>
202
- <div className="empty-state-title">No ontology frontier concepts yet</div>
203
- <div className="empty-state-desc">Run “Refresh ontology frontier after pressure motifs, project gaps, or topology review patterns accumulate.</div>
204
- </div>
207
+ <NextStepEmptyState
208
+ title="No ontology frontier concepts yet"
209
+ description="Run a frontier refresh after pressure motifs, project gaps, or topology review patterns accumulate. Frontier creation is the first step before any concept can become active semantic control."
210
+ command="helixevo ontology --refresh"
211
+ pageLink={{ label: 'Open Co-Evolution', href: '/coevolution', tone: 'purple' }}
212
+ guideLink={{ label: 'Guide · Semantic Control', anchor: 'semanticcontrol', tone: 'green' }}
213
+ />
205
214
  )}
206
215
  </div>
207
216
  </SectionFrame>
@@ -240,10 +249,13 @@ export default function OntologyClient({ initialDashboard }: { initialDashboard:
240
249
  {concept.warning ? <div className="signal-text" style={{ marginTop: 10 }}>• {concept.warning}</div> : null}
241
250
  </div>
242
251
  )) : (
243
- <div className="empty-state" style={{ padding: 24 }}>
244
- <div className="empty-state-title">No approved extensions yet</div>
245
- <div className="empty-state-desc">Promoted frontier concepts will appear here once they pass semantic review.</div>
246
- </div>
252
+ <NextStepEmptyState
253
+ title="No approved extensions yet"
254
+ description="Approved extensions appear after frontier concepts pass semantic review. Promotion is what turns reviewed ontology into live semantic adoption."
255
+ command="helixevo ontology --review <conceptId> --decision promote"
256
+ pageLink={{ label: 'Open Co-Evolution', href: '/coevolution', tone: 'purple' }}
257
+ guideLink={{ label: 'Guide · Semantic Control', anchor: 'semanticcontrol', tone: 'green' }}
258
+ />
247
259
  )}
248
260
  </div>
249
261
  </SectionFrame>
@@ -267,10 +279,13 @@ export default function OntologyClient({ initialDashboard }: { initialDashboard:
267
279
  </div>
268
280
  </div>
269
281
  )) : (
270
- <div className="empty-state" style={{ padding: 24 }}>
271
- <div className="empty-state-title">No ontology changes logged yet</div>
272
- <div className="empty-state-desc">Refresh the frontier or review a concept to create the first native ontology events.</div>
273
- </div>
282
+ <NextStepEmptyState
283
+ title="No ontology changes logged yet"
284
+ description="Refresh the frontier or review a concept to create the first native ontology events and start a visible semantic history instead of hidden drift."
285
+ command="helixevo ontology --refresh"
286
+ pageLink={{ label: 'Open Topology', href: '/topology', tone: 'yellow' }}
287
+ guideLink={{ label: 'Guide · Semantic Control', anchor: 'semanticcontrol', tone: 'green' }}
288
+ />
274
289
  )}
275
290
  </div>
276
291
  </SectionFrame>
@@ -4,6 +4,9 @@ import { OverviewActions } from '@/components/overview-actions'
4
4
  import { PageHero } from '@/components/page-hero'
5
5
  import { MetricCard } from '@/components/metric-card'
6
6
  import { SectionFrame } from '@/components/section-frame'
7
+ import { OperatorLoopTrail } from '@/components/operator-loop-trail'
8
+ import { SurfaceJumpLinks } from '@/components/surface-jump-links'
9
+ import { CURRENT_RELEASE_SPOTLIGHT } from '@/lib/release-spotlight'
7
10
 
8
11
  export const dynamic = 'force-dynamic'
9
12
 
@@ -57,6 +60,8 @@ export default function Overview() {
57
60
  }
58
61
  />
59
62
 
63
+ <OperatorLoopTrail surface="overview" />
64
+
60
65
  <div className="grid-5">
61
66
  <MetricCard label="Total skills" value={summary.skills.total} sublabel={`${summary.skills.evolved} evolved • ${summary.skillTests} skill tests`} tone="purple" href="/network" icon="◆" />
62
67
  <MetricCard label="Accepted proposals" value={summary.evolution.accepted} sublabel={`${summary.evolution.rejected} rejected`} tone="green" href="/evolution" icon="✓" />
@@ -65,6 +70,29 @@ export default function Overview() {
65
70
  <MetricCard label="Frontier candidates" value={frontier.programs.length} sublabel={`${summary.canaries} active canaries`} tone="neutral" href="/frontier" icon="▲" />
66
71
  </div>
67
72
 
73
+ <SectionFrame
74
+ eyebrow={`Release spotlight · v${CURRENT_RELEASE_SPOTLIGHT.version}`}
75
+ title={CURRENT_RELEASE_SPOTLIGHT.title}
76
+ description={CURRENT_RELEASE_SPOTLIGHT.summary}
77
+ tone="blue"
78
+ >
79
+ <div className="grid-2" style={{ gap: 16 }}>
80
+ <div style={{ display: 'grid', gap: 10 }}>
81
+ {CURRENT_RELEASE_SPOTLIGHT.bullets.map((item) => (
82
+ <div key={item} className="signal-text">• {item}</div>
83
+ ))}
84
+ <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 4 }}>
85
+ {CURRENT_RELEASE_SPOTLIGHT.nextActions.map((action) => (
86
+ <Link key={action.href} href={action.href} className={`hero-chip hero-chip-${action.tone}`} style={{ textDecoration: 'none' }}>
87
+ {action.label}
88
+ </Link>
89
+ ))}
90
+ </div>
91
+ </div>
92
+ <SurfaceJumpLinks surface="overview" variant="panel" title="Jump into the updated loop" />
93
+ </div>
94
+ </SectionFrame>
95
+
68
96
  <SectionFrame
69
97
  eyebrow="Execution layer"
70
98
  title="Quick actions"
@@ -6,6 +6,9 @@ import { ConsolePanel } from '@/components/console-panel'
6
6
  import { MetricCard } from '@/components/metric-card'
7
7
  import { PageHero } from '@/components/page-hero'
8
8
  import { SectionFrame } from '@/components/section-frame'
9
+ import { OperatorLoopTrail } from '@/components/operator-loop-trail'
10
+ import { SurfaceJumpLinks } from '@/components/surface-jump-links'
11
+ import { NextStepEmptyState } from '@/components/next-step-empty-state'
9
12
  import type { ProjectProfile } from '@/lib/data'
10
13
 
11
14
  type SetupState = 'idle' | 'analyzing' | 'done' | 'error' | 'cancelled'
@@ -364,18 +367,13 @@ export default function ProjectsClient({ profiles, skillCount, projectAnalysisTr
364
367
  <div className="hero-note-title">Analyze → Match → Gap scan → Action</div>
365
368
  <div className="hero-note-copy">Run a profile, review the skill fit, then send uncovered needs into Research or the Skill Network.</div>
366
369
  </div>
367
- <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
368
- <Link href="/network" style={buttonStyle('purple')}>
369
- Open Skill Network
370
- </Link>
371
- <Link href="/research" style={buttonStyle('blue')}>
372
- Open Research
373
- </Link>
374
- </div>
370
+ <SurfaceJumpLinks surface="projects" variant="compact" title="Observation handoffs" />
375
371
  </div>
376
372
  }
377
373
  />
378
374
 
375
+ <OperatorLoopTrail surface="projects" />
376
+
379
377
  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 16, marginBottom: 24 }}>
380
378
  <MetricCard
381
379
  label="Portfolio"
@@ -764,17 +762,13 @@ export default function ProjectsClient({ profiles, skillCount, projectAnalysisTr
764
762
  tone="yellow"
765
763
  >
766
764
  {profiles.length === 0 ? (
767
- <div className="empty-state">
768
- <div className="empty-state-icon">
769
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
770
- <path d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" />
771
- </svg>
772
- </div>
773
- <div className="empty-state-title">No analyzed projects yet</div>
774
- <div className="empty-state-desc">
775
- Start with a local folder or GitHub repository. The resulting profile will show matched skills, uncovered gaps, and recommended next steps.
776
- </div>
777
- </div>
765
+ <NextStepEmptyState
766
+ title="No analyzed projects yet"
767
+ description={`Start with a local folder or GitHub repository. The resulting profile will show matched skills, uncovered gaps, activation traces, and the next routed action against your ${skillCount} current skills.`}
768
+ command="helixevo project-setup <path>"
769
+ pageLink={{ label: 'Open Research', href: '/research', tone: 'blue' }}
770
+ guideLink={{ label: 'Guide · Quick Start', anchor: 'quickstart', tone: 'purple' }}
771
+ />
778
772
  ) : (
779
773
  <div style={{ display: 'grid', gap: 18 }}>
780
774
  {profiles.map(profile => {
@@ -5,6 +5,9 @@ import { ConsolePanel } from '@/components/console-panel'
5
5
  import { MetricCard } from '@/components/metric-card'
6
6
  import { PageHero } from '@/components/page-hero'
7
7
  import { SectionFrame } from '@/components/section-frame'
8
+ import { OperatorLoopTrail } from '@/components/operator-loop-trail'
9
+ import { SurfaceJumpLinks } from '@/components/surface-jump-links'
10
+ import { NextStepEmptyState } from '@/components/next-step-empty-state'
8
11
 
9
12
  interface Discovery {
10
13
  id: string
@@ -190,8 +193,20 @@ export default function ResearchClient({ buffer, projects, coevolution }: Props)
190
193
  { label: `${buffer.drafts.length} drafts`, tone: 'yellow' },
191
194
  { label: `${nearPass.length} near-pass drafts`, tone: 'green' },
192
195
  ]}
196
+ actions={
197
+ <div style={{ display: 'grid', gap: 12 }}>
198
+ <div className="hero-note-card">
199
+ <div className="hero-note-label">Discovery handoff</div>
200
+ <div className="hero-note-title">Observe gaps → research patterns → draft reusable skills</div>
201
+ <div className="hero-note-copy">Use Research when recurring project demand needs external evidence before it can become a stronger response or semantic pattern.</div>
202
+ </div>
203
+ <SurfaceJumpLinks surface="research" variant="compact" title="Discovery handoffs" />
204
+ </div>
205
+ }
193
206
  />
194
207
 
208
+ <OperatorLoopTrail surface="research" />
209
+
195
210
  <SectionFrame
196
211
  eyebrow="Why research now"
197
212
  title="Current pressure handoff"
@@ -371,10 +386,13 @@ export default function ResearchClient({ buffer, projects, coevolution }: Props)
371
386
  tone="blue"
372
387
  >
373
388
  {buffer.discoveries.length === 0 ? (
374
- <div className="empty-state" style={{ padding: 24 }}>
375
- <div className="empty-state-title">No discoveries yet</div>
376
- <div className="empty-state-desc">Run research to search the web for techniques your skill network does not cover yet.</div>
377
- </div>
389
+ <NextStepEmptyState
390
+ title="No discoveries yet"
391
+ description="Run research to search the web for techniques your skill network does not cover yet, then compare those discoveries against the current routed pressure picture."
392
+ command="helixevo research"
393
+ pageLink={{ label: 'Open Co-Evolution', href: '/coevolution', tone: 'green' }}
394
+ guideLink={{ label: 'Guide · Adaptation Loop', anchor: 'loop', tone: 'purple' }}
395
+ />
378
396
  ) : (
379
397
  <div className="summary-list">
380
398
  {buffer.discoveries.sort((a, b) => b.score - a.score).map((discovery) => (
@@ -400,10 +418,13 @@ export default function ResearchClient({ buffer, projects, coevolution }: Props)
400
418
  tone="yellow"
401
419
  >
402
420
  {buffer.drafts.length === 0 ? (
403
- <div className="empty-state" style={{ padding: 24 }}>
404
- <div className="empty-state-title">No drafts yet</div>
405
- <div className="empty-state-desc">Run research to generate the first draft skills and evaluate them against the current thresholds.</div>
406
- </div>
421
+ <NextStepEmptyState
422
+ title="No drafts yet"
423
+ description="Once research has enough evidence, it will generate the first draft skills and evaluate them against the current thresholds before they enter the wider loop."
424
+ command="helixevo research --verbose"
425
+ pageLink={{ label: 'Open Projects', href: '/projects', tone: 'blue' }}
426
+ guideLink={{ label: 'Guide · Quick Start', anchor: 'quickstart', tone: 'purple' }}
427
+ />
407
428
  ) : (
408
429
  <div className="summary-list">
409
430
  {buffer.drafts.sort((a, b) => b.avgScore - a.avgScore).map((draft) => (
@@ -6,6 +6,9 @@ import { ConsolePanel } from '@/components/console-panel'
6
6
  import { MetricCard } from '@/components/metric-card'
7
7
  import { PageHero } from '@/components/page-hero'
8
8
  import { SectionFrame } from '@/components/section-frame'
9
+ import { OperatorLoopTrail } from '@/components/operator-loop-trail'
10
+ import { SurfaceJumpLinks } from '@/components/surface-jump-links'
11
+ import { NextStepEmptyState } from '@/components/next-step-empty-state'
9
12
  import type { GovernanceModeName, GovernanceState, TopologyDashboardSummary, TopologyReviewDecisionStatus, TopologyReviewStatus } from '@/lib/data'
10
13
 
11
14
  type RunState = 'idle' | 'running' | 'success' | 'error' | 'stopped'
@@ -251,16 +254,18 @@ export default function TopologyClient({
251
254
  <div className="hero-note-title">{formatMode(dashboard.governance.activeMode)}</div>
252
255
  <div className="hero-note-copy">{dashboard.governance.profile.explanation}</div>
253
256
  </div>
254
- <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
255
- <button onClick={handleOptimize} disabled={runState === 'running'} className="badge badge-blue" style={{ border: 'none', cursor: 'pointer' }}>Run graph optimize</button>
256
- <Link href="/ontology" className="badge badge-gray">Open ontology</Link>
257
- <Link href="/coevolution" className="badge badge-gray">Open co-evolution</Link>
258
- <Link href="/network" className="badge badge-gray">Open network</Link>
257
+ <div style={{ display: 'grid', gap: 10 }}>
258
+ <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
259
+ <button onClick={handleOptimize} disabled={runState === 'running'} className="badge badge-blue" style={{ border: 'none', cursor: 'pointer' }}>Run graph optimize</button>
260
+ </div>
261
+ <SurfaceJumpLinks surface="topology" variant="compact" title="Structural handoffs" />
259
262
  </div>
260
263
  </div>
261
264
  }
262
265
  />
263
266
 
267
+ <OperatorLoopTrail surface="topology" />
268
+
264
269
  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 16 }}>
265
270
  <MetricCard label="Open review items" value={dashboard.summary.open} sublabel={`${dashboard.summary.deferred} deferred • ${dashboard.summary.accepted} accepted`} tone={dashboard.summary.open > 0 ? 'yellow' : 'green'} icon="⇄" />
266
271
  <MetricCard label="Accepted ready" value={dashboard.acceptedReady.length} sublabel="accepted candidates not yet prepared for execution" tone={dashboard.acceptedReady.length > 0 ? 'blue' : 'neutral'} icon="✓" />
@@ -300,10 +305,13 @@ export default function TopologyClient({
300
305
  </div>
301
306
  </div>
302
307
  )) : (
303
- <div className="empty-state" style={{ padding: 24 }}>
304
- <div className="empty-state-title">No accepted candidates waiting for preparation</div>
305
- <div className="empty-state-desc">Accept a topology review item first, then it will enter the reviewed execution pipeline here.</div>
306
- </div>
308
+ <NextStepEmptyState
309
+ title="No accepted candidates waiting for preparation"
310
+ description="Accept a topology review item first, then it can enter the reviewed execution pipeline and become a prepared apply plan."
311
+ command="helixevo graph --optimize"
312
+ pageLink={{ label: 'Open Co-Evolution', href: '/coevolution', tone: 'purple' }}
313
+ guideLink={{ label: 'Guide · Maturity & Safety', anchor: 'maturity', tone: 'yellow' }}
314
+ />
307
315
  )}
308
316
  </div>
309
317
 
@@ -342,10 +350,13 @@ export default function TopologyClient({
342
350
  </div>
343
351
  </div>
344
352
  )) : (
345
- <div className="empty-state" style={{ padding: 24 }}>
346
- <div className="empty-state-title">No prepared plans yet</div>
347
- <div className="empty-state-desc">Prepared plans will appear here after you convert an accepted review candidate into an explicit apply plan.</div>
348
- </div>
353
+ <NextStepEmptyState
354
+ title="No prepared plans yet"
355
+ description="Prepared plans will appear here after an accepted review candidate is converted into an explicit apply plan with snapshot-backed safety."
356
+ command="helixevo topology --prepare <candidateId>"
357
+ pageLink={{ label: 'Open Ontology', href: '/ontology', tone: 'green' }}
358
+ guideLink={{ label: 'Guide · Maturity & Safety', anchor: 'maturity', tone: 'yellow' }}
359
+ />
349
360
  )}
350
361
  </div>
351
362
  </div>
@@ -426,10 +437,13 @@ export default function TopologyClient({
426
437
  </div>
427
438
  </div>
428
439
  )) : (
429
- <div className="empty-state" style={{ padding: 24 }}>
430
- <div className="empty-state-title">No topology decisions yet</div>
431
- <div className="empty-state-desc">Run graph optimize to populate the queue, then accept, defer, or reject structural candidates from here.</div>
432
- </div>
440
+ <NextStepEmptyState
441
+ title="No topology decisions yet"
442
+ description="Run graph optimize to populate the queue, then accept, defer, or reject structural candidates from this page so the review memory becomes explicit."
443
+ command="helixevo graph --optimize"
444
+ pageLink={{ label: 'Open Co-Evolution', href: '/coevolution', tone: 'purple' }}
445
+ guideLink={{ label: 'Guide · Surface Map', anchor: 'surfaces', tone: 'blue' }}
446
+ />
433
447
  )}
434
448
  </div>
435
449
  </SectionFrame>
@@ -491,10 +505,13 @@ export default function TopologyClient({
491
505
  </div>
492
506
  </div>
493
507
  )) : (
494
- <div className="empty-state" style={{ padding: 28 }}>
495
- <div className="empty-state-title">No topology backlog yet</div>
496
- <div className="empty-state-desc">Run <code>graph --optimize</code> from this page to refresh structural review candidates and turn manual-review into a populated operator lane.</div>
497
- </div>
508
+ <NextStepEmptyState
509
+ title="No topology backlog yet"
510
+ description="Refresh structural review candidates from this page to turn manual-review into a populated operator lane instead of a placeholder route label."
511
+ command="helixevo graph --optimize"
512
+ pageLink={{ label: 'Open Ontology', href: '/ontology', tone: 'green' }}
513
+ guideLink={{ label: 'Guide · Surface Map', anchor: 'surfaces', tone: 'blue' }}
514
+ />
498
515
  )}
499
516
  </div>
500
517
  </SectionFrame>
@@ -539,10 +556,12 @@ export default function TopologyClient({
539
556
  </div>
540
557
  </div>
541
558
  )) : (
542
- <div className="empty-state" style={{ padding: 24 }}>
543
- <div className="empty-state-title">No applied topology history yet</div>
544
- <div className="empty-state-desc">Once a prepared safe plan is applied, it will appear here with rollback continuity.</div>
545
- </div>
559
+ <NextStepEmptyState
560
+ title="No applied topology history yet"
561
+ description="Applied topology history will appear here once a prepared safe plan is executed and snapshot-backed rollback continuity becomes relevant."
562
+ command="helixevo topology --apply <planId>"
563
+ guideLink={{ label: 'Guide · Maturity & Safety', anchor: 'maturity', tone: 'yellow' }}
564
+ />
546
565
  )}
547
566
  </div>
548
567
  </SectionFrame>
@@ -567,10 +586,13 @@ export default function TopologyClient({
567
586
  </div>
568
587
  </div>
569
588
  )) : (
570
- <div className="empty-state" style={{ padding: 24 }}>
571
- <div className="empty-state-title">No structural candidates stored yet</div>
572
- <div className="empty-state-desc">The ledger will populate after the first topology refresh.</div>
573
- </div>
589
+ <NextStepEmptyState
590
+ title="No structural candidates stored yet"
591
+ description="The structural review ledger will populate after the first topology refresh and then persist reviewed intent across decisions and execution."
592
+ command="helixevo graph --optimize"
593
+ pageLink={{ label: 'Open Co-Evolution', href: '/coevolution', tone: 'purple' }}
594
+ guideLink={{ label: 'Guide · Surface Map', anchor: 'surfaces', tone: 'blue' }}
595
+ />
574
596
  )}
575
597
  </div>
576
598
  </SectionFrame>
@@ -0,0 +1,22 @@
1
+ import Link from 'next/link'
2
+ import { guideHref, type GuideAnchorId, type SurfaceTone } from '@/lib/loop-map'
3
+
4
+ function toneClass(tone: SurfaceTone) {
5
+ return `hero-chip hero-chip-${tone}`
6
+ }
7
+
8
+ export function GuideDeepLink({
9
+ anchor,
10
+ label,
11
+ tone = 'neutral',
12
+ }: {
13
+ anchor: GuideAnchorId
14
+ label: string
15
+ tone?: SurfaceTone
16
+ }) {
17
+ return (
18
+ <Link href={guideHref(anchor)} className={toneClass(tone)} style={{ textDecoration: 'none' }}>
19
+ {label}
20
+ </Link>
21
+ )
22
+ }
@@ -0,0 +1,53 @@
1
+ import Link from 'next/link'
2
+ import { GuideDeepLink } from '@/components/guide-deep-link'
3
+ import type { GuideAnchorId, SurfaceTone } from '@/lib/loop-map'
4
+
5
+ export function NextStepEmptyState({
6
+ title,
7
+ description,
8
+ command,
9
+ pageLink,
10
+ guideLink,
11
+ }: {
12
+ title: string
13
+ description: string
14
+ command?: string
15
+ pageLink?: { label: string; href: string; tone?: SurfaceTone }
16
+ guideLink?: { label: string; anchor: GuideAnchorId; tone?: SurfaceTone }
17
+ }) {
18
+ return (
19
+ <div className="empty-state" style={{ padding: 24 }}>
20
+ <div className="empty-state-title">{title}</div>
21
+ <div className="empty-state-desc" style={{ maxWidth: 680 }}>{description}</div>
22
+ {command ? (
23
+ <div
24
+ style={{
25
+ marginTop: 14,
26
+ padding: '12px 14px',
27
+ borderRadius: 16,
28
+ border: '1px solid var(--border)',
29
+ background: 'rgba(255,255,255,0.76)',
30
+ display: 'inline-grid',
31
+ gap: 6,
32
+ textAlign: 'left',
33
+ }}
34
+ >
35
+ <div style={{ fontSize: 10.5, fontWeight: 700, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: 0.9 }}>Try next</div>
36
+ <code style={{ fontFamily: 'var(--font-mono)', fontSize: 11.5, color: 'var(--text)' }}>$ {command}</code>
37
+ </div>
38
+ ) : null}
39
+ {(pageLink || guideLink) ? (
40
+ <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', justifyContent: 'center', marginTop: 14 }}>
41
+ {pageLink ? (
42
+ <Link href={pageLink.href} className={`hero-chip hero-chip-${pageLink.tone ?? 'blue'}`} style={{ textDecoration: 'none' }}>
43
+ {pageLink.label}
44
+ </Link>
45
+ ) : null}
46
+ {guideLink ? (
47
+ <GuideDeepLink anchor={guideLink.anchor} label={guideLink.label} tone={guideLink.tone ?? 'purple'} />
48
+ ) : null}
49
+ </div>
50
+ ) : null}
51
+ </div>
52
+ )
53
+ }
@@ -0,0 +1,46 @@
1
+ import Link from 'next/link'
2
+ import { LOOP_STAGES, getSurfaceLoopConfig, type SurfaceKey } from '@/lib/loop-map'
3
+
4
+ export function OperatorLoopTrail({ surface }: { surface: SurfaceKey }) {
5
+ const config = getSurfaceLoopConfig(surface)
6
+
7
+ return (
8
+ <div
9
+ style={{
10
+ padding: '14px 16px',
11
+ borderRadius: 20,
12
+ border: '1px solid var(--border)',
13
+ background: 'linear-gradient(180deg, rgba(255,255,255,0.82), rgba(245,241,236,0.72))',
14
+ boxShadow: 'var(--shadow-xs)',
15
+ display: 'grid',
16
+ gap: 10,
17
+ }}
18
+ >
19
+ <div style={{ display: 'flex', justifyContent: 'space-between', gap: 12, alignItems: 'center', flexWrap: 'wrap' }}>
20
+ <div>
21
+ <div className="section-label">Operator loop</div>
22
+ <div style={{ fontSize: 12.5, color: 'var(--text-dim)', marginTop: 4, lineHeight: 1.55 }}>{config.context}</div>
23
+ </div>
24
+ <span className="badge badge-gray">
25
+ {config.stage ? `Current stage · ${LOOP_STAGES.find((stage) => stage.id === config.stage)?.label}` : 'Cockpit view'}
26
+ </span>
27
+ </div>
28
+
29
+ <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
30
+ {LOOP_STAGES.map((stage) => {
31
+ const active = config.stage === stage.id
32
+ return (
33
+ <Link
34
+ key={stage.id}
35
+ href={stage.href}
36
+ className={`hero-chip hero-chip-${active ? stage.tone : 'neutral'}`}
37
+ style={{ textDecoration: 'none' }}
38
+ >
39
+ {stage.label}
40
+ </Link>
41
+ )
42
+ })}
43
+ </div>
44
+ </div>
45
+ )
46
+ }
@@ -0,0 +1,69 @@
1
+ import Link from 'next/link'
2
+ import { getSurfaceLoopConfig, guideHref, type SurfaceKey } from '@/lib/loop-map'
3
+
4
+ export function SurfaceJumpLinks({
5
+ surface,
6
+ title = 'Next hops',
7
+ variant = 'compact',
8
+ }: {
9
+ surface: SurfaceKey
10
+ title?: string
11
+ variant?: 'compact' | 'panel'
12
+ }) {
13
+ const config = getSurfaceLoopConfig(surface)
14
+
15
+ if (variant === 'compact') {
16
+ return (
17
+ <div style={{ display: 'grid', gap: 8 }}>
18
+ <div style={{ fontSize: 10.5, fontWeight: 700, color: 'var(--text-muted)', letterSpacing: 0.9, textTransform: 'uppercase' }}>{title}</div>
19
+ <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
20
+ {config.adjacentLinks.map((link) => (
21
+ <Link key={link.href} href={link.href} className={`badge badge-${link.tone === 'neutral' ? 'gray' : link.tone}`} style={{ textDecoration: 'none' }}>
22
+ {link.label}
23
+ </Link>
24
+ ))}
25
+ {config.guideLinks.map((link) => (
26
+ <Link key={link.anchor} href={guideHref(link.anchor)} className={`hero-chip hero-chip-${link.tone}`} style={{ textDecoration: 'none' }}>
27
+ {link.label}
28
+ </Link>
29
+ ))}
30
+ </div>
31
+ </div>
32
+ )
33
+ }
34
+
35
+ return (
36
+ <div style={{ display: 'grid', gap: 12 }}>
37
+ <div>
38
+ <div className="section-label">{title}</div>
39
+ <div style={{ fontSize: 12, color: 'var(--text-dim)', marginTop: 6, lineHeight: 1.6 }}>
40
+ Move deliberately into the next most relevant surface instead of backing out to Overview every time.
41
+ </div>
42
+ </div>
43
+
44
+ <div className="grid-2" style={{ gap: 12 }}>
45
+ {config.adjacentLinks.map((link) => (
46
+ <Link
47
+ key={link.href}
48
+ href={link.href}
49
+ className="card"
50
+ style={{ padding: '14px 16px', textDecoration: 'none', display: 'grid', gap: 6 }}
51
+ >
52
+ <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
53
+ <span className={`hero-chip hero-chip-${link.tone}`}>{link.label}</span>
54
+ </div>
55
+ <div style={{ fontSize: 12, color: 'var(--text-dim)', lineHeight: 1.6 }}>{link.description}</div>
56
+ </Link>
57
+ ))}
58
+ </div>
59
+
60
+ <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
61
+ {config.guideLinks.map((link) => (
62
+ <Link key={link.anchor} href={guideHref(link.anchor)} className={`hero-chip hero-chip-${link.tone}`} style={{ textDecoration: 'none' }}>
63
+ {link.label}
64
+ </Link>
65
+ ))}
66
+ </div>
67
+ </div>
68
+ )
69
+ }
@@ -0,0 +1,190 @@
1
+ export type LoopStageId = 'observe' | 'route' | 'adopt' | 'restructure' | 'prove'
2
+ export type SurfaceKey = 'overview' | 'projects' | 'research' | 'coevolution' | 'ontology' | 'topology'
3
+ export type SurfaceTone = 'blue' | 'green' | 'purple' | 'yellow' | 'neutral'
4
+ export type GuideAnchorId = 'quickstart' | 'brainstack' | 'loop' | 'semanticcontrol' | 'surfaces' | 'commands' | 'maturity' | 'metrics'
5
+
6
+ export interface LoopStageMeta {
7
+ id: LoopStageId
8
+ label: string
9
+ href: string
10
+ tone: SurfaceTone
11
+ description: string
12
+ }
13
+
14
+ export interface SurfaceJumpLink {
15
+ label: string
16
+ href: string
17
+ tone: SurfaceTone
18
+ description: string
19
+ }
20
+
21
+ export interface GuideDeepLinkDef {
22
+ label: string
23
+ anchor: GuideAnchorId
24
+ tone: SurfaceTone
25
+ description: string
26
+ }
27
+
28
+ export interface SurfaceLoopConfig {
29
+ key: SurfaceKey
30
+ label: string
31
+ context: string
32
+ stage?: LoopStageId
33
+ adjacentLinks: SurfaceJumpLink[]
34
+ guideLinks: GuideDeepLinkDef[]
35
+ }
36
+
37
+ export const LOOP_STAGES: LoopStageMeta[] = [
38
+ {
39
+ id: 'observe',
40
+ label: 'Observe',
41
+ href: '/projects',
42
+ tone: 'blue',
43
+ description: 'Project intake, pressure discovery, and activation-aware observation.',
44
+ },
45
+ {
46
+ id: 'route',
47
+ label: 'Route',
48
+ href: '/coevolution',
49
+ tone: 'purple',
50
+ description: 'Governed response selection across research, evolve, generalize, and review lanes.',
51
+ },
52
+ {
53
+ id: 'adopt',
54
+ label: 'Adopt',
55
+ href: '/ontology',
56
+ tone: 'green',
57
+ description: 'Promote approved concepts into active semantic consumers inside the live loop.',
58
+ },
59
+ {
60
+ id: 'restructure',
61
+ label: 'Restructure',
62
+ href: '/topology',
63
+ tone: 'yellow',
64
+ description: 'Turn reviewed structural intent into prepared, applied, and rollbackable change.',
65
+ },
66
+ {
67
+ id: 'prove',
68
+ label: 'Prove',
69
+ href: '/guide#metrics',
70
+ tone: 'neutral',
71
+ description: 'Check evidence, metrics, and guide-backed operator understanding.',
72
+ },
73
+ ]
74
+
75
+ export const GUIDE_ANCHOR_LABELS: Record<GuideAnchorId, string> = {
76
+ quickstart: 'Quick Start',
77
+ brainstack: 'Brain Stack',
78
+ loop: 'Adaptation Loop',
79
+ semanticcontrol: 'Semantic Control',
80
+ surfaces: 'Surface Map',
81
+ commands: 'Commands',
82
+ maturity: 'Maturity & Safety',
83
+ metrics: 'Closed-Loop Metrics',
84
+ }
85
+
86
+ export function guideHref(anchor: GuideAnchorId) {
87
+ return `/guide#${anchor}`
88
+ }
89
+
90
+ export const SURFACE_LOOP_CONFIG: Record<SurfaceKey, SurfaceLoopConfig> = {
91
+ overview: {
92
+ key: 'overview',
93
+ label: 'Overview',
94
+ context: 'Use Overview as the cockpit entry into the full loop, then jump into the stage that currently needs attention.',
95
+ adjacentLinks: [
96
+ { label: 'Open Projects', href: '/projects', tone: 'blue', description: 'Start from project intake, gap discovery, and observation.' },
97
+ { label: 'Open Co-Evolution', href: '/coevolution', tone: 'purple', description: 'Inspect governed routing and the active response backlog.' },
98
+ { label: 'Open Ontology', href: '/ontology', tone: 'green', description: 'Inspect semantic adoption, frontier review, and concept consumers.' },
99
+ { label: 'Open Topology', href: '/topology', tone: 'yellow', description: 'Review structural candidates, preparation, and rollbackable execution.' },
100
+ ],
101
+ guideLinks: [
102
+ { label: 'Read Quick Start', anchor: 'quickstart', tone: 'blue', description: 'See the shortest operator path into the live brain loop.' },
103
+ { label: 'Read Surface Map', anchor: 'surfaces', tone: 'purple', description: 'Understand how each dashboard surface fits together.' },
104
+ ],
105
+ },
106
+ projects: {
107
+ key: 'projects',
108
+ label: 'Projects',
109
+ stage: 'observe',
110
+ context: 'Projects is where local context becomes explicit observation: capabilities, gaps, activation traces, and pressure feeders.',
111
+ adjacentLinks: [
112
+ { label: 'Open Research', href: '/research', tone: 'purple', description: 'Turn uncovered project gaps into discovery work.' },
113
+ { label: 'Open Co-Evolution', href: '/coevolution', tone: 'green', description: 'See how project pressure is being routed into response.' },
114
+ { label: 'Open Ontology', href: '/ontology', tone: 'blue', description: 'Check whether recurring project demand is becoming semantic adoption.' },
115
+ { label: 'Open Skill Network', href: '/network', tone: 'neutral', description: 'Inspect the skills that were matched or may need specialization.' },
116
+ ],
117
+ guideLinks: [
118
+ { label: 'Guide · Quick Start', anchor: 'quickstart', tone: 'blue', description: 'Follow the operator path from project intake to response.' },
119
+ { label: 'Guide · Adaptation Loop', anchor: 'loop', tone: 'purple', description: 'Trace how project observation becomes routed adaptation.' },
120
+ ],
121
+ },
122
+ research: {
123
+ key: 'research',
124
+ label: 'Research',
125
+ stage: 'observe',
126
+ context: 'Research extends observation into discovery by turning recurring capability pressure into external evidence and candidate skills.',
127
+ adjacentLinks: [
128
+ { label: 'Open Projects', href: '/projects', tone: 'blue', description: 'Return to the project contexts that produced the gaps.' },
129
+ { label: 'Open Co-Evolution', href: '/coevolution', tone: 'green', description: 'Check how governed routing is prioritizing research pressure.' },
130
+ { label: 'Open Ontology', href: '/ontology', tone: 'purple', description: 'Inspect whether recurring research demand is becoming active semantics.' },
131
+ ],
132
+ guideLinks: [
133
+ { label: 'Guide · Quick Start', anchor: 'quickstart', tone: 'blue', description: 'See how research fits the current operator path.' },
134
+ { label: 'Guide · Adaptation Loop', anchor: 'loop', tone: 'purple', description: 'Connect discovery work back to the broader loop.' },
135
+ ],
136
+ },
137
+ coevolution: {
138
+ key: 'coevolution',
139
+ label: 'Co-Evolution',
140
+ stage: 'route',
141
+ context: 'Co-Evolution is the response cockpit where observed demand is routed under governance into the next adaptation lane.',
142
+ adjacentLinks: [
143
+ { label: 'Open Ontology', href: '/ontology', tone: 'green', description: 'Inspect which approved concepts are influencing current route rationale.' },
144
+ { label: 'Open Topology', href: '/topology', tone: 'yellow', description: 'Escalate mixed-signal structural demand into review and execution.' },
145
+ { label: 'Open Research', href: '/research', tone: 'blue', description: 'Run or inspect the discovery lane when research is the governed response.' },
146
+ ],
147
+ guideLinks: [
148
+ { label: 'Guide · Semantic Control', anchor: 'semanticcontrol', tone: 'green', description: 'See how semantic adoption shapes route explanation without bypassing governance.' },
149
+ { label: 'Guide · Surface Map', anchor: 'surfaces', tone: 'purple', description: 'Compare the response cockpit with the nearby control surfaces.' },
150
+ ],
151
+ },
152
+ ontology: {
153
+ key: 'ontology',
154
+ label: 'Ontology',
155
+ stage: 'adopt',
156
+ context: 'Ontology is where reviewed concepts become approved extensions and then become visible as active semantic consumers.',
157
+ adjacentLinks: [
158
+ { label: 'Open Co-Evolution', href: '/coevolution', tone: 'purple', description: 'See where active concepts are influencing current route rationale.' },
159
+ { label: 'Open Topology', href: '/topology', tone: 'yellow', description: 'Compare semantic adoption with structural review and execution.' },
160
+ { label: 'Open Skill Network', href: '/network', tone: 'blue', description: 'Inspect semantic context alongside graph relationships and inspector detail.' },
161
+ ],
162
+ guideLinks: [
163
+ { label: 'Guide · Semantic Control', anchor: 'semanticcontrol', tone: 'green', description: 'Read the post-M8 / post-M9 ontology lifecycle and operator playbooks.' },
164
+ { label: 'Guide · Surface Map', anchor: 'surfaces', tone: 'purple', description: 'See where ontology sits relative to Co-Evolution and Topology.' },
165
+ ],
166
+ },
167
+ topology: {
168
+ key: 'topology',
169
+ label: 'Topology',
170
+ stage: 'restructure',
171
+ context: 'Topology is the structural handoff where reviewed intent becomes prepared, applied, and rollbackable graph change.',
172
+ adjacentLinks: [
173
+ { label: 'Open Ontology', href: '/ontology', tone: 'green', description: 'Check the semantic families clustering around current structural candidates.' },
174
+ { label: 'Open Co-Evolution', href: '/coevolution', tone: 'purple', description: 'Return to the governed response backlog feeding structural review.' },
175
+ { label: 'Open Skill Network', href: '/network', tone: 'blue', description: 'Inspect the graph context around the candidates being reviewed or applied.' },
176
+ ],
177
+ guideLinks: [
178
+ { label: 'Guide · Surface Map', anchor: 'surfaces', tone: 'purple', description: 'See how topology fits the rest of the dashboard operator loop.' },
179
+ { label: 'Guide · Maturity & Safety', anchor: 'maturity', tone: 'yellow', description: 'Review the current bounded-safe-execution limits before structural action.' },
180
+ ],
181
+ },
182
+ }
183
+
184
+ export function getSurfaceLoopConfig(surface: SurfaceKey) {
185
+ return SURFACE_LOOP_CONFIG[surface]
186
+ }
187
+
188
+ export function getLoopStage(stageId: LoopStageId) {
189
+ return LOOP_STAGES.find((stage) => stage.id === stageId)
190
+ }
@@ -0,0 +1,17 @@
1
+ export const CURRENT_RELEASE_SPOTLIGHT = {
2
+ version: '0.6.1',
3
+ title: 'What changed in 0.6.1',
4
+ summary:
5
+ 'This patch turns the dashboard into a more connected operator system: the major control surfaces now show where they sit in the live loop, where to jump next, and what to do when the system is still cold.',
6
+ bullets: [
7
+ 'Overview, Projects, Research, Co-Evolution, Ontology, and Topology now show a shared operator-loop trail.',
8
+ 'Each major surface now exposes contextual handoffs instead of isolated one-off page links.',
9
+ 'Cold-state pages now provide command-level next steps, relevant adjacent pages, and direct Guide anchors.',
10
+ 'Overview now includes a curated release spotlight so operators can immediately see what this patch added.',
11
+ ],
12
+ nextActions: [
13
+ { label: 'Open the operator loop', href: '/', tone: 'blue' as const },
14
+ { label: 'Inspect semantic control', href: '/ontology', tone: 'green' as const },
15
+ { label: 'Read dashboard handoffs', href: '/guide#surfaces', tone: 'purple' as const },
16
+ ],
17
+ } as const
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helixevo",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Co-evolving skill and project brain for AI agents, with ontology-aware learning, governed response, rollbackable topology control, and a premium dashboard.",
5
5
  "type": "module",
6
6
  "bin": {