Replay

One session. 7 changes. Nobody watching.

This is the autopilot run that built this website, replayed from its own logs. The changes below are shown in the order they ran, each with its own timestamp, its recorded token counts, and the motivation from its plan — nothing here is a mock-up.

epic shipd-now-site·15 Aug 2026 23:21 → 16 Aug 2026 04:48 UTC·shipd-now-website · session 28fa66c6-20e7-448c-9595-07c6fb9634fe
7
changes
56
tasks
5h 27m
wall clock
1.3k
input tokens
121.0k
logged output
Timeline
laneshipd-now-site7 changes · 56 tasks
finish
+21m 51s
+14m 51s
+10m 48s
+8m 50s
+12m 22s
+2h 43m
23:21site-scaffold10m 38s9.2k outverified
23:54landing-page22m 24s20.4k outverified
00:31how-it-works-page13m 11s7.5k outarchived
00:55docs-page12m 52s6.7k outverified
01:17manifesto-page7m 38s3.3k outverified
01:37site-launch10m 10s12.9k outverified
04:30install-cta18m 45s61.0k outverified
WHY

The repository holds only the epic artifact — there is no application at all — and all four page members of shipd-now-site depend on a shared foundation existing first. The epic's Design names this scaffold as the piece everything else depends on.

WHY

app/page.tsx is a scaffold placeholder rendering only an h1 — the epic's landing member exists precisely to replace it, and the public installer URL (https://shipd.now/install) has no product story behind it until this page ships.

WHY

app/how-it-works/page.tsx is a scaffold placeholder rendering only an h1 — the epic's how-it-works member exists precisely to replace it, and the site's product story (stages, question ladder, roles, autopilot) has no page until this ships.

WHY

app/docs/page.tsx is a scaffold placeholder rendering only an h1 — the epic's docs member exists precisely to replace it, and the landing and how-it-works pages already link to /docs and /docs#faq, anchors that currently resolve to nothing.

WHY

app/manifesto/page.tsx is a scaffold placeholder rendering only an h1 — the epic's manifesto member exists precisely to replace it, and the shared nav and footer already link to /manifesto from every page.

WHY

All four pages are built and verified, but app/layout.tsx still carries the scaffold-placeholder metadata and the site has no OG image, favicon, robots, sitemap, redirect rule, or deployment documentation — nothing a launch needs. The epic's success criterion that https://shipd.now/install resolves to the installer depends on the _redirects rule this change adds.

WHY

The INSTALL button disappears on /docs — the page a visitor most needs it on — and on hover every primary button's text turns accent-on-accent and becomes unreadable, because the global a:hover color rule outranks .btn-primary's dark ink. Both were reported from the live site with screenshots.

