Architecture

High-level overview of how ciderpress is structured, its design philosophy, and how data flows through the system.

Overview

ciderpress is a documentation framework for monorepos. It takes a single config file, syncs markdown content into a structured output directory, and builds a static site via Rspress. The information architecture -- sections, navigation, sidebar, landing pages -- is derived entirely from the config.

The codebase follows a functional, immutable, composition-first design. There are no classes, no let, no throw statements, and no loops. Errors are returned as Result tuples. Side effects (process exit, terminal output) are pushed to the outermost edges.

Package Ecosystem

packages
cli# CLI commands + sync engine (dev, build, serve, check, diff, draft, clean, setup, dump, sync)
ui# Rspress plugin, theme components, styles
config# @ciderpress/config — c12-based config loading, Zod validation
templates# @ciderpress/templates — Liquid template registry for draft command
theme# @ciderpress/theme — theme definitions and schema
ciderpress# ciderpress — public wrapper (re-exports config + ui + cli bin)
PackagePurpose
@ciderpress/cliCLI commands + sync engine: dev, build, serve, check, diff, draft, clean, setup, dump, sync
@ciderpress/uiRspress plugin, React theme components, CSS overrides
@ciderpress/configConfig schema (Zod), type definitions, c12-based loading
@ciderpress/templatesLiquid template registry for the draft command
@ciderpress/themeTheme definitions and schema
ciderpressPublic package: . and ./config entry points + ciderpress CLI bin

ciderpress (wrapper)

The public-facing package. Two entry points and a CLI bin:

EntryPurpose
.Public API: defineConfig, defineTheme, hasGlobChars, CiderpressLogo
./configLightweight: just defineConfig + types

The ciderpress CLI bin is provided by this package and delegates to @ciderpress/cli. Users import defineConfig from ciderpress (or ciderpress/config) in their config file.

Layers

CLI Layer

Package: @ciderpress/cli

The command-line interface. Uses @kidd-cli/core for command routing. Styled terminal output goes through @clack/prompts (see packages/cli/src/lib/sync/index.ts:7). Commands orchestrate the core sync engine and Rspress build APIs. See CLI Reference for command details.

Core Layer

Package: @ciderpress/cli (sync engine lives at packages/cli/src/lib/sync/)

The sync engine. Config loading lives separately in @ciderpress/config. See Engine for pipeline details.

ModulePurpose
lib/paths.tsPath constants for .ciderpress/ output structure
lib/sync/index.tsMain sync pipeline orchestrator
lib/sync/errors.tsSyncError and ConfigError definitions
lib/sync/types.tsSync-specific type definitions
lib/sync/copy.tsPage writing with frontmatter injection and hash tracking
lib/sync/home.tsDefault home page generation
lib/sync/manifest.tsIncremental sync tracking via content hashes
lib/sync/openapi.tsOpenAPI spec sync (dereference, MDX generation)
lib/sync/openapi-spec.tsOpenAPI spec loading and dereferencing
lib/sync/openapi-markdown.tsOpenAPI operation MDX generation
lib/sync/images.tsImage discovery, copy, and path rewriting
lib/sync/planning.tsPlanning page discovery from .planning/ directory
lib/sync/rewrite-links.tsRelative link rewriting during copy
lib/sync/strip-xml.tsXML tag stripping for planning documents
lib/sync/workspace.tsWorkspace item synthesis and card enrichment
lib/sync/frontmatter.tsFrontmatter parse(raw) and stringify(content, data) (merge + hash live in copy.ts)
lib/sync/resolve/index.tsEntry tree resolution (globs, text derivation, sorting)
lib/sync/resolve/path.tsPath resolution utilities
lib/sync/resolve/recursive.tsRecursive directory resolution
lib/sync/resolve/sort.tsEntry sorting strategies
lib/sync/resolve/text.tsText derivation from filename/heading/frontmatter
lib/sync/sidebar/index.tsSidebar and nav JSON generation
lib/sync/sidebar/inject.tsVirtual landing page generation (MDX)
lib/sync/sidebar/landing.tsLanding page MDX generation
lib/sync/sidebar/meta.tsSidebar meta resolution
lib/sync/sidebar/write-meta.tsSidebar meta serialization
lib/banner/index.tsSVG asset generation (banner, logo, icon)

UI Layer

Package: @ciderpress/ui

The Rspress theme and plugin:

ModulePurpose
plugin.tsRspress plugin: registers global UI components
config.tsRspress config factory: loads generated JSON, themes
theme/index.tsxTheme entry: re-exports Rspress base + custom styles
theme/componentsReact components: sidebar, home, workspace cards
theme/iconsIconify icon mappings for tech tags
theme/stylesCSS overrides for Rspress default theme

Data Flow

Error Handling

ciderpress uses the Result<T, E> tuple pattern for expected failures:

LayerStrategyType
Core/syncResult<T, E> tuples[error, null] or [null, value]
ConfigReturns Result<T, ConfigError> at boundary; CLI consumes and exits[ConfigError, null] or [null, CiderpressConfig]
CLIConsumes Result tuples, reports via @clack/prompts, calls process.exit(1)process.exit(1) after logging (e.g. dev-headless.ts:43-46)

Design Decisions

  1. Config is the information architecture -- A single file defines content structure, routing, navigation, and metadata. No separate sidebar/nav config files.
  2. Factories over classes -- All components are factory functions returning plain objects.
  3. Result tuples over throw -- Expected failures use Result<T, E>. No exceptions.
  4. Incremental sync -- Mtime checks, content hashes, and config hashes skip unchanged work. Manifest comparison removes stale files.
  5. Virtual pages via MDX -- Landing pages are generated at sync time as MDX with React components.
  6. Multi-sidebar from config -- Isolated sections get independent sidebar namespaces automatically.
  7. Glob-driven content discovery -- Patterns auto-discover files without manual entry per page.
  8. Frontmatter inheritance -- Entries inherit frontmatter from ancestors in the config tree.

References