Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,87 @@ jobs:
- name: Wrangler config + bundle dry-run
run: bun x wrangler deploy --dry-run

# Verifies the sandbox image tags pinned in wrangler.jsonc actually
# exist in the Cloudflare managed registry. Catches the failure
# mode where a contributor bumps the Dockerfile + pin but forgets
# `wrangler containers build -p` (the image push). The dry-run
# above does NOT validate tag existence, so without this guard the
# failure would surface at deploy time rather than PR time.
#
# Pin alignment between env blocks is workflow-aware:
# dev-targeting PRs: pins may diverge (staging-leads-prod
# during the soak-then-promote workflow;
# see RELEASES.md § Sandbox image releases).
# Each pin is verified independently against
# the registry.
# main-targeting PRs: pins MUST be equal (released state).
# The release PR is expected to promote the
# top-level pin to match env.staging before
# merging.
#
# Skipped on forks (secrets are unavailable to PRs from forks by
# default). Same-repo branches always hit it.
- name: Verify pinned sandbox image exists in CF registry
if: github.event.pull_request.head.repo.full_name == github.repository
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
BASE_REF: ${{ github.base_ref }}
run: |
set -euo pipefail

prod_img=$(bun x wrangler deploy --dry-run 2>&1 \
| grep -oE 'registry\.cloudflare\.com/[^ )]+' | head -1 || true)
stg_img=$(bun x wrangler deploy --dry-run --env staging 2>&1 \
| grep -oE 'registry\.cloudflare\.com/[^ )]+' | head -1 || true)

if [ -z "$prod_img" ] || [ -z "$stg_img" ]; then
echo "::warning::could not extract image URI from wrangler dry-run; skipping registry probe"
exit 0
fi

prod_tag="${prod_img##*:}"
stg_tag="${stg_img##*:}"

# Always: independent registry-existence check on each pinned
# tag. Allows staging to lead prod during development.
images=$(bun x wrangler containers images list 2>/dev/null || true)
fail=0

if echo "$images" | grep -qE "anc-sandbox[[:space:]]+${prod_tag}\b"; then
echo "verified: top-level pin anc-sandbox:${prod_tag} is in the CF managed registry"
else
echo "::error::top-level pin anc-sandbox:${prod_tag} not found in CF managed registry"
echo "did you forget: bun x wrangler containers build -p -t anc-sandbox:${prod_tag} docker/sandbox/"
fail=1
fi

if [ "$prod_tag" = "$stg_tag" ]; then
echo "verified: env.staging pin equals top-level pin (lockstep)"
elif echo "$images" | grep -qE "anc-sandbox[[:space:]]+${stg_tag}\b"; then
echo "verified: env.staging pin anc-sandbox:${stg_tag} is in the CF managed registry"
else
echo "::error::env.staging pin anc-sandbox:${stg_tag} not found in CF managed registry"
echo "did you forget: bun x wrangler containers build -p -t anc-sandbox:${stg_tag} docker/sandbox/"
fail=1
fi

# Release-time invariant: main-targeting PRs must have aligned
# pins. Dev-targeting PRs may have divergent pins (staging
# leads prod during development).
if [ "${BASE_REF}" = "main" ] && [ "$prod_tag" != "$stg_tag" ]; then
echo "::error::release PR to main has divergent image pins"
echo " top-level: anc-sandbox:${prod_tag}"
echo " env.staging: anc-sandbox:${stg_tag}"
echo "Promote the top-level pin to match env.staging before merging."
echo "See RELEASES.md § Sandbox image releases for the soak-and-promote procedure."
fail=1
fi

if [ "$fail" -ne 0 ]; then
exit 1
fi

annotate-warnings:
# Surfaces scorecard/registry orphan counts (U8) as a PR comment so
# reviewers see drift without grepping CI logs. Build still passes
Expand Down
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,10 @@ playwright-report/
# the local CLI checkout (not committed); per-run logs land in out/.
/docker/score/anc
/docker/score/out/

# Vale baseline packs — downloaded by `vale sync` from the URLs in .vale.ini's
# Packages directive. The brand and site packs are committed; these are
# fetched per-machine.
/styles/proselint/
/styles/write-good/
/styles/.vale-config/
118 changes: 0 additions & 118 deletions .impeccable.md

This file was deleted.

46 changes: 46 additions & 0 deletions .vale.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
StylesPath = styles
MinAlertLevel = warning
Vocab = brand, site
Packages = https://github.com/vale-cli/write-good/releases/download/v0.4.1/write-good.zip, https://github.com/vale-cli/proselint/releases/download/v0.3.4/proselint.zip

[*.md]
BasedOnStyles = Vale, brand, site, write-good, proselint
Vale.Terms = NO
brand.MarketingRegister = error
brand.HedgeWords = error
brand.FillerAdjectives = error
site.BannedFonts = error
site.BannedAesthetics = error
write-good.E-Prime = NO
write-good.Passive = warning
write-good.TooWordy = warning
write-good.ThereIs = warning
proselint.But = NO
proselint.Annotations = NO
proselint.Typography = warning

