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 /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.
# 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__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.1.0
# Or pull it locally first
helm pull oci://ghcr.io/sunbeamdotpt/doc/chart --version 0.1.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.
- Rust + Axum — async HTTP API
- PostgreSQL + sqlx — strongly-typed queries with compile-time checking
- 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