Building fastforward.sh
- Development
- Digital Strategy
- Design
Three authoring surfaces converging on a single rendered page — a code editor, a Google Doc, and a Claude Code prompt.
Hero composite, 16:9. Left third: MDX file open in a dark code editor. Middle third: a Google Doc with the PCC sidebar visible. Right third: a terminal showing a Claude Code prompt. Subtle teal gradient background pulling the three surfaces together; all three should clearly converge toward a single rendered case study page in the foreground.
(01)The Challenge
A repo full of content is great — until a non-developer needs to publish
The story behind the move from WordPress to a single Next.js repository is told in Growing with Pantheon. The short version: editorial work had already moved out of the CMS and into Google Docs, so we moved the site model to match — MDX and YAML in version control, deployed on Pantheon's Next.js platform.
That solved the editor-edits-content problem for the half of the team that lives in the repo. It left a real gap for the other half. A marketing collaborator wanting to push a copy edit shouldn't have to open a pull request. A client co-authoring a case study shouldn't have to learn MDX. And the routine authoring tasks — drafting a new case study, drafting a new static page, moving a draft through review — were exactly the kind of repeatable work a WordPress site would have leaned on a plugin to scaffold.
The real question wasn't "how do we put a CMS back" — it was "what does a version-controlled site look like when it has to serve developers, non-developers, and the repeated authoring rituals in between?"
A project MDX file open in a code editor next to the rendered case study page in a browser.
Split-screen screenshot. Left half: VS Code with a project MDX file showing the frontmatter and a MainSection. Right half: the rendered case study page in a browser at the matching section. Pair them so reader's eye can trace YAML field → rendered element.
(02)The Approach
Two doors into the same repo, and a set of rituals that don't need a plugin
Three options were on the table.
- Option 01
- Add a headless CMS — Sanity, Contentful, Storyblok — back in front of the site. Solves the non-developer surface, but reintroduces the runtime dependency and the upgrade tax we just paid to get rid of.
- Option 02
- Point non-developer authors at GitHub's web editor. Free, no new dependencies — but YAML frontmatter breaks under casual editing, and "use Git" is not an answer for someone who lives in Google Docs.
- Option 03
- Keep MDX in the repo as the primary surface, layer Pantheon Content Publisher over Google Docs as a second surface for non-developers, and replace the repeating-task plugin layer with Claude Skills — markdown files in the repo that codify the authoring workflows themselves.
Option three was the only one that kept every benefit of the version-controlled move and still answered the non-developer question. PCC handles the Google Docs path; MDX handles the developer path; the skills handle the processes — drafting, reviewing, deploying — that a CMS would have provided as plugin chrome.
(03)The Stack
Next.js, MDX, PCC, and a skills directory
The site runs on Next.js 16 with the App Router, React 19, and TypeScript, deployed on Pantheon's Next.js platform — the foundation laid in Growing with Pantheon. Content is plain MDX and YAML under content/, loaded at build time and rendered to static HTML.
Pantheon Content Publisher sits alongside as the non-developer surface. Authors draft in Google Docs with a Pantheon add-on sidebar; on publish, a webhook fires to /api/revalidate and Next.js refetches that article on the next request. PCC and MDX are merged into a single content list at build time and on every revalidation. On a slug collision, the MDX file wins and we log a warning.
The third layer is a small directory of Claude Skills at .claude/commands/ — four markdown files today: /new-project, /new-page, /workflow, and /design-session. Each one codifies a repeated authoring ritual — drafting a case study, drafting a static page, moving a draft through review, working on brand/visuals without touching application code. Authors invoke them from inside Claude Code; the skills read the live schema and voice guides before doing anything.
A diagram showing three authoring inputs — MDX, Google Docs via PCC, and Claude Code skills — flowing into the same Next.js build output.
Three input nodes on the left (MDX file icon, Google Doc icon, Claude Code prompt icon) all flow via labelled arrows into a single "Next.js build" node in the center, which outputs to a static page glyph on the right. Brand teal arrows; monospace labels on every node.
(04)How We Built It
Three pieces, shipped in order, each reviewable on its own
We built the three pieces in sequence, each in its own pull request.
Skills first. The skills were the cheapest to ship and the highest leverage — each one is a markdown file with a YAML header declaring its description, argument-hint, and an allowed-tools whitelist, plus a body of instructions written for Claude as the audience. Every skill reads CONTENT.md for voice rules, lib/types.ts for the live schema, and content/services.yml for the current service taxonomy before drafting. When the schema changes, the skill that depends on it gets updated in the same PR. The authoring affordance and the thing it authors live next to each other in the same repository.
PCC next. The Pantheon Content Publisher integration was the larger lift. The fetch pipeline in lib/pcc.ts dispatches on the article's authoringApproach metadata — ArchieML for now, Smart Components reserved for a phase 1b that isn't wired yet — and feeds the parsed pageSections into the same renderer the MDX pipeline uses. The webhook at app/api/revalidate/route.ts calls revalidateTag on the affected slug; the next visit refetches from PCC with no rebuild. The hardest part was, predictably, the boring part — we started with full HMAC signature verification on the webhook, hit signature drift between PCC and our verifier twice, and eventually simplified to URL-token auth against a tag invalidation. It has been stable since.
Harness automation last. The surrounding workflow — PR-only deploys, the scripts/deploy-feature-branch.sh helper that cuts a Pantheon multidev for visual review, the editorial: frontmatter block that tracks draft state without polluting production MDX, the five-point visual spot check from DESIGN.md — was the last piece to settle. It's the connective tissue: skills produce the draft, PCC accepts the Google-Docs path, and the harness moves whichever one came out the other side through review and onto a multidev for visual sign-off before promotion to Live.
Two things failed worth naming. We tried to express ImageBlocks with nested array fields in ArchieML and gave up — the format can't cleanly represent objects-in-arrays, so the adapter accepts flat imageSrc / imageAlt / imageWidth / imageHeight fields on each ImageBlock row and assembles them at parse time. And we initially tried to share a single "case study" content type between project case studies and capability pages — they look identical visually but need different list-page treatments, and forcing them to share a slug namespace produced collisions. They are now two separate content types served by two layout modes.
A flow diagram — Google Doc → Pantheon Content Publisher → webhook to /api/revalidate → Next.js refetches and renders fresh.
Horizontal four-step flow. Step 1: Google Doc icon labelled "Author". Step 2: PCC logo labelled "Publish". Step 3: webhook glyph pointing at "/api/revalidate". Step 4: Next.js logo labelled "Refetch on next visit". Connecting arrows in brand teal; small monospace caption under each step.
(05)The Result
Three doors, one rendered site, no CMS to patch
A developer drafts a case study by typing /new-project in Claude Code and getting a schema-correct MDX file at the end of an interview. A marketing collaborator drafts the same kind of piece in a Google Doc with the PCC sidebar open and publishes without ever cloning the repo. A reviewer moves either one through draft → review → revisions → approved → live via the /workflow skill, which manages the editorial: block and opens the PR. Three surfaces, one rendered site.
What we didn't build is as important as what we did. There is no CMS database. There are no plugins to patch. There is no admin UI to log into. The skills are four markdown files under .claude/commands/, versioned with the rest of the code, reviewed in pull requests, and changed in the same diff that changes the schema they depend on. When a new authoring ritual becomes worth codifying, the answer is "open a new markdown file" — not "evaluate three vendors."
The lesson, in one line: treat the authoring system like the production system — version it, review it, ship it in a PR — and the editorial surface stops being a maintenance line item.
(06)Behind the Curtain
Technical Notes
Skills live in .claude/commands/ as markdown files with YAML frontmatter (description, argument-hint, allowed-tools). The bodies are written as numbered workflows with pointers into CONTENT.md, DESIGN.md, and lib/types.ts for the ground truth. Skills reference each other by slash-command name — /new-project ends by handing off to the pre-publish checklist; /workflow picks up from there for review and deploy.
The PCC adapter is in lib/pcc.ts; the MDX↔PCC merge is in lib/content.ts; the revalidation webhook is at app/api/revalidate/route.ts. PCC bodies flow through ArchieML today and a SmartComponentMap exposed via a PantheonAPI route once phase 1b ships. Cache invalidation uses revalidateTag with per-slug tags, so a publish from PCC busts only the affected article. Background and trade-offs live in docs/pantheon-content-publisher-integration.md.
Two routes are dynamic at runtime — app/api/contact/route.ts for form submissions and app/api/revalidate/route.ts for PCC webhooks. Everything else, including every page authored in either MDX or PCC, is statically generated at build time and served from Pantheon's CDN.


