GitHub Pages

The project documentation is published as a small static site from the docs/ folder in this repository.

The application does not depend on GitHub Pages. Pages hosts the project website and documentation only. Mind Archive itself is local-first and runs entirely on your own machine.

How it works

.github/workflows/docs-pages.yml builds and deploys the site with Jekyll whenever docs/ changes on main. The Markdown files stay readable both on the site and directly in the repository.

Every Markdown file needs YAML front matter. Jekyll only converts files that have it; a file without front matter is copied through verbatim, so PRODUCT.md would stay PRODUCT.md and every link to it would 404. That is exactly what happened the first time this site was built.

Every page also needs an explicit permalink. Pages live at clean lowercase routes — /product/, not /PRODUCT.html — and Jekyll will not invent one for you:

---
title: Product
permalink: /product/
---

# Product

_config.yml supplies layout: default to every page through defaults, so the front matter needs only the title and the route.

Do not add a top-level permalink: key to _config.yml. A global permalink applies to pages as well as posts. Setting /blog/:title/ at the top level once rewrote every documentation page from PRODUCT.html to PRODUCT/index.html and broke the whole nav. The blog’s permalink is scoped to type: posts inside defaults for exactly that reason. See D-036.

docs/
├── index.html          The landing page
├── blog.html           The blog index, at /blog/
├── feed.xml            RSS, hand-written — no plugin (D-035)
├── _posts/             Published posts. YYYY-MM-DD-slug.md
├── _drafts/
│   └── TEMPLATE.md     House style. Never published
├── _layouts/
│   ├── default.html    Header, appearance controls, footer — every page
│   └── post.html       Date, tags and summary on top of that
├── assets/
│   └── site.css        The same colour tokens the application uses
├── _config.yml         Jekyll settings (layout defaults, permalinks)
├── _data/
│   └── support.yml     Donation and licence URLs (D-038)
├── PRODUCT.md          These render on the site and in GitHub alike
├── ARCHITECTURE.md
├── DEVELOPMENT.md
├── SECURITY.md
├── ROADMAP.md
├── BACKLOG.md
└── DECISIONS.md

The working memory is not in here. project-memory/ sits at the repository root, one level up and outside this folder entirely, so Jekyll never sees it and no exclusion rule is needed — the site cannot publish what it cannot reach (D-039). It is useful to anyone reading the repository and noise on a public documentation site, which is exactly the split.

Enabling it

Once the repository is on GitHub:

  1. Settings → Pages
  2. Source: GitHub Actions
  3. Push to main

The site appears at https://narainsagar.github.io/mindarchive/.

The workflow needs pages: write and id-token: write permissions, which are already declared in docs-pages.yml.

Working on the site locally

python -m http.server is not enough, and will mislead you. It serves files as they are on disk. It does not run Jekyll, so no .md becomes .html and every documentation link 404s — which looks exactly like a broken site when the site is fine. Use it only to check the landing page’s own layout.

To see what GitHub will actually publish:

python scripts/dev.py docs        # http://localhost:4000

Use this rather than jekyll serve directly. Eleven pages are generated before the build — /licensing/, /agents/, /decisions/log/ and the rest — and they are git-ignored, so a bare jekyll serve shows a site that is missing them and full of dead links (D-043). dev.py docs generates them, checks every internal link, and then serves.

If you would rather drive it yourself, generate first and then build:

python scripts/sync_site_pages.py

docker run --rm -v "$PWD/docs:/srv/jekyll" -v /tmp/ma_site:/out \
  jekyll/jekyll:4 jekyll build --destination /out

python -m http.server 8080 --directory /tmp/ma_site

If you have Ruby and the gems locally, cd docs && bundle exec jekyll serve does the same thing — again, after generating.

Pages generated from the repository’s own documents

Jekyll is rooted at docs/ and cannot read above it, and the Pages build runs in safe mode so it will not follow a symlink out of the source folder either. LICENSING.md, LICENSE, CONTRIBUTING.md, CODE_OF_CONDUCT.md and .env.example live at the repository root and are therefore generated into docs/reference/ by scripts/sync_site_pages.py.

python scripts/sync_site_pages.py --list    # what is published, and where

What to check in the built output, not the source folder:

Writing a post

docs/_drafts/TEMPLATE.md is the starting point and carries the house style:

cp docs/_drafts/TEMPLATE.md docs/_posts/2026-01-31-a-short-slug.md

The date in the filename orders the blog; the URL is /blog/a-short-slug/ with no date in it, so a post does not look stale a year later. _drafts is ignored unless you build with --drafts, so work in progress never ships.

Nothing publishes itself — see decision D-035 and the Writing a blog post section of CONTRIBUTING.md.

Writing for the documentation site

Same rule as everywhere else in this project: write for humans. Short sentences, plain words, concrete examples. The documentation is part of the product, not an afterthought.

Keep it accurate. If behaviour changes, the documentation changes in the same pull request.

A note on the custom domain

This site’s eventual home is docs.mindarchive.narainsagar.com — a subdomain, so one CNAME record pointing at narainsagar.github.io is all the DNS it needs, and no apex A records are involved. The application takes mindarchive.narainsagar.com and its API takes api.mindarchive.narainsagar.com; neither is a Pages concern (D-047).

project.json holds site.domain with useCustomDomain still false, and nothing is configured. Full steps are in DEPLOYMENT.md.