0s / 1h 36m active
space plays and pauses · ← → scrub 30 seconds of session time · hover or tab a block for its numbers
View as table
site-scaffold 23:21:40 → 23:32:18 UTC
11 tasks · times in UTC
tasklabelstartenddurationoutput tokens
1.1Create `package.json` (name `shipd-now-website`, private) with scripts `dev` (`next dev -p 1337`), `build` (`next build`), `lint` (`eslint`), `typecheck` (`tsc --noEmit`); dependencies `[email protected]`, `[email protected]`, `[email protected]`; dev dependencies `typescript@^5`, `@types/node@^20`, `@types/react@^19`, `@types/react-dom@^19`, `tailwindcss@^4`, `@tailwindcss/postcss@^4`, `eslint@^9`, `[email protected]`. Run `npm install`.23:22:5023:23:3848s789
1.2Add `next.config.ts` (`output: 'export'`, `images: { unoptimized: true }`), `tsconfig.json` (target ES2017, `moduleResolution: "bundler"`, `@/*` paths — mirror `~/projects/mikkelbergmann-website/tsconfig.json`), `postcss.config.mjs` (`@tailwindcss/postcss`), `eslint.config.mjs` (`eslint-config-next` flat config), and `.gitignore` (node_modules, .next, out, *.tsbuildinfo, .DS_Store).23:23:3823:23:5416s226
1.3Create `app/globals.css`: line 1 `@import "tailwindcss";`, then the full content of `/Users/mikkelbergmann/.shipd/designs/site-scaffold/colors_and_type.css` minus its `@import url('https://fonts.googleapis.com/...')` line, with the three font tokens redefined as `--font-display: var(--font-space-grotesk), sans-serif;` `--font-body: var(--font-dm-sans), sans-serif;` `--font-mono: var(--font-jetbrains-mono), monospace;`. Append the shared link/responsive CSS block and the `logo-ripple` keyframes from `/Users/mikkelbergmann/.shipd/designs/site-scaffold/chrome.md`.23:23:5423:24:2329s263
1.4Create `app/layout.tsx`: load Space Grotesk (weights 400,500,600,700, variable `--font-space-grotesk`), DM Sans (300,400,500, `--font-dm-sans`), and JetBrains Mono (400,500, `--font-jetbrains-mono`) via Next's built-in Google font loader; apply the three variables on `<html lang="en">`; import `./globals.css`; export `metadata` with title "shipd.now — converged context, compiled to specs." and the landing hero paragraph as description.23:24:2323:24:5128s407
2.1Create `components/logo.tsx` from the Logo section of `/Users/mikkelbergmann/.shipd/designs/site-scaffold/chrome.md`: props `size` (default `"40px"`) and `animate` (default `true`); render the two ripple rings only when `animate` is true.23:24:5123:25:0413s1,165
2.2Create `components/nav.tsx` (`"use client"`) from the Nav section of `chrome.md`: `usePathname()` colors the matching link `var(--color-accent)` (others `var(--color-fg-2)`); the INSTALL `btn btn-primary` link to `/docs` is not rendered when the pathname starts with `/docs`; keep the hidden checkbox (`id="mnav-toggle"`, class `m-nav-toggle`) and `.m-menu-panel` as siblings inside `<nav>`; use Next Link components for all links and `<Logo size="22px" />` for the wordmark.23:25:0423:25:2117s1,339
2.3Create `components/footer.tsx` from the Footer section of `chrome.md`: props `maxWidth` (default `1100`), `links` (default How it works `/how-it-works`, Docs `/docs`, Manifesto `/manifesto`), `accentSquare` (default `true`).23:25:2123:25:3311s976
2.4Mount `<Nav />` in `app/layout.tsx` directly above `{children}` inside a `<body>` styled with the page wrapper from `chrome.md` (`min-height:100vh`, `background:var(--color-bg-base)`, `color:var(--color-fg-1)`, `font-family:var(--font-body)`).23:25:3323:25:4310s727
2.5Create placeholder pages `app/page.tsx`, `app/how-it-works/page.tsx`, `app/docs/page.tsx`, `app/manifesto/page.tsx`: each renders a `main` with an `h1` in `font-family:var(--font-display)` naming the page (e.g. "How it works") and `<Footer />` with that page's design variant: `/` uses the defaults (1100, all links); how-it-works `maxWidth={1000}`; manifesto `maxWidth={820}`; docs `maxWidth={880}` with `accentSquare={false}` and only the How it works link.23:25:4323:26:0017s295
2.6Create `app/not-found.tsx`: centered layout on the page wrapper with `<Logo size="40px" />`, the line "404 — this page never shipped", and a `btn btn-secondary` link to `/`.23:26:0023:26:099s565
3.1Run `npm run typecheck`, `npm run lint`, and `npm run build`; confirm all exit 0, the exported `index.html` and `404.html` exist in the build output directory, a recursive grep for fonts.googleapis.com or fonts.gstatic.com over the output matches nothing, the built CSS contains `#C6FF4E` and `.stripe-bg`, the exported `404.html` contains "404 — this page never shipped", and each of the four route HTML files contains the `/how-it-works`, `/docs`, and `/manifesto` nav links.23:26:0923:27:191m 11s879
landing-page 23:54:09 → 00:16:33 UTC
8 tasks · times in UTC
tasklabelstartenddurationoutput tokens
1.1Create `components/landing-hero.tsx` with `"use client"`: port the `steps` array (9 entries: label, color, why, cmd, title, lines with per-line color) and the `icons` array (9 pairs of SVG path strings) character-for-character from the `DCLogic` script in `/Users/mikkelbergmann/.shipd/designs/landing-page/landing-v2.dc.html` (lines 237–296) as typed module constants. Preserve the literal `\n` newlines inside the investigate step's first line.23:55:0323:55:4845s190
1.2In `components/landing-hero.tsx`, default-export `LandingHero` rendering the design's `<header>` (design lines 36–88) as JSX: stripe-bg overlay, accent label, `m-h1` h1, paragraph, "Install" label, hero command box, HOW IT WORKS `btn btn-secondary` link, and the loop strip — pill row (`the loop:` prefix, mapped pills with arrows, no arrow after the ninth) plus the two-panel detail view (icon SVG with the second path rendered only when non-empty, mono label, why line, `$ cmd` + title row, colored `pre-wrap` lines). Hold `step` in state with the interval id in a ref: advance `(step + 1) % 9` every 6300 ms from mount, clear the interval on unmount, and on pill click clear the interval permanently and set that step. Active pill text/border use the step color; inactive pills use `var(--color-fg-3)` text and transparent border; keep the design's 200 ms color/border transitions. Add class `landing-panel` next to `m-panel m-grid` on the detail panel wrapper.23:55:4823:56:521m 4s334
1.3In `components/landing-hero.tsx`, implement the copy behavior (design lines 328–334): a click handler that writes `curl -fsSL https://shipd.now/install | sh` via the clipboard API when available, sets a `copied` state, and resets it after 1600 ms. The hero box (class `cmd-box`, design line 46–50) shows the accent `$`, the `m-cmd` command span, and a chip reading "copied" when copied else "copy". Also named-export `CtaInstallCommand` (design lines 222–226): the same box with its own `copied` state and click handler, accent `$`, `m-cmd` span, and the 7×15px accent cursor block with `animation: blink 1.1s step-end infinite` instead of the chip.23:56:5223:57:1524s673
1.4In `components/landing-hero.tsx`, render a `<style>` element carrying the page-scoped CSS: `@keyframes blink` (design line 20), `.cmd-box:hover { border-color: var(--color-accent); }`, `.epic-row:hover { background: var(--color-bg-hover); }`, and `@media (max-width: 760px) { .m-panel.landing-panel { height: 490px !important; overflow: hidden; } }`. Do not modify `app/globals.css`.23:57:1523:58:0549s1,125
2.1Replace `app/page.tsx` with the server component: render `<LandingHero />`, then the Capture/Gate/Verify section (design lines 91–122: label, `m-h2` heading, three `card` blocks with their SVG icons, mono kickers 01 · CAPTURE / 02 · GATE / 03 · VERIFY, headings and paragraphs verbatim), then the artifacts section (lines 125–180: heading "The spec is the product.", the "real artifacts from shipd-now/shipd" note, three zero-padding cards with header rows — plan.md/badge-accent, specs/shipd-plan/spec.md/ badge-blue, tasks.md/badge-purple — and their mono body lines verbatim including colored spans).23:58:0523:58:5247s232
2.2Continue `app/page.tsx`: the board-peek section (design lines 183–215: stripe-bg overlay, heading "shipd builds itself. This is the board.", `$ shipd board text` note, the three stat tiles 175/36/11 with captions, and the epic table — five rows from an inline array of slug/note/status/color exactly as design lines 322–326, each row class `epic-row` with the mono slug, muted note, and right-aligned status dot+label, followed by the "+ 6 more epics · lifecycle: draft → ready → active → complete → verified" footer line), then the CTA section (lines 218–229: centered "Stop watching agents type.", `<CtaInstallCommand />`, and the "then, in your repo: /s:plan → /s:build → merged PR" mono line), then `<Footer />` with defaults.23:58:5223:59:2937s2,516
2.3Verify chrome integration: the page renders no nav of its own (the layout provides it) and no wrapper besides the design's section markup; the h1 keeps class `m-h1`, section grids keep `m-grid`, headings keep `m-h2`, and command spans keep `m-cmd` so the shared 760px overrides apply.23:59:2923:59:5627s296
3.1Run `npm run typecheck`, `npm run lint`, and `npm run build`; confirm all exit 0 and, in the exported landing HTML of the build output, confirm: the hero h1 text, "Spec-driven agent orchestration", "Stop watching agents type.", two occurrences of the install command, the three capture/gate/verify card headings, the stat values with captions, the five epic slugs, the lifecycle footer line, exactly one nav, and the footer line "shipd.now — converged context, compiled to specs."23:59:5600:00:3236s821
how-it-works-page 00:31:24 → 00:44:35 UTC
7 tasks · times in UTC
tasklabelstartenddurationoutput tokens
1.1Create `components/question-ladder.tsx` with `"use client"`: port the `ladder` array (4 entries: title, tag, color, icon, icon2, detail) character-for-character from the `DCLogic` script in `/Users/mikkelbergmann/.shipd/designs/how-it-works-page/how-it-works.dc.html` (lines 237–250) as a typed module constant.00:32:2400:33:0035s234
1.2In `components/question-ladder.tsx`, default-export `QuestionLadder` rendering the design's ladder column (lines 84–101): map the four rungs into a header row (add class `rung-head`; icon SVG rendering the second path only when its `d` string is non-empty, mono number "01"–"04", title with `var(--color-accent)` on the fourth rung and `var(--color-fg-1)` otherwise, mono tag in the rung color, chevron span) plus the collapsible detail block, keeping the design's transition styles. Hold `rung` state initialized to 0; clicking rung i sets `rung === i ? null : i`. Open rung: maxHeight 260px, opacity 1, border `var(--color-border-strong)`, chevron `rotate(180deg)`; closed: 0px, 0, `var(--color-border)`, `0deg`. Render the "↓ escalates only if unanswered" connector after each rung except the last, then the trailing "every answer you give teaches a lower rung — over time, less escalates to you" line (design line 100).00:33:0000:33:3434s1,785
1.3In `components/question-ladder.tsx`, render a `<style>` element carrying the page-scoped CSS: the ≤760px `.m-stage` overrides (design lines 25–29), the `.m-metro` base grid rule and its ≤900px collapse with `.m-metro-joint { display: flex !important }` (design lines 31–32), and `.rung-head:hover { border-color: var(--color-border-strong) !important }`. Do not modify `app/globals.css`.00:33:3400:33:4916s191
2.1Replace `app/how-it-works/page.tsx` with the server component: port the `stages` array (5 entries: num, color, name, tag, desc, artifact — design lines 265–271) and the `roles` array (3 entries: tag, color, name, desc — lines 272–276) character-for-character as typed module constants; render the hero header (design lines 38–45: stripe-bg overlay, accent "How it works" label, `m-h1` h1, paragraph), then the flow section (lines 48–74: one `m-stage` grid block per stage — bordered number chip in the stage color, connector line, name and mono tag, description, artifact chip — followed by the capability-library loop line with the accent "↺"), then the ladder section (lines 77–103: `m-grid` two-column layout with the left copy column verbatim — label "The question ladder", `m-h2` heading "Most questions never reach you.", paragraph — and `<QuestionLadder />` as the right column).00:33:4900:34:4556s10
2.2Continue `app/how-it-works/page.tsx`: the roles section (design lines 106–132: label "Division of labor", `m-h2` heading, three mapped `card` blocks with mono tag, colored dot, name, description, then the "every change:" pipeline strip verbatim including the orange "(explicitly dispositioned)", green "merged", and accent "capability library" spans), the autopilot section (lines 135–220: stripe-bg overlay, accent label, `m-h2` heading "One human approval: the epic.", the paragraph with the mono orange "rejected" span, and the metro diagram card verbatim — the mono uppercase caption, the two `m-metro` columns with stops 1–7, the dashed orange side branch under stop 3, the hidden `m-metro-joint` element, and the dashed-top footer note), the CTA section (lines 222–230: centered `m-h2` "Try it on your next change.", GET STARTED link to /docs with `btn btn-primary`, READ THE FAQ link to /docs#faq with `btn btn-secondary`), and finally `<Footer maxWidth={1000} />`.00:34:4500:35:451m 1s192
2.3Verify chrome integration in `app/how-it-works/page.tsx`: the page renders no nav of its own (the layout provides it) and no wrapper besides the design's section markup; the h1 keeps class `m-h1`, section headings keep `m-h2`, the ladder and roles grids keep `m-grid`, stage blocks keep the `m-stage` family classes, and the metro keeps `m-metro`/`m-metro-joint` so the page-scoped and shared responsive overrides apply.00:35:4500:35:559s5
3.1Run `npm run typecheck`, `npm run lint`, and `npm run build`; confirm all exit 0 and, in the exported how-it-works HTML of the build output, confirm: the hero h1 "From stated intent to a merged, verified pull request.", the five stage names and their artifact chips, the loop line "the capability library compiles context for the next change", the four rung titles with tags and the three "escalates only if unanswered" connectors, the three role names, the "every change:" pipeline strip, the autopilot heading and all seven metro stop labels with the side-branch lines, the CTA links to /docs and /docs#faq, exactly one nav, and the footer line "shipd.now — converged context, compiled to specs."00:35:5500:36:571m 2s361
docs-page 00:55:23 → 01:08:15 UTC
6 tasks · times in UTC
tasklabelstartenddurationoutput tokens
1.1In `app/docs/page.tsx`, port the three data arrays character-for-character from the `DCLogic` script in `/Users/mikkelbergmann/.shipd/designs/docs-page/docs.dc.html` as typed module constants: `verbs` (6 entries: cmd, desc — design lines 231–238), `caps` (10 entries: name, cmd, area, color, desc, gives — lines 219–230), and `faqs` (3 entries: num, q, a1, a2 — lines 208–218). Keep every color value as its design token var string.00:56:3000:57:0839s189
2.1Replace the `main` block of `app/docs/page.tsx` with the design's hero and steps: the header (design lines 33–40: stripe-bg overlay, accent label "Docs · Getting started", `m-h1` h1 "From install to merged PR.", paragraph), then the steps section (lines 42–94) with the four 44px/1fr grid blocks — step 1's accent number chip and install terminal (the $ prompt line and two ✓ lines), steps 2–3 with their border-strong chips, headings, paragraphs with inline mono spans, and terminal blocks, and step 4's verb table: map `verbs` into the design's row template (line 87: `m-grid`, 220px/1fr grid, mono accent cmd, fg-2 desc) inside the rounded overflow-hidden container, with the bottom border on every row except the last. Render angle-bracket copy (e.g. the /s: skill-name pattern in step 1's ✓ line) via JSX string expressions.00:57:0800:57:5850s12
2.2Continue `app/docs/page.tsx` with the lifecycle section (design lines 96–111: label "The lifecycle", the mono chip strip draft → ready → active(orange) → complete → verified(green), the "|" divider, the red rejected chip and its fg-3 note, and the closing guarded-transitions paragraph) and the supersession section (lines 138–159: label "The supersession gate", `m-h2` heading "Stale plans never build.", intro paragraph, the three-row clean/content drift/superseded table — last row without a bottom border — and the closing note with the mono check-base and id-collision spans).00:57:5800:58:3233s185
2.3Continue `app/docs/page.tsx` with section id "workspaces" (design lines 113–136: stripe-bg overlay, accent label, `m-h2` heading "One job, many repos, any machine.", intro paragraph with the bold "portable workspace", the `m-grid` two-column layout pairing the mono file-tree panel — six 170px/1fr rows with tracked/machine-local annotations — with the three accent-arrow sync bullets, each bold lead carried verbatim).00:58:3200:59:0836s187
2.4Finish `app/docs/page.tsx` with section id "capabilities" (design lines 161–179: accent label "What can shipd do", heading "Every capability, one page.", intro paragraph, and the `m-grid` two-column grid mapping `caps` into the design's card template — name, area badge colored per `cap.color`, mono accent cmd, description, and the border-top "→ gives" footer) and section id "faq" (lines 181–199: accent label "FAQ", heading "The questions worth asking.", and the three `faqs` cards with mono accent num, question h3, and both answer paragraphs). Keep the existing Footer call (maxWidth 880, accentSquare false, only the "How it works" link) and add no "use client" directive, no page style element, and no nav.00:59:0800:59:3326s187
3.1Run `npm run typecheck`, `npm run lint`, and `npm run build`; confirm all exit 0 and, in the exported docs HTML of the build output (the flat docs file at the export root), confirm: the h1 "From install to merged PR.", the four step headings, the install command line and both ✓ lines, all six verb commands with their descriptions, the six lifecycle chips with the rejected note, the workspaces heading with the six file-tree entries and three bullet leads, the supersession heading with its three rows, all ten capability names with their commands and gives-footers, the three FAQ questions with two paragraphs each, exactly one occurrence of each id workspaces/capabilities/faq, exactly one nav with no INSTALL button, and the footer line "shipd.now — converged context, compiled to specs." followed by only the "How it works" link.00:59:3301:01:131m 39s1,636
manifesto-page 01:17:05 → 01:24:43 UTC
4 tasks · times in UTC
tasklabelstartenddurationoutput tokens
1.1In `app/manifesto/page.tsx`, port the `theses` array character-for-character from the `DCLogic` script in `/Users/mikkelbergmann/.shipd/designs/manifesto-page/manifesto.dc.html` as a typed module constant: 5 entries with fields num, title, body (design lines 72–76).01:17:5901:18:3536s131
2.1Replace the `main` block of `app/manifesto/page.tsx` with the design's hero header (design lines 31–41): the border-bottom header with the stripe-bg overlay div, the m-super "WHY" supergraphic div with its absolute-position inline styles (line 33), and the 820px inner container holding the accent label "The bet", the m-h1 h1, and the 620px intro paragraph — all copy verbatim, with JSX-text apostrophes escaped per the sibling convention.01:18:3501:18:5621s190
2.2Continue `app/manifesto/page.tsx` with the theses section (design lines 43–52): the 820px flex column with 56px gap, mapping `theses` into the design's block template — m-grid 64px/1fr grid, mono fg-3 num span, m-h2 h2 title, fg-2 body paragraph capped at 600px — and the closing CTA section (lines 54–62): border-top, stripe-bg overlay div, centered 820px container with the display-font closing line and the GET STARTED link (href /docs, class "btn btn-primary", the design's inline styles). Keep the existing `Footer maxWidth={820}` call unchanged and add no "use client" directive, no page style element, and no nav.01:18:5601:19:1215s20
3.1Run `npm run typecheck`, `npm run lint`, and `npm run build`; confirm all exit 0 and, in the exported manifesto HTML of the build output (the flat manifesto file at the export root), confirm: the label "The bet", the h1 "The scarce resource isn't code generation. It's converged context.", the "WHY" supergraphic in an element with class m-super, the intro paragraph, all five thesis nums 01–05 with their titles and full bodies (including "175 changes, 36 verified capabilities, 11 epics"), the CTA line "Compile context into specs, and you can ship software you didn't watch being written." with the GET STARTED link to the docs route, exactly one nav with the INSTALL button present, and the footer line "shipd.now — converged context, compiled to specs." followed by the three default links.01:19:1201:19:5544s263
site-launch 01:37:05 → 01:47:15 UTC
13 tasks · times in UTC
tasklabelstartenddurationoutput tokens
1.1In `app/layout.tsx`, replace the placeholder `metadata` export with the plan's bound root metadata: `metadataBase: new URL("https://shipd.now")`; `title: { default: "shipd.now — converged context, compiled to specs.", template: "%s — shipd.now" }`; `description: "Spec-driven agent orchestration. shipd makes agents converge on a spec before they write code, then an adversarial validator tries to break every scenario before anything merges."`; `openGraph: { siteName: "shipd.now", type: "website" }`; `twitter: { card: "summary_large_image" }`.01:38:0201:38:1614s575
1.2Add `export const metadata: Metadata = ...` (importing `Metadata` from next, per the layout's existing import) to `app/how-it-works/page.tsx` (title "How it works"), `app/docs/page.tsx` (title "Docs"), and `app/manifesto/page.tsx` (title "Manifesto"), each with the exact description bound in the plan's Implementation section.01:38:1601:38:3217s1,247
1.3Add `export const metadata: Metadata = { title: "404" }` to `app/not-found.tsx`.01:38:3201:38:397s424
2.1Generate the OG asset: run `npm run build`, then find the Space Grotesk latin woff2 by grepping the built CSS under the out directory's static chunks for `@font-face{font-family:Space Grotesk` and taking the `src` whose filename contains `-s.p.`. Copy that woff2 to a scratch directory as `space-grotesk-latin.woff2`, write `og.html` beside it with exactly this markup, substituting nothing: `<!doctype html><html><head><style>@font-face{font-family:"Space Grotesk";src:url("./space-grotesk-latin.woff2")format("woff2");font-weight:300 700}*{margin:0;box-sizing:border-box}body{width:1200px;height:630px;background:#0A0A0D;display:flex;flex-direction:column;justify-content:center;padding:0 96px;font-family:"Space Grotesk",sans-serif;position:relative}.label{font-size:22px;letter-spacing:.18em;text-transform:uppercase;color:#55556A;margin-bottom:28px}.logo{display:flex;align-items:baseline;gap:.22em}.wordmark{font-weight:700;font-size:150px;letter-spacing:-.045em;color:#F0F0F8;line-height:1}.dot{width:26px;height:26px;border-radius:50%;background:#C6FF4E;transform:translateY(-6px);box-shadow:0 0 40px rgba(198,255,78,.45)}.tag{margin-top:34px;font-size:40px;font-weight:500;letter-spacing:-.01em;color:#8888A0}.rule{position:absolute;left:0;right:0;bottom:0;height:6px;background:#C6FF4E}</style></head><body><div class="label">Spec-driven agent orchestration</div><div class="logo"><span class="wordmark">shipd</span><span class="dot"></span></div><div class="tag">converged context, compiled to specs.</div><div class="rule"></div></body></html>` then render it with `"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --headless --disable-gpu --screenshot=<scratch>/opengraph-image.png --window-size=1200,630 --hide-scrollbars file://<scratch>/og.html` and copy the result to `app/opengraph-image.png`.01:38:3901:39:2849s768
2.2Create `app/opengraph-image.alt.txt` containing exactly: shipd — converged context, compiled to specs.01:39:2801:39:356s313
3.1Create `app/icon.svg` with exactly the SVG markup bound in the plan's Implementation section (64 viewBox, rx 14 rect filled #0A0A0D, r 13 circle filled #C6FF4E).01:39:3501:39:417s388
3.2Render `app/apple-icon.png`: write a scratch HTML `<!doctype html><html><head><style>*{margin:0}body{width:180px;height:180px}svg{display:block}</style></head><body><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="180" height="180"><rect width="64" height="64" fill="#0A0A0D"/><circle cx="32" cy="32" r="13" fill="#C6FF4E"/></svg></body></html>` (square corners — iOS applies its own mask) and screenshot it with the same Chrome invocation as task 2.1 at `--window-size=180,180`.01:39:4101:40:0019s939
4.1Create `public/robots.txt` (new public directory) containing a comment stating the site is intentionally open to AI crawlers, then exactly these directives: `User-agent: *`, `Content-Signal: search=yes,ai-train=yes,ai-input=yes`, `Allow: /`, a blank line, and `Sitemap: https://shipd.now/sitemap.xml`.01:40:0001:40:077s385
4.2Create `app/sitemap.ts`: import `MetadataRoute` from next as in the reference pattern, export `const dynamic = "force-static"`, and default-export a function returning entries for `https://shipd.now` (priority 1), `https://shipd.now/how-it-works`, `https://shipd.now/docs`, and `https://shipd.now/manifesto` (each priority 0.8), with no lastModified fields.01:40:0701:40:158s198
5.1Create `public/_redirects` whose content is exactly one line: `/install https://raw.githubusercontent.com/shipd-now/shipd/main/install.sh 302`01:40:1501:40:216s324
6.1Create `docs/deployment.md` (new docs directory) with two sections. Setup: connect Cloudflare (Workers & Pages → Create → Pages → Connect to Git) to the GitHub repository shipd-now/shipd-now-website, production branch `main`, build command `npm run build`, build output directory `out`, no environment variables; then add the custom domain shipd.now under the project's Custom domains (DNS is on Cloudflare, records are created automatically). Verification checklist (checkbox list of curl-able checks): each of the four pages returns 200 with its expected title; `curl -sI https://shipd.now/install` returns 302 with the raw install.sh Location; robots.txt, sitemap.xml, the OG image, and icon.svg return 200; an unknown path returns the 404 page ("404 — this page never shipped"); note that the /install target 404s until the shipd repo's public-install change lands and that repo is public.01:40:2101:40:4120s1,420
7.1Append a `.shipd/autopilot/` entry to `.gitignore` and run `git rm --cached` on `.shipd/autopilot/landing-page-build-heartbeat.json` and `.shipd/autopilot/site-scaffold-build-heartbeat.json`; confirm `git ls-files` prints nothing under that directory.01:40:4101:40:5716s570
8.1Run `npm run build`, `npm run typecheck`, and `npm run lint` (all must exit 0), then verify the built output: `out/index.html` title and description match task 1.1; the three subpage html files carry their templated titles; every page html contains an `og:image` URL starting with `https://shipd.now/` whose PNG exists under `out/`; `out/icon.svg` and the apple icon are linked and present; `out/robots.txt` and `out/sitemap.xml` match the robots-sitemap scenarios; `out/_redirects` matches task 5.1 exactly.01:40:5701:43:482m 50s1,642
install-cta 04:30:03 → 04:48:48 UTC
7 tasks · times in UTC
tasklabelstartenddurationoutput tokens
1.1In `app/globals.css` (line 280), extend the existing rule to `.btn-primary:hover { background: #d4ff6e; color: var(--color-fg-inverse); }` so its (0,2,0) specificity outranks the global `a:hover` accent rule at line 340.04:30:4504:31:0116s699
2.1In `components/nav.tsx`, remove the `showInstall` constant (line 19) and the `{showInstall && (...)}` wrapper (lines 83–96) so the INSTALL Link always renders, and change its `href` to `/docs#install`. Leave active-link coloring, the checkbox/menu-panel structure, and the mobile panel links untouched.04:31:0104:31:1413s873
2.2In `app/docs/page.tsx`, on the getting-started step 1 grid div (the `gridTemplateColumns: "44px 1fr"` block whose number chip renders `1`, ~line 219), add `id="install"` and `scrollMarginTop: "72px"` to its style object.04:31:1404:31:3016s499
2.3Append to `app/globals.css` a `@media (prefers-reduced-motion: no-preference)` block containing: `html { scroll-behavior: smooth; }`; an `install-flash` keyframes that pulses `background` to `var(--color-accent-subtle)` and `box-shadow` to `0 0 0 6px var(--color-accent-glow)` at 50% and returns both to transparent at 0%/100%; and `#install:target { animation: install-flash 1.4s var(--ease-speed) 2; border-radius: 8px; }`.04:31:3004:31:4616s1,097
3.1Run `npm run typecheck`, `npm run lint`, and `npm run build`; confirm all exit 0, every one of the four exported route HTML files contains the INSTALL button with href `/docs#install` (the exported docs HTML included), the exported docs HTML contains exactly one `id="install"`, and the built CSS contains the `#install:target` rule, the `install-flash` keyframes, and the `.btn-primary:hover` rule with `color: var(--color-fg-inverse)`.04:31:4604:32:481m 2s1,593
4.1In `components/nav.tsx`, replace the INSTALL `Link` element with a plain `<a href="/docs#install" className="btn btn-primary" ...>` keeping the identical style object and label — a native anchor performs real hash navigation so `#install:target` matches on same-page clicks and on cross-page loads, which Next Link's pushState never does. All other nav links stay `Link`.04:41:0304:41:2117s402
4.2Re-run `npm run typecheck`, `npm run lint`, and `npm run build`; confirm all exit 0 and every one of the four exported route HTML files still contains exactly one INSTALL anchor with href `/docs#install` and the `btn btn-primary` classes.04:41:2104:41:5029s809

site-scaffold

Status: verified Epic: shipd-now-site

Idea

Stand up the Next.js static-export scaffold for shipd.now with the design system's tokens, self-hosted fonts, and the shared chrome (nav, footer, Logo, 404) that every page member of the shipd-now-site epic builds on.

Motivation

The repository holds only the epic artifact — there is no application at all — and all four page members of shipd-now-site depend on a shared foundation existing first. The epic's Design names this scaffold as the piece everything else depends on.

Details

  • Next.js 16 App Router + TypeScript + Tailwind v4 project with output: 'export', mirroring mikkelbergmann-website's conventions.
  • app/globals.css carries the design system ported from the parked colors_and_type.css; fonts self-host via next/font/google.
  • Shared chrome components: Logo (ripple wordmark), Nav (sticky, active link, mobile burger), Footer (per-page props), plus a 404 page and minimal placeholder pages for the four routes.

Affected capabilities: site-foundation (added). Impact: package.json, next.config.ts, tsconfig.json, postcss.config.mjs, eslint.config.mjs, app/layout.tsx, app/globals.css, app/page.tsx, app/not-found.tsx, app/{how-it-works,docs,manifesto}/page.tsx, components/{logo,nav,footer}.tsx. No backend, no new services.

Non-goals

  • No real page content — the landing, how-it-works, docs, and manifesto sections are sibling member changes; this change ships placeholders only.
  • No SEO/OG assets, sitemap, robots.txt, or _redirects — that is site-launch.
  • No CI workflow and no Cloudflare configuration (epic non-goal: manual dashboard setup).
  • No theme switcher and none of the reference site's blog machinery.

Implementation

  • Design reference: /Users/mikkelbergmann/.shipd/designs/site-scaffold/ — read verbatim by the execution sub-agent and the validator as a read-only, out-of-worktree reference; match it, never edit it. It holds colors_and_type.css (the canonical design-system stylesheet) and chrome.md (exact nav/footer/Logo markup, shared responsive CSS, route mapping).
  • Versions mirror the reference site: next 16.1.0, react/react-dom 19.2.3, tailwindcss/@tailwindcss/postcss ^4, typescript ^5, eslint-config-next 16.1.0. Scripts: dev (port 1337), build, lint, typecheck (tsc --noEmit). Rejected: pinning newer majors — the epic says mirror the reference.
  • next.config.ts: output: 'export', images: { unoptimized: true } — identical to the reference; Cloudflare serves out/.
  • app/globals.css opens with @import "tailwindcss" (PostCSS plugin @tailwindcss/postcss, as in the reference), then the ported design system: everything in the parked colors_and_type.css except its Google Fonts @import url(...) line, with the three font tokens redefined to the next/font variables (--font-display: var(--font-space-grotesk), sans-serif, --font-body: var(--font-dm-sans), sans-serif, --font-mono: var(--font-jetbrains-mono), monospace), plus chrome.md's shared link/responsive CSS and the logo-ripple keyframes. Keep html { font-size: 14px }. Rejected: linking the DS file or fetching fonts at runtime — the export must make zero external requests.
  • Fonts in app/layout.tsx via next/font/google: Space Grotesk (400/500/600/700, variable --font-space-grotesk), DM Sans (300/400/500, --font-dm-sans), JetBrains Mono (400/500, --font-jetbrains-mono); variables applied on <html>. Layout metadata is minimal (title "shipd.now — converged context, compiled to specs.", description from the landing hero); full SEO belongs to site-launch.
  • Page styling keeps the design markup's inline styles (as JSX style objects) plus the DS utility classes — fidelity over idiom. Rejected: translating the design to Tailwind utility classes — needless drift risk against the .dc.html sources; Tailwind stays available for future work.
  • Nav is one "use client" component in app/layout.tsx (identical on every page in the design): usePathname() drives the active link color (--color-accent vs --color-fg-2) and hides the INSTALL button on /docs (the design's Docs nav omits it). The mobile burger keeps the design's CSS-only checkbox mechanism — checkbox and .m-menu-panel stay siblings so :checked ~ works. Rejected: React state for the menu — the design's mechanism needs no JS.
  • Footer is a shared component rendered per page, not in the layout — the design varies its max-width (1100/1000/820/880) and link set per page. Props: maxWidth (default 1100), links (default all three pages), accentSquare (default true; Docs omits it).
  • Logo component per chrome.md: size (default "40px") and animate (default true) props; nav mounts it at size="22px".
  • Placeholder pages for /, /how-it-works, /docs, /manifesto: the design's page wrapper div, an h1 naming the page, and the page's Footer variant — just enough for chrome scenarios to be exercised; each sibling member replaces its placeholder wholesale.
  • app/not-found.tsx (no 404 design exists): centered Logo (size="40px"), the line "404 — this page never shipped", and a btn-secondary link home, on the standard page wrapper.

Risk: next/font variable names must match the tokens globals.css redefines — a typo silently falls back to system fonts; the verification task greps the built CSS for the font-family variables and for the absence of fonts.googleapis.com.

ADDED Requirements

Requirement: Static export build

id: static-export-build

The system SHALL build as a fully static Next.js export: npm run build SHALL produce an out/ directory containing index.html and 404.html, and npm run typecheck and npm run lint SHALL exit 0.

Scenario: Build produces the static export

  • WHEN npm run build runs on a clean checkout after npm install
  • THEN it exits 0 and out/index.html and out/404.html exist

Scenario: Typecheck and lint are clean

  • WHEN npm run typecheck and npm run lint run
  • THEN both exit 0

Requirement: Design-token foundation

id: design-token-foundation

The system SHALL carry the shipd design system in app/globals.css — the color/type/spacing tokens and the utility classes (.label, .card, .btn-primary/.btn-secondary/.btn-ghost/.btn-danger, .badge-*, .stripe-bg) from the parked colors_and_type.css — and SHALL self-host all three font families so the built site makes no external requests.

Scenario: Tokens present in the built CSS

  • WHEN the site is built
  • THEN the CSS emitted under out/_next/ defines --color-accent as #C6FF4E and the .stripe-bg and .btn-primary classes

Scenario: No external font or CDN references

  • WHEN the site is built
  • THEN no file under out/ references fonts.googleapis.com or fonts.gstatic.com, and font files are served from out/_next/

Requirement: Shared chrome

id: shared-chrome

Every page SHALL render the shared chrome: the sticky nav (Logo linking home; How it works, Docs, Manifesto links; INSTALL button linking to /docs except on /docs itself; CSS-checkbox burger menu at ≤900px) and a Footer component with per-page width and links, matching the parked chrome.md markup. When rendered on a page, the nav SHALL color that page's link with var(--color-accent).

Scenario: Nav on every route

  • WHEN any of /, /how-it-works, /docs, /manifesto is rendered
  • THEN the nav contains links to /how-it-works, /docs, /manifesto and the Logo linking to /

Scenario: Active link and INSTALL visibility

  • WHEN /docs is rendered
  • THEN the Docs nav link uses the accent color and no INSTALL button is rendered, while on / the INSTALL button links to /docs

Scenario: Mobile menu mechanism preserved

  • WHEN the rendered nav markup is inspected
  • THEN the menu panel is a following sibling of the hidden checkbox so the .m-nav-toggle:checked ~ .m-menu-panel rule can open it

Requirement: Not-found page

id: not-found-page

If a request does not match any route, then the system SHALL serve an on-brand 404 page carrying the Logo, the text "404 — this page never shipped", and a link back to /.

Scenario: Unknown path renders the 404 page

  • WHEN the site is built and out/404.html is inspected
  • THEN it contains "404 — this page never shipped" and a link to /

1. App scaffold

  • 1.1 [req: static-export-build] Create package.json (name shipd-now-website, private) with scripts dev (next dev -p 1337), build (next build), lint (eslint), typecheck (tsc --noEmit); dependencies [email protected], [email protected], [email protected]; dev dependencies typescript@^5, @types/node@^20, @types/react@^19, @types/react-dom@^19, tailwindcss@^4, @tailwindcss/postcss@^4, eslint@^9, [email protected]. Run npm install.
  • 1.2 [req: static-export-build] Add next.config.ts (output: 'export', images: { unoptimized: true }), tsconfig.json (target ES2017, moduleResolution: "bundler", @/* paths — mirror ~/projects/mikkelbergmann-website/tsconfig.json), postcss.config.mjs (@tailwindcss/postcss), eslint.config.mjs (eslint-config-next flat config), and .gitignore (node_modules, .next, out, *.tsbuildinfo, .DS_Store).
  • 1.3 [req: design-token-foundation] Create app/globals.css: line 1 @import "tailwindcss";, then the full content of /Users/mikkelbergmann/.shipd/designs/site-scaffold/colors_and_type.css minus its @import url('https://fonts.googleapis.com/...') line, with the three font tokens redefined as --font-display: var(--font-space-grotesk), sans-serif; --font-body: var(--font-dm-sans), sans-serif; --font-mono: var(--font-jetbrains-mono), monospace;. Append the shared link/responsive CSS block and the logo-ripple keyframes from /Users/mikkelbergmann/.shipd/designs/site-scaffold/chrome.md.
  • 1.4 [req: design-token-foundation] Create app/layout.tsx: load Space Grotesk (weights 400,500,600,700, variable --font-space-grotesk), DM Sans (300,400,500, --font-dm-sans), and JetBrains Mono (400,500, --font-jetbrains-mono) via Next's built-in Google font loader; apply the three variables on <html lang="en">; import ./globals.css; export metadata with title "shipd.now — converged context, compiled to specs." and the landing hero paragraph as description.

2. Shared chrome

  • 2.1 [req: shared-chrome] Create components/logo.tsx from the Logo section of /Users/mikkelbergmann/.shipd/designs/site-scaffold/chrome.md: props size (default "40px") and animate (default true); render the two ripple rings only when animate is true.
  • 2.2 [req: shared-chrome] Create components/nav.tsx ("use client") from the Nav section of chrome.md: usePathname() colors the matching link var(--color-accent) (others var(--color-fg-2)); the INSTALL btn btn-primary link to /docs is not rendered when the pathname starts with /docs; keep the hidden checkbox (id="mnav-toggle", class m-nav-toggle) and .m-menu-panel as siblings inside <nav>; use Next Link components for all links and <Logo size="22px" /> for the wordmark.
  • 2.3 [req: shared-chrome] Create components/footer.tsx from the Footer section of chrome.md: props maxWidth (default 1100), links (default How it works /how-it-works, Docs /docs, Manifesto /manifesto), accentSquare (default true).
  • 2.4 [req: shared-chrome] Mount <Nav /> in app/layout.tsx directly above {children} inside a <body> styled with the page wrapper from chrome.md (min-height:100vh, background:var(--color-bg-base), color:var(--color-fg-1), font-family:var(--font-body)).
  • 2.5 [req: shared-chrome] Create placeholder pages app/page.tsx, app/how-it-works/page.tsx, app/docs/page.tsx, app/manifesto/page.tsx: each renders a main with an h1 in font-family:var(--font-display) naming the page (e.g. "How it works") and <Footer /> with that page's design variant: / uses the defaults (1100, all links); how-it-works maxWidth={1000}; manifesto maxWidth={820}; docs maxWidth={880} with accentSquare={false} and only the How it works link.
  • 2.6 [req: not-found-page] Create app/not-found.tsx: centered layout on the page wrapper with <Logo size="40px" />, the line "404 — this page never shipped", and a btn btn-secondary link to /.

3. Verify

  • 3.1 [req: *] Run npm run typecheck, npm run lint, and npm run build; confirm all exit 0, the exported index.html and 404.html exist in the build output directory, a recursive grep for fonts.googleapis.com or fonts.gstatic.com over the output matches nothing, the built CSS contains #C6FF4E and .stripe-bg, the exported 404.html contains "404 — this page never shipped", and each of the four route HTML files contains the /how-it-works, /docs, and /manifesto nav links.

landing-page

Status: verified Epic: shipd-now-site

Idea

Replace the placeholder / route with the real shipd.now landing page from the Shipd Landing v2 design: hero with copyable install command, the animated nine-step loop strip, the Capture/Gate/Verify cards, the artifact cards, the board peek, and the blinking-cursor closing CTA.

Motivation

app/page.tsx is a scaffold placeholder rendering only an h1 — the epic's landing member exists precisely to replace it, and the public installer URL (https://shipd.now/install) has no product story behind it until this page ships.

Details

  • One "use client" component in components/landing-hero.tsx carries all interactivity: the hero header with the copy-to-clipboard install command and the nine-step loop strip (6.3s auto-advance, click-to-pin), plus a named export for the CTA install command with its blinking cursor.
  • app/page.tsx becomes a server component rendering the client hero, then the static sections verbatim from the design — Capture/Gate/Verify card trio, three artifact cards, board peek (stat tiles 175/36/11 + five epic rows + lifecycle footer line), CTA — and the default Footer.
  • Copy is carried verbatim from the parked design; inline styles stay as JSX style objects plus the DS utility classes, per the scaffold convention.

Affected capabilities: landing-page (added). Impact: app/page.tsx (replaced), components/landing-hero.tsx (new). No new dependencies; nav, footer, tokens, and responsive .m-* rules come from site-foundation.

Non-goals

  • No per-page Metadata, OG tags, sitemap, robots, or _redirects — that is the site-launch member.
  • No changes to the shared chrome (nav, footer, Logo) or to the design tokens and utility classes in app/globals.css — the page only adds page-scoped CSS.
  • No other routes — how-it-works, docs, and manifesto are sibling members.
  • No live data — the board-peek numbers and epic rows are baked in verbatim from the design (epic non-goal).

Implementation

  • Design reference: /Users/mikkelbergmann/.shipd/designs/landing-page/landing-v2.dc.html — read verbatim by the execution sub-agent and the validator as a read-only, out-of-worktree reference; match it, never edit it. Its <x-dc> body (lines 31–232) is the page markup; the DCLogic script (lines 235–336) holds the steps, icons, and epics data and the timer/clipboard behavior. The <sc-for>/{{ ... }} machinery is design-tool templating — re-implemented as React maps and state, never shipped.
  • Client/server split. components/landing-hero.tsx is the single "use client" file. Default export LandingHero: the full hero <header> (accent label, h1, paragraph, Install label, command box, HOW IT WORKS btn btn-secondary link, and the loop strip with its detail panel). Named export CtaInstallCommand: the CTA command box with the blinking-cursor span. Everything else in app/page.tsx stays server-rendered. Rejected: making the whole page a client component — static sections need no JS and the design comment marks the split explicitly.
  • Loop strip state. step state (0–8) plus an interval id in a ref. On mount, setInterval advances step = (step + 1) % 9 every 6300 ms; clicking a pill clears the interval permanently (no restart) and sets that step — exactly the design's select(). The active pill gets its step color as text and border color; inactive pills get var(--color-fg-3) text and transparent border. The detail panel derives icon paths, label, why, cmd, title, and colored lines from the active step; the ninth pill renders no trailing arrow. The second SVG path renders only when its d string is non-empty (several icons have an empty second path). Lines render with white-space: pre-wrap — the investigate step's first line contains literal newlines that must survive.
  • Clipboard copy. Each command box owns its own copied state: on click, write curl -fsSL https://shipd.now/install | sh via the clipboard API when available (guarded exactly like the design), set copied, and reset after 1600 ms. Only the hero box renders the copy/copied chip; the CTA box shows the blinking cursor instead, so independent state is indistinguishable from the design's shared state. Rejected: lifting shared state to the page — it would force the page client-side for no observable difference.
  • Page-scoped CSS. A <style> element rendered by LandingHero carries only what app/globals.css lacks: the blink keyframes (1.1s step-end infinite cursor), .cmd-box:hover { border-color: var(--color-accent) !important } and .epic-row:hover { background: var(--color-bg-hover) } replacing the design's style-hover attributes — the command boxes carry their base border as an inline shorthand, which beats any non-!important selector, so the hover rule needs !important to fire (validated: without it the rule is dead on both boxes), and a 760px media override .m-panel.landing-panel { height: 490px !important; overflow: hidden } restoring the design's fixed mobile panel height. The extra landing-panel class out-specifies the scaffold's generic .m-panel { height: auto !important } rule regardless of stylesheet order. Rejected: editing app/globals.css — it is shared foundation CSS that parallel page members also build on.
  • Fidelity convention (from the verified scaffold): design inline styles become JSX style objects; DS utility classes (.label, .card, .stripe-bg, .badge-*, .btn-secondary) and the responsive .m-h1, .m-h2, .m-grid, .m-cmd, .m-panel classes are used as in the design. All copy — headlines, paragraphs, step lines, artifact card text, epic rows, stat captions — is carried character-for-character.
  • Chrome contract. The page renders no nav (the layout mounts it) and ends with <Footer /> using its defaults (maxWidth 1100, all three links, accent square), matching the design's chrome comments.
  • Runnable premise verified: npm run typecheck, npm run lint, and npm run build were run in this worktree before planning — all exit 0 and the build emits the static export including the landing route.

Risk: the design's long mono lines (loop-strip detail, install command) can overflow small viewports; guarded by the design's own .m-cmd font-size override and flex-wrap styles, carried verbatim. Risk: a typo in the ported steps data silently breaks fidelity; guarded by the delta's verbatim-copy scenarios refuted against the parked design file.

ADDED Requirements

Requirement: Landing page content

id: landing-page-content

The system SHALL render the / route with the Shipd Landing v2 sections in design order — hero, loop strip, Capture/Gate/Verify cards, artifact cards, board peek, closing CTA, footer — with all copy carried verbatim from the parked design at /Users/mikkelbergmann/.shipd/designs/landing-page/landing-v2.dc.html, and the static sections SHALL be present in the exported landing HTML of the static build.

Scenario: Hero and CTA copy are verbatim

  • WHEN the site is built and the exported landing HTML is inspected
  • THEN it contains the h1 "Code generation is solved." / "Context isn't.", the label "Spec-driven agent orchestration", the CTA heading "Stop watching agents type.", and the install command curl -fsSL https://shipd.now/install | sh in both the hero and the CTA

Scenario: Static sections render server-side

  • WHEN the exported landing HTML is inspected
  • THEN it contains the three card headings ("Everything becomes a spec.", "Insufficient context never builds.", "Quality is checked, not assumed."), the artifact card file names (plan.md, specs/shipd-plan/spec.md, tasks.md), the stat values 175, 36, and 11 with their captions, the five epic slugs (autonomous-delivery, video-ingest, mikk-knowledge, delivery-metrics, portable-workspaces), and the lifecycle footer line "+ 6 more epics · lifecycle: draft → ready → active → complete → verified"

Scenario: Chrome contract holds

  • WHEN the / route is rendered
  • THEN exactly one nav (from the layout) is present and the page ends with the shared Footer at maxWidth 1100 with all three page links and the accent square

Scenario: Design fidelity of structure and styling

  • WHEN the rendered page is compared against the parked design file
  • THEN each section's markup structure, inline styles (as JSX style objects), DS utility classes (label, card, stripe-bg, badge-accent, badge-blue, badge-purple, btn-secondary), and responsive classes (m-h1, m-h2, m-grid, m-cmd, m-panel) match the design, and on viewports ≤760px the loop-strip panel is 490px tall with hidden overflow per the design's mobile override

Requirement: Loop strip auto-advance and pinning

id: loop-strip-interaction

The system SHALL render the hero loop strip as nine clickable step pills (intent, investigate, spec, context gate, build, refute, review, merge, capability library ↺) driving a two-panel detail view. While no pill has been clicked, the system SHALL auto-advance the active step every 6.3 seconds, wrapping from the last step to the first. When a pill is clicked, the system SHALL pin that step and stop the auto-advance timer permanently.

Scenario: Initial state and auto-advance

  • WHEN the page loads and 6.3 seconds pass without interaction
  • THEN the strip starts on "intent" (blue active pill, detail panel showing its icon, why-line, command, title, and colored lines) and then advances to "investigate" with the detail panel updated to that step's content

Scenario: Click pins a step and stops the timer

  • WHEN the "context gate" pill is clicked and more than 6.3 seconds pass
  • THEN the detail panel shows the context-gate content (accent color, command spec_gate.py checkout-retries) and the active step does not change again

Scenario: Pill styling tracks the active step

  • WHEN a step is active
  • THEN its pill text and border use that step's color while inactive pills use the muted foreground color with a transparent border, and the ninth pill renders no trailing arrow

Requirement: Install command copy interaction

id: install-command-copy

When an install command box is clicked, the system SHALL copy curl -fsSL https://shipd.now/install | sh to the clipboard where the clipboard API is available. When the hero command box is clicked, the system SHALL flip its chip label from "copy" to "copied" for 1.6 seconds before reverting. The CTA command box SHALL render a blinking accent cursor block animated at 1.1s step-end infinite instead of a chip.

Scenario: Hero copy flips the chip label

  • WHEN the hero install command box is clicked
  • THEN the clipboard receives the install command, the chip reads "copied", and after 1.6 seconds it reads "copy" again

Scenario: CTA box copies with a blinking cursor

  • WHEN the CTA install command box is inspected and clicked
  • THEN it shows the accent cursor block with the blink animation (no chip) and clicking it writes the install command to the clipboard

1. Client component

  • 1.1 [req: loop-strip-interaction] Create components/landing-hero.tsx with "use client": port the steps array (9 entries: label, color, why, cmd, title, lines with per-line color) and the icons array (9 pairs of SVG path strings) character-for-character from the DCLogic script in /Users/mikkelbergmann/.shipd/designs/landing-page/landing-v2.dc.html (lines 237–296) as typed module constants. Preserve the literal \n newlines inside the investigate step's first line.
  • 1.2 [req: loop-strip-interaction] In components/landing-hero.tsx, default-export LandingHero rendering the design's <header> (design lines 36–88) as JSX: stripe-bg overlay, accent label, m-h1 h1, paragraph, "Install" label, hero command box, HOW IT WORKS btn btn-secondary link, and the loop strip — pill row (the loop: prefix, mapped pills with arrows, no arrow after the ninth) plus the two-panel detail view (icon SVG with the second path rendered only when non-empty, mono label, why line, $ cmd + title row, colored pre-wrap lines). Hold step in state with the interval id in a ref: advance (step + 1) % 9 every 6300 ms from mount, clear the interval on unmount, and on pill click clear the interval permanently and set that step. Active pill text/border use the step color; inactive pills use var(--color-fg-3) text and transparent border; keep the design's 200 ms color/border transitions. Add class landing-panel next to m-panel m-grid on the detail panel wrapper.
  • 1.3 [req: install-command-copy] In components/landing-hero.tsx, implement the copy behavior (design lines 328–334): a click handler that writes curl -fsSL https://shipd.now/install | sh via the clipboard API when available, sets a copied state, and resets it after 1600 ms. The hero box (class cmd-box, design line 46–50) shows the accent $, the m-cmd command span, and a chip reading "copied" when copied else "copy". Also named-export CtaInstallCommand (design lines 222–226): the same box with its own copied state and click handler, accent $, m-cmd span, and the 7×15px accent cursor block with animation: blink 1.1s step-end infinite instead of the chip.
  • 1.4 [req: landing-page-content, install-command-copy] In components/landing-hero.tsx, render a <style> element carrying the page-scoped CSS: @keyframes blink (design line 20), .cmd-box:hover { border-color: var(--color-accent); }, .epic-row:hover { background: var(--color-bg-hover); }, and @media (max-width: 760px) { .m-panel.landing-panel { height: 490px !important; overflow: hidden; } }. Do not modify app/globals.css.

2. Landing page

  • 2.1 [req: landing-page-content] Replace app/page.tsx with the server component: render <LandingHero />, then the Capture/Gate/Verify section (design lines 91–122: label, m-h2 heading, three card blocks with their SVG icons, mono kickers 01 · CAPTURE / 02 · GATE / 03 · VERIFY, headings and paragraphs verbatim), then the artifacts section (lines 125–180: heading "The spec is the product.", the "real artifacts from shipd-now/shipd" note, three zero-padding cards with header rows — plan.md/badge-accent, specs/shipd-plan/spec.md/ badge-blue, tasks.md/badge-purple — and their mono body lines verbatim including colored spans).
  • 2.2 [req: landing-page-content] Continue app/page.tsx: the board-peek section (design lines 183–215: stripe-bg overlay, heading "shipd builds itself. This is the board.", $ shipd board text note, the three stat tiles 175/36/11 with captions, and the epic table — five rows from an inline array of slug/note/status/color exactly as design lines 322–326, each row class epic-row with the mono slug, muted note, and right-aligned status dot+label, followed by the "+ 6 more epics · lifecycle: draft → ready → active → complete → verified" footer line), then the CTA section (lines 218–229: centered "Stop watching agents type.", <CtaInstallCommand />, and the "then, in your repo: /s:plan → /s:build → merged PR" mono line), then <Footer /> with defaults.
  • 2.3 [req: landing-page-content] Verify chrome integration: the page renders no nav of its own (the layout provides it) and no wrapper besides the design's section markup; the h1 keeps class m-h1, section grids keep m-grid, headings keep m-h2, and command spans keep m-cmd so the shared 760px overrides apply.

3. Verify

  • 3.1 [req: *] Run npm run typecheck, npm run lint, and npm run build; confirm all exit 0 and, in the exported landing HTML of the build output, confirm: the hero h1 text, "Spec-driven agent orchestration", "Stop watching agents type.", two occurrences of the install command, the three capture/gate/verify card headings, the stat values with captions, the five epic slugs, the lifecycle footer line, exactly one nav, and the footer line "shipd.now — converged context, compiled to specs."

how-it-works-page

Status: verified Epic: shipd-now-site

Idea

Replace the placeholder /how-it-works route with the real page from the How It Works design: hero, the five-stage numbered flow closed by the capability-library loop line, the question-ladder accordion, the three role cards plus the every-change pipeline strip, the autopilot section with its two-column metro diagram, and the GET STARTED / READ THE FAQ CTA.

Motivation

app/how-it-works/page.tsx is a scaffold placeholder rendering only an h1 — the epic's how-it-works member exists precisely to replace it, and the site's product story (stages, question ladder, roles, autopilot) has no page until this ships.

Details

  • One "use client" component in components/question-ladder.tsx carries the page's only interactivity: the single-open four-rung accordion, plus the page-scoped <style>.
  • app/how-it-works/page.tsx becomes a server component rendering the hero, the five-stage flow (from a stages module constant) with the loop line, the ladder section (left copy column + the client accordion), the role cards and pipeline strip, the autopilot metro diagram (verbatim static markup), the CTA, and Footer maxWidth={1000}.
  • Copy is carried verbatim from the parked design; inline styles stay as JSX style objects plus the DS utility classes, per the scaffold convention.

Affected capabilities: how-it-works-page (added). Impact: app/how-it-works/page.tsx (replaced), components/question-ladder.tsx (new). No new dependencies; nav, footer, tokens, and the shared responsive rules come from site-foundation.

Non-goals

  • No per-page Metadata, OG tags, sitemap, robots, or _redirects — that is the site-launch member.
  • No changes to the shared chrome (nav, footer, Logo) or to the design tokens and utility classes in app/globals.css — the page only adds page-scoped CSS.
  • No other routes — landing, docs, and manifesto are sibling members.
  • No animation or state in the autopilot metro diagram — it ships as the design's static markup.

Implementation

  • Design reference: /Users/mikkelbergmann/.shipd/designs/how-it-works-page/how-it-works.dc.html — read verbatim by the execution sub-agent and the validator as a read-only, out-of-worktree reference; match it, never edit it. Its <x-dc> body (lines 35–232) is the page markup; the DCLogic script (lines 235–279) holds the ladder, stages, and roles data and the accordion state. The {{ ... }} machinery is design-tool templating — re-implemented as React maps and state, never shipped.
  • Client/server split. components/question-ladder.tsx is the single "use client" file — the accordion is the page's only stateful piece. Default export QuestionLadder renders the design's right-hand ladder column (lines 84–101): the four rung blocks mapped from the ported ladder array, the "↓ escalates only if unanswered" connector after each rung except the last, and the trailing "every answer you give teaches a lower rung…" line. Everything else in the page stays server-rendered. Rejected: making the whole page a client component — the other sections need no JS and the epic's decision marks the ladder as the one client component.
  • Accordion state. rung state initialized to 0 (rung 0 open initially). Clicking rung i sets rung === i ? null : i — exactly the design's toggle, so clicking the open rung closes all rungs. The open rung gets maxHeight 260px, opacity 1, border var(--color-border-strong), and chevron rotate(180deg); closed rungs get 0px, 0, var(--color-border), and 0deg, keeping the design's transitions. Rung numbers render "01"–"04"; the fourth rung's title uses var(--color-accent) while the others use var(--color-fg-1); each rung icon's second SVG path renders only when its d string is non-empty (the oracle rung's is empty).
  • Data placement. The stages array (5 entries: num, color, name, tag, desc, artifact — design lines 265–271) and the roles array (3 entries: tag, color, name, desc — lines 272–276) live as typed module constants in app/how-it-works/page.tsx, mapped by the server sections. The ladder array (4 rungs: title, tag, color, icon, icon2, detail — lines 237–250) lives in components/question-ladder.tsx. All ported character-for-character.
  • Page-scoped CSS. A <style> element rendered by QuestionLadder carries only what app/globals.css lacks: the ≤760px .m-stage overrides (design lines 25–29: 40px 1fr grid, shrunk number chip, re-placed head/body), the .m-metro base rule (two-column grid, gap 0 48px) with its ≤900px single-column collapse and .m-metro-joint { display:flex !important } (lines 31–32 — !important because the joint's inline style is display:none), and .rung-head:hover { border-color: var(--color-border-strong) !important } replacing the design's style-hover — the rung header carries its border inline (state-driven), so the hover rule needs !important to fire, per the landing-page precedent; on the open rung the hover is a no-op since its border is already border-strong, matching the design. Rejected: editing app/globals.css — shared foundation CSS that parallel page members also build on.
  • Metro diagram. Verbatim static markup: two flex columns inside the .m-metro grid (design lines 143–216), the dashed orange side branch under stop 3, and the joint element (class m-metro-joint, inline display:none) that the 900px rule reveals when the columns stack. No state, no client code.
  • Fidelity convention (from the verified scaffold and landing-page): design inline styles become JSX style objects; DS utility classes (.label, .card, .stripe-bg, .btn, .btn-primary, .btn-secondary) and the responsive classes (m-h1, m-h2, m-grid, the m-stage family, m-metro, m-metro-joint) are used as in the design. All copy — headline, stage descriptions and artifact chips, rung details, role cards, pipeline strip, autopilot paragraphs and metro labels — is carried character-for-character.
  • Chrome contract. The page renders no nav (the layout mounts it and colors the How it works link per site-foundation) and ends with Footer maxWidth={1000} per the design's footer comment — the width the placeholder already uses.
  • Runnable premise verified: npm run typecheck, npm run lint, and npm run build were run in this worktree before planning — all exit 0 and the build emits the static export including the how-it-works route.

Risk: a typo in the ported stages/ladder/roles data silently breaks fidelity; guarded by the delta's verbatim-copy scenarios refuted against the parked design file. Risk: the long mono pipeline strip overflows small viewports; guarded by the design's own flex-wrap:wrap style, carried verbatim.

ADDED Requirements

Requirement: How-it-works page content

id: how-it-works-content

The system SHALL render the /how-it-works route with the How It Works sections in design order — hero, five-stage flow with the capability-library loop line, question-ladder section, role cards with the pipeline strip, autopilot metro diagram, closing CTA, footer — with all copy carried verbatim from the parked design at /Users/mikkelbergmann/.shipd/designs/how-it-works-page/how-it-works.dc.html, and the static sections SHALL be present in the exported how-it-works HTML of the static build.

Scenario: Hero and CTA copy are verbatim

  • WHEN the site is built and the exported how-it-works HTML is inspected
  • THEN it contains the h1 "From stated intent to a merged, verified pull request.", the accent label "How it works", the hero paragraph ending "Gates are only ever skipped through explicit configuration.", the CTA heading "Try it on your next change.", a GET STARTED link to /docs with classes btn btn-primary, and a READ THE FAQ link to /docs#faq with classes btn btn-secondary

Scenario: Five-stage flow renders server-side

  • WHEN the exported how-it-works HTML is inspected
  • THEN it contains the five stage names Intent, Converge, Gate, Build & refute, and Ship & record with their numbers 01–05, their mono tags (e.g. "prose · brief · recording", "deterministic · LLM-free engine"), their descriptions, and their artifact chips (e.g. the Intent chip naming research/<slug>/report.md and video/<slug>/brief.md, the Build & refute chip "→ one change · one worktree · one branch · one PR"), followed by the loop line "the capability library compiles context for the next change" with the accent "↺"

Scenario: Roles and autopilot sections are verbatim

  • WHEN the exported how-it-works HTML is inspected
  • THEN it contains the heading "Three roles, tiered by model strength." with the three role cards (ORCHESTRATOR / "Plans and designs", EXECUTION AGENTS / "Claim and implement", VALIDATOR / "Tries to break it"), the pipeline strip starting "every change:" running worktree → branch → PR → CI → semantic review (explicitly dispositioned) → merged → capability library, the autopilot heading "One human approval: the epic.", the seven metro stop labels ("1 · you approve the epic" through "7 · merged ↺ next member"), the orange side branch lines ("insufficient? side branch:", "parked as rejected", "you enrich → ↺ rejoins at plan"), and the note "a parked member pauses only itself — the run continues with the rest and reports it"

Scenario: Chrome contract holds

  • WHEN the /how-it-works route is rendered
  • THEN exactly one nav (from the layout) is present and the page ends with the shared Footer at maxWidth 1000

Scenario: Design fidelity of structure and styling

  • WHEN the rendered page is compared against the parked design file
  • THEN each section's markup structure, inline styles (as JSX style objects), DS utility classes (label, card, stripe-bg, btn-primary, btn-secondary), and responsive classes (m-h1, m-h2, m-grid, the m-stage family, m-metro, m-metro-joint) match the design; the metro diagram lays out as two columns above 900px and collapses to one column with the m-metro-joint connector shown at ≤900px; and at ≤760px each stage block collapses to the 40px 1fr grid with the shrunk 30px number chip

Requirement: Question ladder accordion

id: question-ladder-accordion

The system SHALL render the question ladder as four rung rows (Codebase investigation, Wiki + personal memory, The oracle, You) with a single-open accordion: the first rung SHALL be open on load; when a closed rung's header is clicked, the system SHALL open it and close the previously open rung; when the open rung's header is clicked, the system SHALL close it leaving no rung open.

Scenario: First rung open on load

  • WHEN the page loads
  • THEN the "Codebase investigation" rung shows its detail text ("The plan reads before it asks…"), a border of var(--color-border-strong), and a chevron rotated 180deg, while the other three rungs are collapsed (max-height 0, opacity 0, border var(--color-border), chevron at 0deg)

Scenario: Clicking a closed rung switches the open rung

  • WHEN the "The oracle" rung header is clicked
  • THEN its detail ("An ask-first agent holding your standing positions…") expands and the previously open rung collapses, so exactly one rung is open

Scenario: Clicking the open rung closes all

  • WHEN the currently open rung's header is clicked again
  • THEN that rung collapses and no rung is open

Scenario: Rung chrome and connectors are verbatim

  • WHEN the ladder markup is inspected
  • THEN the rungs carry numbers 01–04 and their tags ("answers most", "recorded decisions", "standing positions, cited", "only what's genuinely open"), the fourth rung's title "You" uses var(--color-accent), the connector line "↓ escalates only if unanswered" appears exactly three times (between rungs, never after the last), and the column ends with "every answer you give teaches a lower rung — over time, less escalates to you"

1. Client component

  • 1.1 [req: question-ladder-accordion] Create components/question-ladder.tsx with "use client": port the ladder array (4 entries: title, tag, color, icon, icon2, detail) character-for-character from the DCLogic script in /Users/mikkelbergmann/.shipd/designs/how-it-works-page/how-it-works.dc.html (lines 237–250) as a typed module constant.
  • 1.2 [req: question-ladder-accordion] In components/question-ladder.tsx, default-export QuestionLadder rendering the design's ladder column (lines 84–101): map the four rungs into a header row (add class rung-head; icon SVG rendering the second path only when its d string is non-empty, mono number "01"–"04", title with var(--color-accent) on the fourth rung and var(--color-fg-1) otherwise, mono tag in the rung color, chevron span) plus the collapsible detail block, keeping the design's transition styles. Hold rung state initialized to 0; clicking rung i sets rung === i ? null : i. Open rung: maxHeight 260px, opacity 1, border var(--color-border-strong), chevron rotate(180deg); closed: 0px, 0, var(--color-border), 0deg. Render the "↓ escalates only if unanswered" connector after each rung except the last, then the trailing "every answer you give teaches a lower rung — over time, less escalates to you" line (design line 100).
  • 1.3 [req: how-it-works-content, question-ladder-accordion] In components/question-ladder.tsx, render a <style> element carrying the page-scoped CSS: the ≤760px .m-stage overrides (design lines 25–29), the .m-metro base grid rule and its ≤900px collapse with .m-metro-joint { display: flex !important } (design lines 31–32), and .rung-head:hover { border-color: var(--color-border-strong) !important }. Do not modify app/globals.css.

2. Page

  • 2.1 [req: how-it-works-content] Replace app/how-it-works/page.tsx with the server component: port the stages array (5 entries: num, color, name, tag, desc, artifact — design lines 265–271) and the roles array (3 entries: tag, color, name, desc — lines 272–276) character-for-character as typed module constants; render the hero header (design lines 38–45: stripe-bg overlay, accent "How it works" label, m-h1 h1, paragraph), then the flow section (lines 48–74: one m-stage grid block per stage — bordered number chip in the stage color, connector line, name and mono tag, description, artifact chip — followed by the capability-library loop line with the accent "↺"), then the ladder section (lines 77–103: m-grid two-column layout with the left copy column verbatim — label "The question ladder", m-h2 heading "Most questions never reach you.", paragraph — and <QuestionLadder /> as the right column).
  • 2.2 [req: how-it-works-content] Continue app/how-it-works/page.tsx: the roles section (design lines 106–132: label "Division of labor", m-h2 heading, three mapped card blocks with mono tag, colored dot, name, description, then the "every change:" pipeline strip verbatim including the orange "(explicitly dispositioned)", green "merged", and accent "capability library" spans), the autopilot section (lines 135–220: stripe-bg overlay, accent label, m-h2 heading "One human approval: the epic.", the paragraph with the mono orange "rejected" span, and the metro diagram card verbatim — the mono uppercase caption, the two m-metro columns with stops 1–7, the dashed orange side branch under stop 3, the hidden m-metro-joint element, and the dashed-top footer note), the CTA section (lines 222–230: centered m-h2 "Try it on your next change.", GET STARTED link to /docs with btn btn-primary, READ THE FAQ link to /docs#faq with btn btn-secondary), and finally <Footer maxWidth={1000} />.
  • 2.3 [req: how-it-works-content] Verify chrome integration in app/how-it-works/page.tsx: the page renders no nav of its own (the layout provides it) and no wrapper besides the design's section markup; the h1 keeps class m-h1, section headings keep m-h2, the ladder and roles grids keep m-grid, stage blocks keep the m-stage family classes, and the metro keeps m-metro/m-metro-joint so the page-scoped and shared responsive overrides apply.

3. Verify

  • 3.1 [req: *] Run npm run typecheck, npm run lint, and npm run build; confirm all exit 0 and, in the exported how-it-works HTML of the build output, confirm: the hero h1 "From stated intent to a merged, verified pull request.", the five stage names and their artifact chips, the loop line "the capability library compiles context for the next change", the four rung titles with tags and the three "escalates only if unanswered" connectors, the three role names, the "every change:" pipeline strip, the autopilot heading and all seven metro stop labels with the side-branch lines, the CTA links to /docs and /docs#faq, exactly one nav, and the footer line "shipd.now — converged context, compiled to specs."

docs-page

Status: verified Epic: shipd-now-site

Idea

Replace the placeholder /docs route with the real page from the Docs design: hero, getting-started steps 1–4 (step 4 carrying the six shipd CLI verb rows), the lifecycle strip, the workspaces section, the supersession-gate table, the ten-card capabilities grid, and the three-entry FAQ — with the load-bearing anchors #workspaces, #capabilities, #faq.

Motivation

app/docs/page.tsx is a scaffold placeholder rendering only an h1 — the epic's docs member exists precisely to replace it, and the landing and how-it-works pages already link to /docs and /docs#faq, anchors that currently resolve to nothing.

Details

  • app/docs/page.tsx becomes a fully static server component rendering, in design order: the hero header, the four getting-started step blocks, the lifecycle strip, section id workspaces (file-tree panel + three sync bullets), the supersession-gate section with its three-row table, section id capabilities (ten cards), section id faq (three cards), and the existing Footer maxWidth={880} call unchanged.
  • The design's verbs (6), caps (10), and faqs (3) arrays are ported character-for-character as typed module constants in the page file and mapped into the verb rows, capability cards, and FAQ cards.
  • Copy is carried verbatim from the parked design; inline styles stay as JSX style objects plus the DS utility classes, per the scaffold convention.

Affected capabilities: docs-page (added). Impact: app/docs/page.tsx (replaced) — the only file. No new dependencies; nav, footer, tokens, and the shared responsive rules come from site-foundation.

Non-goals

  • No per-page Metadata, OG tags, sitemap, robots, or _redirects — that is the site-launch member.
  • No changes to the shared chrome (nav, footer, Logo) or to the design tokens and utility classes in app/globals.css.
  • No other routes — landing, how-it-works, and manifesto are sibling members.
  • No client-side state or interactivity — the page has none in the design; card hover styling comes from the DS card class.

Implementation

  • Design reference: /Users/mikkelbergmann/.shipd/designs/docs-page/docs.dc.html — read verbatim by the execution sub-agent and the validator as a read-only, out-of-worktree reference; match it, never edit it. Its <x-dc> body (lines 30–202) is the page markup; the DCLogic script (lines 204–242) holds the faqs, caps, and verbs data. The {{ ... }} machinery is design-tool templating — re-implemented as React maps, never shipped.
  • No client component and no page-scoped CSS. The design defines no state or handlers, so app/docs/page.tsx stays a server component with no "use client" file — card hovers come from the DS card class in the global stylesheet. The design helmet's <style> is already fully covered by app/globals.css: the anchor color/hover rules (lines 339–340) and the ≤760px m-grid/m-h1/m-h2/m-super/m-panel block (lines 346–352). Rejected: a page <style> element per the how-it-works precedent — that page needed rules globals lacked; this one needs none.
  • Data placement. verbs (6 entries: cmd, desc — design lines 231–238), caps (10 entries: name, cmd, area, color, desc, gives — lines 219–230), and faqs (3 entries: num, q, a1, a2 — lines 208–218) live as typed module constants in app/docs/page.tsx, all ported character-for-character. The cap badge's color value (e.g. the blue token var) binds as the JSX style object's color, exactly as the design's inline binding does.
  • Verb-row borders. Each of the six verb rows renders the design's row template (line 87: m-grid, 220px/1fr grid, mono accent cmd, fg-2 desc) with a bottom border on every row except the last — the design's own supersession table (lines 144–152) omits the border on its final row inside the same rounded overflow-hidden container, fixing the intent. Rejected: border on all six — it would draw a stray line against the container edge.
  • Anchors are load-bearing. The section ids workspaces, capabilities, and faq are carried exactly (design lines 113, 161, 181) — the landing and how-it-works pages link to /docs#faq and the nav INSTALL button targets /docs.
  • Angle-bracket copy. Literal copy such as /s:<name>, Q<n>, shipd epic <slug>, /s:build [change], and spec_status.py check-base [change] renders through JSX string expressions so it lands verbatim in the HTML without JSX parsing errors.
  • Fidelity convention (from the verified scaffold and shipped siblings): design inline styles become JSX style objects; DS utility classes (label, card, stripe-bg) and responsive classes (m-h1, m-h2, m-grid) are used as in the design; all copy — hero, step titles and terminal blocks, lifecycle chips, workspaces file tree and bullets, supersession rows, capability cards, FAQs — is carried character-for-character, including the ✓ and → glyphs and the | divider.
  • Chrome contract. The page renders no nav (the layout mounts it; the nav already accent-colors Docs and hides INSTALL on /docs per site-foundation) and keeps the placeholder's exact Footer call: maxWidth 880, accentSquare false, links only "How it works".
  • Runnable premise verified: npm ci, npm run typecheck, npm run lint, and npm run build were run in this worktree before planning — all exit 0, and the static export writes the docs route as a flat docs HTML file at the export root (not a nested index), which the verify task inspects.

Risk: a typo in the ported verbs/caps/faqs data silently breaks fidelity; guarded by the delta's verbatim-copy scenarios refuted against the parked design file. Risk: mis-escaped angle-bracket copy drops characters in the exported HTML; guarded by the scenario checks quoting those strings.

ADDED Requirements

Requirement: Docs page content

id: docs-content

The system SHALL render the /docs route as a fully static server-rendered page with the Docs sections in design order — hero, getting-started steps 1–4, lifecycle strip, workspaces section, supersession-gate section, capabilities grid, FAQ, footer — with all copy carried verbatim from the parked design at /Users/mikkelbergmann/.shipd/designs/docs-page/docs.dc.html, and the sections SHALL be present in the exported docs HTML of the static build.

Scenario: Hero and step copy are verbatim

  • WHEN the site is built and the exported docs HTML is inspected
  • THEN it contains the accent label "Docs · Getting started", the h1 "From install to merged PR.", the hero paragraph ending "Four steps to your first spec-driven change.", the four step headings "Install", "Plan — converge on the spec", "Build — gated, refuted, merged", and "Watch the board", and the step terminal lines including "curl -fsSL https://shipd.now/install | sh", "✓ plugin installed — skills available as /s:<name>", "→ .shipd/planned/checkout-retries/ · status: draft", and "gate: PASS → 4 tasks → refute: confirmed → PR #212 merged"

Scenario: Six CLI verb rows render from the ported data

  • WHEN the exported docs HTML is inspected
  • THEN step 4's table contains exactly six rows pairing the mono accent commands shipd list, shipd status [change], shipd epic <slug>, shipd board, shipd metrics, and shipd lint [change] with their descriptions ("in-flight changes across the root and its worktrees" through "structurally validate specs and change deltas"), where every row except the last carries the bottom border

Scenario: Lifecycle and supersession sections are verbatim

  • WHEN the exported docs HTML is inspected
  • THEN the lifecycle strip shows the chips draft → ready → active → complete → verified, the "|" divider, the red "rejected" chip with the note "← the gate parks insufficient context for human enrichment", and the supersession section shows the heading "Stale plans never build." with the three table rows clean / content drift / superseded (last row without a bottom border) and the closing note naming spec_status.py check-base [change] and id-collision

Scenario: Workspaces section is verbatim

  • WHEN the exported docs HTML is inspected
  • THEN the workspaces section shows the heading "One job, many repos, any machine.", the file-tree panel rooted at ~/jobs/documents-linking/ with its six entries (.shipd-config.json through incentives/) and their tracked/machine-local annotations, and the three accent-arrow bullets starting "Clone the workspace, not the repos.", "Knowledge travels with the job.", and "Drift is reported, never "repaired"."

Scenario: Capability cards and FAQs render from the ported data

  • WHEN the exported docs HTML is inspected
  • THEN the capabilities grid contains the ten card names "Plan a change" through "Stand up a workspace" with their mono commands (e.g. "/s:plan <intent>", "automatic during planning"), area badges in their per-card colors (core loop, intent, knowledge, scale, visibility, quality), descriptions, and "→" gives-footers (e.g. "→ plan.md · delta specs · tasks.md, status: draft"), and the FAQ section contains the three numbered cards 01–03 with their questions ("Which agents and models does it work with?", "What does shipd see of my code? What leaves my machine?", "What if the validator is wrong?") and both answer paragraphs each

Scenario: Chrome contract holds

  • WHEN the /docs route is rendered
  • THEN exactly one nav (from the layout) is present with the Docs link in the accent color and no INSTALL button, and the page ends with the shared Footer at maxWidth 880, without the accent square, whose only page link is "How it works"

Scenario: Design fidelity of structure and styling

  • WHEN the rendered page is compared against the parked design file
  • THEN each section's markup structure, inline styles (as JSX style objects), DS utility classes (label, card, stripe-bg), and responsive classes (m-h1, m-h2, m-grid) match the design; the page ships no "use client" component and no page-scoped style element; and at ≤760px the m-grid two-column layouts (verb rows, workspaces panel, supersession rows, capabilities grid) collapse to one column while the h1 and h2 sizes shrink per the shared global rules

Requirement: Stable documentation anchors

id: docs-anchors

The system SHALL expose the ids workspaces, capabilities, and faq on the corresponding /docs sections so that fragment links from other pages resolve.

Scenario: Anchor ids present in the export

  • WHEN the exported docs HTML is inspected
  • THEN it contains exactly one element with id "workspaces" (the workspaces section), one with id "capabilities" (the capabilities section), and one with id "faq" (the FAQ section)

1. Data

  • 1.1 [req: docs-content] In app/docs/page.tsx, port the three data arrays character-for-character from the DCLogic script in /Users/mikkelbergmann/.shipd/designs/docs-page/docs.dc.html as typed module constants: verbs (6 entries: cmd, desc — design lines 231–238), caps (10 entries: name, cmd, area, color, desc, gives — lines 219–230), and faqs (3 entries: num, q, a1, a2 — lines 208–218). Keep every color value as its design token var string.

2. Page

  • 2.1 [req: docs-content] Replace the main block of app/docs/page.tsx with the design's hero and steps: the header (design lines 33–40: stripe-bg overlay, accent label "Docs · Getting started", m-h1 h1 "From install to merged PR.", paragraph), then the steps section (lines 42–94) with the four 44px/1fr grid blocks — step 1's accent number chip and install terminal (the $ prompt line and two ✓ lines), steps 2–3 with their border-strong chips, headings, paragraphs with inline mono spans, and terminal blocks, and step 4's verb table: map verbs into the design's row template (line 87: m-grid, 220px/1fr grid, mono accent cmd, fg-2 desc) inside the rounded overflow-hidden container, with the bottom border on every row except the last. Render angle-bracket copy (e.g. the /s: skill-name pattern in step 1's ✓ line) via JSX string expressions.
  • 2.2 [req: docs-content] Continue app/docs/page.tsx with the lifecycle section (design lines 96–111: label "The lifecycle", the mono chip strip draft → ready → active(orange) → complete → verified(green), the "|" divider, the red rejected chip and its fg-3 note, and the closing guarded-transitions paragraph) and the supersession section (lines 138–159: label "The supersession gate", m-h2 heading "Stale plans never build.", intro paragraph, the three-row clean/content drift/superseded table — last row without a bottom border — and the closing note with the mono check-base and id-collision spans).
  • 2.3 [req: docs-content, docs-anchors] Continue app/docs/page.tsx with section id "workspaces" (design lines 113–136: stripe-bg overlay, accent label, m-h2 heading "One job, many repos, any machine.", intro paragraph with the bold "portable workspace", the m-grid two-column layout pairing the mono file-tree panel — six 170px/1fr rows with tracked/machine-local annotations — with the three accent-arrow sync bullets, each bold lead carried verbatim).
  • 2.4 [req: docs-content, docs-anchors] Finish app/docs/page.tsx with section id "capabilities" (design lines 161–179: accent label "What can shipd do", heading "Every capability, one page.", intro paragraph, and the m-grid two-column grid mapping caps into the design's card template — name, area badge colored per cap.color, mono accent cmd, description, and the border-top "→ gives" footer) and section id "faq" (lines 181–199: accent label "FAQ", heading "The questions worth asking.", and the three faqs cards with mono accent num, question h3, and both answer paragraphs). Keep the existing Footer call (maxWidth 880, accentSquare false, only the "How it works" link) and add no "use client" directive, no page style element, and no nav.

3. Verify

  • 3.1 [req: *] Run npm run typecheck, npm run lint, and npm run build; confirm all exit 0 and, in the exported docs HTML of the build output (the flat docs file at the export root), confirm: the h1 "From install to merged PR.", the four step headings, the install command line and both ✓ lines, all six verb commands with their descriptions, the six lifecycle chips with the rejected note, the workspaces heading with the six file-tree entries and three bullet leads, the supersession heading with its three rows, all ten capability names with their commands and gives-footers, the three FAQ questions with two paragraphs each, exactly one occurrence of each id workspaces/capabilities/faq, exactly one nav with no INSTALL button, and the footer line "shipd.now — converged context, compiled to specs." followed by only the "How it works" link.

manifesto-page

Status: verified Epic: shipd-now-site

Idea

Replace the placeholder /manifesto route with the real page from the Manifesto design: the stripe-bg hero with the translucent "WHY" supergraphic and the converged-context headline, the five numbered theses, and the striped closing CTA.

Motivation

app/manifesto/page.tsx is a scaffold placeholder rendering only an h1 — the epic's manifesto member exists precisely to replace it, and the shared nav and footer already link to /manifesto from every page.

Details

  • app/manifesto/page.tsx becomes a fully static server component rendering, in design order: the hero header (stripe-bg overlay, "WHY" supergraphic, accent label "The bet", h1, intro paragraph), the theses section mapping the five-entry theses array into the numbered two-column blocks, the striped CTA section ("Compile context into specs…" + GET STARTED → /docs), and the existing Footer maxWidth={820} call unchanged.
  • The design's theses array (5 entries: num, title, body) is ported character-for-character as a typed module constant in the page file.
  • Copy is carried verbatim from the parked design; inline styles stay as JSX style objects plus the DS utility classes, per the scaffold convention.

Affected capabilities: manifesto-page (added). Impact: app/manifesto/page.tsx (replaced) — the only file. No new dependencies; nav, footer, tokens, and the shared responsive rules come from site-foundation.

Non-goals

  • No per-page Metadata, OG tags, sitemap, robots, or _redirects — that is the site-launch member.
  • No changes to the shared chrome (nav, footer, Logo) or to the design tokens and utility classes in app/globals.css.
  • No other routes — landing, how-it-works, and docs are sibling members (already shipped).
  • No client-side state or interactivity — the page has none in the design.

Implementation

  • Design reference: /Users/mikkelbergmann/.shipd/designs/manifesto-page/manifesto.dc.html — read verbatim by the execution sub-agent and the validator as a read-only, out-of-worktree reference; match it, never edit it. Its <x-dc> body (lines 28–65) is the page markup; the DCLogic script (lines 67–81) holds the theses data. The {{ ... }} machinery is design-tool templating — re-implemented as a React map, never shipped.
  • No client component and no page-scoped CSS. The design defines no state or handlers, so app/manifesto/page.tsx stays a server component with no "use client" file. The design helmet's <style> is already fully covered by app/globals.css: the anchor color/hover rules (lines 339–340) and the ≤760px m-grid/m-h1/m-h2/m-super block (lines 346–350) — the .m-super rule that hides the "WHY" supergraphic on mobile is verified present at line 350. Rejected: a page <style> element per the how-it-works precedent — that page needed rules globals lacked; this one needs none (same reasoning as the shipped docs-page member).
  • Data placement. theses (5 entries: num, title, body — design lines 72–76) lives as a typed module constant in app/manifesto/page.tsx, ported character-for-character, and is mapped into the design's thesis block template (lines 45–51: m-grid 64px/1fr grid, mono fg-3 num, m-h2 display title, fg-2 body capped at 600px).
  • Supergraphic and hero. The "WHY" div carries class m-super and the design's exact inline styles (line 33: absolute right -60px / bottom -50px, 240px display type, rgba(240,240,248,0.025)); both striped sections layer the stripe-bg overlay div exactly as the design does (lines 32, 55).
  • Apostrophe copy. Copy rendered as JSX text (the h1 and intro paragraph contain straight apostrophes in "isn't", "It's", "doesn't") uses the sibling convention of HTML entities in JSX text — the same characters land verbatim in the exported HTML; copy inside the theses string constants needs no escaping.
  • Fidelity convention (from the verified scaffold and shipped siblings): design inline styles become JSX style objects; DS utility classes (label, stripe-bg, btn btn-primary) and responsive classes (m-h1, m-h2, m-grid, m-super) are used as in the design; all copy — hero, theses, CTA — is carried character-for-character, including the em-dashes and the "175 changes, 36 verified capabilities, 11 epics" figures in thesis 05.
  • Chrome contract. The page renders no nav (the layout mounts it; the nav accent-colors Manifesto on this route and shows INSTALL) and keeps the placeholder's exact Footer call — maxWidth={820} with the default links and accent square — which matches the design's own footer annotation (design line 64).
  • Runnable premise verified: npm run typecheck, npm run lint, and npm run build were run in this worktree before planning — all exit 0, and the static export writes the manifesto route as a flat manifesto HTML file at the export root (not a nested index), which the verify task inspects.

Risk: a typo in the ported theses data or hero copy silently breaks fidelity; guarded by the delta's verbatim-copy scenarios refuted against the parked design file. Risk: a wrongly escaped apostrophe drops or mangles characters in the exported HTML; guarded by the scenario checks quoting those strings.

ADDED Requirements

Requirement: Manifesto page content

id: manifesto-content

The system SHALL render the /manifesto route as a fully static server-rendered page with the Manifesto sections in design order — hero header with the "WHY" supergraphic, the five numbered theses, the striped closing CTA, footer — with all copy carried verbatim from the parked design at /Users/mikkelbergmann/.shipd/designs/manifesto-page/manifesto.dc.html, and the sections SHALL be present in the exported manifesto HTML of the static build.

Scenario: Hero copy is verbatim

  • WHEN the site is built and the exported manifesto HTML is inspected
  • THEN it contains the accent label "The bet", the h1 "The scarce resource isn't code generation. It's converged context.", the "WHY" supergraphic text, and the intro paragraph beginning "Agents write code faster than anyone can read it" and ending "every one enforced by the pipeline today."

Scenario: Five theses render from the ported data

  • WHEN the exported manifesto HTML is inspected
  • THEN the theses section contains exactly five numbered blocks pairing the mono nums 01–05 with the titles "Intent is a file in the repository.", "No code before the gate passes.", "Nothing merges until someone tried to break it.", "Every question is asked exactly once.", and "shipd ships shipd.", each followed by its full body paragraph verbatim — including thesis 01's "plan.md, testable requirement deltas, tasks.md", thesis 04's "A question you answered in March does not come back in August.", and thesis 05's "175 changes, 36 verified capabilities, 11 epics"

Scenario: Closing CTA is verbatim

  • WHEN the exported manifesto HTML is inspected
  • THEN the closing section contains the line "Compile context into specs, and you can ship software you didn't watch being written." and a "GET STARTED" link styled btn btn-primary whose href resolves to the docs route

Scenario: Chrome contract holds

  • WHEN the /manifesto route is rendered
  • THEN exactly one nav (from the layout) is present with the Manifesto link in the accent color and the INSTALL button showing, and the page ends with the shared Footer at maxWidth 820 with the accent square and the default links "How it works", "Docs", and "Manifesto"

Scenario: Design fidelity of structure and styling

  • WHEN the rendered page is compared against the parked design file
  • THEN each section's markup structure, inline styles (as JSX style objects), DS utility classes (label, stripe-bg, btn btn-primary), and responsive classes (m-h1, m-h2, m-grid, m-super) match the design — both striped sections carry the stripe-bg overlay div, and the "WHY" div carries class m-super with the design's absolute-position styles; the page ships no "use client" component and no page-scoped style element; and at ≤760px the shared global rules hide the m-super supergraphic, collapse the m-grid thesis blocks to one column, and shrink the m-h1 and m-h2 sizes

1. Data

  • 1.1 [req: manifesto-content] In app/manifesto/page.tsx, port the theses array character-for-character from the DCLogic script in /Users/mikkelbergmann/.shipd/designs/manifesto-page/manifesto.dc.html as a typed module constant: 5 entries with fields num, title, body (design lines 72–76).

2. Page

  • 2.1 [req: manifesto-content] Replace the main block of app/manifesto/page.tsx with the design's hero header (design lines 31–41): the border-bottom header with the stripe-bg overlay div, the m-super "WHY" supergraphic div with its absolute-position inline styles (line 33), and the 820px inner container holding the accent label "The bet", the m-h1 h1, and the 620px intro paragraph — all copy verbatim, with JSX-text apostrophes escaped per the sibling convention.
  • 2.2 [req: manifesto-content] Continue app/manifesto/page.tsx with the theses section (design lines 43–52): the 820px flex column with 56px gap, mapping theses into the design's block template — m-grid 64px/1fr grid, mono fg-3 num span, m-h2 h2 title, fg-2 body paragraph capped at 600px — and the closing CTA section (lines 54–62): border-top, stripe-bg overlay div, centered 820px container with the display-font closing line and the GET STARTED link (href /docs, class "btn btn-primary", the design's inline styles). Keep the existing Footer maxWidth={820} call unchanged and add no "use client" directive, no page style element, and no nav.

3. Verify

  • 3.1 [req: *] Run npm run typecheck, npm run lint, and npm run build; confirm all exit 0 and, in the exported manifesto HTML of the build output (the flat manifesto file at the export root), confirm: the label "The bet", the h1 "The scarce resource isn't code generation. It's converged context.", the "WHY" supergraphic in an element with class m-super, the intro paragraph, all five thesis nums 01–05 with their titles and full bodies (including "175 changes, 36 verified capabilities, 11 epics"), the CTA line "Compile context into specs, and you can ship software you didn't watch being written." with the GET STARTED link to the docs route, exactly one nav with the INSTALL button present, and the footer line "shipd.now — converged context, compiled to specs." followed by the three default links.

site-launch

Status: verified Epic: shipd-now-site

Idea

Ship the launch layer of shipd.now: real per-page metadata with a shared OG image, favicon, robots.txt, sitemap.xml, the /install redirect, the documented Cloudflare deployment steps, and the autopilot-heartbeat repo hygiene fix.

Motivation

All four pages are built and verified, but app/layout.tsx still carries the scaffold-placeholder metadata and the site has no OG image, favicon, robots, sitemap, redirect rule, or deployment documentation — nothing a launch needs. The epic's success criterion that https://shipd.now/install resolves to the installer depends on the _redirects rule this change adds.

Details

  • Replace the placeholder root metadata and add per-page metadata exports for /how-it-works, /docs, /manifesto, and the 404 page.
  • Check in a shared 1200×630 OG image (Next file convention) and an SVG + PNG favicon set derived from the logo's accent dot.
  • Add public/robots.txt (new public directory), a four-URL app/sitemap.ts, and public/_redirects carrying the /install rule.
  • Document the manual Cloudflare git-integration setup and a post-deploy verification checklist in a new deployment guide at docs/deployment.md.
  • Stop tracking .shipd/autopilot/ heartbeat state.

Affected capabilities: site-launch (added). Impact: app/layout.tsx, app/how-it-works/page.tsx, app/docs/page.tsx, app/manifesto/page.tsx, app/not-found.tsx, new files under the app, public, and docs directories, .gitignore. No new npm dependencies.

Non-goals

  • No CI workflow and no Cloudflare dashboard/DNS automation — the manual steps are documented instead (epic non-goals).
  • No build-time OG generation script — the OG image and favicon PNGs are one-off checked-in assets.
  • No llms.txt — the epic's launch layer does not list it.
  • No copy changes to the pages themselves; descriptions quote existing hero copy.

Implementation

  • Root metadata (app/layout.tsx): metadataBase: new URL("https://shipd.now"); title: { default: "shipd.now — converged context, compiled to specs.", template: "%s — shipd.now" }; description "Spec-driven agent orchestration. shipd makes agents converge on a spec before they write code, then an adversarial validator tries to break every scenario before anything merges."; openGraph: { siteName: "shipd.now", type: "website" }; twitter: { card: "summary_large_image" }. Rejected: per-page openGraph image lists — the root app/opengraph-image.png file convention emits og:image for every route automatically.
  • Per-page metadata — exact strings, all server components so plain export const metadata works:
    • /how-it-works: title "How it works"; description "From stated intent to a merged, verified pull request: five stages, a context gate before any code is written, and independent validation before anything merges."
    • /docs: title "Docs"; description "From install to merged PR: shipd runs inside your coding-agent session as a plugin, backed by an LLM-free spec engine. Four steps to your first spec-driven change."
    • /manifesto: title "Manifesto"; description "The scarce resource isn't code generation. It's converged context. Five theses on why intent belongs in the repository."
    • 404 page: title "404" (the template renders "404 — shipd.now").
  • OG image: checked-in app/opengraph-image.png (1200×630) plus app/opengraph-image.alt.txt ("shipd — converged context, compiled to specs."). Generated once with headless Google Chrome from a throwaway HTML (exact markup in tasks.md) using the built site's own Space Grotesk latin woff2, so the wordmark matches the logo. Verified premises: npm run build exits 0 and emits the woff2 files under the out directory's static media path, with the built CSS @font-face blocks identifying the latin subset (its filename contains -s.p.); the Chrome invocation --headless --disable-gpu --screenshot --window-size=1200,630 --hide-scrollbars produced "PNG image data, 1200 x 630" with the local woff2 applied. Rejected: a build-time script (epic wants a one-off asset) and dynamic next/og image generation (needs a runtime; this is a static export).
  • Favicon: app/icon.svg — exact markup: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="14" fill="#0A0A0D"/><circle cx="32" cy="32" r="13" fill="#C6FF4E"/></svg> (the logo's accent dot on the base background) — plus a 180×180 app/apple-icon.png rendered from the same design with the same Chrome recipe. Rejected: a favicon.ico — no ico tooling is installed and the link-tag icons Next emits cover modern browsers; the bare /favicon.ico request 404s, accepted.
  • robots.txt: static file at public/robots.txt (Cloudflare serves public/ contents from the output root). Mirrors the reference site's AI-open stance: User-agent: *, Content-Signal: search=yes,ai-train=yes,ai-input=yes, Allow: /, and Sitemap: https://shipd.now/sitemap.xml. Rejected: a robots.ts route — the static-file convention is the reference pattern and needs no code.
  • Sitemap: app/sitemap.ts with export const dynamic = "force-static" (the reference site proves this works under output: 'export'), returning exactly https://shipd.now, /how-it-works, /docs, /manifesto — priority 1 for the root, 0.8 for the rest, no lastModified (keeps builds deterministic).
  • Redirect: public/_redirects containing exactly /install https://raw.githubusercontent.com/shipd-now/shipd/main/install.sh 302. Until the public-install change lands in the shipd repo and that repo is public, the target 404s — accepted per the epic.
  • Deployment guide: new docs/deployment.md documenting the manual Cloudflare Pages git-integration setup (connect GitHub repo shipd-now/shipd-now-website, production branch main, build command npm run build, build output directory out, custom domain shipd.now) and a post-deploy verification checklist (every page 200 with its title, the /install 302 Location, robots/sitemap/OG image/favicon served, unknown path renders the 404 page).
  • Repo hygiene: append .shipd/autopilot/ to .gitignore and git rm --cached the two tracked heartbeat json files, so root pulls stop colliding with locally written heartbeat state.

Risk: the OG/favicon PNGs are environment-dependent one-off renders; guarded by binding the exact source markup and Chrome invocation in tasks.md so they are reproducible, and by the verification barrier checking the assets land in the built output.

ADDED Requirements

Requirement: Per-page metadata

id: page-metadata

The system SHALL set real document metadata: the root layout SHALL define metadataBase https://shipd.now, the default title "shipd.now — converged context, compiled to specs." with title template %s — shipd.now, a site description, openGraph.siteName/type, and a summary_large_image twitter card; and each of /how-it-works, /docs, /manifesto, and the 404 page SHALL export its own title and (except the 404 page) description per the plan's bound strings.

Scenario: Landing page carries the default metadata

  • WHEN the site is built and out/index.html is inspected
  • THEN its title tag is "shipd.now — converged context, compiled to specs." and a meta description is present

Scenario: Subpages carry templated titles

  • WHEN the site is built
  • THEN out/how-it-works.html has title "How it works — shipd.now", out/docs.html has "Docs — shipd.now", out/manifesto.html has "Manifesto — shipd.now", and each has its own meta description

Requirement: Shared OG image

id: og-image

The system SHALL serve a checked-in 1200×630 shared Open Graph image via the root opengraph-image file convention, so every page emits an absolute og:image URL under https://shipd.now.

Scenario: Every page emits the absolute og:image

  • WHEN the site is built
  • THEN out/index.html, out/how-it-works.html, out/docs.html, and out/manifesto.html each contain an og:image meta tag whose URL starts with https://shipd.now/ and references the opengraph image, and the referenced PNG exists under out/

Requirement: Favicon set

id: favicon

The system SHALL serve a favicon derived from the logo's accent dot: an SVG icon (base background #0A0A0D rounded square with a #C6FF4E dot) plus a 180×180 apple touch icon PNG, both via the app icon file conventions.

Scenario: Icon links in the built pages

  • WHEN the site is built and out/index.html is inspected
  • THEN it links an SVG icon and an apple touch icon, and both files exist under out/

Requirement: Robots and sitemap

id: robots-sitemap

The system SHALL publish robots.txt allowing all crawlers (with the AI-open content signals search=yes,ai-train=yes,ai-input=yes) and naming the sitemap URL, and SHALL publish sitemap.xml listing exactly the four page URLs https://shipd.now, https://shipd.now/how-it-works, https://shipd.now/docs, and https://shipd.now/manifesto.

Scenario: robots.txt is served from the output root

  • WHEN the site is built
  • THEN out/robots.txt exists, contains Allow: / and Sitemap: https://shipd.now/sitemap.xml

Scenario: sitemap.xml lists the four pages

  • WHEN the site is built
  • THEN out/sitemap.xml exists and contains exactly the four page URLs

Requirement: Install redirect rule

id: install-redirect

The system SHALL ship a Cloudflare _redirects file in the build output root whose content is exactly /install https://raw.githubusercontent.com/shipd-now/shipd/main/install.sh 302.

Scenario: The redirect rule reaches the output root

  • WHEN the site is built
  • THEN out/_redirects exists and its only rule line is the /install 302 to the raw install.sh URL

Requirement: Deployment documentation

id: deployment-doc

The system SHALL document the manual Cloudflare git-integration deployment in a deployment guide at docs/deployment.md: connecting the GitHub repository, production branch main, build command npm run build, build output directory out, the custom domain shipd.now, and a post-deploy verification checklist covering the four pages, the /install redirect, robots.txt, sitemap.xml, the OG image, the favicon, and the 404 page.

Scenario: The guide carries the build settings and checklist

  • WHEN docs/deployment.md is read
  • THEN it names build command npm run build, output directory out, and domain shipd.now, and contains a post-deploy checklist with the /install redirect check

Requirement: Autopilot heartbeat hygiene

id: autopilot-hygiene

The repository SHALL ignore .shipd/autopilot/ and SHALL track no files under it, so locally written heartbeat state never collides with pulls.

Scenario: Heartbeat files are untracked and ignored

  • WHEN the git index and .gitignore are inspected
  • THEN git ls-files prints nothing under .shipd/autopilot/ and .gitignore contains a .shipd/autopilot/ entry

1. Page metadata

  • 1.1 [req: page-metadata] In app/layout.tsx, replace the placeholder metadata export with the plan's bound root metadata: metadataBase: new URL("https://shipd.now"); title: { default: "shipd.now — converged context, compiled to specs.", template: "%s — shipd.now" }; description: "Spec-driven agent orchestration. shipd makes agents converge on a spec before they write code, then an adversarial validator tries to break every scenario before anything merges."; openGraph: { siteName: "shipd.now", type: "website" }; twitter: { card: "summary_large_image" }.
  • 1.2 [req: page-metadata] Add export const metadata: Metadata = ... (importing Metadata from next, per the layout's existing import) to app/how-it-works/page.tsx (title "How it works"), app/docs/page.tsx (title "Docs"), and app/manifesto/page.tsx (title "Manifesto"), each with the exact description bound in the plan's Implementation section.
  • 1.3 [req: page-metadata] Add export const metadata: Metadata = { title: "404" } to app/not-found.tsx.

2. Shared OG image

  • 2.1 [req: og-image] Generate the OG asset: run npm run build, then find the Space Grotesk latin woff2 by grepping the built CSS under the out directory's static chunks for @font-face{font-family:Space Grotesk and taking the src whose filename contains -s.p.. Copy that woff2 to a scratch directory as space-grotesk-latin.woff2, write og.html beside it with exactly this markup, substituting nothing: <!doctype html><html><head><style>@font-face{font-family:"Space Grotesk";src:url("./space-grotesk-latin.woff2")format("woff2");font-weight:300 700}*{margin:0;box-sizing:border-box}body{width:1200px;height:630px;background:#0A0A0D;display:flex;flex-direction:column;justify-content:center;padding:0 96px;font-family:"Space Grotesk",sans-serif;position:relative}.label{font-size:22px;letter-spacing:.18em;text-transform:uppercase;color:#55556A;margin-bottom:28px}.logo{display:flex;align-items:baseline;gap:.22em}.wordmark{font-weight:700;font-size:150px;letter-spacing:-.045em;color:#F0F0F8;line-height:1}.dot{width:26px;height:26px;border-radius:50%;background:#C6FF4E;transform:translateY(-6px);box-shadow:0 0 40px rgba(198,255,78,.45)}.tag{margin-top:34px;font-size:40px;font-weight:500;letter-spacing:-.01em;color:#8888A0}.rule{position:absolute;left:0;right:0;bottom:0;height:6px;background:#C6FF4E}</style></head><body><div class="label">Spec-driven agent orchestration</div><div class="logo"><span class="wordmark">shipd</span><span class="dot"></span></div><div class="tag">converged context, compiled to specs.</div><div class="rule"></div></body></html> then render it with "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --headless --disable-gpu --screenshot=<scratch>/opengraph-image.png --window-size=1200,630 --hide-scrollbars file://<scratch>/og.html and copy the result to app/opengraph-image.png.
  • 2.2 [req: og-image] Create app/opengraph-image.alt.txt containing exactly: shipd — converged context, compiled to specs.

3. Favicon

  • 3.1 [req: favicon] Create app/icon.svg with exactly the SVG markup bound in the plan's Implementation section (64 viewBox, rx 14 rect filled #0A0A0D, r 13 circle filled #C6FF4E).
  • 3.2 [req: favicon] Render app/apple-icon.png: write a scratch HTML <!doctype html><html><head><style>*{margin:0}body{width:180px;height:180px}svg{display:block}</style></head><body><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="180" height="180"><rect width="64" height="64" fill="#0A0A0D"/><circle cx="32" cy="32" r="13" fill="#C6FF4E"/></svg></body></html> (square corners — iOS applies its own mask) and screenshot it with the same Chrome invocation as task 2.1 at --window-size=180,180.

4. Robots and sitemap

  • 4.1 [req: robots-sitemap] Create public/robots.txt (new public directory) containing a comment stating the site is intentionally open to AI crawlers, then exactly these directives: User-agent: *, Content-Signal: search=yes,ai-train=yes,ai-input=yes, Allow: /, a blank line, and Sitemap: https://shipd.now/sitemap.xml.
  • 4.2 [req: robots-sitemap] Create app/sitemap.ts: import MetadataRoute from next as in the reference pattern, export const dynamic = "force-static", and default-export a function returning entries for https://shipd.now (priority 1), https://shipd.now/how-it-works, https://shipd.now/docs, and https://shipd.now/manifesto (each priority 0.8), with no lastModified fields.

5. Install redirect

  • 5.1 [req: install-redirect] Create public/_redirects whose content is exactly one line: /install https://raw.githubusercontent.com/shipd-now/shipd/main/install.sh 302

6. Deployment guide

  • 6.1 [req: deployment-doc] Create docs/deployment.md (new docs directory) with two sections. Setup: connect Cloudflare (Workers & Pages → Create → Pages → Connect to Git) to the GitHub repository shipd-now/shipd-now-website, production branch main, build command npm run build, build output directory out, no environment variables; then add the custom domain shipd.now under the project's Custom domains (DNS is on Cloudflare, records are created automatically). Verification checklist (checkbox list of curl-able checks): each of the four pages returns 200 with its expected title; curl -sI https://shipd.now/install returns 302 with the raw install.sh Location; robots.txt, sitemap.xml, the OG image, and icon.svg return 200; an unknown path returns the 404 page ("404 — this page never shipped"); note that the /install target 404s until the shipd repo's public-install change lands and that repo is public.

7. Repo hygiene

  • 7.1 [req: autopilot-hygiene] Append a .shipd/autopilot/ entry to .gitignore and run git rm --cached on .shipd/autopilot/landing-page-build-heartbeat.json and .shipd/autopilot/site-scaffold-build-heartbeat.json; confirm git ls-files prints nothing under that directory.

8. Verification barrier

  • 8.1 [req: *] Run npm run build, npm run typecheck, and npm run lint (all must exit 0), then verify the built output: out/index.html title and description match task 1.1; the three subpage html files carry their templated titles; every page html contains an og:image URL starting with https://shipd.now/ whose PNG exists under out/; out/icon.svg and the apple icon are linked and present; out/robots.txt and out/sitemap.xml match the robots-sitemap scenarios; out/_redirects matches task 5.1 exactly.

install-cta

Status: verified Epic: shipd-now-site

Idea

Make the nav's INSTALL button always visible (including on /docs, where it scrolls to and gently flashes the install section) and fix the unreadable .btn-primary hover text.

Motivation

The INSTALL button disappears on /docs — the page a visitor most needs it on — and on hover every primary button's text turns accent-on-accent and becomes unreadable, because the global a:hover color rule outranks .btn-primary's dark ink. Both were reported from the live site with screenshots.

Details

  • Always render the nav INSTALL button; it links to /docs#install.
  • Give the Docs getting-started step 1 the install anchor; targeting it scrolls beneath the sticky nav and plays a gentle two-pulse accent flash.
  • Fix .btn-primary:hover to keep high-contrast dark text.

Affected capabilities: site-foundation (modified), docs-page (modified). Impact: components/nav.tsx, app/globals.css, app/docs/page.tsx. No new dependencies, no new client components.

Non-goals

  • No INSTALL entry in the mobile burger menu panel — the design's panel lists only the four page links.
  • No JS-driven scrolling or re-flash: a second click while the URL is already /docs#install does not replay the flash (the hash does not change) — accepted to keep the mechanism CSS-only.
  • No hover-color changes to .btn-secondary/.btn-ghost/.btn-danger — only .btn-primary has an accent background that erases accent text.

Implementation

  • Hover fix in the utility layer, by specificity. Extend the existing rule at app/globals.css:280 to .btn-primary:hover { background: #d4ff6e; color: var(--color-fg-inverse); }. .btn-primary:hover (0,2,0) outranks the global a:hover (0,1,1) at app/globals.css:340, which is what currently repaints the text accent. The ink is --color-fg-inverse (#0A0A0D) — identical to the resting button text, maximum contrast on the lightened accent. Rejected: a literal gray token — lower contrast than the resting ink and inconsistent with the unhovered state.
  • Nav renders INSTALL unconditionally. In components/nav.tsx, delete the showInstall gating (line 19 and the conditional at lines 83–96) and point the button at /docs#install. Active-link coloring and the checkbox-menu mechanism are untouched. This deliberately supersedes the scaffold's design-fidelity choice (the design's Docs nav omitted INSTALL) — the delta updates the shared-chrome requirement accordingly.
  • Anchor on the step-1 block. In app/docs/page.tsx, the getting-started step 1 grid div (the 44px 1fr grid whose number chip is 1, ~line 219) gets id="install" and scrollMarginTop: "72px" (56px sticky nav + 16px breathing room). The docs-anchors requirement gains install alongside workspaces/capabilities/faq.
  • CSS-only scroll + flash, motion-safe. Append to app/globals.css, inside @media (prefers-reduced-motion: no-preference): html { scroll-behavior: smooth; }, an install-flash keyframes ramping background and box-shadow through var(--color-accent-subtle) / var(--color-accent-glow) and back to transparent, and #install:target { animation: install-flash 1.4s var(--ease-speed) 2; border-radius: 8px; } — two gentle pulses, then settled. Under reduced motion the anchor still jumps (default instant scroll) and no flash plays. Rejected: a JS scroll/flash handler — more code for the only gain of re-flash on repeat clicks, which the Non-goals accept losing.
  • The INSTALL button is a plain <a>, not a Next Link. Validation proved Next Link navigates via History pushState, which never updates the document's target element — #install:target stayed unmatched on every in-app click, so the flash only played on hard loads. A native anchor performs real hash navigation: same-page clicks on /docs set :target and smooth-scroll (flash plays), and cross-page clicks are full document loads whose hash sets :target on arrival (flash plays). Cost: INSTALL clicks from other pages are full page loads instead of client-side transitions — acceptable on a static marketing site. All other nav links remain Link. Rejected: a JS hashchange/animation-class handler — more code to preserve a client-side transition nobody needs on this button.
  • The docs-content master is amended in the same change. Its chrome scenario asserted "no INSTALL button" on /docs, duplicating the old shared-chrome behavior; the delta modifies it so the verified library stays self-consistent once shared-chrome makes INSTALL universal.

Risk: the :target animation replays on hard reloads of /docs#install — acceptable, it is the section the URL points at. The flash uses only existing DS tokens, so no new colors enter the palette.

MODIFIED Requirements

Requirement: Stable documentation anchors

id: docs-anchors base: 50882c6d7a79

The system SHALL expose the ids install, workspaces, capabilities, and faq on the corresponding /docs sections so that fragment links from other pages resolve. The install anchor SHALL sit on the getting-started step 1 block with a scroll margin clearing the sticky nav, and when targeted the block SHALL play a gentle two-pulse accent flash — under prefers-reduced-motion: no-preference only.

Scenario: Anchor ids present in the export

  • WHEN the exported docs HTML is inspected
  • THEN it contains exactly one element each with ids "install" (the step 1 install block), "workspaces", "capabilities", and "faq"

Scenario: Install anchor scrolls clear of the nav and flashes

  • WHEN /docs#install is loaded, or the nav INSTALL button is clicked from /docs, with no reduced-motion preference
  • THEN the viewport scrolls so the step 1 block is visible below the sticky nav (its scroll margin exceeds the nav's 56px height) and the block's :target animation plays its accent flash a finite number of times and settles

Scenario: Reduced motion suppresses the flash

  • WHEN prefers-reduced-motion: reduce is active and /docs#install is targeted
  • THEN the page jumps to the anchor without smooth scrolling and no flash animation plays

Requirement: Docs page content

id: docs-content base: 72c575ceff96

The system SHALL render the /docs route as a fully static server-rendered page with the Docs sections in design order — hero, getting-started steps 1–4, lifecycle strip, workspaces section, supersession-gate section, capabilities grid, FAQ, footer — with all copy carried verbatim from the parked design at /Users/mikkelbergmann/.shipd/designs/docs-page/docs.dc.html, and the sections SHALL be present in the exported docs HTML of the static build.

Scenario: Hero and step copy are verbatim

  • WHEN the site is built and the exported docs HTML is inspected
  • THEN it contains the accent label "Docs · Getting started", the h1 "From install to merged PR.", the hero paragraph ending "Four steps to your first spec-driven change.", the four step headings "Install", "Plan — converge on the spec", "Build — gated, refuted, merged", and "Watch the board", and the step terminal lines including "curl -fsSL https://shipd.now/install | sh", "✓ plugin installed — skills available as /s:<name>", "→ .shipd/planned/checkout-retries/ · status: draft", and "gate: PASS → 4 tasks → refute: confirmed → PR #212 merged"

Scenario: Six CLI verb rows render from the ported data

  • WHEN the exported docs HTML is inspected
  • THEN step 4's table contains exactly six rows pairing the mono accent commands shipd list, shipd status [change], shipd epic <slug>, shipd board, shipd metrics, and shipd lint [change] with their descriptions ("in-flight changes across the root and its worktrees" through "structurally validate specs and change deltas"), where every row except the last carries the bottom border

Scenario: Lifecycle and supersession sections are verbatim

  • WHEN the exported docs HTML is inspected
  • THEN the lifecycle strip shows the chips draft → ready → active → complete → verified, the "|" divider, the red "rejected" chip with the note "← the gate parks insufficient context for human enrichment", and the supersession section shows the heading "Stale plans never build." with the three table rows clean / content drift / superseded (last row without a bottom border) and the closing note naming spec_status.py check-base [change] and id-collision

Scenario: Workspaces section is verbatim

  • WHEN the exported docs HTML is inspected
  • THEN the workspaces section shows the heading "One job, many repos, any machine.", the file-tree panel rooted at ~/jobs/documents-linking/ with its six entries (.shipd-config.json through incentives/) and their tracked/machine-local annotations, and the three accent-arrow bullets starting "Clone the workspace, not the repos.", "Knowledge travels with the job.", and "Drift is reported, never "repaired"."

Scenario: Capability cards and FAQs render from the ported data

  • WHEN the exported docs HTML is inspected
  • THEN the capabilities grid contains the ten card names "Plan a change" through "Stand up a workspace" with their mono commands (e.g. "/s:plan <intent>", "automatic during planning"), area badges in their per-card colors (core loop, intent, knowledge, scale, visibility, quality), descriptions, and "→" gives-footers (e.g. "→ plan.md · delta specs · tasks.md, status: draft"), and the FAQ section contains the three numbered cards 01–03 with their questions ("Which agents and models does it work with?", "What does shipd see of my code? What leaves my machine?", "What if the validator is wrong?") and both answer paragraphs each

Scenario: Chrome contract holds

  • WHEN the /docs route is rendered
  • THEN exactly one nav (from the layout) is present with the Docs link in the accent color and the INSTALL button linking to /docs#install, and the page ends with the shared Footer at maxWidth 880, without the accent square, whose only page link is "How it works"

Scenario: Design fidelity of structure and styling

  • WHEN the rendered page is compared against the parked design file
  • THEN each section's markup structure, inline styles (as JSX style objects), DS utility classes (label, card, stripe-bg), and responsive classes (m-h1, m-h2, m-grid) match the design; the page ships no "use client" component and no page-scoped style element; and at ≤760px the m-grid two-column layouts (verb rows, workspaces panel, supersession rows, capabilities grid) collapse to one column while the h1 and h2 sizes shrink per the shared global rules

MODIFIED Requirements

Requirement: Shared chrome

id: shared-chrome base: 02815544a592

Every page SHALL render the shared chrome: the sticky nav (Logo linking home; How it works, Docs, Manifesto links; an INSTALL button linking to /docs#install on every page, /docs included; CSS-checkbox burger menu at ≤900px) and a Footer component with per-page width and links, matching the parked chrome.md markup except for the INSTALL button's universal visibility. When rendered on a page, the nav SHALL color that page's link with var(--color-accent).

Scenario: Nav on every route

  • WHEN any of /, /how-it-works, /docs, /manifesto is rendered
  • THEN the nav contains links to /how-it-works, /docs, /manifesto and the Logo linking to /

Scenario: INSTALL button on every page

  • WHEN any of the four routes is rendered, /docs included
  • THEN the nav renders the INSTALL btn btn-primary button linking to /docs#install, and on /docs the Docs nav link uses the accent color

Scenario: Mobile menu mechanism preserved

  • WHEN the rendered nav markup is inspected
  • THEN the menu panel is a following sibling of the hidden checkbox so the .m-nav-toggle:checked ~ .m-menu-panel rule can open it

Requirement: Design-token foundation

id: design-token-foundation base: 631cf1c9bf07

The system SHALL carry the shipd design system in app/globals.css — the color/type/spacing tokens and the utility classes (.label, .card, .btn-primary/.btn-secondary/.btn-ghost/.btn-danger, .badge-*, .stripe-bg) from the parked colors_and_type.css — and SHALL self-host all three font families so the built site makes no external requests. On hover, .btn-primary SHALL keep its dark ink: the hover rule sets color: var(--color-fg-inverse) so the global a:hover accent color can never render accent text on the accent background.

Scenario: Tokens present in the built CSS

  • WHEN the site is built
  • THEN the CSS emitted under the export's _next/ assets defines --color-accent as #C6FF4E and the .stripe-bg and .btn-primary classes

Scenario: No external font or CDN references

  • WHEN the site is built
  • THEN no exported file references fonts.googleapis.com or fonts.gstatic.com, and font files are served from the export's _next/ assets

Scenario: Primary button hover text stays readable

  • WHEN an anchor with btn btn-primary is hovered in the rendered site
  • THEN its computed text color is #0A0A0D (--color-fg-inverse), not the a:hover accent color, while the background lightens to #d4ff6e

1. Hover contrast

  • 1.1 [req: design-token-foundation] In app/globals.css (line 280), extend the existing rule to .btn-primary:hover { background: #d4ff6e; color: var(--color-fg-inverse); } so its (0,2,0) specificity outranks the global a:hover accent rule at line 340.

2. Always-visible INSTALL with scroll-and-flash target

  • 2.1 [req: shared-chrome] In components/nav.tsx, remove the showInstall constant (line 19) and the {showInstall && (...)} wrapper (lines 83–96) so the INSTALL Link always renders, and change its href to /docs#install. Leave active-link coloring, the checkbox/menu-panel structure, and the mobile panel links untouched.
  • 2.2 [req: docs-anchors] In app/docs/page.tsx, on the getting-started step 1 grid div (the gridTemplateColumns: "44px 1fr" block whose number chip renders 1, ~line 219), add id="install" and scrollMarginTop: "72px" to its style object.
  • 2.3 [req: docs-anchors] Append to app/globals.css a @media (prefers-reduced-motion: no-preference) block containing: html { scroll-behavior: smooth; }; an install-flash keyframes that pulses background to var(--color-accent-subtle) and box-shadow to 0 0 0 6px var(--color-accent-glow) at 50% and returns both to transparent at 0%/100%; and #install:target { animation: install-flash 1.4s var(--ease-speed) 2; border-radius: 8px; }.

3. Verify

  • 3.1 [req: *] Run npm run typecheck, npm run lint, and npm run build; confirm all exit 0, every one of the four exported route HTML files contains the INSTALL button with href /docs#install (the exported docs HTML included), the exported docs HTML contains exactly one id="install", and the built CSS contains the #install:target rule, the install-flash keyframes, and the .btn-primary:hover rule with color: var(--color-fg-inverse).

4. Fix loop (validator refutation)

  • 4.1 [req: docs-anchors] In components/nav.tsx, replace the INSTALL Link element with a plain <a href="/docs#install" className="btn btn-primary" ...> keeping the identical style object and label — a native anchor performs real hash navigation so #install:target matches on same-page clicks and on cross-page loads, which Next Link's pushState never does. All other nav links stay Link.
  • 4.2 [req: docs-content] Re-run npm run typecheck, npm run lint, and npm run build; confirm all exit 0 and every one of the four exported route HTML files still contains exactly one INSTALL anchor with href /docs#install and the btn btn-primary classes.

shipd-now-site

Status: complete

Introduction

shipd is about to get a public distribution — the public-install change in shipd-now/shipd ships a one-command installer whose documented invocation is curl -fsSL https://shipd.now/install | sh — but nothing exists at shipd.now: this repository was empty before this epic. The product's story (spec-driven agent orchestration, the context gate, the adversarial validator, autopilot) is fully told in the Claude Design project "Shipd.now landing page design" (34462134-c6fb-4ae5-b9eb-4f2f6caea148), and that design needs to become a real, deployed site before the installer's URL is live.

This epic builds the complete shipd.now website as a static site, the same way mikkelbergmann-website works: Next.js (App Router) + Tailwind v4 + TypeScript with output: 'export', built to ./out, deployed by Cloudflare's git integration from GitHub. Four pages (Landing v2, How It Works, Docs, Manifesto) plus shared chrome, faithful to the design's markup, tokens, copy, and client-side interactions.

Success criteria:

  • All four pages render pixel-faithful to their .dc.html sources, including the design's 900px/760px responsive behavior and the mobile burger menu.
  • The design's interactions work client-side: the landing's auto-advancing loop strip, copy-to-clipboard install command, the question-ladder accordion.
  • npm run build produces a clean static export with zero runtime calls to external services (fonts self-hosted at build time).
  • https://shipd.now/install resolves to the installer script via a redirect.

Non-goals

  • No Landing v1 (Shipd Landing.dc.html) content — the waitlist email form and roadmap section are superseded by Landing v2, which github.md's screen map records as the landing. The site ships no forms and no backend.
  • No standalone FAQ or Changelog pages — github.md maps FAQ.dc.html and Changelog.dc.html but no design file exists for them; FAQ lives as the #faq section of Docs. They join a later epic when designed.
  • No build-time data sync from shipd-now/shipd — the board-peek stats (175 / 36 / 11) and epic rows are baked in verbatim from the design, which was itself synced from real repo data on 2026-08-15.
  • No hosting of install.sh content — /install is a redirect to the raw file in shipd-now/shipd, never a copy that could drift.
  • No Cloudflare dashboard or DNS automation — the git-integration hookup and the shipd.now domain are configured manually; the epic documents the exact steps.
  • None of the reference site's blog machinery (tags, generators, OG pipeline, theme switcher) — this site is single-theme, fixed-page.

Decisions

  • Stack mirrors mikkelbergmann-website. Next.js 16 App Router, TypeScript, Tailwind CSS v4, npm; next.config.ts sets output: 'export' and images.unoptimized: true. No wrangler config and no deploy CI in the repo — Cloudflare's git integration builds npm run build and serves out/.
  • The design project is the source of truth. Member authors read pages via DesignSync from project 34462134-c6fb-4ae5-b9eb-4f2f6caea148: Shipd Landing v2.dc.html → /, How It Works.dc.html → /how-it-works, Docs.dc.html → /docs, Manifesto.dc.html → /manifesto; Logo.dc.html is the shared wordmark component. Copy is carried over verbatim — no rewriting. A local, indicative copy of the design-system handoff lives at ~/projects/shipd-now/docs/shipd-now-design-system/.
  • Tokens are ported, not linked. Every custom property in the design system's colors_and_type.css (bg/border/accent/semantic/text colors, the Space Grotesk / DM Sans / JetBrains Mono font stack, type scale on a 14px root, spacing, radii, shadows, --ease-speed and durations) lands in app/globals.css, and its utility classes (.label, .card, .btn-*, .badge-*, .stripe-bg, type classes) are recreated there. Single dark theme; no theme switcher.
  • Fonts self-host via next/font/google (Space Grotesk 400–700, DM Sans 300–500, JetBrains Mono 400–500), exposed as --font-display, --font-body, --font-mono — no runtime Google Fonts CDN import, keeping the export fully static.
  • The dc-runtime is design-tool plumbing, never shipped. support.js and _ds_bundle.js only render .dc.html previews. Each page's DCLogic class component is re-implemented as a React client component ("use client"): the landing's loop strip (6.3s interval auto-advance, click-to-pin), clipboard copy with 1.6s "copied" state, and the question ladder's single-open accordion. Static sections render as server components.
  • Responsive behavior follows the design's own breakpoints: nav links collapse to the burger/checkbox menu at ≤900px, grids collapse and display headings shrink at ≤760px, supergraphics hide on mobile — matching the .m-* media-query overrides in each .dc.html.
  • /install is a Cloudflare redirect. public/_redirects carries /install https://raw.githubusercontent.com/shipd-now/shipd/main/install.sh 302. This depends on the in-flight public-install change landing in shipd-now/shipd (worktree .worktrees/public-install, status: ready) and on that repo being publicly readable; until both hold, the redirect 404s — accepted, since the alternative (hosting a copy) drifts.
  • Repo and shipping: shipd-now/shipd-now-website, private, default branch main. One change = one worktree = one branch = one PR, per the engine's workflow.

Design

The site is five pieces on three seams.

Foundation (everything depends on it). The scaffold: Next.js app with static export, app/globals.css holding the ported tokens and utility classes, the three fonts, and the shared chrome — sticky blurred nav with desktop links + mobile burger panel, the Logo component (Space Grotesk "shipd" + accent dot with 2.5s ripple rings + uppercase "now"), the shared footer ("shipd.now — converged context, compiled to specs." + page links), and a 404 page. Nav marks the active page with the accent color.

Pages (independent of each other, all on the foundation).

  • / — full-viewport hero ("Code generation is solved. Context isn't."), copyable install command, and the animated loop strip: nine pill steps (intent → investigate → spec → context gate → build → refute → review → merge → capability library ↺) driving a two-panel detail view that auto-advances every 6.3s and pins on click. Then the Capture/Gate/Verify card trio, the "spec is the product" artifact cards (plan.md / delta spec / tasks.md with real oracle-qa-ledger content), the board peek (stat tiles 175/36/11 + five epic rows + lifecycle footer), and the closing CTA with blinking-cursor install command.
  • /how-it-works — hero, the five-stage numbered flow (Intent, Converge, Gate, Build & refute, Ship & record — each with tag, description, artifact chip) closed by the capability-library loop line, the question-ladder accordion (codebase → wiki+memory → oracle → you, one rung open at a time, "escalates only if unanswered" connectors), the three role cards plus every-change pipeline strip, the autopilot section with its two-column metro-map diagram (7 stops, dashed orange "parked as rejected" side branch), and the GET STARTED / READ THE FAQ CTA.
  • /docs — getting-started steps 1–4 (install with doctor output, plan, build, watch the board with the six shipd CLI verb rows), the lifecycle strip (draft → ready → active → complete → verified | rejected), the #workspaces section (tracked-vs-machine-local file tree + three sync bullets), the supersession gate (clean / content drift / superseded table), the #capabilities grid (ten capability cards: name, command, area badge, description, "gives" footer), and the #faq section (three long-form Q&As). Anchors #workspaces, #capabilities, #faq must resolve — other pages link to /docs#faq.
  • /manifesto — hero with the giant translucent "WHY" supergraphic and "The scarce resource isn't code generation. It's converged context.", the five numbered theses (Intent is a file… through shipd ships shipd), and the striped closing CTA.

Launch layer (last, on top of the pages). Per-page Metadata (titles, descriptions, OG tags), a shared OG image, robots.txt, sitemap.xml, favicon derived from the logo dot/wordmark, public/_redirects with the /install rule, and the documented Cloudflare git-integration steps (build command npm run build, output out, domain shipd.now) with a post-deploy verification checklist.

The stub table follows these seams: one scaffold change, four page changes that can proceed in parallel once the scaffold merges, one launch change last.

Changes

ChangeDescriptionCodeIntegrationUnknownsRisk
site-scaffoldNext.js 16 static-export scaffold with ported design tokens, self-hosted fonts, shared nav/footer/Logo chrome, and 404 pagemediumlowlowlow
landing-page/ per Shipd Landing v2: hero, animated loop strip, clipboard install command, capture/gate/verify cards, artifact cards, board peek, CTAmediumlowlowlow
how-it-works-page/how-it-works: five-stage flow, question-ladder accordion, role cards, autopilot metro diagram, CTAmediumlowlowlow
docs-page/docs: getting-started steps, CLI verbs, lifecycle, workspaces, supersession gate, capabilities grid, FAQ with stable anchorsmediumlowlowlow
manifesto-page/manifesto: WHY-supergraphic hero, five theses, closing CTAlowlowlowlow
site-launchMetadata/OG, robots.txt, sitemap, favicon, _redirects for /install, documented Cloudflare git-integration setup and verificationlowmediummediumlow

On the token figures. They are the build log's own accounting, taken verbatim. That accounting counts only the first streamed usage record per build, so it under-reports output tokens — finding G8 in docs/replay-data-audit.md. Input and cache figures are exact, and every number here is re-checkable against the session transcript named above.