samjwest.net

Personal portfolio and blog rebuilt from Orchard to Astro 7 — a Digital Frontier design system and a Claude Code agent harness that shipped 26 backlog stories with minimal hands-on-keyboard input.

activeClaudeAstroTypeScriptTailwind CSS v4MDXGitHub ActionsBluehost
↗ Visit Site

The client and the objective

This one’s a case of the same person sitting on both sides of the table. As the client, I needed an online home for my work as a software architect — somewhere to establish a real presence for the architecture and AI writing I’d otherwise only be having in Slack threads and conference hallways, after years of a stale Orchard site that I hadn’t had the time or energy to update.

As the builder, I had a second objective layered on top of the first: use this rebuild as a live test of how far a Claude Code agent harness could carry a real project with minimal hands-on-keyboard input from me. A production site, with a design system, a content model, and a deploy pipeline, built the way I’d want a team to build it if I weren’t typing every line myself. I didn’t

Both objectives pointed at the same decision: build the structure first, then let the agent execute against it.

Design system before scaffold

Before any component existed, I defined “Digital Frontier” — a Southwestern desert meets AI architecture aesthetic — as a fixed set of CSS custom properties: --color-frontier for the near-black page background, --color-signal (signal orange) as the primary accent, and a trio of category colors (sky blue, gold, clay) tying each blog section to its own identity. Three fonts — Space Grotesk for headings, Inter for body, IBM Plex Mono for labels and code — rounded out the vocabulary.

That vocabulary is what let the agent build fast later without re-litigating color decisions component by component. When it came time to build the blog listing page, the theme toggle, or the mobile nav, the tokens were already the source of truth. A later cleanup story replaced nine raw hex values across the codebase with their token equivalents in a single session, because the tokens already existed to replace them with.

The backlog as the contract

The operational core of the project is .claude/backlog/: thirty-plus user stories, each written as As a [reader/developer] / I want [behavior] / So that [outcome], with acceptance criteria specific enough to be checkable — not “add filtering” but “filter tabs use aria-selected, URL state persists on back/forward, empty states are announced to screen readers.” A completed story gets renamed DONE-XXX-...md with notes on what changed and why.

That format is what made it safe to hand real, unsupervised work to an agent. Ambiguous instructions produce ambiguous results; a backlog with verifiable acceptance criteria gives the agent — and me, reviewing after the fact — a binary check for done. Twenty-six stories shipped this way across a couple dozen sessions, each one traceable back to its own commit and its own completion note.

Agent orchestration

The part that made minimal-input delivery actually work was Claude Code’s subagent harness, used deliberately rather than as a single long-running chat. A story touching multiple components gets decomposed before any code is written: one subagent scans existing component patterns, another checks what the design system already defines, another reads the backlog for related or conflicting work. Research runs in parallel and lands before implementation starts, so the agent isn’t discovering constraints mid-edit.

CLAUDE.md carried the persistent context between sessions — project status, stack, commands, conventions — so each new session could pick up work without me re-explaining the project from scratch. A sibling Notebook repository held the deeper record: deployment configuration, DNS history, design rationale. The agent was instructed to read both before starting anything, so decisions were grounded in what was already documented rather than reinvented or guessed at.

Crucially, none of that memory persisted within a session by default — each one started cold from CLAUDE.md and the backlog. That forced the backlog to be the actual source of truth for project state, not chat history. A story either has completion notes or it doesn’t; that binary is what kept multi-session, low-supervision delivery from drifting.

The “minimal hands-on-keyboard” objective wasn’t theoretical. A large share of the backlog got dispatched remotely through Claude Cowork rather than from a laptop at a desk — story handed off, harness runs, results reviewed later from a phone. Some of that review happened at a concert waiting for Sting to take the stage, backlog notifications competing for attention with a concert. If the structure holds up under that kind of inattention, it holds up.

What shipped

The site runs on Astro 7 with static output, deployed to Bluehost via GitHub Actions over SSH/rsync on every push to master, building in under three seconds. The blog grew from a single listing page with client-side category tabs into three dedicated landing pages — AI Frontier, Architecture Notes, Field Journal — each with its own hero and filtered post set. Light/dark theming, an RSS feed, a custom 404, Open Graph metadata, and syntax-highlighted code blocks with copy buttons all shipped the same way: a story written, an agent harness decomposing and executing it, a commit closing it out.

The result

Twenty-six of thirty-plus backlog stories closed, with the remainder a known, tracked remainder rather than debt hiding in the corners of the codebase. More importantly, the second objective held up: the structure — design tokens, verifiable stories, persistent written context — did the work that oversight would otherwise have had to do. My role shrank from “write every line” to “define the system, write the stories, review what came back.”

Stack

Claude Code · Astro 7 · TypeScript · Tailwind CSS v4 · MDX · GitHub Actions · Bluehost (SSH/rsync)