This document explains how the Soliplex multi-project documentation system works and how to use it.
The Soliplex documentation site aggregates documentation from multiple git submodules located in the projects/ directory. Each submodule is a separate repository that can be updated independently. The site is built with Zensical.
soliplex.github.io/
├── docs/ # Site content directory for Zensical
│ ├── index.md # Landing page (tracked)
│ ├── img/ # Shared images (tracked)
│ ├── soliplex/ # Copied from projects/soliplex/docs/
│ ├── ingester/ # Copied from projects/ingester/docs/
│ ├── chatbot/ # Copied from projects/chatbot/docs/
│ ├── frontend/ # Copied from projects/frontend/docs/
│ ├── ingester-agents/ # Created from projects/ingester-agents/README.md
│ ├── pdf-splitter/ # Created from projects/pdf-splitter/README.md
│ ├── bubble-sandbox/ # Created from projects/bubble-sandbox/README.md
│ └── .gitignore # Ignores copied project directories
├── projects/ # Git submodules (upstream sources)
├── scripts/
│ └── build-docs.py # Copy docs + generate zensical.toml + validate nav
├── zensical.toml.template # Source of truth: site config + nav stubs (tracked)
├── zensical.toml # Generated from the template (git-ignored)
└── pyproject.toml # Dependencies, ruff & pymarkdown config
- Git Submodules: Each project is a git submodule in
projects/. - Copy step:
scripts/build-docs.pycopies each submodule'sdocs/directory (or, for README-only projects, itsREADME.mdasindex.md) intodocs/<project>/. - Config generation: the same script generates
zensical.tomlfromzensical.toml.template. Each@auto:<project>stub in the template's nav is expanded by walking the copied docs tree, so new/renamed/removed upstream pages appear automatically. The current submodule commit hashes are recorded in a[doc_sources]table for provenance. - Validation: the script validates the generated nav — failing the build on broken references or orphaned pages (copied files that no nav entry points to).
- Build:
zensical buildrenders the static site intosite/.
Copied docs/<project>/ directories and the generated zensical.toml are git-ignored; only docs/index.md, shared assets, and zensical.toml.template are tracked.
- Python 3.13+
- Git
- uv (Python package manager)
-
Clone the repository with submodules:
git clone --recursive https://github.com/soliplex/soliplex.github.io.git cd soliplex.github.io -
If you already cloned without
--recursive, initialize submodules:git submodule update --init --recursive
-
Install dependencies (including dev tools):
uv sync
To update submodules, copy docs, and generate zensical.toml:
uv run python scripts/build-docs.pyTo do the same without pulling new submodule commits:
uv run python scripts/build-docs.py --no-updateThe script will:
- Update submodules (unless
--no-update) - Clean and re-copy each project's docs into
docs/ - Generate
zensical.tomlfromzensical.toml.template - Validate the navigation (broken references and orphaned pages)
Then preview or build the site:
uv run zensical serve # Preview at http://127.0.0.1:9001/
uv run zensical build # Production build into site/To regenerate the config and validate navigation without re-copying files:
uv run python scripts/build-docs.py --validate-onlyuv run python scripts/build-docs.py [OPTIONS]Options:
--no-update: Skip thegit submodule update--validate-only: Generate the config and validate navigation; do not copy files-h, --help: Show help message
Upstream documentation changes flow in automatically — the deploy workflow runs nightly and on a repository_dispatch from each submodule repo. To roll an update in manually:
-
Update the submodule pointer:
cd projects/soliplex git pull origin main cd ../..
-
Rebuild locally and preview:
uv run python scripts/build-docs.py --no-update uv run zensical serve
-
Commit the submodule update:
git add projects/soliplex git commit -m "docs: update soliplex documentation"
build-docs.py auto-discovers any submodule under projects/ (a docs/ directory makes it a full-docs project; otherwise its README.md becomes index.md), so adding a project is mostly a navigation change:
-
Add the project as a submodule:
git submodule add https://github.com/soliplex/new-project.git projects/new-project
-
Add an
@auto:new-projectnav stub tozensical.toml.template(and any[nav_title_overrides]you want). -
Run the build and confirm the nav validates:
uv run python scripts/build-docs.py
Deployment is handled by .github/workflows/build-docs.yml, which on each run:
- Checks out the repo with submodules
- Installs dependencies with
uv sync - Lints with
ruff check . - Runs
scripts/build-docs.py - Builds the site with
zensical build - Publishes
site/to thegh-pagesbranch withghp-import
It triggers on push to main, a nightly schedule, repository_dispatch (docs_update), and manual dispatch.
If the build reports "Referenced file not found" or "Orphaned page not in navigation":
-
See exactly what is wrong:
uv run python scripts/build-docs.py --validate-only
-
Verify the files exist in the source submodule:
ls projects/PROJECT_NAME/docs/
-
A broken reference usually means a
[nav_title_overrides]key inzensical.toml.templatepoints at a path that no longer exists; an orphan means a new upstream page that the auto-generated nav now includes (no action needed) — or a stale manual entry.
If submodules won't update:
# Reset to tracking branch
git submodule update --remote --merge
# Or force update
git submodule foreach git pull origin mainThe script handles UTF-8 encoding automatically. If you still see encoding errors, ensure your terminal supports UTF-8:
# PowerShell
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8Each project submodule must have:
README.md(guaranteed to exist)- Optional:
docs/directory with markdown files
The build script handles both cases automatically.
.md— Standard Markdown (emitted into the navigation).mdx— MDX format (copied, but not added to the generated nav)
The current implementation uses Method 3 (Copy Files). Other methods were evaluated:
- Symlinks: Not cross-platform compatible (Windows issues)
- MkDocs Monorepo Plugin: Requires additional plugin and configuration
The build script is located at scripts/build-docs.py. Key pieces:
discover_projects(): Auto-detects projects underprojects/and classifies them as full-docs vs README-onlygenerate_config(): Generateszensical.tomlfrom the template, expanding@auto:nav stubsvalidate_nav(): Validates navigation — broken references and orphaned pages
Edit zensical.toml.template. Curate section structure and titles there; the per-project page lists are generated from the copied docs. All paths are relative to the docs/ directory.
- Always run the build script before deploying to ensure documentation and the generated config are current
- Validate after changes using the
--validate-onlyflag - Never edit copied docs or
zensical.tomlby hand — edit upstream sources orzensical.toml.template