Sidebar Configuration
The sidebar is configured entirely in starspec.config.js via the sidebar.entries array. Each entry is a triplet that maps a processor ID to a section/group path with optional display overrides.
Triplet syntax
[id, 'Section/Group', opts?]| Position | Type | Description |
|---|---|---|
id | string | Tag-processor tag name or aggregate-processor id (see reference below) |
path | string | 'Section' places the entry directly in a section. 'Section/Group' nests it in a named sub-group. '' (empty) places it at the sidebar root with no section wrapper. |
opts | SidebarEntryOpts | Optional overrides (see below) |
Options (SidebarEntryOpts)
| Option | Type | Default | Description |
|---|---|---|---|
label | string | Processor-defined | Override the display label (static) |
collapsed | boolean | true | Whether the group starts collapsed |
groupByDomain | boolean | false | Create sub-groups per domain |
groupByCategory | boolean | false | Create sub-groups per category |
link | string | — | Static link (bypasses processor resolution) |
filter | (entry: SidebarEntryContext) => boolean | — | Exclude entries; return true to keep |
mapLabel | (entry: SidebarEntryContext) => string | — | Compute display label from entry data |
sort | (a: SidebarEntryContext, b: SidebarEntryContext) => number | Alphabetical | Custom sort comparator |
Entry hooks
The three function hooks — filter, mapLabel, and sort — let you dynamically control which entries appear, how they are labelled, and in what order. All three are optional and independent; use any combination.
Pipeline order: filter → sort → mapLabel. Labels are mapped last so that sort can compare on original labels when needed.
When a custom sort is provided, the default alphabetical sort within domain and category groups is skipped — entries preserve the order established by the pipeline.
The hooks receive a SidebarEntryContext:
interface SidebarEntryContext { id: string; // document slug (last segment of link path) label: string; // resolved display label link: string; // URL path, e.g. '/features/export-data' domain?: string; // domain slug category?: string; // category slug status?: string; // frontmatter status (draft, pending, ready, qa, done, published)}Ordering rules
- Section order is determined by first appearance in the entries array. The first entry mentioning
'Specification'determines where that section appears relative to others. - Entry order within a section follows array position.
- Only listed entries appear. Omitting an ID hides it from the sidebar.
- Multiple entries sharing the same
Section/Grouppath merge into one group.
Sections
Six sections are available:
| Section | Default collapsed | Description |
|---|---|---|
Product | false | Product-level views: manifest, glossary, roadmap, tours, tags |
Journal | false | Articles, quotes, knowledge base, bibliography |
Specification | false | Roles, domains, stories, features, flows, designs |
Reference | true | Cross-cutting aggregate pages |
Implementation | true | Blueprints, component registry |
StarSpec | — | Auto-populated from instruction documents (configurable via sidebar.starspec) |
Special entries
- Changelog: Appended automatically at the end when changesets exist. No entry needed.
- StarSpec: Appended at the end by default. Can be positioned explicitly by adding an entry with section
'StarSpec'.
Entry ID reference
Every ID below can be used as the first element of a sidebar triplet. IDs fall into two categories: tag processors (document types with individual pages) and aggregate processors (cross-cutting summary pages).
Tag processors
Tag processors produce one sidebar entry per document of that type. They support groupByDomain and groupByCategory to create sub-groups.
| ID | Content | Supports |
|---|---|---|
article | Journal articles — free-form writing, research, reflection | groupByCategory |
surface | UI wireframe sketches (Pug DSL) | groupByDomain |
tour | Guided product tours with narrated stops and spotlights | groupByDomain |
role | User/system roles | — |
domain | Domain models (terms, APIs, policies) | — |
story | User stories narrating role interactions | groupByDomain |
feature | Feature specifications (requirements, criteria, API) | groupByDomain |
flow | Step-by-step interaction flows | groupByDomain |
blueprint | Implementation blueprints for development | groupByDomain |
Aggregate processors
Aggregate processors collect data across all documents and produce summary pages. Most render a single link; some produce expandable sub-items.
| ID | Content | Renders |
|---|---|---|
manifest | Product manifest (values, principles, goals) | Single link → /manifest |
glossary | All domain terms sorted alphabetically | Single link → /glossary |
roadmap | Milestones and future plans | Single link → /roadmap |
tags | All documents grouped by tag | Single link → /tags |
traceability | Requirement coverage matrix across features | Single link → /traceability |
api-reference | All actions, events, operations, errors | Expandable sub-items by API category |
policies | Business rules: action-event-policy chains | Single link → /policies |
autoflow | System-wide reactive topology diagram | Single link → /autoflow |
settings | Consolidated registry of application settings | Single link → /settings |
surfaces | Visual library of all wireframe sketches | Single link → /surfaces |
tours | Gallery of all product tours | Single link → /tours-gallery |
showroom | UI component variant gallery | Expandable sub-items by category |
diagrams | Inventory of all interactive diagrams | Single link → /diagrams |
examples | All illustrative examples from the spec | Single link → /examples |
markers | Work-in-progress markers across documents | Single link → /markers |
taxonomy | Hierarchical tag taxonomy tree | Single link → /taxonomy |
components | Architectural components and wiring | Expandable sub-items by domain |
article-tags | Browse articles by tag | Single link → /articles/tags |
quotes | Quotes collected from articles, grouped by author | Single link → /quotes |
atoms | Knowledge atoms (definitions, hypotheses, axioms, etc.) | Expandable sub-items by category |
bibliography | Cited and recommended resources from articles | Single link → /bibliography |
Global transform
The sidebar.transform function is an escape hatch for structural changes that the declarative layer cannot express. It receives the fully assembled SidebarItem[] tree after all entries, changelog, and instructions have been placed, and returns a new tree.
export default defineConfig({ sidebar: { entries: [ /* ... */ ], transform: (sidebar) => { // Reorder sections, inject custom items, strip empty groups, etc. return sidebar; }, },});The transform runs after SidebarBuilder.build() and before sidebar.json is written. It has full access to the tree shape — sections, groups, links, and badges.
Full example
import { defineConfig } from '@starspec/compiler';
export default defineConfig({ sidebar: { entries: [ // Product ['manifest', 'Product'], ['glossary', 'Product', { label: 'Glossary' }], ['roadmap', 'Product', { label: 'Roadmap' }], ['tour', 'Product/Tours', { collapsed: true, groupByDomain: true }], ['tags', 'Product', { label: 'By Tags' }],
// Journal ['article', 'Journal', { collapsed: false, groupByCategory: true }], ['article-tags', 'Journal', { label: 'By Tag' }], ['quotes', 'Journal', { label: 'Quotes' }], ['atoms', 'Journal', { label: 'Knowledge Base' }], ['bibliography', 'Journal', { label: 'Bibliography' }],
// Specification ['role', 'Specification/Roles', { collapsed: true }], ['domain', 'Specification/Domains', { collapsed: true }], ['story', 'Specification/Stories', { collapsed: true, groupByDomain: true }], ['feature', 'Specification/Features', { collapsed: true, groupByDomain: true }], ['flow', 'Specification/Flows', { collapsed: true, groupByDomain: true }], ['surface', 'Specification/Designs', { collapsed: true, groupByDomain: true }],
// Reference ['traceability', 'Reference', { label: 'Requirements' }], ['api-reference', 'Reference', { label: 'API' }], ['policies', 'Reference/API'], ['autoflow', 'Reference', { label: 'Reactive Topology' }], ['settings', 'Reference', { label: 'Settings' }], ['surfaces', 'Reference', { label: 'Designs' }], ['tours', 'Reference', { label: 'Tours' }], ['showroom', 'Reference', { label: 'Component Gallery' }], ['diagrams', 'Reference', { label: 'Diagrams' }], ['examples', 'Reference', { label: 'Examples' }], ['markers', 'Reference', { label: 'Markers' }], ['taxonomy', 'Reference', { label: 'Taxonomy' }],
// Implementation ['blueprint', 'Implementation/Blueprints', { collapsed: true, groupByDomain: true }], ['components', 'Implementation', { label: 'Components' }], ], },});Adding a new aggregate to the sidebar
After implementing a new AggregateProcessor (see starspec/adding-a-tag § 11), register it in the sidebar by adding a triplet to the entries array in starspec.config.js:
['my-aggregate', 'Reference', { label: 'My Aggregate' }],The id must match the id property on your AggregateProcessor. If the aggregate produces expandable sub-items via sidebarEntry(), those render automatically — no extra configuration needed. If it only declares a static sidebar property, it renders as a single link.