diff --git a/.cursor/skills/verify-kylecesmat/.run/.gitkeep b/.cursor/skills/verify-kylecesmat/.run/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/.cursor/skills/verify-kylecesmat/SKILL.md b/.cursor/skills/verify-kylecesmat/SKILL.md
new file mode 100644
index 0000000..c438223
--- /dev/null
+++ b/.cursor/skills/verify-kylecesmat/SKILL.md
@@ -0,0 +1,115 @@
+---
+name: verify-kylecesmat
+description: Prove kylecesmat.com — a static Astro personal site (browser). Use after homepage, IA, or content changes. Preview-only local/preview proof; never production go-live, custom domain, or orange-cloud.
+---
+
+# Verify kylecesmat.com
+
+Static Astro 7 personal site. Users hit HTML in a browser. There is no app server, auth, or database. Verification proves a **local preview** of `dist/`. Do not attach `kylecesmat.com`, orange-cloud DNS, or retire GitHub Pages / `gh-pages`.
+
+Hard constraints from Kyle:
+
+1. **No quantitative metrics** in site copy or in assertions that require numbers on the page (no `0→15`, enablement %, MCP counts, latency). The Syntax.fm episode title is a talk name, not a KPI — match the heading text, do not treat it as a metric.
+2. **Preview-only.** This skill never deploys, never flips DNS, never hits production as the system under test.
+3. **Locked qualitative hero.** Homepage `
` is `Building Agent Experience for enterprise engineering orgs`. If you still see `headlinePick` or `[TODO: headline`, stop and fix copy before driving.
+
+Default origin: `http://127.0.0.1:4321`.
+
+## Launch
+
+Preferred (production-build proof):
+
+```bash
+npm install
+npm run build
+.cursor/skills/verify-kylecesmat/helpers/launch.sh
+```
+
+`launch.sh` stops this checkout’s leftover Astro preview **lockfile PID** (`.astro/preview.json`) if present, then runs `./node_modules/.bin/astro preview --host 127.0.0.1 --port ${VERIFY_PORT:-4321}` with `ASTRO_PREVIEW_BACKGROUND=1` so Cursor does not daemonize the server out from under the recorded PID. It writes PID/port to `.cursor/skills/verify-kylecesmat/.run/state` and waits until `/` returns 200 **and** that PID tree owns the port.
+
+Do not `pkill astro`. Do not kill a listener that is not this checkout’s lockfile PID.
+
+Faster loops (not a production-build proof): `npm run dev` on the same host/port, then write the PID you started into `.run/state` yourself. Prefer `launch.sh` for a recorded proof.
+
+Teardown: `.cursor/skills/verify-kylecesmat/helpers/cleanup.sh` (kills the PID in `.run/state` and any listener it spawned). Never `pkill astro` / never kill by process name.
+
+If port `4321` is already bound by a process this run did not start, **refuse**. Set `VERIFY_PORT` to an open port only for an instance **you** launch. Do not drive a foreign preview.
+
+## Doctor
+
+```bash
+.cursor/skills/verify-kylecesmat/helpers/doctor.sh
+```
+
+Read-only. Passes only when all of these hold:
+
+- Node major version `>= 22` (`node -v`, `.nvmrc` is `22`).
+- `.run/state` exists and names a live PID.
+- That PID (or a descendant) owns `LISTEN` on `VERIFY_PORT` / `127.0.0.1`.
+- `GET /` returns **200**.
+- Response body contains the locked hero string: `Building Agent Experience for enterprise engineering orgs`.
+- Response body contains the trajectory line: `Coinbase SEM · formerly Formidable`.
+
+Fail if the hero is still a placeholder (`headlinePick`, `[TODO: headline`). Do not assert counts, percents, or latency figures.
+
+## Drive
+
+Harness: **curl** (HTTP + HTML) plus **Google Chrome headless** for screenshots. Prefer visible **link text and headings** (`about`, `writing`, `talks`, `contact`, section `h2`s). Do not target CSS classes as the primary handle.
+
+Stable routes (from `src/pages/`):
+
+| User path | Handle |
+| --- | --- |
+| Home | `/` — heading `Building Agent Experience for enterprise engineering orgs` |
+| About | nav link `about` → `/about` |
+| Writing index | nav `writing` or home `all writing` → `/writing` |
+| Talks index | nav `talks` or home `all talks` → `/talks` |
+| Contact | nav `contact` → `/contact` |
+| Now | footer `now` → `/now` (not in primary nav) |
+| Archive | footer `archive` → `/archive` (not in primary nav) |
+
+Chrome (this environment): `/usr/bin/google-chrome-stable`. Always pass `--headless=new --disable-gpu --no-sandbox`.
+
+```bash
+RUN_ID=homepage-$(date -u +%Y%m%dT%H%M%SZ)
+export RUN_ID
+.cursor/skills/verify-kylecesmat/helpers/snapshot.sh http://127.0.0.1:${VERIFY_PORT:-4321}/ homepage
+```
+
+Read `features/` before driving. For the first proof, drive **homepage-hiring-brief** only.
+
+## Evidence
+
+Directory: `.cursor/skills/verify-kylecesmat/evidence//` (gitignored except `.gitkeep`).
+
+A homepage proof must include (stem `homepage`):
+
+- `homepage.status.txt` — HTTP status for `/` (expect `200`)
+- `homepage.html` — response body
+- `homepage.aria.txt` — headings, `aria-label` / `aria-current`, and link names
+- `homepage.png` — screenshot with the wordmark `Kyle Cesmat` and hero heading visible
+
+Capture the **request** (URL) and the **resulting** HTML/screenshot together. Do not prove via reading `src/` instead of fetching the preview.
+
+Cleanup must **not** delete this directory.
+
+## Cleanup
+
+```bash
+.cursor/skills/verify-kylecesmat/helpers/cleanup.sh
+```
+
+Stops only the preview PID recorded in `.run/state`. Removes `.run/state`. Leaves `evidence/` untouched. Confirm evidence still exists at the named path after cleanup.
+
+## Helpers
+
+All under `.cursor/skills/verify-kylecesmat/helpers/`. Executable. Invocations:
+
+| Script | Purpose |
+| --- | --- |
+| `launch.sh` | `npm install` + `npm run build` + `astro preview`; write `.run/state`; wait until `/` answers |
+| `doctor.sh` | Node, PID owns port, GET `/` 200, locked hero + trajectory strings |
+| `snapshot.sh ` | curl headers/body + Chrome screenshot + heading/link snapshot into `evidence/$RUN_ID/` |
+| `cleanup.sh` | kill recorded PID only; keep evidence |
+
+Optional env: `VERIFY_PORT` (default `4321`), `RUN_ID` (snapshot target folder name).
diff --git a/.cursor/skills/verify-kylecesmat/evidence/.gitkeep b/.cursor/skills/verify-kylecesmat/evidence/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/.cursor/skills/verify-kylecesmat/features/README.md b/.cursor/skills/verify-kylecesmat/features/README.md
new file mode 100644
index 0000000..1201f84
--- /dev/null
+++ b/.cursor/skills/verify-kylecesmat/features/README.md
@@ -0,0 +1,38 @@
+# kylecesmat.com verification map
+
+Maintained source for proving user-facing behavior of the static Astro site. Read this index, then the matching feature file.
+
+## Baseline preconditions
+
+- Preview origin `http://127.0.0.1:${VERIFY_PORT:-4321}` started by `helpers/launch.sh` (build then `astro preview`).
+- `helpers/doctor.sh` exits 0 (Node >=22, our PID owns the port, `/` is 200, locked qualitative hero is present).
+- Never drive a foreign process on 4321.
+- Never assert quantitative metrics (org size, enablement %, MCP counts, latency).
+- Preview-only: do not treat production `kylecesmat.com` as the system under test.
+
+## Driving conventions
+
+- Start from `/` unless a feature lists another entry.
+- Prefer link text and headings over CSS.
+- Use `helpers/snapshot.sh` for HTTP + HTML + screenshot + `aria.txt`.
+- Chrome: `/usr/bin/google-chrome-stable --headless=new --disable-gpu --no-sandbox`.
+- Cleanup with `helpers/cleanup.sh`; evidence stays on disk.
+
+## Proof and skip reporting
+
+- Capture the URL fetched and the resulting status/HTML/screenshot.
+- UI proof includes `aria.txt` and a screenshot with `Kyle Cesmat` visible.
+- Record `RUN_ID` and feature id on every artifact.
+- Do not report a skipped route as verified via a different URL.
+
+## Feature entry contract
+
+Each feature file: H1, one paragraph, then exactly four H2s — `Sub-features`, `How to get to it (user POV)`, `Driving it with helpers`, `Gotchas`.
+
+## Features
+
+- [Homepage hiring brief](./homepage-hiring-brief.md) — hero, trajectory, three qualitative proof blocks, writing/talks, contact.
+- [Writing and talks](./writing-and-talks.md) — MDX writing stubs; Syntax.fm episode listed first.
+- [About and contact](./about-and-contact.md) — press-kit bio, ways I can help, email and LinkedIn.
+- [Now and archive](./now-and-archive.md) — `/now` stub; Formidable work demoted to `/archive`.
+- [Build and headers](./build-and-headers.md) — `npm run build`; `dist` has robots, sitemap, `_headers`.
diff --git a/.cursor/skills/verify-kylecesmat/features/about-and-contact.md b/.cursor/skills/verify-kylecesmat/features/about-and-contact.md
new file mode 100644
index 0000000..6fe1d52
--- /dev/null
+++ b/.cursor/skills/verify-kylecesmat/features/about-and-contact.md
@@ -0,0 +1,34 @@
+# About and contact
+
+About is the press kit: qualitative bio, ways I can help, and contact links. Contact is a short page with the same email and LinkedIn.
+
+## Sub-features
+
+- `about-bio` shows the qualitative Agent Experience bio (no org-size or enablement figures).
+- `about-help` shows `Ways I can help` and the governed-leverage paragraph.
+- `about-contact` lists `kylecesmat@gmail.com` and `LinkedIn`.
+- `contact-page` repeats email and LinkedIn at `/contact`.
+
+## How to get to it (user POV)
+
+- Primary nav `about`.
+- Primary nav `contact`.
+- Home section `contact` mailto / LinkedIn (same destinations).
+
+## Driving it with helpers
+
+Preconditions:
+
+- Preview is healthy (`helpers/doctor.sh`).
+
+- **Open about.** Choose nav link `about`. Run `helpers/snapshot.sh http://127.0.0.1:${VERIFY_PORT:-4321}/about about`. Status `200`. Heading `About`. Body includes `Senior Engineering Manager at Coinbase leading Agent Experience` and `Ways I can help`. Fail if the bio contains metric patterns (`0→`, `2,200`, enablement `%`).
+- **Confirm help.** Paragraph starting `I help engineering organizations turn AI coding tools into governed, measurable developer leverage`.
+- **Confirm about contact.** Links `kylecesmat@gmail.com` and `LinkedIn`.
+- **Open contact page.** Choose nav `contact`. Snapshot `/contact`. Status `200`. Same email and LinkedIn link names.
+- **Proof.** Screenshots show `about` or `contact` current in nav (`aria-current="page"`).
+
+## Gotchas
+
+- About is MDX (`src/pages/about.mdx`); prove the rendered page, not the source file alone.
+- LinkedIn is off-site; proving the href is enough — do not scrape LinkedIn.
+- Do not “fix” a failed bio assertion by allowing numbers back onto the page.
diff --git a/.cursor/skills/verify-kylecesmat/features/build-and-headers.md b/.cursor/skills/verify-kylecesmat/features/build-and-headers.md
new file mode 100644
index 0000000..e70ae79
--- /dev/null
+++ b/.cursor/skills/verify-kylecesmat/features/build-and-headers.md
@@ -0,0 +1,33 @@
+# Build and headers
+
+A production static build writes `dist/` with HTML plus `robots.txt`, sitemap, and Cloudflare `_headers`. CI is build-only (no deploy).
+
+## Sub-features
+
+- `build-ok` — `npm run build` exits 0.
+- `robots` — `dist/robots.txt` exists and allows crawlers, pointing at the sitemap.
+- `sitemap` — `dist/sitemap-index.xml` exists.
+- `headers` — `dist/_headers` exists (security headers for when the hostname is later proxied).
+
+## How to get to it (user POV)
+
+- A visitor never sees this directly. Authors run `npm run build` or CI `Build`. Preview serves the same `dist/` via `astro preview`.
+
+## Driving it with helpers
+
+Preconditions:
+
+- Node >=22. This feature does **not** require a running preview if you only inspect `dist/`. For a served proof, run `helpers/launch.sh` first (it builds).
+
+- **Build.** From repo root: `npm run build`. Exit code `0`. Directory `dist/` exists.
+- **Robots.** `test -f dist/robots.txt`. File contains `User-agent: *` and a `Sitemap:` line. Do not require production DNS to resolve.
+- **Sitemap.** `test -f dist/sitemap-index.xml`.
+- **Headers.** `test -f dist/_headers`. File mentions `X-Content-Type-Options` (and typically `Referrer-Policy`).
+- **Optional serve check.** After launch, `curl -sI http://127.0.0.1:${VERIFY_PORT:-4321}/robots.txt` is 200.
+- **Proof.** Copy those three files (or `ls -l` output) into `evidence/$RUN_ID/` as `robots.txt`, `sitemap-index.xml`, `_headers`. Cleanup must not delete `evidence/`. Do not delete `dist/` in cleanup (build output is not proof; the copies in `evidence/` are).
+
+## Gotchas
+
+- CI must stay build-only. A passing build is not permission to attach a custom domain or orange-cloud.
+- `_headers` apply on Cloudflare when the hostname is proxied; absence of `cf-ray` on today’s live GitHub Pages origin is expected.
+- `npm run check` (`astro check`) is useful but not a substitute for the `dist/` artifact checks.
diff --git a/.cursor/skills/verify-kylecesmat/features/homepage-hiring-brief.md b/.cursor/skills/verify-kylecesmat/features/homepage-hiring-brief.md
new file mode 100644
index 0000000..ea5c17a
--- /dev/null
+++ b/.cursor/skills/verify-kylecesmat/features/homepage-hiring-brief.md
@@ -0,0 +1,38 @@
+# Homepage hiring brief
+
+The home page is a short hiring brief: locked qualitative headline and subhead, a one-line trajectory, three restrained proof blocks, writing and talks lists, then contact.
+
+## Sub-features
+
+- `hero-lock` shows heading `Building Agent Experience for enterprise engineering orgs` and the qualitative subhead (no `headlinePick` placeholder).
+- `trajectory` shows `Coinbase SEM · formerly Formidable`.
+- `proof-blocks` shows three headings: `Agent Experience`, `Governed agent platform`, `Platform / App Infra`, each with a qualitative paragraph (no numeric KPIs).
+- `writing-tease` lists writing titles and an `all writing` link.
+- `talks-tease` lists talks with Syntax.fm first and an `all talks` link.
+- `contact-cta` shows `kylecesmat@gmail.com` and `LinkedIn`.
+
+## How to get to it (user POV)
+
+- Open `/` (wordmark `Kyle Cesmat` also returns here).
+- Land from any primary nav item by choosing the wordmark.
+
+## Driving it with helpers
+
+Preconditions:
+
+- `helpers/launch.sh` has started preview.
+- `helpers/doctor.sh` exits 0.
+
+- **Open home.** Fetch `/`. Run `helpers/snapshot.sh http://127.0.0.1:${VERIFY_PORT:-4321}/ homepage`. `status.txt` is `200`. `aria.txt` and `homepage.html` include the locked `` text `Building Agent Experience for enterprise engineering orgs`.
+- **Confirm trajectory.** In the same HTML, the line `Coinbase SEM · formerly Formidable` is present.
+- **Confirm proof.** Headings `Agent Experience`, `Governed agent platform`, and `Platform / App Infra` appear. Bodies are prose. Fail the proof if the HTML contains metric patterns such as `0→`, `%→`, or `MCP servers`.
+- **Confirm writing and talks.** A heading `writing` and a link `all writing`; a heading `talks` and a link `all talks`. Syntax.fm talk title is listed (match the visible title string; do not assert a productivity percentage).
+- **Confirm contact.** Links named `kylecesmat@gmail.com` (mailto) and `LinkedIn`.
+- **Proof.** `homepage.png` shows the wordmark `Kyle Cesmat` and the locked hero heading. Keep artifacts under `evidence/$RUN_ID/`.
+
+## Gotchas
+
+- A 200 with a placeholder hero (`[TODO: headline`) is a failed proof, not a pass.
+- Do not use production `https://kylecesmat.com` as the origin.
+- Nav labels are lowercase (`about`, `writing`, `talks`, `contact`).
+- Proof copy is qualitative. If a future edit reintroduces counts or percents, fail — do not “update the assertion” to match metrics.
diff --git a/.cursor/skills/verify-kylecesmat/features/now-and-archive.md b/.cursor/skills/verify-kylecesmat/features/now-and-archive.md
new file mode 100644
index 0000000..4b981d0
--- /dev/null
+++ b/.cursor/skills/verify-kylecesmat/features/now-and-archive.md
@@ -0,0 +1,32 @@
+# Now and archive
+
+`/now` is a dated-focus stub. `/archive` holds Formidable-era projects and meetup talks off the primary nav.
+
+## Sub-features
+
+- `now-stub` renders `/now` with heading `now` and placeholder focus/reading/location slots.
+- `archive-demote` renders `/archive` with Formidable projects and meetup talks, not linked from primary nav.
+
+## How to get to it (user POV)
+
+- Footer link `now`.
+- Footer link `archive`.
+- Direct URL `/now` or `/archive`.
+- Not listed in the primary nav (`about` / `writing` / `talks` / `contact`).
+
+## Driving it with helpers
+
+Preconditions:
+
+- Preview is healthy (`helpers/doctor.sh`).
+
+- **Confirm demotion.** Snapshot `/`. `aria.txt` primary nav (`aria-label="Primary"`) has `about`, `writing`, `talks`, `contact` and does **not** include `now` or `archive`. Footer does.
+- **Open now.** Choose footer `now`. Run `helpers/snapshot.sh http://127.0.0.1:${VERIFY_PORT:-4321}/now now`. Status `200`. Heading `now`.
+- **Open archive.** Choose footer `archive`. Snapshot `/archive`. Status `200`. Heading `archive`. Visible copy mentions Formidable and lists project titles (NDA-light).
+- **Proof.** Keep HTML + screenshot for both routes plus the homepage nav snapshot that shows they are footer-only.
+
+## Gotchas
+
+- `/currently` redirects to `/` (legacy). Do not treat it as Now.
+- Archive titles are historical names, not current hiring metrics.
+- Placeholders on `/now` (`[TODO: now`) are expected until that copy is written.
diff --git a/.cursor/skills/verify-kylecesmat/features/writing-and-talks.md b/.cursor/skills/verify-kylecesmat/features/writing-and-talks.md
new file mode 100644
index 0000000..7d04b0e
--- /dev/null
+++ b/.cursor/skills/verify-kylecesmat/features/writing-and-talks.md
@@ -0,0 +1,35 @@
+# Writing and talks
+
+Writing is a list of MDX pillar stubs. Talks is a separate list with the Syntax.fm episode first, plus notes at `/talks/syntax-fm-944`.
+
+## Sub-features
+
+- `writing-index` lists pillar stubs at `/writing` with titles from MDX frontmatter.
+- `writing-piece` opens a stub at `/writing/` (heading is the piece title).
+- `talks-index` lists talks at `/talks` with Syntax.fm first.
+- `talk-notes` opens `/talks/syntax-fm-944` notes.
+
+## How to get to it (user POV)
+
+- Primary nav `writing` or home link `all writing`.
+- Primary nav `talks` or home link `all talks`.
+- A writing or talk title on the home page.
+
+## Driving it with helpers
+
+Preconditions:
+
+- Preview is healthy (`helpers/doctor.sh`).
+- Drive from `/` unless noted.
+
+- **Open writing.** Choose link `writing` or `all writing`. Run `helpers/snapshot.sh http://127.0.0.1:${VERIFY_PORT:-4321}/writing writing-index`. Status `200`. Heading `writing`. At least one title link is present (stubs may say `draft`).
+- **Open a piece.** Follow a writing title link (prefer the visible title, not a CSS selector). Snapshot that URL. Status `200`. The `` matches the link text.
+- **Open talks.** Choose `talks` or `all talks`. Run `helpers/snapshot.sh http://127.0.0.1:${VERIFY_PORT:-4321}/talks talks-index`. Status `200`. First listed title is `Is Coinbase Really Writing Half Their Code With AI?` (episode name, not a metric assertion).
+- **Open notes.** Follow that title to `/talks/syntax-fm-944`. Status `200`. Heading matches the talk title.
+- **Proof.** Keep HTML, `aria.txt`, and screenshots for index + one piece + talk notes.
+
+## Gotchas
+
+- Writing stubs are placeholders; empty body is OK if the title heading renders.
+- Do not require a public Syntax.fm URL; notes are on-site.
+- `#944` is the episode id in the venue string — match the visible venue/title, do not parse it as a site KPI.
diff --git a/.cursor/skills/verify-kylecesmat/helpers/aria_snapshot.py b/.cursor/skills/verify-kylecesmat/helpers/aria_snapshot.py
new file mode 100755
index 0000000..1e9d9c2
--- /dev/null
+++ b/.cursor/skills/verify-kylecesmat/helpers/aria_snapshot.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python3
+"""Extract headings, labeled landmarks, and link names from HTML for an ARIA-ish snapshot."""
+from __future__ import annotations
+
+import sys
+from html.parser import HTMLParser
+from pathlib import Path
+
+
+class Snapshot(HTMLParser):
+ def __init__(self) -> None:
+ super().__init__(convert_charrefs=True)
+ self.lines: list[str] = []
+ self._capture: list[str] | None = None
+ self._buf: list[str] = []
+ self._skip = 0
+
+ def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None:
+ if tag in {"script", "style"}:
+ self._skip += 1
+ return
+ ad = {k: v or "" for k, v in attrs}
+ if tag in {"h1", "h2", "h3", "title", "a", "nav"}:
+ self._capture = tag
+ self._buf = []
+ extra = []
+ if ad.get("aria-label"):
+ extra.append(f"aria-label={ad['aria-label']!r}")
+ if ad.get("aria-current"):
+ extra.append(f"aria-current={ad['aria-current']!r}")
+ if tag == "a" and ad.get("href"):
+ extra.append(f"href={ad['href']!r}")
+ self._pending_extra = extra
+ elif ad.get("aria-label") or ad.get("aria-current"):
+ bits = [tag]
+ if ad.get("aria-label"):
+ bits.append(f"aria-label={ad['aria-label']!r}")
+ if ad.get("aria-current"):
+ bits.append(f"aria-current={ad['aria-current']!r}")
+ self.lines.append(" ".join(bits))
+
+ def handle_endtag(self, tag: str) -> None:
+ if tag in {"script", "style"} and self._skip:
+ self._skip -= 1
+ return
+ if self._capture == tag:
+ text = "".join(self._buf).strip()
+ extra = getattr(self, "_pending_extra", [])
+ suffix = (" " + " ".join(extra)) if extra else ""
+ if text or extra:
+ self.lines.append(f"{tag}: {text}{suffix}".rstrip())
+ self._capture = None
+ self._buf = []
+
+ def handle_data(self, data: str) -> None:
+ if self._skip:
+ return
+ if self._capture is not None:
+ self._buf.append(data)
+
+
+def main() -> None:
+ path = Path(sys.argv[1])
+ parser = Snapshot()
+ parser.feed(path.read_text(encoding="utf-8", errors="replace"))
+ sys.stdout.write("\n".join(parser.lines) + "\n")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/.cursor/skills/verify-kylecesmat/helpers/cleanup.sh b/.cursor/skills/verify-kylecesmat/helpers/cleanup.sh
new file mode 100755
index 0000000..0781b8a
--- /dev/null
+++ b/.cursor/skills/verify-kylecesmat/helpers/cleanup.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+# Stop only the preview this run started. Do not delete evidence.
+set -euo pipefail
+
+HELPERS="$(cd "$(dirname "$0")" && pwd)"
+SKILL_DIR="$(cd "$HELPERS/.." && pwd)"
+STATE="$SKILL_DIR/.run/state"
+
+if [[ ! -f "$STATE" ]]; then
+ echo "cleanup: no state file; nothing to stop"
+ exit 0
+fi
+# shellcheck disable=SC1090
+source "$STATE"
+
+kill_tree() {
+ local pid="$1"
+ local kids
+ kids="$(ps -o pid= --ppid "$pid" 2>/dev/null || true)"
+ for k in $kids; do
+ kill_tree "$k"
+ done
+ if kill -0 "$pid" 2>/dev/null; then
+ kill "$pid" 2>/dev/null || true
+ fi
+}
+
+if [[ -n "${PID:-}" ]] && kill -0 "$PID" 2>/dev/null; then
+ kill_tree "$PID"
+ for _ in $(seq 1 20); do
+ kill -0 "$PID" 2>/dev/null || break
+ sleep 0.1
+ done
+ if kill -0 "$PID" 2>/dev/null; then
+ kill -9 "$PID" 2>/dev/null || true
+ fi
+ echo "cleanup: stopped pid=$PID"
+else
+ echo "cleanup: recorded pid ${PID:-unset} already gone"
+fi
+
+rm -f "$STATE"
+echo "cleanup: evidence directories were not touched"
diff --git a/.cursor/skills/verify-kylecesmat/helpers/doctor.sh b/.cursor/skills/verify-kylecesmat/helpers/doctor.sh
new file mode 100755
index 0000000..d3b1663
--- /dev/null
+++ b/.cursor/skills/verify-kylecesmat/helpers/doctor.sh
@@ -0,0 +1,107 @@
+#!/usr/bin/env bash
+# Read-only: is this preview instance worth driving?
+set -euo pipefail
+
+HELPERS="$(cd "$(dirname "$0")" && pwd)"
+SKILL_DIR="$(cd "$HELPERS/.." && pwd)"
+ROOT="$(cd "$SKILL_DIR/../../.." && pwd)"
+STATE="$SKILL_DIR/.run/state"
+HERO='Building Agent Experience for enterprise engineering orgs'
+TRAJECTORY='Coinbase SEM · formerly Formidable'
+
+if [[ ! -f "$STATE" ]]; then
+ echo "doctor: missing $STATE (run launch.sh)" >&2
+ exit 1
+fi
+# shellcheck disable=SC1090
+source "$STATE"
+
+NODE_V="$(node -v)"
+NODE_MAJOR="${NODE_V#v}"
+NODE_MAJOR="${NODE_MAJOR%%.*}"
+if [[ "$NODE_MAJOR" -lt 22 ]]; then
+ echo "doctor: Node >=22 required, got $NODE_V" >&2
+ exit 1
+fi
+
+NVMRC="$(tr -d '[:space:]' <"$ROOT/.nvmrc")"
+if [[ "$NVMRC" != "22" ]]; then
+ echo "doctor: .nvmrc is '$NVMRC', expected 22" >&2
+ exit 1
+fi
+
+if [[ -z "${PID:-}" ]] || ! kill -0 "$PID" 2>/dev/null; then
+ echo "doctor: recorded PID ${PID:-unset} is not running" >&2
+ exit 1
+fi
+
+LISTEN_PIDS=""
+if command -v lsof >/dev/null 2>&1; then
+ LISTEN_PIDS="$(lsof -iTCP:"$PORT" -sTCP:LISTEN -t 2>/dev/null || true)"
+fi
+
+owns=0
+for lp in $LISTEN_PIDS; do
+ if [[ "$lp" == "$PID" ]]; then
+ owns=1
+ break
+ fi
+ # npm/npx often spawn a child that actually binds the port
+ if [[ "$(ps -o ppid= -p "$lp" 2>/dev/null | tr -d ' ')" == "$PID" ]]; then
+ owns=1
+ break
+ fi
+ # walk a couple of ancestors
+ cur="$lp"
+ for _ in 1 2 3 4; do
+ parent="$(ps -o ppid= -p "$cur" 2>/dev/null | tr -d ' ' || true)"
+ [[ -z "$parent" || "$parent" == "1" ]] && break
+ if [[ "$parent" == "$PID" ]]; then
+ owns=1
+ break
+ fi
+ cur="$parent"
+ done
+ [[ "$owns" == 1 ]] && break
+done
+
+if [[ "$owns" != 1 ]]; then
+ echo "doctor: port $PORT is not owned by pid $PID (listen pids: ${LISTEN_PIDS:-none})" >&2
+ exit 1
+fi
+
+TMP="$(mktemp)"
+STATUS="$(curl -sS -o "$TMP" -w '%{http_code}' "http://${HOST}:${PORT}/")"
+if [[ "$STATUS" != "200" ]]; then
+ echo "doctor: GET / returned $STATUS" >&2
+ rm -f "$TMP"
+ exit 1
+fi
+
+if ! grep -q "$HERO" "$TMP"; then
+ echo "doctor: homepage missing locked hero string" >&2
+ rm -f "$TMP"
+ exit 1
+fi
+
+if grep -q '\[TODO: headline' "$TMP" || grep -q 'headlinePick' "$TMP"; then
+ echo "doctor: homepage still has placeholder headline" >&2
+ rm -f "$TMP"
+ exit 1
+fi
+
+if ! grep -q "$TRAJECTORY" "$TMP"; then
+ echo "doctor: homepage missing trajectory line" >&2
+ rm -f "$TMP"
+ exit 1
+fi
+
+# Fail if quantitative hiring metrics leaked back onto the homepage.
+if grep -E '0→|2,200|0%→94%|~170 MCP|4\.8k|16k runs|26s→|98% down' "$TMP"; then
+ echo "doctor: homepage contains quantitative metrics (forbidden)" >&2
+ rm -f "$TMP"
+ exit 1
+fi
+
+rm -f "$TMP"
+echo "doctor: ok node=$NODE_V pid=$PID http://${HOST}:${PORT}/ hero=locked"
diff --git a/.cursor/skills/verify-kylecesmat/helpers/launch.sh b/.cursor/skills/verify-kylecesmat/helpers/launch.sh
new file mode 100755
index 0000000..733cd4e
--- /dev/null
+++ b/.cursor/skills/verify-kylecesmat/helpers/launch.sh
@@ -0,0 +1,106 @@
+#!/usr/bin/env bash
+# Start a local astro preview owned by this verification run.
+set -euo pipefail
+
+HELPERS="$(cd "$(dirname "$0")" && pwd)"
+SKILL_DIR="$(cd "$HELPERS/.." && pwd)"
+ROOT="$(cd "$SKILL_DIR/../../.." && pwd)"
+RUN_DIR="$SKILL_DIR/.run"
+STATE="$RUN_DIR/state"
+PORT="${VERIFY_PORT:-4321}"
+HOST="${VERIFY_HOST:-127.0.0.1}"
+
+mkdir -p "$RUN_DIR"
+
+if [[ -f "$STATE" ]]; then
+ # shellcheck disable=SC1090
+ source "$STATE"
+ if [[ -n "${PID:-}" ]] && kill -0 "$PID" 2>/dev/null; then
+ echo "verify-kylecesmat: already launched pid=$PID port=$PORT" >&2
+ exit 0
+ fi
+ rm -f "$STATE"
+fi
+
+LOCK="$ROOT/.astro/preview.json"
+if [[ -f "$LOCK" ]]; then
+ lock_pid="$(python3 -c "import json; print(json.load(open('$LOCK')).get('pid',''))" 2>/dev/null || true)"
+ if [[ -n "$lock_pid" ]] && kill -0 "$lock_pid" 2>/dev/null; then
+ echo "verify-kylecesmat: stopping this checkout's leftover preview pid=$lock_pid"
+ kill "$lock_pid" 2>/dev/null || true
+ for _ in $(seq 1 30); do
+ kill -0 "$lock_pid" 2>/dev/null || break
+ sleep 0.1
+ done
+ if kill -0 "$lock_pid" 2>/dev/null; then
+ kill -9 "$lock_pid" 2>/dev/null || true
+ fi
+ fi
+ rm -f "$LOCK"
+fi
+
+if command -v lsof >/dev/null 2>&1 && lsof -iTCP:"$PORT" -sTCP:LISTEN >/dev/null 2>&1; then
+ echo "verify-kylecesmat: port $PORT still bound after releasing this checkout's lock. Refuse." >&2
+ exit 1
+fi
+
+cd "$ROOT"
+npm install
+npm run build
+
+# ASTRO_PREVIEW_BACKGROUND=1 keeps preview in the foreground under our PID
+# (Cursor would otherwise daemonize `astro preview` and drop ownership).
+LOG="$RUN_DIR/preview.log"
+: >"$LOG"
+ASTRO_PREVIEW_BACKGROUND=1 ./node_modules/.bin/astro preview --host "$HOST" --port "$PORT" >"$LOG" 2>&1 &
+PID=$!
+
+{
+ echo "PID=$PID"
+ echo "PORT=$PORT"
+ echo "HOST=$HOST"
+ echo "STARTED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
+} >"$STATE"
+
+cleanup_on_fail() {
+ if kill -0 "$PID" 2>/dev/null; then
+ kill "$PID" 2>/dev/null || true
+ wait "$PID" 2>/dev/null || true
+ fi
+ rm -f "$STATE"
+}
+
+owns_listen() {
+ local want="$1"
+ local lp parent cur
+ lp="$(lsof -iTCP:"$PORT" -sTCP:LISTEN -t 2>/dev/null | head -1 || true)"
+ [[ -z "$lp" ]] && return 1
+ [[ "$lp" == "$want" ]] && return 0
+ cur="$lp"
+ for _ in 1 2 3 4 5; do
+ parent="$(ps -o ppid= -p "$cur" 2>/dev/null | tr -d ' ' || true)"
+ [[ -z "$parent" || "$parent" == "1" ]] && break
+ [[ "$parent" == "$want" ]] && return 0
+ cur="$parent"
+ done
+ return 1
+}
+
+for _ in $(seq 1 40); do
+ if curl -sf -o /dev/null "http://${HOST}:${PORT}/" && owns_listen "$PID"; then
+ echo "verify-kylecesmat: ready pid=$PID http://${HOST}:${PORT}/"
+ exit 0
+ fi
+ if ! kill -0 "$PID" 2>/dev/null; then
+ echo "verify-kylecesmat: preview exited before ready. log:" >&2
+ cat "$LOG" >&2 || true
+ cleanup_on_fail
+ exit 1
+ fi
+ sleep 0.25
+done
+
+echo "verify-kylecesmat: timed out waiting for http://${HOST}:${PORT}/" >&2
+cat "$LOG" >&2 || true
+cleanup_on_fail
+exit 1
diff --git a/.cursor/skills/verify-kylecesmat/helpers/snapshot.sh b/.cursor/skills/verify-kylecesmat/helpers/snapshot.sh
new file mode 100755
index 0000000..8d9bc28
--- /dev/null
+++ b/.cursor/skills/verify-kylecesmat/helpers/snapshot.sh
@@ -0,0 +1,51 @@
+#!/usr/bin/env bash
+# Fetch a preview URL into evidence/$RUN_ID/: HTTP status, HTML, aria-ish snapshot, screenshot.
+set -euo pipefail
+
+HELPERS="$(cd "$(dirname "$0")" && pwd)"
+SKILL_DIR="$(cd "$HELPERS/.." && pwd)"
+STATE="$SKILL_DIR/.run/state"
+
+URL="${1:-}"
+STEM="${2:-page}"
+if [[ -z "$URL" ]]; then
+ echo "usage: snapshot.sh [stem]" >&2
+ exit 1
+fi
+
+if [[ -z "${RUN_ID:-}" ]]; then
+ echo "snapshot.sh: set RUN_ID (evidence folder name)" >&2
+ exit 1
+fi
+
+OUT="$SKILL_DIR/evidence/$RUN_ID"
+mkdir -p "$OUT"
+
+STATUS="$(curl -sS -D "$OUT/${STEM}.headers" -o "$OUT/${STEM}.html" -w '%{http_code}' "$URL")"
+echo "$STATUS" >"$OUT/${STEM}.status.txt"
+echo "url=$URL" >"$OUT/${STEM}.meta.txt"
+echo "status=$STATUS" >>"$OUT/${STEM}.meta.txt"
+echo "fetched_at=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >>"$OUT/${STEM}.meta.txt"
+if [[ -f "$STATE" ]]; then
+ echo "state=$(tr '\n' ' ' <"$STATE")" >>"$OUT/${STEM}.meta.txt"
+fi
+
+python3 "$HELPERS/aria_snapshot.py" "$OUT/${STEM}.html" >"$OUT/${STEM}.aria.txt"
+
+CHROME="${CHROME_BIN:-/usr/bin/google-chrome-stable}"
+if [[ -x "$CHROME" ]]; then
+ "$CHROME" \
+ --headless=new \
+ --disable-gpu \
+ --no-sandbox \
+ --hide-scrollbars \
+ --window-size=1280,1800 \
+ --screenshot="$OUT/${STEM}.png" \
+ "$URL" >/dev/null 2>"$OUT/${STEM}.chrome.log" || {
+ echo "snapshot.sh: chrome screenshot failed (see ${STEM}.chrome.log)" >&2
+ }
+else
+ echo "snapshot.sh: no chrome at $CHROME; skipped screenshot" >&2
+fi
+
+echo "snapshot: $OUT/${STEM}.* status=$STATUS"
diff --git a/.gitignore b/.gitignore
index 4bc9b02..bcd760a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,9 @@ yarn-error.log*
.DS_Store
*.pem
.vercel
+
+# pstack verification evidence and live preview PID (keep .gitkeep)
+.cursor/skills/verify-kylecesmat/evidence/*
+!.cursor/skills/verify-kylecesmat/evidence/.gitkeep
+.cursor/skills/verify-kylecesmat/.run/*
+!.cursor/skills/verify-kylecesmat/.run/.gitkeep