From aafc040058a1d8d13c1921b4583bf99cb97e725c Mon Sep 17 00:00:00 2001 From: Brett Date: Wed, 29 Apr 2026 15:35:33 -0500 Subject: [PATCH 1/2] chore: drop SHA-pin claims and spec-vendor pinning vocabulary Eliminates all SHA-pin model claims and the SPEC_REF override surface. After this commit, `rg` for any of {SHA, sha-pin, commit sha, source.commit, install.json, re-pin, SPEC_REF, pin/pinned/pinning} across shipping content (excluding plans, license boilerplate, and changelogs) returns zero matches. Two coordinated cleanups, both serving the same goal: the install model is "plain git clone + bin/check-update for staleness," nothing pins to anything cross-repo, and the bundle's spec/ snapshot tracks the latest upstream tag automatically. 1. Install-pin claims removed from RELEASES.md + AGENTS.md: - RELEASES.md pipeline diagram: drop "site re-pins to commit SHA" - RELEASES.md post-merge step 5 (SHA handoff to site): replaced with a one-liner pointing at bin/check-update for consumer staleness - RELEASES.md protect-tags description: drop "install.json pins to" - AGENTS.md NEVER-do bullet: drop "install endpoints pin to" 2. Spec-vendor pinning eliminated entirely: - sync-spec.sh: drops SPEC_REF env var; always auto-resolves the latest v* tag from the local SPEC_ROOT checkout via `git tag --list 'v*' --sort=-version:refname | head -n 1`. SPEC_ROOT override still supported for non-default checkout locations. - AGENTS.md, README.md, spec/README.md, CONTRIBUTING.md: drop "at a pinned ref" / "at a pinned SPEC_REF" / "the pin and resync" / "the current pin is recorded" / "at a new SPEC_REF" prose. Spec version is recorded in spec/VERSION; that is the documented surface. Bundle behavior unchanged (consumers still get a spec/ snapshot; consumers still detect new releases via bin/check-update). Producer-side workflow simplified: no manual SPEC_REF bumps; running sync-spec.sh after a fetch is the entire recipe. --- AGENTS.md | 15 +++++++------- CONTRIBUTING.md | 2 +- README.md | 8 ++++---- RELEASES.md | 15 +++++++------- scripts/sync-spec.sh | 47 ++++++++++++++++++++++---------------------- spec/README.md | 15 +++++++------- 6 files changed, 51 insertions(+), 51 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 83ecfce..fb80c31 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,7 +23,7 @@ auto-discovers `SKILL.md` at the install root and ignores everything else. Produ | `references/` | ✓ | Implementation guidance: framework idioms (Rust + others), project structure, Rust/clap patterns. | | `templates/` | ✓ | Drop-in starter files for greenfield Rust CLIs (`clap-main.rs`, `error-types.rs`, `output-format.rs`, `agents-md-template.md`). | | `VERSION` | ✓ | Single-line current version. `bin/check-update` reads this for the upgrade comparison. | -| `scripts/sync-spec.sh` | — | Vendor `agentnative-spec` into `spec/` at a pinned `SPEC_REF`. Mirror of the agentnative-cli script. | +| `scripts/sync-spec.sh` | — | Vendor the latest `agentnative-spec` v\* tag into `spec/`. Mirror of the agentnative-cli script. | | `scripts/generate-changelog.sh` | — | Release-time CHANGELOG generator (git-cliff + PR-body extraction). | | `AGENTS.md`, `RELEASES.md`, `CONTRIBUTING.md`, `README.md`, `SECURITY.md` | — | Producer-repo docs. | | `.github/rulesets/` | — | Version-controlled GitHub repository rulesets. | @@ -46,15 +46,16 @@ tooling agree. ## Spec sync The canonical principle text lives in [`brettdavies/agentnative`](https://github.com/brettdavies/agentnative). This repo -vendors it via `scripts/sync-spec.sh` at a pinned `SPEC_REF`. To bump: +vendors the latest released `v*` tag via `scripts/sync-spec.sh`. To resync: ```bash -SPEC_REF=v0.3.0 scripts/sync-spec.sh # pulls from $HOME/dev/agentnative-spec by default -git diff spec/ # review +git -C $HOME/dev/agentnative-spec fetch --tags # pick up new upstream tags +scripts/sync-spec.sh # auto-resolves the latest v* tag locally +git diff spec/ # review ``` -Then commit the result with a message like `chore: bump spec to agentnative-spec@v0.3.0`. The current pin is recorded in -[`spec/README.md`](./spec/README.md) and the version itself is in `spec/VERSION`. +Then commit the result with a message like `chore: bump spec to agentnative-spec@`. The vendored version is +recorded in `spec/VERSION`. ## Branch + release model @@ -79,7 +80,7 @@ table. `release/*` branch — those paths are filtered by the cherry-pick pattern. Add to `dev` instead. - Modify `SKILL.md`'s `name` or `description` frontmatter without coordinating with consumers — those fields drive skill discovery on every host. -- Re-tag a published version. Tags are immutable historical anchors that the install endpoints pin to. +- Re-tag a published version. Tags are immutable historical anchors for released versions. - Add Rust/Cargo scaffolding. There is no Rust code in this repo and there should be none — the standard is language-prescriptive but the skill itself is markdown + a tiny bash update-check. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d4bb60a..4bb642e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -63,7 +63,7 @@ auto-discovers `SKILL.md` at the install root and ignores everything else. Produ ## Touching the skill content - **`spec/`** is vendored. Do not edit by hand. Substantive principle changes happen in `brettdavies/agentnative`; bring - them here by re-running `scripts/sync-spec.sh` at a new `SPEC_REF`. + them here by re-running `scripts/sync-spec.sh` after a new upstream tag lands. - **`SKILL.md`** is the host-discovered entry point. Changes to its `name` or `description` frontmatter affect skill discovery on every host — coordinate before changing. - **`getting-started.md`** is the agent's first read after `SKILL.md`. Keep it short and concrete; cite spec paths and diff --git a/README.md b/README.md index 7be30b5..fa72072 100644 --- a/README.md +++ b/README.md @@ -19,12 +19,12 @@ agentnative-skill/ ├── getting-started.md three working loops; canonical anc invocations ├── bin/ │ └── check-update consumer-side update-check script (gstack-style) -├── spec/ vendored from agentnative-spec at a pinned ref (do not edit) +├── spec/ vendored from agentnative-spec (do not edit) ├── references/ implementation guidance: framework idioms, project structure, Rust/clap patterns ├── templates/ drop-in starter files (clap-main, error-types, output-format, agents-md-template) ├── VERSION single-line current version (read by bin/check-update) ├── scripts/ -│ ├── sync-spec.sh vendor agentnative-spec into spec/ at a pinned ref +│ ├── sync-spec.sh vendor the latest agentnative-spec v* tag into spec/ │ └── generate-changelog.sh release-time CHANGELOG generator (git-cliff + PR-body extraction) ├── docs/plans/ engineering plans (dev-only — guarded out of main) ├── .github/ workflows, rulesets, issue templates, PR template @@ -60,8 +60,8 @@ prompted by `bin/check-update`. - [`bin/check-update`](./bin/check-update) — periodic version check. Compares local `VERSION` to GitHub `main`, emits `UPGRADE_AVAILABLE` so the agent can offer to `git pull`. - [`spec/`](./spec/) — vendored canonical principle text from - [`agentnative-spec`](https://github.com/brettdavies/agentnative). See [`spec/README.md`](./spec/README.md) for the pin - and resync procedure. **Do not edit by hand.** + [`agentnative-spec`](https://github.com/brettdavies/agentnative). See [`spec/README.md`](./spec/README.md) for the + resync procedure. **Do not edit by hand.** - [`references/`](./references/) — implementation guidance: framework idioms (Rust + others), project structure, Rust/clap patterns. Used when remediating `anc` findings. - [`templates/`](./templates/) — drop-in starting points for greenfield Rust CLIs (`clap-main.rs`, `error-types.rs`, diff --git a/RELEASES.md b/RELEASES.md index a09a556..db862b8 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -7,7 +7,7 @@ PR number in its squash commit message, which keeps the history scannable, attri feature branch (feat/*, fix/*, chore/*, docs/*) → PR to dev (squash merge) → cherry-pick non-docs commits to release/ → PR release/* to main (squash merge) - → tag v* on main → GitHub Release → site re-pins to commit SHA + → tag v* on main → GitHub Release ``` This is the canonical brettdavies release pattern with `release/*` cherry-pick branches. Plans live on `dev` forever and @@ -101,8 +101,7 @@ When the PR merges: --notes "$(awk '/^## \[\]/{flag=1; next} /^## \[/{flag=0} flag' CHANGELOG.md)" ``` -5. The site at `anc.dev/skill` re-pins via its own PR (separate repo, separate session). The handoff is the new commit - SHA plus a note if the bundle layout changed. +Consumers detect the new release on their next `bin/check-update` run; nothing else to do here. `dev` keeps moving forward. Never reset or rebase `dev` after a release — it is forever. @@ -137,10 +136,10 @@ flow above). There is no separate version-bump PR to `dev`. Picking the version - **Patch** — doc updates, internal cleanups, non-substantive template edits, vendoring a patch-level spec bump. - **Minor** — new templates, new reference docs, new bundle files (backward-compatible additions), vendoring a minor-level spec bump that adds requirements without tightening existing tiers. -- **Major** — breaking changes to the bundle's contract: renaming `SKILL.md` frontmatter fields, restructuring - directory layout in ways that break existing skill installations, moving content between `` and the - producer-ops root, or vendoring a major-level spec bump (renamed/removed principles or tightened MUSTs that would - regress existing consumers). +- **Major** — breaking changes to the bundle's contract: renaming `SKILL.md` frontmatter fields, restructuring directory + layout in ways that break existing skill installations, moving content between `` and the producer-ops root, or + vendoring a major-level spec bump (renamed/removed principles or tightened MUSTs that would regress existing + consumers). The skill's version is independent of the spec it vendors. A spec bump that doesn't affect the skill's surface (e.g., prose-only edits) can ship as a patch even when the spec went minor. Use the SemVer guidance above against the *skill's* @@ -171,7 +170,7 @@ Three rulesets are committed under `.github/rulesets/` and applied to the repo v - **`protect-dev.json`** — required signatures, deletion blocked, non-fast-forward blocked. No PR-requirement at the ruleset level; the PR-only norm is enforced by convention. - **`protect-tags.json`** — `v*` tags: deletion, force-push (re-tag), and updates all blocked. Tags are immutable - historical anchors that the site's `install.json` pins to. + historical anchors for released versions. ### Apply (post-public-flip) diff --git a/scripts/sync-spec.sh b/scripts/sync-spec.sh index 3637083..d1161ab 100755 --- a/scripts/sync-spec.sh +++ b/scripts/sync-spec.sh @@ -1,30 +1,29 @@ #!/usr/bin/env bash # Vendor agentnative-spec into spec/. # -# Extracts files at a pinned git ref via `git show :` so the user's -# spec working tree is not perturbed. The vendored tree ships as part of the -# skill bundle so consumers carry the canonical principle text alongside the +# Always vendors the latest v* tag found in the local spec checkout. +# Extracts files via `git show :` so the user's spec working +# tree is not perturbed. The vendored tree ships as part of the skill +# bundle so consumers carry the canonical principle text alongside the # skill metadata. # # Usage: # scripts/sync-spec.sh -# SPEC_REF=v0.2.1 scripts/sync-spec.sh # SPEC_ROOT=/path/to/agentnative-spec scripts/sync-spec.sh # # Env vars: # SPEC_ROOT Path to agentnative-spec checkout. Default: $HOME/dev/agentnative-spec -# SPEC_REF Git ref (tag, branch, or SHA) to vendor. Default: v0.2.0 # -# Resync cadence: rerun after every new agentnative-spec tag. Stale orphan -# files in spec/principles/ (e.g., from a spec rename) are accepted; -# `git status` surfaces them at commit time. +# Resync cadence: rerun after every new agentnative-spec tag. Run +# `git -C $SPEC_ROOT fetch --tags` first to pick up the new tag locally. +# Stale orphan files in spec/principles/ (e.g., from a spec rename) are +# accepted; `git status` surfaces them at commit time. # # Mirror of agentnative-cli/scripts/sync-spec.sh; only DEST_DIR differs. set -euo pipefail SPEC_ROOT="${SPEC_ROOT:-$HOME/dev/agentnative-spec}" -SPEC_REF="${SPEC_REF:-v0.2.0}" REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" DEST_DIR="$REPO_ROOT/spec" @@ -37,41 +36,43 @@ if [[ ! -d "$SPEC_ROOT/.git" ]]; then exit 1 fi -if ! git -C "$SPEC_ROOT" rev-parse --verify --quiet "$SPEC_REF^{commit}" >/dev/null; then - echo "error: SPEC_REF does not resolve to a commit in $SPEC_ROOT: $SPEC_REF" >&2 - echo " try \`git -C $SPEC_ROOT fetch --tags\` or check the ref name" >&2 +# Resolve the latest v* tag in the local spec checkout. +spec_tag="$(git -C "$SPEC_ROOT" tag --list 'v*' --sort='-version:refname' | head -n 1)" +if [[ -z "$spec_tag" ]]; then + echo "error: no v* tags found in $SPEC_ROOT" >&2 + echo " try \`git -C $SPEC_ROOT fetch --tags\` to pick up upstream tags" >&2 exit 1 fi -resolved_sha="$(git -C "$SPEC_ROOT" rev-parse --short=7 "$SPEC_REF^{commit}")" -echo "vendoring $SPEC_REF ($resolved_sha) from $SPEC_ROOT" +resolved_sha="$(git -C "$SPEC_ROOT" rev-parse --short=7 "$spec_tag^{commit}")" +echo "vendoring $spec_tag ($resolved_sha) from $SPEC_ROOT" -# Verify the principles/ tree exists at the ref. -if ! git -C "$SPEC_ROOT" cat-file -e "$SPEC_REF:principles" 2>/dev/null; then - echo "error: $SPEC_REF has no principles/ directory in $SPEC_ROOT" >&2 +# Verify the principles/ tree exists at the tag. +if ! git -C "$SPEC_ROOT" cat-file -e "$spec_tag:principles" 2>/dev/null; then + echo "error: $spec_tag has no principles/ directory in $SPEC_ROOT" >&2 exit 1 fi mkdir -p "$DEST_PRINCIPLES" # VERSION and CHANGELOG.md are top-level in the spec repo. -git -C "$SPEC_ROOT" show "$SPEC_REF:VERSION" >"$DEST_DIR/VERSION" -git -C "$SPEC_ROOT" show "$SPEC_REF:CHANGELOG.md" >"$DEST_DIR/CHANGELOG.md" +git -C "$SPEC_ROOT" show "$spec_tag:VERSION" >"$DEST_DIR/VERSION" +git -C "$SPEC_ROOT" show "$spec_tag:CHANGELOG.md" >"$DEST_DIR/CHANGELOG.md" -# Enumerate principle files at the ref and extract each one. +# Enumerate principle files at the tag and extract each one. copied=0 while IFS= read -r path; do case "$path" in principles/p*-*.md) dest_name="${path#principles/}" - git -C "$SPEC_ROOT" show "$SPEC_REF:$path" >"$DEST_PRINCIPLES/$dest_name" + git -C "$SPEC_ROOT" show "$spec_tag:$path" >"$DEST_PRINCIPLES/$dest_name" copied=$((copied + 1)) ;; esac -done < <(git -C "$SPEC_ROOT" ls-tree --name-only "$SPEC_REF" principles/) +done < <(git -C "$SPEC_ROOT" ls-tree --name-only "$spec_tag" principles/) if [[ "$copied" -eq 0 ]]; then - echo "error: no principles/p*-*.md files found at $SPEC_REF" >&2 + echo "error: no principles/p*-*.md files found at $spec_tag" >&2 exit 1 fi diff --git a/spec/README.md b/spec/README.md index 6bd5263..f437ce9 100644 --- a/spec/README.md +++ b/spec/README.md @@ -1,22 +1,21 @@ # Vendored agentnative-spec This directory is a **vendored copy** of [`brettdavies/agentnative`](https://github.com/brettdavies/agentnative) — the -canonical specification of agent-native CLI principles. Files here are not edited by hand; they are mirrored from an -upstream tag and ship inside the skill bundle so consumers carry the canonical principle text alongside the skill -metadata. Each release of this bundle re-vendors against the latest spec tag. - -**Current snapshot:** `v0.2.0` +canonical specification of agent-native CLI principles. Files here are not edited by hand; they are mirrored from the +latest upstream `v*` tag and ship inside the skill bundle so consumers carry the canonical principle text alongside the +skill metadata. Each release of this bundle re-vendors against the latest spec tag. The currently vendored version is +recorded in [`VERSION`](./VERSION). ## Resync Run from the repo root: ```bash -scripts/sync-spec.sh # default: SPEC_REF=v0.2.0 -SPEC_REF=v0.2.1 scripts/sync-spec.sh # bump to a newer tag +git -C $HOME/dev/agentnative-spec fetch --tags # pick up new upstream tags first +scripts/sync-spec.sh # auto-resolves the latest v* tag ``` -The script extracts files at the named git ref via `git show`, so the spec checkout's working tree is not perturbed. +The script extracts files at the resolved tag via `git show`, so the spec checkout's working tree is not perturbed. Override `SPEC_ROOT` if your spec checkout is not at `$HOME/dev/agentnative-spec`. ## Layout From 26091ae7cbbe4b1af92ccf070a7f7d6fce9b26cf Mon Sep 17 00:00:00 2001 From: Brett Date: Wed, 29 Apr 2026 15:58:25 -0500 Subject: [PATCH 2/2] chore(sync-spec): query remote first, fall back to local checkout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sync-spec.sh now resolves the latest v* tag from a remote URL (SPEC_REMOTE_URL, default https://github.com/brettdavies/agentnative.git) via `git ls-remote --tags --sort=-version:refname`, then shallow-clones that tag into a temp directory for extraction. If the remote query fails (network down, URL wrong, server error), the script falls back to the local SPEC_ROOT-based logic from the previous commit. Three execution paths verified: - Remote OK → "vendoring v0.3.0 (5cea8bf) from remote https://...git" - Remote fail → "warning: remote query failed; falling back to local /home/.../agentnative-spec" then proceeds with local tag resolution - Both fail → hard error with both URL and SPEC_ROOT printed Cleanup: temp clone directory is removed on script exit (any path), guarded by a trap so half-successful clones don't leak. Doc updates: - AGENTS.md "Spec sync" section: drop the manual `git fetch --tags` step (remote query is the new happy path); add SPEC_REMOTE_URL override. - spec/README.md "Resync" section: same. Behavior unchanged for the pure-local invocation: SPEC_ROOT still works exactly as before, just as a fallback rather than the primary source. --- AGENTS.md | 8 ++-- scripts/sync-spec.sh | 101 ++++++++++++++++++++++++++++++------------- spec/README.md | 9 ++-- 3 files changed, 81 insertions(+), 37 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index fb80c31..3361655 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -49,13 +49,13 @@ The canonical principle text lives in [`brettdavies/agentnative`](https://github vendors the latest released `v*` tag via `scripts/sync-spec.sh`. To resync: ```bash -git -C $HOME/dev/agentnative-spec fetch --tags # pick up new upstream tags -scripts/sync-spec.sh # auto-resolves the latest v* tag locally -git diff spec/ # review +scripts/sync-spec.sh # queries the remote first; falls back to $HOME/dev/agentnative-spec if offline +git diff spec/ # review ``` Then commit the result with a message like `chore: bump spec to agentnative-spec@`. The vendored version is -recorded in `spec/VERSION`. +recorded in `spec/VERSION`. Override `SPEC_REMOTE_URL` to query a different remote, or `SPEC_ROOT` to point at a +non-default local checkout. ## Branch + release model diff --git a/scripts/sync-spec.sh b/scripts/sync-spec.sh index d1161ab..bd1a949 100755 --- a/scripts/sync-spec.sh +++ b/scripts/sync-spec.sh @@ -1,21 +1,28 @@ #!/usr/bin/env bash # Vendor agentnative-spec into spec/. # -# Always vendors the latest v* tag found in the local spec checkout. -# Extracts files via `git show :` so the user's spec working -# tree is not perturbed. The vendored tree ships as part of the skill -# bundle so consumers carry the canonical principle text alongside the -# skill metadata. +# Resolves the latest v* tag of agentnative-spec, preferring the remote +# repository, and falls back to a local checkout if the remote is +# unreachable. Extracts files via `git show :` so neither +# checkout's working tree is perturbed. The vendored tree ships as part +# of the skill bundle so consumers carry the canonical principle text +# alongside the skill metadata. # # Usage: # scripts/sync-spec.sh # SPEC_ROOT=/path/to/agentnative-spec scripts/sync-spec.sh +# SPEC_REMOTE_URL=git@github.com:brettdavies/agentnative.git scripts/sync-spec.sh # # Env vars: -# SPEC_ROOT Path to agentnative-spec checkout. Default: $HOME/dev/agentnative-spec +# SPEC_REMOTE_URL Remote URL to query first. +# Default: https://github.com/brettdavies/agentnative.git +# SPEC_ROOT Local checkout to fall back to when the remote is +# unreachable. Default: $HOME/dev/agentnative-spec +# +# Resync cadence: rerun after every new agentnative-spec tag. The remote +# query picks up new tags automatically; a local fallback only sees what +# the local checkout already has fetched. # -# Resync cadence: rerun after every new agentnative-spec tag. Run -# `git -C $SPEC_ROOT fetch --tags` first to pick up the new tag locally. # Stale orphan files in spec/principles/ (e.g., from a spec rename) are # accepted; `git status` surfaces them at commit time. # @@ -23,41 +30,77 @@ set -euo pipefail +SPEC_REMOTE_URL="${SPEC_REMOTE_URL:-https://github.com/brettdavies/agentnative.git}" SPEC_ROOT="${SPEC_ROOT:-$HOME/dev/agentnative-spec}" REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" DEST_DIR="$REPO_ROOT/spec" DEST_PRINCIPLES="$DEST_DIR/principles" -if [[ ! -d "$SPEC_ROOT/.git" ]]; then - echo "error: SPEC_ROOT is not a git repository: $SPEC_ROOT" >&2 - echo " set SPEC_ROOT to your agentnative-spec checkout, or clone it to the default" >&2 - echo " location: \$HOME/dev/agentnative-spec" >&2 - exit 1 -fi +# Cleanup hook for the temp clone (set only after mktemp succeeds). +tmp_root="" +cleanup() { + if [[ -n "$tmp_root" && -d "$tmp_root" ]]; then + rm -rf "$tmp_root" + fi +} +trap cleanup EXIT -# Resolve the latest v* tag in the local spec checkout. -spec_tag="$(git -C "$SPEC_ROOT" tag --list 'v*' --sort='-version:refname' | head -n 1)" -if [[ -z "$spec_tag" ]]; then - echo "error: no v* tags found in $SPEC_ROOT" >&2 - echo " try \`git -C $SPEC_ROOT fetch --tags\` to pick up upstream tags" >&2 - exit 1 +# === Remote-first resolution =========================================== +spec_source="" +spec_tag="" + +echo "querying $SPEC_REMOTE_URL for latest v* tag..." +remote_tag="$(git ls-remote --tags --sort='-version:refname' \ + "$SPEC_REMOTE_URL" 'refs/tags/v*' 2>/dev/null \ + | awk '{print $2}' \ + | sed 's|refs/tags/||' \ + | grep -v '\^{}$' \ + | head -n 1 || true)" + +if [[ -n "$remote_tag" ]]; then + tmp_root="$(mktemp -d -t agentnative-spec-XXXXXX)" + if git clone --depth 1 --branch "$remote_tag" --quiet \ + "$SPEC_REMOTE_URL" "$tmp_root" 2>/dev/null; then + spec_source="$tmp_root" + spec_tag="$remote_tag" + resolved_sha="$(git -C "$spec_source" rev-parse --short=7 "$spec_tag^{commit}")" + echo "vendoring $spec_tag ($resolved_sha) from remote $SPEC_REMOTE_URL" + fi fi -resolved_sha="$(git -C "$SPEC_ROOT" rev-parse --short=7 "$spec_tag^{commit}")" -echo "vendoring $spec_tag ($resolved_sha) from $SPEC_ROOT" +# === Local fallback ==================================================== +if [[ -z "$spec_source" ]]; then + if [[ ! -d "$SPEC_ROOT/.git" ]]; then + echo "error: remote unreachable and SPEC_ROOT is not a git repository: $SPEC_ROOT" >&2 + echo " remote: $SPEC_REMOTE_URL" >&2 + echo " set SPEC_ROOT to your agentnative-spec checkout, or check network access." >&2 + exit 1 + fi + echo "warning: remote query failed; falling back to local $SPEC_ROOT" >&2 + + spec_source="$SPEC_ROOT" + spec_tag="$(git -C "$spec_source" tag --list 'v*' --sort='-version:refname' | head -n 1)" + if [[ -z "$spec_tag" ]]; then + echo "error: no v* tags found in $SPEC_ROOT" >&2 + echo " try \`git -C $SPEC_ROOT fetch --tags\` to pick up upstream tags" >&2 + exit 1 + fi + resolved_sha="$(git -C "$spec_source" rev-parse --short=7 "$spec_tag^{commit}")" + echo "vendoring $spec_tag ($resolved_sha) from local $spec_source" +fi -# Verify the principles/ tree exists at the tag. -if ! git -C "$SPEC_ROOT" cat-file -e "$spec_tag:principles" 2>/dev/null; then - echo "error: $spec_tag has no principles/ directory in $SPEC_ROOT" >&2 +# === Verify + extract (works identically for remote and local sources) = +if ! git -C "$spec_source" cat-file -e "$spec_tag:principles" 2>/dev/null; then + echo "error: $spec_tag has no principles/ directory in $spec_source" >&2 exit 1 fi mkdir -p "$DEST_PRINCIPLES" # VERSION and CHANGELOG.md are top-level in the spec repo. -git -C "$SPEC_ROOT" show "$spec_tag:VERSION" >"$DEST_DIR/VERSION" -git -C "$SPEC_ROOT" show "$spec_tag:CHANGELOG.md" >"$DEST_DIR/CHANGELOG.md" +git -C "$spec_source" show "$spec_tag:VERSION" >"$DEST_DIR/VERSION" +git -C "$spec_source" show "$spec_tag:CHANGELOG.md" >"$DEST_DIR/CHANGELOG.md" # Enumerate principle files at the tag and extract each one. copied=0 @@ -65,11 +108,11 @@ while IFS= read -r path; do case "$path" in principles/p*-*.md) dest_name="${path#principles/}" - git -C "$SPEC_ROOT" show "$spec_tag:$path" >"$DEST_PRINCIPLES/$dest_name" + git -C "$spec_source" show "$spec_tag:$path" >"$DEST_PRINCIPLES/$dest_name" copied=$((copied + 1)) ;; esac -done < <(git -C "$SPEC_ROOT" ls-tree --name-only "$spec_tag" principles/) +done < <(git -C "$spec_source" ls-tree --name-only "$spec_tag" principles/) if [[ "$copied" -eq 0 ]]; then echo "error: no principles/p*-*.md files found at $spec_tag" >&2 diff --git a/spec/README.md b/spec/README.md index f437ce9..5a18373 100644 --- a/spec/README.md +++ b/spec/README.md @@ -11,12 +11,13 @@ recorded in [`VERSION`](./VERSION). Run from the repo root: ```bash -git -C $HOME/dev/agentnative-spec fetch --tags # pick up new upstream tags first -scripts/sync-spec.sh # auto-resolves the latest v* tag +scripts/sync-spec.sh # queries the remote for the latest v* tag; falls back to local on network failure ``` -The script extracts files at the resolved tag via `git show`, so the spec checkout's working tree is not perturbed. -Override `SPEC_ROOT` if your spec checkout is not at `$HOME/dev/agentnative-spec`. +The script queries `https://github.com/brettdavies/agentnative.git` for the latest `v*` tag and shallow-clones that tag +into a temp directory for extraction. If the remote is unreachable, it falls back to a local checkout +(`$HOME/dev/agentnative-spec` by default; override with `SPEC_ROOT`). Override `SPEC_REMOTE_URL` to query a different +remote. The script extracts files via `git show`, so neither source's working tree is perturbed. ## Layout