Where documentation takes shape.
Pagenary turns a folder of Markdown in a git repo into a fast, searchable, SEO-ready documentation site you host yourself — for next to nothing. Write your docs, run one tool, and deploy the static output to any free static host (GitHub/Gitea Pages, Netlify, Cloudflare Pages, S3, a CDN, or your own box). No server, no database, no monthly SaaS bill — just the things you'd expect from a paid docs platform: command-palette search with ranking, theming and branding, Mermaid diagrams, syntax highlighting, SEO, and one-click export.
It's a great fit if you're shipping a project, an app, or a side project and want real docs without the overhead. And when you outgrow one site, the same tool publishes many from a shared template catalog — so it scales from a weekend project to a multi-product portal without changing tools.
Built with AIWG, the multi-agent AI framework used to plan, audit, and ship this project.
npm install --save-dev @pagenary/publisher # add Pagenary to your project
npx pagenary build my-docs # build your docs tenant
npx pagenary serve # serve on http://localhost:5173Docs Site · Quick Start · Features · Architecture · Documentation
Pagenary is a static site generator for documentation. The core application is the publisher (apps/publisher/): point it at your content (Markdown, HTML, or JS) plus a small config file, and it produces a self-contained docs site with search, navigation, theming, and SEO built in. The same engine scales to many sites through a shared template/tenant model, so one repository can publish anywhere from a single site to a dozen.
Each published bundle is a static single-page app — hash-based routing (#/page-id), no server-side rendering, no runtime dependencies. You build it once and host the output anywhere that serves files. Asset and module URLs resolve through a per-tenant <base>, so the same bundle works whether a tenant is served at its own domain root or mounted under a subpath of a shared host. Tenants share the template catalog but keep isolated content, branding, navigation, and domains, so a single repository can publish a dozen distinct documentation sites — each with real ranked search and SEO-ready output, not just static pages.
Pagenary is composed from a small set of plain inputs:
- Templates — the shared section catalog (
welcome,guide,reference,tutorial, …) that defines how each page type renders - Tenants — a named publication with its own content, branding, and navigation, defined under
tenants/<tenant-id>/ - Content — Markdown (
.md), HTML (.html), or JS modules (.js) that supply each tenant's pages - Manifests — per-tenant navigation structure and section metadata
- Overrides — post-build file replacements for tenant-specific customization
Nothing is bundled at runtime. The build resolves templates + content + config into static dist/<tenant-id>/ output the browser reads directly.
The leverage comes from the template/tenant split:
- One template improvement (better search, a new page category, an accessibility fix) propagates to every tenant on the next build.
- One tenant is a thin layer — content, a config file, a manifest — over the shared catalog, so standing up a new branded site is cheap.
- Branding, theming, and navigation are data, not code: a tenant changes its look through
config.json, not by forking the generator. - Builds are Git-aware and incremental, so a large multi-tenant repository rebuilds only what changed.
The result is that the marginal cost of an additional documentation site trends toward the cost of its content alone.
- Not a hosted service. Pagenary produces static files. You own hosting — any static host, CDN, or the bundled Caddy setup works.
- Not a runtime framework. The published output has zero runtime dependencies. There is no server to run and nothing to import into a consuming app.
- Not a headless CMS. Content lives as files (Markdown/HTML/JS) in the repository, versioned with everything else — not in a database behind an API.
Developers and app makers who want real documentation for a project without standing up — or paying for — a hosted docs platform: solo devs, indie hackers, and small teams shipping fast. You get a searchable, SEO-ready site from a git repo and a free static host.
It scales up cleanly, too: teams publishing many sites from shared conventions — white-label SaaS docs, multi-product portals, agency-managed client docs — use the same template/tenant model to keep them consistent without maintaining each one by hand.
Maintaining several documentation sites by hand has three recurring failure modes:
Each site is edited independently, so structure, navigation, and styling diverge over time. A fix applied to one portal never reaches the others.
Without Pagenary: Every site is a snowflake. Consistency is a manual, never-finished chore.
With Pagenary: All tenants render from one template catalog. A structural or visual change is made once and rebuilt into every bundle.
Customizing a site's look means forking the generator or hand-editing output, which makes upgrades painful.
Without Pagenary: Branding changes require touching build logic; tenant-specific tweaks accumulate as un-mergeable forks.
With Pagenary: Branding is per-tenant configuration (config.json — colors, brand marks, typography) plus optional overrides/. The generator stays shared and upgradable.
Regenerating every site on every change wastes time as the number of tenants grows.
Without Pagenary: Build time scales with the whole repository, not the change.
With Pagenary: Git-aware incremental builds (build:incremental, build:diff) rebuild only the tenants and pages affected by a change.
Each tenant is defined in tenants/<tenant-id>/ with a manifest.json (navigation overrides), a content/ directory, and optional overrides/. The build emits an isolated dist/<tenant-id>/ bundle with its own manifest.js and sections/.
src/sections/section-templates.js is the shared catalog. Categories (welcome, guide, reference, tutorial, …) define rendering for each page type, so all tenants inherit consistent page structure.
Published bundles are single-page apps. All navigation runs client-side through app.js via #/page-id routes — no server-side rendering, deployable as plain files.
Tenant content can be Markdown (converted to HTML by a lightweight parser), HTML (wrapped and shipped as-is), or JS modules (copied unchanged; must export load() returning { html, afterRender? }).
Per-tenant config.json controls title, brand marks, tagline, accent and surface colors, and typography. Branding is data the build applies, never a fork of the generator.
The build pipeline tracks changes against Git to support incremental and diff-only rebuilds, keeping large multi-tenant repositories fast to publish.
Shipping a project or app and wanting polished, searchable docs you host yourself for ~free — no SaaS subscription, no server to run, just a git repo and a static host. It's equally at home publishing many sites that share structure but differ in content and branding (white-label docs, multi-product portals, agency/client documentation). Especially strong when you want real in-page search and clean SEO out of the box, with flexible hosting: a site on its own domain, or many mounted under subpaths of a single host (e.g. docs.example.com/product-a/, /product-b/).
Content that must be edited by non-technical authors through a web UI (you write Markdown/HTML/JS in the repo, not in a CMS), or a site that genuinely needs server-side rendering or dynamic, per-request content. Pagenary produces static files.
Your docs live as files in git, not in a hosted CMS behind a login. In return you get zero hosting cost, full version control, and no vendor lock-in — and the option to scale from one site to many on the same shared-catalog model, which is what keeps a fleet of sites from drifting apart.
Templates + per-tenant content/config
│
▼
apps/publisher (build)
│
▼
dist/<tenant-id>/ ── static SPA bundle (hash routing, zero runtime deps)
│
▼
Any static host / CDN / bundled Caddy
- Define a tenant under
tenants/<tenant-id>/with content, a manifest, and a branding config. - Build with the publisher — templates from the shared catalog are merged with the tenant's content and config.
- Output lands in
dist/<tenant-id>/as a self-contained static SPA with a tenant-specificmanifest.jsandsections/. - Serve the bundle from any static host, or use the bundled Caddy setup for multi-tenant domain testing.
- Multi-Tenant Architecture — isolated content, branding, and configuration per tenant
- Zero Runtime Dependencies — published output is vanilla HTML, CSS, and ES modules
- Fortemi-backed search + graph — command palette (
Ctrl/Cmd+K) ranks results with snippets over a static chunked index (@fortemi/core), with lazy precache, infinite scroll, page metadata, and an inspectable Docs Map with weighted relationships and a static fallback snapshot — all client-side (no server, no WASM) - SEO-first output — metadata-driven page titles, a configurable no-JS root HTML fallback, crawlable
/pages/static snapshots, andsitemap.xml/robots.txt/llms.txt/ JSON-LD / Open Graph generated at build time - Agentic SEO / AI discoverability surfaces — GEO/AEO-friendly static output, open-profile corpus artifacts,
llms.txt, and Git-native review loops for agent-proposed maintenance without silent live-site mutation - Flexible hosting — per-tenant
<base>resolution serves the same bundle at a domain root or under a subpath; any static host, CDN, or the bundled Caddy - Mermaid Diagrams — native flowcharts, sequence diagrams, and more
- Syntax Highlighting — Prism.js integration for code blocks
- Theming — per-tenant colors, branding, and typography
- Blog Layout — a reading-first
layout: "blog"family: chronological post index, hero post pages, post navigation, optional living scroll, and themeable like the docs layout - Page Effects — opt-in, accessible primitives: hero/banner (full-bleed, overlay, parallax, sticky, CTA band), reveal-on-scroll and staggered reveal, a reading-progress bar, living scroll, disclosure accordions, scroll-snap sections, scrollytelling, figure zoom, generalized parallax, and a quick-copy control on code blocks — authored by class, fenced HTML, or a declarative frontmatter block
- Navigation — collapsible sidebar with configurable drawer modes (
overlay/push/instant) and an opt-in on-this-page TOC (scroll-spy, prev/next) with selectable placement: a persistent nav-style list in the right gutter or left sidebar mirror, a bordered top block, or a pinnable/collapsible rail with a viewport-capped internal heading scroller - Document Export — compile the current page or whole site to the browser's print / Save-as-PDF dialog (no pop-up window); configurable per tenant
- Incremental Builds — Git-aware builds for fast iteration
Pagenary is an npm package — no clone required to use it. New to Pagenary? The Getting Started guide walks you from zero to a published docs site step by step.
# See the available commands
npx @pagenary/publisher --help
# Add it to your project, then build and serve your docs
npm install --save-dev @pagenary/publisher
npx pagenary build my-docs # build your tenant (see "Creating Your First Tenant")
npx pagenary serve # serve on http://localhost:5173pagenary commands: build, serve, tenants list, check, new (run pagenary --help for the full list).
Extra flags pass through to the underlying script (e.g.
pagenary build --incremental). The published tarball also ships a
compiled reference site under site/ — the Pagenary docs, built by Pagenary
itself.
Clone the repo only if you want to change the templates, hack on the generator, or develop Pagenary itself — not to use it:
git clone https://github.com/jmagly/pagenary.git
cd pagenary && npm run bootstrap
npm run publisher:build && npm run publisher:serve # default bundle → http://localhost:5173
npm run publisher:build:tenants # all tenant bundlesThis project is developed with AIWG. On this host, the AIWG
project source is available at ~/dev/aiwg for maintainers who want to inspect,
build, or run the framework that supports Pagenary development.
With @pagenary/publisher installed in your project (npm install -D @pagenary/publisher):
- Register the tenant in a
tenants.jsonat your project root (validated by the bundledtenants.schema.json):
{
"tenants": [
{
"id": "my-docs",
"source": { "type": "local", "path": "./docs" },
"strictLinks": true
}
]
}- Add your content under the source path:
docs/
├── config.json # branding and theme
├── manifest.json # navigation structure (optional)
└── content/
├── welcome.md # Markdown content
├── guide.html # HTML content
└── dashboard.js # dynamic JS modules
- Configure branding in
config.json:
{
"title": "My Documentation",
"brandMark": "ACME",
"brandSub": "Docs",
"tagline": "Your tagline here",
"accentColor": "#6366F1",
"surfaceColor": "#F7FAFC"
}- Build and preview:
npx pagenary build my-docs
npx pagenary serve
# Visit http://localhost:5173/my-docs/Building Pagenary from source instead? Use
npm run publisher:build:tenants my-docsand register tenants inapps/publisher/tenants.json.
Static SPA pattern: hash-based routing (#/page-id), no server-side rendering. All navigation runs through app.js; all styling lives in a single styles.css.
Key files:
src/manifest.js— navigation structure and section metadatasrc/sections/section-templates.js— template catalog with category-based renderingsrc/app.js— router, command palette, and export logicscripts/build-tenants.js— multi-tenant bundle generation
Repository layout:
pagenary/
├── apps/
│ └── publisher/ # Static site generator
│ ├── src/ # SPA shell and templates
│ ├── scripts/ # Build, serve, and utility scripts
│ ├── tenants/ # Built-in example tenants
│ ├── docs/ # Developer documentation
│ └── dist/ # Build output
├── package.json # Workspace orchestration
└── README.md
Using the installed package (the default — npx pagenary <command>):
npx pagenary build # build the default bundle to dist/
npx pagenary build [id] # build a tenant; --all builds all enabled tenants
npx pagenary tenants list # list configured tenants
npx pagenary serve # serve dist/ on localhost:5173From source (after cloning — for contributors / Pagenary development):
npm run bootstrap # install all workspace dependencies
npm run publisher:build # build default bundle
npm run publisher:build:tenants # build all tenant bundles
npm run publisher:serve # serve dist/ on localhost:5173
# from apps/publisher/:
npm run dev # build + serve with watch
npm run build:incremental [id] # Git-aware incremental build
npm run caddy:up # start multi-tenant Caddy server
npm test # run test suite- Tenant registration — a
tenants.jsonat your project root (orapps/publisher/tenants.jsonwhen building from source), validated bytenants.schema.json - Branding & theme — per-tenant
config.json(title, brand marks, tagline, colors, typography) - Navigation — per-tenant
manifest.jsonoverrides the shared structure - Post-build overrides — drop replacements in a tenant's
overrides/directory - Multi-tenant domains — the bundled
Caddyfile+docker-compose.ymlserve tenants by domain for local testing (npm run caddy:up)
The full documentation site is published at docs.pagenary.com — built by Pagenary from the source files below (Pagenary dogfooding its own publisher). Read it online, or browse the source:
- Getting Started — start here: zero to a published docs site using the npm package
- Publisher README — full feature documentation
- Quick Start Guide — step-by-step tenant setup
- Publish with GitHub/Gitea Actions — make any docs repo Pagenary-ready: copy-paste CI workflows + auto-discovery (no manifest required)
- Consuming and Embedding Blog Updates — use
@pagenary/blog-client,<pagenary-blog>, and CORS/CDN settings for cross-site updates pages - Tenant Configuration — all config options
- Theming Recipes — copy-paste recipes for colors, fonts, and nav positions, with screenshots
- Architecture — system design
- API Reference — module documentation
- Deployment — hosting patterns
- Releasing — CalVer release + npm publish flow
Contributions are welcome.
- Found a bug or have a request? Open an issue
- Improving a template benefits every tenant — changes to
src/sections/are high-leverage - Run
npm test(fromapps/publisher/) before opening a PR - Releases follow CalVer (
YYYY.M.PATCH); see docs/contributing/releasing.md
- Issues: GitHub Issues
- Discussions: GitHub Discussions
GNU Affero General Public License v3.0 — strong copyleft. You may use, modify, and distribute Pagenary, but if you run a modified version to provide a network service, you must make the modified source available to its users. See LICENSE.
Built with vanilla web standards and a small set of best-in-class libraries — Mermaid for diagrams and Prism.js for syntax highlighting — kept out of the runtime bundle wherever possible.
Made with care by Joseph Magly