How This Site Runs on project-state (And Why That Matters)
#project-state#website#next.js#architecture#meta
David OlssonYou're reading this on a website that doesn't have a CMS, doesn't have a database, and doesn't have a content team. Everything you see — the dashboard, the spine map, the intelligence layers, the decisions log, the activity feed — is rendered directly from a .project-state/ directory of plain files.
This post explains how, and why that architecture is the point.
The data flow
.project-state/ ← Source of truth (YAML/JSON/MD)
↓
scripts/sync-state.mjs ← Copies state into website/data/
↓
lib/state.ts ← Loaders: getManifest(), getDecisions(), etc.
lib/scsiwyg.ts ← Blog + wiki from scsiwyg API
↓
app/page.tsx, app/spine/page.tsx ← Server components render at build time
↓
Vercel ← Static deploy with ISR for blog/wiki
At build time, the website reads every YAML file, every decision markdown, every activity log entry, and renders them into static HTML. The blog and wiki come from scsiwyg with 5-minute ISR (Incremental Static Regeneration) — so new posts appear within minutes without a full redeploy.
What each page reads
| Page | Source | What it shows |
|---|---|---|
Dashboard / | manifest.yaml, state.json, logs/activity.ndjson | Phase progress, quick links, activity feed |
Spine /spine | manifest.yaml phases + hardcoded spine map | The full Inputs → Intelligence → Decisions → Outcomes map |
Intelligence /intelligence | intelligence/*.md | All 5 intelligence layers, color-coded by phase |
Decisions /decisions | decisions/*.md | Gate decisions 1-5 parsed from markdown |
Milestones /milestones | state.json | Next actions and gates passed |
Blog /blog | scsiwyg API | Blog posts (like this one) |
Wiki /wiki | scsiwyg API | Knowledge base pages |
About /about | manifest.yaml, stakeholders/ | Parties, engagement model, team |
Why plain files?
Three reasons this matters beyond our engagement:
1. Zero lock-in
The entire state of this engagement is a directory of text files. If Vercel goes down, the data survives. If we switch frameworks, the data survives. If the engagement ends, Daanaa gets a zip file of everything — not an export from a proprietary tool.
2. Git-native
Every change to the substrate is a diff. When a decision gets made, the markdown file changes. When a stakeholder is added, the YAML updates. The commit history is the audit trail. No separate change log to maintain.
3. AI as first-class citizen
The substrate is structured text — the native language of LLMs. When we ask Claude to generate a status report, it reads the same YAML files the website reads. When we ask it to draft a gate review deck, it pulls from the same intelligence layers. There's no translation layer between human-readable state and AI-readable state because they're the same thing.
The password
This is a team site, not a public marketing page. It's password-protected because the intelligence layers, stakeholder sentiment data, and decision rationale are engagement-confidential. The blog is the public-facing surface; everything else is for the team.
The meta-point
We're proposing to build Daanaa a substrate for their engineering PDP — a living data layer that captures knowledge as it's created and renders documents, dashboards, and reports automatically.
This site is that substrate in action. Not a mockup. Not a pitch deck. A working system that runs the engagement it describes.
The medium is the message.