| title | Documentation Server |
|---|
A lightweight, read-only documentation aggregation service. It discovers markdown documents across your GitHub organization, syncs them automatically, and serves them through a simple filesystem-like HTTP API.
Documentation lives scattered across repositories. Rather than manually curating a docs site, this service treats your org's repos as the source of truth. It discovers README.md and files under docs/ automatically, parses YAML frontmatter, and exposes everything through a stable URL structure. The API is designed around a filesystem metaphor because developers already think in paths.
The API is organized as a virtual filesystem rooted at each repository:
GET / → list all public repos
GET /{repo}/ → list documents in a repo
GET /{repo}/__tree__ → recursive tree of all documents
GET /{repo}/{path} → fetch a specific document
GET /__index__ → global search index across all repos
GET /__search__?q=… → full-text search with snippets
GET /sitemap.xml → SEO sitemap for crawlers
GET /health → health check
The full API schema is available at runtime:
GET /openapi.json— OpenAPI 3.1 JSONGET /openapi.yaml— OpenAPI 3.1 YAMLGET /swagger-ui/— Interactive Swagger UI
Append ?raw=1 or send Accept: text/markdown to get the raw markdown body without JSON wrapping.
GET /__search__ runs a full-text query across every public document —
titles, tags, and body content — using an embedded tantivy
index that lives in server memory:
GET /__search__?q=<query>&repo=<optional repo name>&limit=<default 12, max 50>
{
"query": "benchma",
"hits": [
{
"repo": "hyperlight",
"repo_full_name": "sunbeamdotpt/hyperlight",
"path": "/benchmarks.md",
"title": "Benchmarks",
"snippet": "…best-matching plain-text fragment (≤ 300 chars)…",
"score": 12.34
}
]
}pathis the normalized path (same form the portal routes on).- Typo tolerance: terms match with edit distance 1; the last term also
prefix-matches, so partial input (
benchma→benchmarks) works. - Title matches rank above tag matches, which rank above body matches.
reposcopes results to a single repository (exact name).- The index is rebuilt on boot and after every successful sync run — no external search service, nothing to back up.
Paths may contain spaces (e.g. docs/guide with spaces/intro.md).
Request such documents with percent-encoded segments
(/test-repo/my%20file.md); responses keep normalized_path raw while
url fields and the sitemap are percent-encoded.
# Spaces in file names: encode the request, read the raw path back
curl https://doc.example.com/backrooms/guide%20with%20spaces/intro.md?raw=1# List all repositories
curl https://doc.example.com/
# Get a document as JSON (frontmatter + body)
curl https://doc.example.com/backrooms/getting-started
# Get raw markdown
curl https://doc.example.com/backrooms/getting-started?raw=1Documents are discovered via a GitHub App with read access to your organization's repositories. On each sync cycle:
- Lists all public repositories
- Extracts
README.md(mapped to/within the repo) - Extracts all files under
docs/(mapped without thedocs/prefix) - Parses YAML frontmatter into structured metadata
- Soft-deletes documents that no longer exist upstream
Private repositories are never indexed or exposed.
Documents may include YAML frontmatter:
---
title: Getting Started
description: How to enter the Backrooms
author: sienna
tags: [guide, safety]
---
# Getting StartedAll frontmatter fields are optional. The title field is used for display; description and tags power search and indexing.
docker run -p 8080:8080 \
-e DOCS__GITHUB_APP_ID=4017767 \
-e DOCS__GITHUB_PRIVATE_KEY="$(cat key.pem)" \
-e DOCS__DATABASE_URL="postgres://user:pass@host/db" \
ghcr.io/sunbeamdotpt/doc:latest| Environment Variable | Description |
|---|---|
DOCS__GITHUB_APP_ID |
GitHub App ID |
DOCS__GITHUB_PRIVATE_KEY |
GitHub App private key (PEM) |
DOCS__DATABASE_URL |
PostgreSQL connection string |
DOCS__BIND_ADDRESS |
HTTP bind address (default: 0.0.0.0:8080) |
DOCS__BASE_URL |
External base URL for sitemap/links |
DOCS__ALLOWED_ORIGINS |
Comma-separated CORS origin allowlist (default: https://sunbeam.pt) |
DOCS__POLL_INTERVAL_SECONDS |
Sync interval (default: 300) |
The chart is published as an OCI artifact to GitHub Container Registry:
# Install directly from GHCR
helm install doc oci://ghcr.io/sunbeamdotpt/doc/chart --version 0.2.0
# Or pull it locally first
helm pull oci://ghcr.io/sunbeamdotpt/doc/chart --version 0.2.0 --untar
helm install doc ./docYou can also use the local source at helm/doc/:
helm install doc ./helm/docSee values.yaml for configuration options including Kubernetes secrets support and an optional 1Gi persistent volume (persistence.*).
- Rust + Axum — async HTTP API
- PostgreSQL + sqlx — strongly-typed queries with compile-time checking
- tantivy (in-memory) — full-text search rebuilt after each sync
- moka LRU cache — hot paths cached with TTL invalidation
- Background sync — tokio task polls GitHub on a configurable interval
- Multi-arch container — ~15-20MB distroless image for
linux/amd64andlinux/arm64
MIT — Copyright (c) 2026 Sunbeam Studios