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.
23:21:40 UTC
0s / 1h 36m active
space plays and pauses · ← → scrub 30 seconds of session time · hover or tab a block for its numbers
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`.
23:23:54
23:24:23
29s
263
1.4
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.
23:24:23
23:24:51
28s
407
2.1
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.
23:24:51
23:25:04
13s
1,165
2.2
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.
23:25:04
23:25:21
17s
1,339
2.3
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`).
23:25:21
23:25:33
11s
976
2.4
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)`).
23:25:33
23:25:43
10s
727
2.5
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.
23:25:43
23:26:00
17s
295
2.6
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 `/`.
23:26:00
23:26:09
9s
565
3.1
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.
23:26:09
23:27:19
1m 11s
879
landing-page 23:54:09 → 00:16:33 UTC
8 tasks · times in UTC
task
label
start
end
duration
output tokens
1.1
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.
23:55:03
23:55:48
45s
190
1.2
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.
23:55:48
23:56:52
1m 4s
334
1.3
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.
23:56:52
23:57:15
24s
673
1.4
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`.
23:57:15
23:58:05
49s
1,125
2.1
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).
23:58:05
23:58:52
47s
232
2.2
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.
23:58:52
23:59:29
37s
2,516
2.3
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.
23:59:29
23:59:56
27s
296
3.1
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."
23:59:56
00:00:32
36s
821
how-it-works-page 00:31:24 → 00:44:35 UTC
7 tasks · times in UTC
task
label
start
end
duration
output tokens
1.1
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.
00:32:24
00:33:00
35s
234
1.2
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).
00:33:00
00:33:34
34s
1,785
1.3
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`.
00:33:34
00:33:49
16s
191
2.1
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).
00:33:49
00:34:45
56s
10
2.2
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} />`.
00:34:45
00:35:45
1m 1s
192
2.3
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.
00:35:45
00:35:55
9s
5
3.1
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."
00:35:55
00:36:57
1m 2s
361
docs-page 00:55:23 → 01:08:15 UTC
6 tasks · times in UTC
task
label
start
end
duration
output tokens
1.1
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.
00:56:30
00:57:08
39s
189
2.1
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.
00:57:08
00:57:58
50s
12
2.2
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).
00:57:58
00:58:32
33s
185
2.3
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).
00:58:32
00:59:08
36s
187
2.4
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.
00:59:08
00:59:33
26s
187
3.1
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.
00:59:33
01:01:13
1m 39s
1,636
manifesto-page 01:17:05 → 01:24:43 UTC
4 tasks · times in UTC
task
label
start
end
duration
output tokens
1.1
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).
01:17:59
01:18:35
36s
131
2.1
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.
01:18:35
01:18:56
21s
190
2.2
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.
01:18:56
01:19:12
15s
20
3.1
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.
01:19:12
01:19:55
44s
263
site-launch 01:37:05 → 01:47:15 UTC
13 tasks · times in UTC
task
label
start
end
duration
output tokens
1.1
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" }`.
01:38:02
01:38:16
14s
575
1.2
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.
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`.
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).
01:39:35
01:39:41
7s
388
3.2
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`.
01:39:41
01:40:00
19s
939
4.1
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`.
01:40:00
01:40:07
7s
385
4.2
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.
01:40:07
01:40:15
8s
198
5.1
Create `public/_redirects` whose content is exactly one line: `/install https://raw.githubusercontent.com/shipd-now/shipd/main/install.sh 302`
01:40:15
01:40:21
6s
324
6.1
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.
01:40:21
01:40:41
20s
1,420
7.1
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.
01:40:41
01:40:57
16s
570
8.1
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.
01:40:57
01:43:48
2m 50s
1,642
install-cta 04:30:03 → 04:48:48 UTC
7 tasks · times in UTC
task
label
start
end
duration
output tokens
1.1
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.
04:30:45
04:31:01
16s
699
2.1
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.
04:31:01
04:31:14
13s
873
2.2
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.
04:31:14
04:31:30
16s
499
2.3
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; }`.
04:31:30
04:31:46
16s
1,097
3.1
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)`.
04:31:46
04:32:48
1m 2s
1,593
4.1
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`.
04:41:03
04:41:21
17s
402
4.2
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.
04:41:21
04:41:50
29s
809
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.
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
WHENnpm 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
WHENnpm 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.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
metadataBasehttps://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
THENout/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
THENout/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
THENout/robots.txt exists, contains Allow: / and
Sitemap: https://shipd.now/sitemap.xml
Scenario: sitemap.xml lists the four pages
WHEN the site is built
THENout/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
THENout/_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
THENgit 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.
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.
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
WHENprefers-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
Change
Description
Code
Integration
Unknowns
Risk
site-scaffold
Next.js 16 static-export scaffold with ported design tokens, self-hosted fonts, shared nav/footer/Logo chrome, and 404 page
/manifesto: WHY-supergraphic hero, five theses, closing CTA
low
low
low
low
site-launch
Metadata/OG, robots.txt, sitemap, favicon, _redirects for /install, documented Cloudflare git-integration setup and verification
low
medium
medium
low
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.