cd /news/developer-tools/show-hn-plain-a-git-native-cms-in-va… · home topics developer-tools article
[ARTICLE · art-52459] src=github.com ↗ pub= topic=developer-tools verified=true sentiment=↑ positive

Show HN: Plain – a Git-native CMS in vanilla JavaScript, no database

Plain, a Git-native CMS built with vanilla JavaScript and no database, launched on Hacker News. The system stores content as plain files in a Git repository, uses static site generation for deployment, and includes an optional AI assistant for content editing. It aims to simplify web publishing by eliminating servers and databases while leveraging Git for version control and collaboration.

read6 min views1 publishedJul 9, 2026
Show HN: Plain – a Git-native CMS in vanilla JavaScript, no database
Image: source

A Git-native CMS for the AI age. The repository is the database, static files are the API, and AI is the admin.

Your whole website is a folder of plain files: Markdown for content, JSON for settings. Git gives you versioning, collaboration, and hosting hooks for free. The build turns it into a fast static site — HTML pages plus a read-only JSON API — that deploys anywhere for $0/month.

No database, no server, nothing to patch. All state lives in this repo.Vanilla by design. No frameworks, no bundlers. One dependency:. The entire engine is a few small, readable files.marked

Works without JavaScript. JS is progressive enhancement only.AI-operable. Deterministic layout, machine-readable content model, and aso agents (or Claude Code) can edit content, add collections, and write plugins safely.CLAUDE.md

Get a copy: clickUse this template(or fork) to create your own repo.** Enable hosting:in your repo, go to Settings → Pagesand set Sourceto GitHub Actions**.** Make it yours:**editsite.config.json

— set yourtitle

,description

, andurl

— and commit.- Push (or edit on github.com and commit). About 30 seconds later, your site is live.

Every later change is the same loop: edit → commit → live in ~30s. Nothing is ever lost; any version of any page can be restored from Git history.

Your live site includes an editor at ** /admin/** — a clean writing screen with Save draft / Publish buttons, live preview, image uploads, and per-page History with one-click restore. No Git knowledge needed.

Sign in once with a GitHub access token (it stays on that device):

  • On GitHub: Settings → Developer settings → Fine-grained tokens → Generate new token. - Repository access: Only select repositories→ pick your site's repo. - Permissions → Repository permissions: Contents: Read and write,** Actions: Read-only**. - Generate, copy, and paste it into the admin's sign-in screen.

The token never leaves the browser except to api.github.com. Editors who prefer files can keep editing files — the admin and direct edits coexist happily.

Prefer a button to a paste? Deploy the optional ~60-line OAuth Worker (free on Cloudflare, backed by a free GitHub App) and the sign-in screen gains "Sign in with GitHub" — one click, and each writer gets a token scoped to just that repo's contents.

AI assist (optional, BYOK): paste an Anthropic API key in Settings and the editor grows ✨ buttons — improve writing, suggest titles, generate the meta description, write image alt text, translate a page into a new draft. Every suggestion shows a before/after and asks before applying. The key stays in your browser and is sent only to Anthropic.

Every build also publishes a read-only JSON API: /api/site.json

, /api/posts/index.json

, /api/posts/<slug>.json

— plain static files any script, app, or AI agent can consume. No keys, no rate limits, cached by the CDN.

A post is a Markdown file in content/posts/

. The filename is the URL: hello-world.md

/blog/hello-world/

.

---
title: Hello world
date: 2026-07-05
description: One sentence for search engines and link previews.
tags:
  - launch
draft: false
---

Body in **Markdown**. Images by path: ![A lake](/media/lake.jpg)

Set draft: true

and the post is saved but not published. Pages work the same in content/pages/

(about.md

/about/

; index.md

is the homepage). Menus live in data/navigation.json

; renamed URLs get an entry in data/redirects.json

.

First sign in and the admin greets you with a five-step wizard: pick what you're building, name it, see it (a live preview already wearing your name), write your first words, and go live. Under the hood it applies a starter — a theme plus the right content types, menu, and example content.

Fifteen starters ship in the box: Journal (blog), Toolbox (trades & local services), Studio (portfolio), Bistro (restaurant), Manual (documentation), Terminal (developer blog), Letters (newsletter & essays), Launch (startup/SaaS), Gazette (local news & magazine), Folio (résumé/CV), Keys (real estate), Cause (nonprofit), Practice (clinic), Form (fitness studio), and Encore (band & artist). The Appearance screen lets you try any of them on your own pages — with device widths and a light/dark toggle — before committing, and a customizer exposes each theme's colors and fonts as live controls. Your tweaks survive theme updates.

A plugin is a folder — install one by copying it into plugins/

and adding its name to "plugins"

in site.config.json

. Ships with search (enabled: a /search/

page over a prebuilt index, no services involved) and contact-form (disabled reference: write [[contact-form]]

in any page, point it at a Formspree-style endpoint). The full hook API is documented in CLAUDE.md — it's small enough that "write me a plugin that adds reading time" is a one-prompt job for an AI agent. Also included:

reading-time(enabled) — written by an AI agent from the docs alone, in one prompt, as proof of that claim — plus

api-form(forms declared in config, POSTing to your own backend via the

"services"

map) and goatcounter(opt-in page-view counts). Good first plugins: giscus comments, image gallery, table of contents.

Already have a site? The importers under tools/migrate/

convert it — content, media, and a complete old→new redirect map so your URLs (and your SEO) survive the move. Run one on your machine:

node tools/migrate/jekyll.js /path/to/your-jekyll-site

It writes content/

, media/

, and data/redirects.json

into ./plain-import/

(never touching your working tree) plus a migration report of anything that needs a human eye. Copy those folders into your plain repo and build. Jekyll ships today; Hugo, Eleventy, and WordPress are on the roadmap (§15).

The full step-by-step walkthrough — keeping your URLs, wiring forms and analytics, the cutover checklist — is tools/migrate/README.md.

plain follows semver. Engine files (build.js

, lib/

, admin/

, themes/default/

) are upstream-owned; your content, config, and custom themes are yours. When a new version ships, the admin shows an Update available banner: click it and a pull request appears with the changelog and any files you'd customized flagged for review. Merge to upgrade, revert to roll back — never a surprise. An optional weekly workflow opens that PR on its own, so even an unattended site keeps getting security fixes as reviewable PRs. See §14 for the mechanism.

npm install
node build.js            # build into dist/
node build.js --watch    # serve on http://localhost:4000, rebuild on change
node --test tests/       # run the test suite
node tools/engine-manifest.js   # regenerate engine.json before a release
site.config.json   all configuration: site info, collections, plugins
config.defaults.json  engine-owned defaults, merged under your config
content/           your words (Markdown, one file per page/post)
data/              navigation, redirects (JSON)
media/             images and files
themes/            fifteen starters ship in the box; add your own
plugins/           a plugin is a folder; install = copy + enable in config
admin/             the browser editor (static, vanilla ES modules)
tools/migrate/     importers (Jekyll today)
workers/oauth/     optional "Sign in with GitHub" worker (v1 uses a token)
build.js + lib/    the whole engine — under 2,500 lines, one dependency, MIT

The full product specification lives in cms-spec.md; instructions for AI agents (and how to add collections, plugins, themes) in

. To contribute, read

CLAUDE.md

.

CONTRIBUTING.md

MIT — open source from day one. Themes, plugins, and importers are the adoption engine; the core will never be closed.

── more in #developer-tools 4 stories · sorted by recency
── more on @plain 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/show-hn-plain-a-git-…] indexed:0 read:6min 2026-07-09 ·