diff --git a/docs/plans/2026-06-20-initial-scaffold.md b/docs/plans/2026-06-20-initial-scaffold.md
new file mode 100644
index 0000000..7441aad
--- /dev/null
+++ b/docs/plans/2026-06-20-initial-scaffold.md
@@ -0,0 +1,250 @@
+# Spine Initial Scaffold — Implementation Plan
+
+**Goal:** A minimal Emacs web server that serves a templated "Hello from Emacs." page, exercising the `simple-httpd` + `mustache.el` stack end-to-end.
+
+**Architecture:** Single `spine.el` entry point bootstraps packages, starts `simple-httpd` on port 8080, and registers a `/hello` servlet. Templates are `.mustache` files read from a `templates/` directory relative to `spine.el`.
+
+**Tech Stack:** Emacs Lisp, `simple-httpd` (MELPA), `mustache` (MELPA), `ht` (transitive).
+
+---
+
+## File structure
+
+| File | Responsibility |
+|------|---------------|
+| `templates/hello.mustache` | Smoke-test HTML template with `{{title}}` and `{{message}}` placeholders |
+| `spine.el` | Entry point: package bootstrap, server config, template renderer, `/hello` handler |
+
+`spine.el` is the sole Elisp file. No project file, no Makefile — invocation is `emacs --quick --load spine.el`.
+
+---
+
+### Task 1: Create the hello.mustache template
+
+**Files:**
+- Create: `templates/hello.mustache`
+
+- [ ] **Step 1: Create templates/ directory and hello.mustache**
+
+```bash
+mkdir -p templates
+```
+
+Write `templates/hello.mustache`:
+
+```html
+
+
+
+
+
+ {{title}}
+
+
+ {{message}}
+
+
+```
+
+- [ ] **Step 2: Verify template file exists**
+
+Run: `cat templates/hello.mustache`
+Expected: outputs the template content above.
+
+- [ ] **Step 3: Commit**
+
+```bash
+git add templates/hello.mustache
+git commit -m "feat: add hello.mustache smoke-test template"
+```
+
+---
+
+### Task 2: Write spine.el entry point
+
+**Files:**
+- Create: `spine.el`
+
+- [ ] **Step 1: Write the full spine.el**
+
+Write `spine.el`:
+
+```elisp
+;;; spine.el — personal reading tracker, served from Emacs
+
+;; --- package bootstrap ------------------------------------------------
+
+(require 'package)
+(add-to-list 'package-archives
+ '("melpa" . "https://melpa.org/packages/")
+ t)
+(package-initialize)
+
+(dolist (pkg '(simple-httpd mustache))
+ (unless (package-installed-p pkg)
+ (package-refresh-contents)
+ (package-install pkg)))
+
+(require 'simple-httpd)
+(require 'mustache)
+
+;; --- configuration ----------------------------------------------------
+
+(defvar spine-port 8080
+ "Port for the Spine HTTP server.")
+
+(defvar spine-template-dir
+ (expand-file-name "templates/"
+ (file-name-directory load-file-name))
+ "Directory containing .mustache templates.")
+
+;; --- template rendering -----------------------------------------------
+
+(defun spine-render (name context)
+ "Render templates/NAME.mustache with CONTEXT (an ht hash table).
+Returns the rendered string."
+ (mustache-render
+ (with-temp-buffer
+ (insert-file-contents
+ (expand-file-name name spine-template-dir))
+ (buffer-string))
+ context))
+
+;; --- handlers ---------------------------------------------------------
+
+(defservlet hello text/html ()
+ (insert (spine-render "hello.mustache"
+ (ht ("title" "Spine")
+ ("message" "Hello from Emacs.")))))
+
+;; --- start ------------------------------------------------------------
+
+(setq httpd-port spine-port)
+(httpd-start)
+(message "Spine listening on http://localhost:%d" spine-port)
+
+(provide 'spine)
+;;; spine.el ends here
+```
+
+- [ ] **Step 2: Verify the file has no syntax errors by loading it with Emacs in batch mode**
+
+Run: `emacs --quick --batch --load spine.el`
+Expected: no errors printed to stderr. The server starts briefly then Emacs exits (batch mode runs the file then quits). You should see something like:
+
+```
+Spine listening on http://localhost:8080
+```
+
+If a package is missing, you'll see MELPA refresh output followed by install messages — that's fine, it means the bootstrap worked.
+
+- [ ] **Step 3: Commit**
+
+```bash
+git add spine.el
+git commit -m "feat: add spine.el — package bootstrap, server, hello handler"
+```
+
+---
+
+### Task 3: Smoke test — first launch (package install)
+
+**Files:**
+- No changes — verification only.
+
+**Prerequisite:** Delete any previously installed `simple-httpd` and `mustache` packages so we test the bootstrap path. Run:
+
+```bash
+rm -rf ~/.emacs.d/elpa/simple-httpd-* ~/.emacs.d/elpa/mustache-* ~/.emacs.d/elpa/ht-*
+```
+
+If you're using a custom `package-user-dir`, adjust the paths accordingly. If you don't want to nuke your real packages, set `package-user-dir` to a temp directory for this test:
+
+```bash
+mkdir -p /tmp/spine-elpa
+emacs --quick --eval "(setq package-user-dir \"/tmp/spine-elpa\")" --load spine.el
+```
+
+(Use whichever approach fits your setup — the key is testing the fresh-install path.)
+
+- [ ] **Step 1: Start Emacs with spine.el (fresh package state)**
+
+Run (in one terminal, Emacs stays running):
+
+```bash
+emacs --quick --load spine.el
+```
+
+Expected output in the `*Messages*` buffer:
+- MELPA archive refresh output (first-time only)
+- Package install messages for `simple-httpd`, `mustache`, `ht`
+- `Spine listening on http://localhost:8080`
+
+- [ ] **Step 2: Verify /hello endpoint**
+
+In another terminal:
+
+```bash
+curl -s http://localhost:8080/hello
+```
+
+Expected: HTML output containing `Hello from Emacs.
` and `Spine`.
+
+- [ ] **Step 3: Stop Emacs**
+
+In the Emacs terminal, press `C-x C-c` to quit.
+
+---
+
+### Task 4: Smoke test — second launch (no package install)
+
+**Files:**
+- No changes — verification only.
+
+- [ ] **Step 1: Start Emacs again (packages already installed)**
+
+```bash
+emacs --quick --load spine.el
+```
+
+Expected: no MELPA refresh output, no package install messages. Only `Spine listening on http://localhost:8080`.
+
+- [ ] **Step 2: Verify /hello still works**
+
+```bash
+curl -s http://localhost:8080/hello
+```
+
+Expected: same HTML as before.
+
+- [ ] **Step 3: Stop Emacs** (`C-x C-c`)
+
+---
+
+### Task 5: Final commit
+
+**Files:**
+- No code changes — just confirming all commits are done.
+
+- [ ] **Step 1: Verify git status is clean**
+
+```bash
+git status
+```
+
+Expected: `nothing to commit, working tree clean`
+
+If anything shows as modified, stage and commit it:
+
+```bash
+git add -A
+git commit -m "chore: finalize initial scaffold"
+```
+
+- [ ] **Step 2: Review commit log**
+
+```bash
+git log --oneline
+```
+
+Expected: 2–4 commits covering the template, spine.el, and any fixes.