Open Source · Apache-2.0

Docs Portal.

A single-file FastAPI application that discovers every project under a documentation root, renders their Markdown and HTML docs in the browser, and exports any document to PDF or an entire project to ZIP.

Install

Transcribed from the repository README; not yet executed from a clean environment:

git clone https://github.com/bulletproofsoftware-ai/bulletproof-docs-portal.git
cd bulletproof-docs-portal
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/uvicorn app:app --host 127.0.0.1 --port 8090
Docs Portal architecture infographic
Architecture infographic — from bulletproof-docs-portal/docs/media/
Domain Documentation / Developer Tooling
Repository bulletproof-docs-portal
Language Python 3.12 · FastAPI
Deployment Single uvicorn process, localhost
License Apache-2.0

1Problem Statement

Documentation accumulates across many project repositories — READMEs, docs/ trees, specification folders — with no unified way to browse it. Finding a document means knowing which repository it lives in and reading raw Markdown in an editor.

Handing a document to a stakeholder is worse. Markdown in a Git repository is not a deliverable; producing a clean PDF usually means pasting into a word processor and losing the formatting.

The portal solves exactly this and deliberately nothing more. As the README states: no auth, no database, no compliance service — one process that reads a directory tree and serves it. The scope is intentionally minimal so it can be run locally against any collection of projects without infrastructure.

2Architecture

The whole application lives in app.py. DOCS_ROOT — configurable by environment variable, defaulting to ~/Code — is resolved once at import, and every route is a read-only view over that tree.

Project discovery

_list_projects() iterates the immediate subdirectories of DOCS_ROOT and keeps only those containing at least one matching document, returning a name and a document count. Projects with no docs are hidden.

Document indexing

_list_docs_in() globs a fixed pattern set (*.md, docs/**/*.md, docs/**/*.html, **/README.md, and others), dedupes through a seen set, and skips anything under .git, node_modules, .venv, __pycache__, dist, or build.

Path-traversal guard

_safe_path() resolves both the project directory and the requested document, raising HTTP 400 unless the project resolves under DOCS_ROOT and the file resolves under the project. Every file-serving route goes through it.

Rendering

_render_markdown() runs the markdown library with fenced_code, tables, toc, codehilite, sane_lists, and attr_list, giving syntax-highlighted code blocks and anchored headings.

PDF export

doc_pdf() composes a print-specific document with a provenance line and calls WeasyPrint's HTML(...).write_pdf(). PRINT_CSS sets letter paper, 1in margins, a counter(page) " / " counter(pages) footer, and a running header via string-set.

Presentation Details

3Requirements

Requirements reflect the behaviour implemented in app.py.

IDRequirement
REQ-DP-001Discover projects as immediate subdirectories of DOCS_ROOT containing at least one document.
REQ-DP-002Index .md and .html documents using a fixed include-pattern set.
REQ-DP-003Exclude build, dependency, and VCS directories from indexing.
REQ-DP-004Reject any request resolving outside DOCS_ROOT or its project directory with HTTP 400.
REQ-DP-005Render Markdown with fenced code, tables, table-of-contents, and syntax highlighting.
REQ-DP-006Serve a raw-source view of any indexed document.
REQ-DP-007Export any document to PDF with page numbers and a running header.
REQ-DP-008Export an entire project as a streamed ZIP archive.
REQ-DP-009Group documents by top-level directory in the project view.
REQ-DP-010Expose a health endpoint reporting the docs root and project count.

4Interfaces

A small read-only HTTP surface. There is no CLI, no hook, and no MCP tool.

RoutePurpose
GET /Project index
GET /p/{project}Grouped document tree for a project
GET /p/{project}/d/{doc_path}Rendered document view
GET /p/{project}/raw/{doc_path}Raw document source
GET /p/{project}/pdf/{doc_path}PDF export of a single document
GET /p/{project}/zipZIP archive of an entire project
GET /healthzHealth check with docs root and project count
DOCS_ROOT (env)Documentation root directory, default ~/Code

5Integration Points

The portal integrates with the local filesystem and nothing else — the property that makes it safe to run anywhere.

6Repository

A deliberately small repository: one application module and pinned dependencies, alongside the usual release documentation, SBOM and scan evidence.

PathPurpose
app.pyThe complete application — discovery, rendering, PDF, ZIP, routing
requirements.txtExact-pinned dependencies (FastAPI, uvicorn, markdown, pygments, weasyprint)
README.mdInstall, native dependency, and configuration notes
docs/Install, administrator and usage guides, CycloneDX SBOM, and the security scan report
.github/workflows/ci.ymlPython 3.12 CI
SECURITY.mdVulnerability disclosure policy
LICENSE / NOTICEApache-2.0

View source on GitHub

7Implementation Notes

Constraints that matter when deciding where to run this.