[{docs/brainstorms,docs/plans,docs/research}/**]
BasedOnStyles =

[AGENTS.md]
BasedOnStyles =

[CHANGELOG.md]
BasedOnStyles =

# PRODUCT.md is the channel's policy doc (was .impeccable.md before the
# 2026-05-12 migration). It names the banned aesthetic patterns and the
# rejected fonts the rule packs catch. Disable both here only (the rules
# fire on the policy doc that defines them).
[PRODUCT.md]
site.BannedAesthetics = NO
site.BannedFonts = NO

# DESIGN.md is the rationale doc (was docs/DESIGN.md before the 2026-05-12
# hoist). It records why specific fonts were rejected (Inter, IBM Plex,
# Fraunces, Space Grotesk, Instrument Serif) and which aesthetic patterns
# are out. Same precedent as PRODUCT.md: the doc that names what was
# rejected legitimately enumerates the rejected names.
[DESIGN.md]
site.BannedFonts = NO
site.BannedAesthetics = NO
12 changes: 6 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ anchors, and semantic HTML. Keep this framing in every decision.
per-host clone commands)
- `/skill.json` — canonical machine-primary skill manifest. Same data, agent-readable. `Content-Type: application/json`,
`X-Robots-Tag: noindex`. Both `/skill` and `/skill.json` derive from `src/data/skill.json` at build time; full surface
contract in `docs/DESIGN.md` §3.9
contract in `DESIGN.md` §3.9
- `content/*.md` — markdown source of truth for every page (principle files, check, about, index)
- Cloudflare Worker — routes requests: `.md` suffix OR `Accept: text/markdown` returns raw markdown source; otherwise
returns HTML rendered from the same markdown via CommonMark
Expand Down Expand Up @@ -96,11 +96,11 @@ narrative, attribution rules) is load-bearing.
- Mobile-first; a11y baseline (skip-link, semantic landmarks, `>= 4.5:1` contrast, `:focus-visible`,
`prefers-reduced-motion`)

The design-survey step produces a `docs/DESIGN.md` in the repo with palette, type stack, spacing scale, code-block
treatment, and dark/light tokens before any HTML is written.
The design-survey step produces a `DESIGN.md` in the repo with palette, type stack, spacing scale, code-block treatment,
and dark/light tokens before any HTML is written.

Design context consumed by the `/impeccable` and `/typeset` skills (users, brand personality, aesthetic direction,
design principles): [`.impeccable.md`](.impeccable.md).
design principles): [`PRODUCT.md`](PRODUCT.md).

## Visual fidelity

Expand Down Expand Up @@ -158,7 +158,7 @@ agent-side browser-verify rule above is the working gate.
| `~/obsidian-vault/Projects/brettdavies-agentnative/research/index.md` | Shared research index for both this site and the `agentnative` CLI linter | External signal (blog posts, HN threads, competitor CLIs) extracted into curated quotes + principle mapping. Read before writing principle copy or launch framing that cites third parties. |
| `~/obsidian-vault/Projects/brettdavies-agentnative/principles/index.md` | Canonical spec for P1-P7 (one file per principle, pressure-testable) | Source of truth for principle meaning. Site copy in `content/principles/` is written **manually** from these files — no build-time import, no live link. When principle spec changes, propagate to site copy deliberately. |
| `~/.gstack/projects/brettdavies-agentnative-site/brett-main-build-plan-20260414-130000.md` | Build & distribution plan | Scaffolding decisions for /ce-plan and /ce-work: target repo tree, build pipeline, deployment. Locked decisions; Cloudflare-specifics verified. |
| `~/.gstack/projects/brettdavies-agentnative-site/brett-main-eng-review-20260414-123800.md` | Eng review | Architecture + code quality + test coverage review for M1. §12 lists all docs/DESIGN.md edits. Decisions resolved; no blockers. |
| `~/.gstack/projects/brettdavies-agentnative-site/brett-main-eng-review-20260414-123800.md` | Eng review | Architecture + code quality + test coverage review for M1. §12 lists all DESIGN.md edits. Decisions resolved; no blockers. |
| `docs/plans/2026-04-17-001-feat-registry-leaderboard-scorecard-pages-plan.md` | Registry + leaderboard plan | Plan 1 scope: tool registry, pre-computed scorecards, `/scorecards` leaderboard, `/score/<tool>` pages. Plan 2 (live scoring via CF Sandbox) is separate. |

## Related repos
Expand Down Expand Up @@ -208,6 +208,6 @@ The production domain (candidates: agentnative.dev / .io / .org) is **Brett's pu
authoritative spec that the site's `content/principles/` copy is written from (manually, not auto-derived).
3. Run a reference-site survey for visual design (clig.dev, 12factor.net, htmx.org, rust-lang.org book, json-schema.org,
fly.io docs, matklad.github.io — pick 3-4 that embody "simple, traditional, modern flair" and extract tokens).
Produce `docs/DESIGN.md` before writing any HTML.
Produce `DESIGN.md` before writing any HTML.
4. Scaffold the markdown sources in `content/` first, then the Worker + HTML renderer, then wire deploy.
5. Check in with Brett before attaching the production domain.
Loading
Loading