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
28 changes: 15 additions & 13 deletions RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,30 +210,32 @@ Committing the JSON alongside the code means ruleset changes land via the same r

`/skill.json` and `/skill` advertise the `agent-native-cli` skill, hosted at
[`brettdavies/agentnative-skill`](https://github.com/brettdavies/agentnative-skill). This site vendors the skill's
upstream commit SHA in `src/data/skill.json`; the skill repo holds the actual content. Surface contract in
`docs/DESIGN.md` §3.9.
manifest (per-host install commands, version, surface metadata) in `src/data/skill.json`; the skill repo holds the
actual content. Surface contract in `docs/DESIGN.md` §3.9. Update detection at install sites is delegated to the skill
bundle's `bin/check-update`, which compares the local bundle's `VERSION` against `main` on GitHub.

The skill repo's branch model: `main` is the published-release pointer (default branch); `dev` is the integration
branch. The bare `git clone --depth 1` in each install command lands on `main` — so each release REQUIRES the skill
maintainer to fast-forward `main` to the new tag before the site re-pins.
branch. The bare `git clone --depth 1` in each install command lands on `main` — so each release requires the skill
maintainer to fast-forward `main` to the new tag.

### Skill-release procedure

1. **Cut the skill release** (in `agentnative-skill`): edit, commit, tag `v0.x.y` (signed if a key is configured), then
`git push origin dev --follow-tags`. Fast-forward `main` to the new tag and push: `git checkout main && git merge
--ff-only v0.x.y && git push origin main`. The site's bare `git clone --depth 1` lands on `main`, so the fast-forward
is what makes the new release reachable.
2. **Re-pin in this repo**: edit `src/data/skill.json` — bump `version`, `source.commit`, and `verify.expected`
(`source.commit` and `verify.expected` are the same SHA until v2 schema decouples them). `loadSkillData()` will
reject a non-hex / non-lowercase / non-40-char SHA at build time, so a typo fails fast.
2. **Bump the manifest in this repo (only when user-facing fields changed)**: edit `src/data/skill.json` to bump
`version` and update any per-host install commands, description, or other surface fields the release modified. If
nothing user-facing changed, skip the manifest bump entirely — the skill bundle's `bin/check-update` is what tells
installed users a new release exists.
3. **PR to `dev`**: CI runs the unit + worker tests on the bumped manifest. Squash-merge on green.
4. **Release `dev` → `main`** via the standard `release/*` flow above. Site deploys to `anc.dev`.
5. **Cache-purge** `/skill`, `/skill.json`, and `/skill.md` via the Cloudflare cache-purge API. Required for
security-relevant pin updates so users don't pick up the old SHA from the 24h `s-maxage` window. Use the API token
stored in 1Password (`secrets-dev` vault, `Cloudflare API Token - Wrangler (bigdaddy)`). First-deploy-after-rename
note (cutover from `/install*` → `/skill*`): also purge `/install`, `/install.json`, and `/install.md` once to evict
any cached skill content under the old paths. Skip this on subsequent deploys.
6. **Verify the deployed pin**: `curl -s https://anc.dev/skill.json | jq -r .source.commit` matches the new SHA. The
5. **Cache-purge** `/skill`, `/skill.json`, and `/skill.md` via the Cloudflare cache-purge API after a manifest bump, so
users don't pick up the old shape from the 24h `s-maxage` window. Use the API token stored in 1Password
(`secrets-dev` vault, `Cloudflare API Token - Wrangler (bigdaddy)`). First-deploy-after-rename note (cutover from
`/install*` → `/skill*`): also purge `/install`, `/install.json`, and `/install.md` once to evict any cached skill
content under the old paths. Skip this on subsequent deploys.
6. **Verify the deployed manifest**: `curl -s https://anc.dev/skill.json | jq -r .version` matches the new version. The
Playwright `skill` project (`bun x playwright test --project=skill`) re-runs the live 4-host clone against the
advertised hosts; run it locally before tagging if anything in the manifest's host commands changed.

Expand Down
61 changes: 29 additions & 32 deletions docs/DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -463,41 +463,37 @@ for the single advertised skill (`agent-native-cli`); per-skill `/skill/<name>`
second skill ships, `/skill` becomes an index and per-skill content moves under `/skill/<name>` — the Worker's
JSON-extension dispatch is already shape-agnostic, so no Worker code change is anticipated for that transition.

**Source repo coupling.** This site vendors a single string — the upstream commit SHA — committed at site build time
into `src/data/skill.json`. No fetch-on-build, no submodule, no `marketplace.json` machinery. Per
**Source repo coupling.** This site vendors the skill manifest's per-host install commands and metadata at site build
time into `src/data/skill.json`. No fetch-on-build, no submodule, no `marketplace.json` machinery. Per
`docs/solutions/architecture-patterns/cross-repo-artifact-sync-commit-over-fetch-20260420.md`. The skill repo
(`brettdavies/agentnative-skill`) holds `main` as the published-release pointer and `dev` as the integration branch; the
install command's bare `git clone --depth 1` lands on the skill repo's default branch (`main`), which the skill
maintainer fast-forwards to each new release tag.
maintainer fast-forwards to each new release tag. Update detection is delegated to the skill bundle's
`bin/check-update`, which compares the local bundle's `VERSION` against `main` on GitHub.

**`/skill.json` shape (v1):**

| Key | Type | Notes |
| ------------------ | -------------------------- | --------------------------------------------------------------------------------------------------- |
| `schema_version` | integer | `1`. Bump on incompatible structural change. |
| `type` | string | `"agent-skill"`. |
| `name` | string | `"agent-native-cli"`. Slug, kebab-case. |
| `version` | string | Semver. Bumped per skill release. |
| `description` | string | One sentence. |
| `principles_url` | string | `https://anc.dev/p1`. |
| `license` | string | `"MIT"`. |
| `source.type` | string | `"git"`. |
| `source.url` | string | `https://github.com/brettdavies/agentnative-skill.git`. |
| `source.commit` | string (40-char lower hex) | The pinned commit. Validated at build time. |
| `install` | object | Per-host map: `claude_code`, `codex`, `cursor`, `opencode` → `git clone --depth 1 …` command. |
| `verify.command` | string | `git -C <install-dir> rev-parse HEAD`. Agent substitutes `<install-dir>`. |
| `verify.expected` | string | Same SHA as `source.commit` until v2 schema decouples them. Mismatch = upstream moved past the pin. |
| `verify.semantics` | string | Free-form description of what mismatch means. |
| `update` | string | `cd <install-dir> && git pull --ff-only`. |
| `uninstall` | string | `rm -rf <install-dir>`. |
| `skill_page_html` | string | `https://anc.dev/skill`. |

**Build-emitter validation (`src/build/skill.mjs`).** `loadSkillData()` is fail-fast: missing required keys, non-hex or
non-lowercase `source.commit`, non-semver `version`, empty `install` map, install commands not starting with `git clone
--depth 1`, and bare-clone commands (no explicit destination path) all reject the build at startup. The
explicit-destination invariant is non-optional defense for the repo-name asymmetry: the skill repo is named
`agentnative-skill` but the skill itself is named `agent-native-cli`; a bare `git clone` lands on the repo name and
breaks every host's skill-discovery convention.
| Key | Type | Notes |
| ----------------- | ------- | --------------------------------------------------------------------------------------------- |
| `schema_version` | integer | `1`. Bump on incompatible structural change. |
| `type` | string | `"agent-skill"`. |
| `name` | string | `"agent-native-cli"`. Slug, kebab-case. |
| `version` | string | Semver. Bumped per skill release. |
| `description` | string | One sentence. |
| `principles_url` | string | `https://anc.dev/p1`. |
| `license` | string | `"MIT"`. |
| `source.type` | string | `"git"`. |
| `source.url` | string | `https://github.com/brettdavies/agentnative-skill.git`. |
| `install` | object | Per-host map: `claude_code`, `codex`, `cursor`, `opencode` → `git clone --depth 1 …` command. |
| `update` | string | `cd <install-dir> && git pull --ff-only`. |
| `uninstall` | string | `rm -rf <install-dir>`. |
| `skill_page_html` | string | `https://anc.dev/skill`. |

**Build-emitter validation (`src/build/skill.mjs`).** `loadSkillData()` is fail-fast: missing required keys, non-semver
`version`, empty `install` map, install commands not starting with `git clone --depth 1`, and bare-clone commands (no
explicit destination path) all reject the build at startup. The explicit-destination invariant is non-optional defense
for the repo-name asymmetry: the skill repo is named `agentnative-skill` but the skill itself is named
`agent-native-cli`; a bare `git clone` lands on the repo name and breaks every host's skill-discovery convention.

**Header contract (`src/worker/headers.ts`).** The Worker's HTML/markdown branches are joined by a JSON-extension branch
detected by URL ending in `.json` (extension, not prefix — any `/<slug>.json` endpoint reuses the branch, so the v2
Expand All @@ -524,9 +520,10 @@ twin.
`/skill` enters `sitemap.xml` and `llms.txt` (under a `## Skill` section); `/skill.json` enters `llms.txt` but NOT the
sitemap because `X-Robots-Tag: noindex` keeps it out of search engines.

**Release runbook entry.** The skill-release procedure lives in `RELEASES.md`. Each skill release bumps `version`,
`source.commit`, and `verify.expected` in `src/data/skill.json` (cache-purge `/skill`, `/skill.json`, and `/skill.md`
against the Cloudflare cache-purge API after deploy).
**Release runbook entry.** The skill-release procedure lives in `RELEASES.md`. Each skill release bumps `version` in
`src/data/skill.json` if the manifest's user-facing fields changed (cache-purge `/skill`, `/skill.json`, and `/skill.md`
against the Cloudflare cache-purge API after deploy). Update detection at install sites is handled by the skill bundle's
`bin/check-update`, not by a manifest field.

### 3.10 CLI install — `/install`

Expand Down
23 changes: 13 additions & 10 deletions scripts/SYNCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ but not built*. Update this file whenever a sync script, workflow, endpoint, or

Existing top-level docs cover adjacent concerns but none give a single map:

- `RELEASES.md` documents the skill-release procedure (the downstream-facing `/skill.json` re-pin) and the deploy
- `RELEASES.md` documents the skill-release procedure (the downstream-facing `/skill.json` manifest bump) and the deploy
pipeline, but treats syncs as one step in a larger runbook.
- `docs/DESIGN.md` §3.9 / §3.10 cover the `/skill` and `/install` build contracts, not the cross-repo data flow.
- `AGENTS.md` describes endpoints and content authorship, not sync direction.
Expand Down Expand Up @@ -95,9 +95,9 @@ site-own version (`package.json` is `"0.0.0"` deliberately — the spec version

### Build-time vendoring by other repos

| Consumer | Mechanism | What's exported | Trigger / cadence | Drift check |
| ------------------------------------------------------------ | ---------------------------------------------------------------------------------- | ----------------------------- | --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `brettdavies/agentnative-cli` `src/skill_install/skill.json` | CLI's `scripts/sync-skill-fixture.sh` pulls from this repo's `src/data/skill.json` | Skill bundle metadata fixture | When this repo bumps `src/data/skill.json` (skill release re-pin per RELEASES.md §"Skill releases") | CLI's `skill-fixture-drift` GitHub Actions workflow runs the fixture's `--check` equivalent on every PR; CLI side fails if its vendored copy lags this repo. Effectively the inverse of the coverage-matrix arrangement: source-of-truth lives here, drift gate lives there. |
| Consumer | Mechanism | What's exported | Trigger / cadence | Drift check |
| ------------------------------------------------------------ | ---------------------------------------------------------------------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `brettdavies/agentnative-cli` `src/skill_install/skill.json` | CLI's `scripts/sync-skill-fixture.sh` pulls from this repo's `src/data/skill.json` | Skill bundle metadata fixture | When this repo bumps `src/data/skill.json` (skill release manifest bump per RELEASES.md §"Skill releases") | CLI's `skill-fixture-drift` GitHub Actions workflow runs the fixture's `--check` equivalent on every PR; CLI side fails if its vendored copy lags this repo. Effectively the inverse of the coverage-matrix arrangement: source-of-truth lives here, drift gate lives there. |

### Deploy-time emission to Cloudflare Workers

Expand Down Expand Up @@ -128,10 +128,13 @@ The four flows interact, but each is independently triggered:
for the workflow). Spec's `repository_dispatch:spec-release` event already fires here on tag publish; a consumer-side
handler that auto-PRs the resync is tracked as follow-up work.

4. **Skill repo cuts a release** → maintainer fast-forwards `agentnative-skill:main` to the new tag → edits this repo's
`src/data/skill.json` (`version`, `source.commit`, `verify.expected`) → PR to `dev` → release flow to `main` →
`wrangler deploy` updates `/skill.json` on `anc.dev` → Cloudflare cache purge → CLI's next PR exercises
`skill-fixture-drift` against the new fixture. Full runbook in `RELEASES.md` §"Skill-release procedure".
4. **Skill repo cuts a release** → maintainer fast-forwards `agentnative-skill:main` to the new tag → if any user-facing
manifest fields changed (per-host install commands, version, description), edits this repo's `src/data/skill.json` to
bump `version` plus the changed fields → PR to `dev` → release flow to `main` → `wrangler deploy` updates
`/skill.json` on `anc.dev` → Cloudflare cache purge → CLI's next PR exercises `skill-fixture-drift` against the new
fixture. If the release didn't change any manifest fields, skip the manifest bump entirely — installed users learn
about the new release via the skill bundle's `bin/check-update`, not via a manifest change here. Full runbook in
`RELEASES.md` §"Skill-release procedure".

5. **Site code/content change** → push to `dev` (auto-deploys to staging Worker) → PR `dev` → `main` → push to `main`
(auto-deploys to `anc.dev`).
Expand All @@ -145,8 +148,8 @@ The four flows interact, but each is independently triggered:
and runs `score-anc100.sh` inside the container, writing scorecards back to the host via bind mount. The container is
the single source of truth for scoring; host-side `regen-scorecards.sh` is deprecated.
- `src/data/spec/README.md` — what's vendored, why, and the manual reconciliation workflow when spec prose drifts.
- `RELEASES.md` §"Skill releases" — the downstream re-pin procedure for `src/data/skill.json` end-to-end (commit →
cache-purge → live verify).
- `RELEASES.md` §"Skill releases" — the downstream manifest-bump procedure for `src/data/skill.json` end-to-end
(manifest edit → cache-purge → live verify).
- `docs/DESIGN.md` §3.9 (`/skill` + `/skill.json` build contract) and §3.10 (`/install` HTML-only contract).
- `AGENTS.md` — repo conventions and the `content/principles/` vs `src/data/spec/principles/` separation rule.
- `docs/plans/2026-04-23-001-feat-sync-spec-plan.md` (dev branch only, gated off main) — the plan that introduced
Expand Down
Loading
Loading