MkDocs Material for Forge: Build Handoff¶
Date: 2026-04-28
Owner: the Opus worker spawned to do this build
Parent session: n8n-telegram_Opus47 (Building The Brain conversation)
Estimated effort: ~45 min
Related handoff: Building The Brain
The Goal¶
Justin needs a web-based markdown viewer for everything in /home/justinwieb/forge so he can read his memory/handoffs/docs/nexus from his phone or any browser without fighting VS Code. Built with MkDocs Material, exposed at forge.justinkrystal.com behind Cloudflare Access. Auto-rebuilds when files change. Mobile-responsive. Full-text search.
When done, he'll be able to tap a link in chat like https://forge.justinkrystal.com/memory/handoffs/building-the-brain-life-os-inbox-2026-04-27/ from his phone and read it instantly.
Why MkDocs Material (the decision is locked, don't redebate)¶
- Static site generator, no DB, no live process risk
- Material theme = beautiful, mobile-responsive, dark mode toggle
- Built-in full-text search (lunr.js, ranked)
- Free + open-source
- ~45 min total to set up
- Auto-rebuild on file change via
mkdocs servewatcher OR a small systemd service
Scope, what the site indexes¶
Include:
| Folder/file | Purpose |
|---|---|
| memory/daily/*.md | Daily logs |
| memory/general/*.md | Topical knowledge (ideas.md, etc.) |
| memory/handoffs/*.md | All handoff docs |
| memory/sessions/*.md | Captured session output |
| system-map/*.md | Fleet, architecture, steering |
| docs/**/*.md | Infra docs, playbooks |
| brands/**/*.md | Brand notes (where md exists) |
| infra/n8n/*.md | Outbound pattern, n8n README |
| CLAUDE.md | Bootstrap doc, root level |
Exclude:
- logs/ (operational logs)
- tasks/ (queue JSON)
- data/ (SQLite DBs)
- comms/ (file-based bus)
- dashboard/ (HTML/CSS for fleet dashboard, served separately on :8099)
- assets/ (binaries)
- sites/ (deployable sites, they have their own URLs)
- scripts/ (code, not docs, except top-level READMEs if any)
- .claude/, .git/, node_modules/, ~/.forge-secrets/, anything dotfile
Likely approach¶
1. Install MkDocs Material on UDev¶
# Use a dedicated venv to keep deps isolated
python3 -m venv ~/.forge-venvs/mkdocs
source ~/.forge-venvs/mkdocs/bin/activate
pip install mkdocs-material mkdocs-monorepo-plugin pymdown-extensions
2. Build the mkdocs config¶
Decision: rather than restructuring forge to look like a standard docs/ tree, use mkdocs-monorepo-plugin OR docs_dir: . with nav overrides OR a small build-time symlink generator.
Cleanest: write infra/mkdocs/mkdocs.yml at this shape:
site_name: Forge
site_url: https://forge.justinkrystal.com
docs_dir: ../../ # forge root
site_dir: /var/www/forge-mkdocs/ # build output
theme:
name: material
palette:
- scheme: default
toggle: { icon: material/weather-sunny, name: dark }
- scheme: slate
toggle: { icon: material/weather-night, name: light }
features:
- navigation.instant
- navigation.tracking
- navigation.sections
- navigation.expand
- navigation.top
- search.suggest
- search.highlight
- content.code.copy
plugins:
- search
- exclude:
glob:
- logs/*
- tasks/*
- data/*
- comms/*
- dashboard/*
- assets/*
- sites/*
- scripts/*
- .claude/*
- .git/*
- node_modules/*
- infra/mkdocs/* # don't index ourselves
- "*.json"
- "*.py"
- "*.sh"
- "*.html"
- "*.css"
- "*.png"
- "*.jpg"
- "*.webp"
markdown_extensions:
- admonition
- codehilite
- pymdownx.superfences
- pymdownx.tabbed
- pymdownx.highlight
- toc:
permalink: true
nav:
- Home: CLAUDE.md
- Memory:
- Daily: memory/daily/
- General: memory/general/
- Handoffs: memory/handoffs/
- Nexus:
- Fleet: system-map/fleet.md
- Architecture: system-map/architecture.md
- Steering: system-map/steering.md
- Docs: docs/
- Brands: brands/
(Hand-tune the nav once you see what builds.)
3. Serve it¶
Two options, pick whichever works:
Option A: Static build + nginx-style serve (recommended for prod)
- mkdocs build outputs to site_dir
- Serve via python3 -m http.server on port 8000 (simple) OR caddy / nginx
- Wrap in a systemd service forge-mkdocs.service that runs the server
- Add a file watcher (mkdocs serve itself, OR inotifywait + rebuild) for auto-update
Option B, mkdocs serve directly (dev mode, has live reload built-in)
- Run mkdocs serve --dev-addr 0.0.0.0:8000 as systemd service
- Auto-rebuilds on file change
- Slightly heavier than static + http.server but zero extra plumbing
- Recommended for v1, simpler, gets shipped tonight
4. Cloudflare Tunnel ingress¶
Use the existing media-server tunnel (id a55b7768-b42a-4d78-82b5-4a427bdbb9b7, catch-all for *.justinkrystal.com). Use the /cf-add skill:
https://forge.justinkrystal.com/ from outside the LAN.
5. Cloudflare Access in front¶
Pattern matches what's on n8n.justinkrystal.com:
- Cloudflare Zero Trust → Access → Applications
- Add a self-hosted app for forge.justinkrystal.com
- Policy: email = [email protected] (Justin's hardened account)
- Justin authenticates via email OTP / Google sign-in
- Anyone hitting forge.justinkrystal.com without auth → 302 to Cloudflare login
6. Test¶
curl https://forge.justinkrystal.com/→ 302 to CF Access (proves Access works)- After login, browse from phone
- Use search bar, verify it returns results
- Tap a daily log link, confirms file viewing
- Confirm the Building The Brain handoff renders properly
Files you'll work with¶
| File | Purpose |
|---|---|
infra/mkdocs/mkdocs.yml |
MkDocs config (NEW) |
infra/mkdocs/build.sh |
Optional rebuild trigger (NEW) |
infra/systemd/forge-mkdocs.service |
systemd unit (NEW) |
~/.forge-venvs/mkdocs/ |
Isolated Python venv |
~/.forge-secrets/cloudflare.env |
Already exists, scoped CF token |
scripts/cloudflare/cf.py |
Existing CF API wrapper for /cf-add |
MEMORY.md |
Add a new "Tools & Pipelines" entry pointing to the new reference doc |
~/.claude/projects/-home-justinwieb-forge/memory/reference_mkdocs.md |
NEW, register the tool |
Don't do¶
- ❌ Don't expose without Cloudflare Access. Forge contains credentials, infra docs, daily logs, secrets references. Public exposure = catastrophic. Verify Access is active before declaring done.
- ❌ Don't index
logs/,tasks/,data/,comms/,dashboard/,assets/,sites/,scripts/,.claude/, secrets. Confirm withfind site_dir -name '*.html' | wc -lmakes sense (a few hundred, not thousands). - ❌ Don't break the existing media-server tunnel. Use
/cf-add(which is non-destructive), don't hand-edit the tunnel config in a way that loses other ingress rules. - ❌ Don't put the venv inside the forge repo. Use
~/.forge-venvs/mkdocs/like the other forge venvs. - ❌ Don't use Opus for the worker's own internal subtasks. You ARE Opus, but if you spawn helpers, keep them Sonnet/Haiku. (Likely no helpers needed for a build this small.)
- ❌ Don't skip the systemd unit. Justin will reboot UDev someday; the viewer needs to come back automatically.
Deliverables¶
- Working
https://forge.justinkrystal.com/behind Cloudflare Access - Auto-rebuild on file change (mkdocs serve OR a watcher), verify by editing a file and seeing it update without restart
- systemd unit
forge-mkdocs.serviceenabled + active infra/mkdocs/mkdocs.ymlchecked into the repo- Reference doc
~/.claude/projects/-home-justinwieb-forge/memory/reference_mkdocs.mdwritten - MEMORY.md "Tools & Pipelines" section updated with a one-line pointer
- Push back to the parent session with: live URL + brief proof it works (e.g. screenshot of search returning results, OR curl output): Justin is in the parent session waiting
Done when¶
-
forge.justinkrystal.comreturns content from outside the LAN, behind Access - Search works (try query "Building The Brain", confirm the new handoff shows up)
- At least 5 daily logs are browseable
- Justin can tap
https://forge.justinkrystal.com/memory/handoffs/building-the-brain-life-os-inbox-2026-04-27/on his phone and it renders - Service survives a
systemctl restart forge-mkdocs - Documented in MEMORY.md
Conversation pointers¶
- Parent conversation: tonight's
n8n-telegram_Opus47session - Daily log:
memory/daily/2026-04-28.md(today) andmemory/daily/2026-04-27.md(yesterday's checkpoints have full context) - Master vision doc:
memory/handoffs/building-the-brain-life-os-inbox-2026-04-27.md - CF tunnel reference: MEMORY.md
## External Service Access→ Cloudflare API - Existing CF Access pattern: applied to
n8n.justinkrystal.com, copy that /cf-addskill at.claude/skills/cf-add/SKILL.md/decrypt-n8nskill at.claude/skills/decrypt-n8n/SKILL.md(not needed but adjacent)
Final note¶
Justin is on Remote Control (Claude Code Web) on his phone, watching this build happen. When done, push the live URL back to the parent session by writing the URL + status to a file or by notify skill, he'll see it and pick up the Notion redesign from there.