agentleFS
fagemxfagemx/edda/.claude/skills/edda-release/SKILL.md

edda-release

Skill36 starsChanged 2 months agoApache-2.0View on GitHub

Release Edda across crates.io, GitHub assets, install.sh, and Homebrew without channel drift

  • Installs packages
  • Commits and pushes

The file

Show its rules and text

We split this skill into the rules it gives an agent

29 rules. About 0 are common, 14 are distinctive, and 15 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈14

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 15

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    If the operation or version is missing, ask for it.

    line 41
  2. Very specific:

    Default compatible fixes and features to the next patch release: after 0.6.0, prefer 0.6.1, 0.6.2, and so on.

    line 47
  3. Very specific:

    Use a new 0.x minor only for a named cohesive milestone or an intentional breaking public CLI, config, ledger, or migration contract.

    line 49
  4. Distinctive:

    After 1.0, return to ordinary SemVer: compatible features bump minor and breaking changes bump major.

    line 55
  5. Distinctive:

    Before proposing a number, read the release range:

    line 58
  6. Distinctive:

    Treat any version or behavior mismatch among them as a release blocker.

    line 73
  7. Very specific:

    Never print or read credential contents.

    line 94
  8. Very specific:

    Read AGENTS.md and .claude/CLAUDE.md completely, then inspect the actual install promises and release automation:

    line 102
  9. Distinctive:

    Treat an absent secret as BLOCKED before pushing anything.

    line 120
  10. Very specific:

    Follow the L0/L1/L2 verification ladder in .claude/CLAUDE.md.

    line 172
  11. Very specific:

    Run repository-root REVIEW.md top to bottom for the prep PR.

    line 201
  12. Very specific:

    Use a freshly built edda that contains the current review deliver surface.

    line 214
  13. Distinctive:

    After merge, freeze the squash/merge commit and wait for that exact main push CI to go green.

    line 219
  14. Distinctive:

    Create the annotated tag locally, then run the plan gate inside a detached tag worktree.

    line 225
  15. Very specific:

    Use the detached worktree for later publish-crates.py verify too.

    line 244
  16. Distinctive:

    Never repair a failed run by moving the tag.

    line 285
  17. Very specific:

    Use a fresh Cargo home and install root.

    line 289
  18. Distinctive:

    Do not declare DONE until this unversioned install canary passes.

    line 305
  19. Very specific:

    Run the one-line installer twice in disposable directories: once pinned and once through its default “latest” path.

    line 309
  20. Very specific:

    After crates.io publication is verified, generate the Homebrew formula from the immutable crates.io source package.

    line 341
  21. Distinctive:

    Commit and push the tap formula only after its diff names the intended static crates.io URL, source hash, and build dependencies.

    line 384
  22. Distinctive:

    Run the public half of the workflow without changing remote state:

    line 423
  23. Distinctive:

    Use the decision table below, then resume at the earliest missing safe step.

    line 452
  24. Very specific:

    Root crate only: all publishable workspace crates must reach crates.io in dependency order — enforced by publish-crates.py and the parity …

    line 480
  25. Very specific:

    Local artifact trust: verify downloaded registry provenance and public install behavior, not only target/release/edda.

    line 482
  26. Distinctive:

    Credential improvisation: never echo tokens or edit repository secrets without explicit authorization.

    line 486
  27. Distinctive:

    Destructive recovery: never yank, delete, recreate, or force-move public release identity as an automatic recovery step.

    line 488
  28. Very specific:

    Manual publication drift: do not run cargo publish locally.

    line 490
  29. Very specific:

    Race toward 1.0: do not bump 0.x minor merely because the range contains feat: commits.

    line 502

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Edda Release

You are Edda's release operator. A release is complete only when every install path advertised in README.md gives users the intended version and its release-critical commands. A GitHub Release alone is not success.

Since GH-648 (PR #847) the repository automates crates.io publication inside .github/workflows/release.yml: pushing the v<VERSION> tag makes CI publish every workspace crate in dependency order, verify registry provenance against the tag SHA, and only then create the GitHub Release. The workflow, not this skill, owns two distribution invariants: both Linux architectures build inside an Ubuntu 22.04 userspace and reject requirements above GLIBC_2.35, and every checksum sidecar is one exact ASCII line ending in LF. This skill explains and re-verifies those gates; prose is never a substitute for enforcing them in CI. Your job shifts from uploading crates to proving the release before the tag push and proving the public channels after CI is green.

Usage

edda-release preflight <version>
edda-release publish <version>
edda-release verify <version>
edda-release recover <version>

Parse args as an operation plus a bare semantic version such as 0.4.1. Reject a leading v in the version argument; derive the tag as v<version>.

  • preflight: read-only release readiness and exact-SHA package proof
  • publish: run the preflight, push the tag, watch CI, then prove every advertised channel
  • verify: read-only public consumer canaries and parity report
  • recover: inspect a partial release, then resume only missing safe steps

If the operation or version is missing, ask for it. Never guess a version.

Version selection — preserve runway before 1.0

Edda uses this operator-approved slow pre-1.0 cadence:

  • Default compatible fixes and features to the next patch release: after 0.6.0, prefer 0.6.1, 0.6.2, and so on.
  • Use a new 0.x minor only for a named cohesive milestone or an intentional breaking public CLI, config, ledger, or migration contract. A feat: commit alone does not force a minor bump.
  • 1.0.0 requires an explicit operator decision that the supported CLI/API, stored-data migration policy, compatibility floor, and all advertised install channels are stable enough to carry a long-lived compatibility promise.
  • After 1.0, return to ordinary SemVer: compatible features bump minor and breaking changes bump major.

Before proposing a number, read the release range:

git tag --sort=-version:refname | head -5
git log --oneline "v<PREVIOUS>..origin/main"

The operator still names the release version. Surface a mismatch with this policy, but never silently substitute another number and never infer a bump from Conventional Commit prefixes alone.

Non-negotiable invariant

The public contract is the README.md Install section. At present it advertises four surfaces: install.sh, Homebrew, crates.io, and GitHub release assets. Treat any version or behavior mismatch among them as a release blocker.

For crates.io, “published” means all publishable workspace crates at the exact version are visible, unyanked, carry the frozen tag SHA in .cargo_vcs_info.json, and a plain unversioned cargo install edda works.

The crates.io-before-GitHub-Release ordering is enforced by CI: the create-release job runs python3 scripts/publish-crates.py verify --tag and fails unless every publishable crate exists unyanked at the tag version. Do not re-implement that gate manually — verify it ran.

Authority boundary

  • preflight and verify are read-only except for disposable build/canary directories.
  • An explicit publish <version> request authorizes pushing the v<VERSION> tag — which triggers CI publication to crates.io and the release workflow — plus the follow-up public canaries.
  • It does not authorize yanking a crate, deleting or replacing a tag/release, force-pushing, editing or creating repository secrets, copying credentials, or merging a PR. Ask separately before any of those actions.
  • Never print or read credential contents. Check only whether the CARGO_REGISTRY_TOKEN secret is configured and whether Cargo authentication is available locally.

Common ground truth

Step 1: Read repository policy and distribution reality

Read AGENTS.md and .claude/CLAUDE.md completely, then inspect the actual install promises and release automation:

rg -n "cargo install|brew install|releases|install.sh" README.md
git status --short --branch
git fetch origin main --tags
git rev-parse HEAD
git ls-remote --tags origin \
  "refs/tags/v<VERSION>" "refs/tags/v<VERSION>^{}"
gh release view "v<VERSION>" --repo fagemx/edda
gh api repos/fagemx/edda/releases/latest --jq .tag_name
gh secret list --repo fagemx/edda

gh secret list must show CARGO_REGISTRY_TOKEN. Without that secret, prepare-crates skips crates publication and every downstream GitHub Release job while the workflow run still looks green — a silent no-op release. Treat an absent secret as BLOCKED before pushing anything.

Preserve unrelated changes. Release from a clean commit on current origin/main unless the operator explicitly names another full SHA. For an annotated tag, the first ls-remote hash is the tag object, not the release commit; the receipt's Tag SHA is the peeled ^{} / git rev-list -n 1 commit.

Step 2: Freeze version, SHA, docs, and verification evidence

Require all workspace packages, Cargo.lock, CHANGELOG.md, and the CLI docs to describe the same version. release.yml extracts release notes from a CHANGELOG heading that starts exactly with ## [<VERSION>] — a missing section fails create-release after publication and cannot be repaired without moving the tag, so it must exist before the push.

rg -n '^version = "' Cargo.toml          # workspace version == <VERSION>
rg -n "^## \[<VERSION>\]" CHANGELOG.md    # release-notes section exists
<EDDA_BIN> --version                     # must be the just-bumped version
rg -n '^> Documented for edda ' docs/reference/cli.md
EDDA_BIN=<EDDA_BIN> bash scripts/check-cli-docs.sh
  • check-cli-docs.sh (GH-650/GH-795) is the CLI reference drift gate: it verifies the documented major/minor version, every verb, and every long flag in docs/reference/cli.md against the built binary. Build <EDDA_BIN> after the version bump from the candidate commit; a warm binary from the previous release can pass the verb/flag checks while hiding a stale Documented for edda 0.x heading. The old check_cli_reference.py no longer exists.
  • Package-version parity against the tag is enforced mechanically by publish-crates.py plan in Step 3, once the local tag exists. Version bump checklist (every release — do this before the CHANGELOG edit):
rg -n '^version = "' Cargo.toml                 # workspace version -> <VERSION>
rg '"<OLD>"' crates/*/Cargo.toml                # internal dependency pins
sed -i 's/"<OLD>"/"<VERSION>"/g' crates/*/Cargo.toml
cargo update -w                                  # fails until every pin matches

Crate manifests pin internal dependencies with explicit versions, so bumping only the workspace version makes cargo update -w fail with "candidate versions found which didn't match". Update every pin, resync the lock, and move the [Unreleased] CHANGELOG entries into a ## [<VERSION>] - <date> section (release.yml's awk extracts exactly that heading for release notes).

An empty [Unreleased] is not evidence that there is nothing to release. When git log v<PREVIOUS>..HEAD is non-empty, reconstruct release notes from the whole frozen range, group user-visible changes under Added/Changed/Fixed/Docs, and cross-check every summarized GH/PR reference against the commit subjects. Empty notes with a non-empty release range are BLOCKED until reconciled.

  • Follow the L0/L1/L2 verification ladder in .claude/CLAUDE.md. Reuse a valid L1 receipt and exact-head CI for the frozen full SHA. Do not rerun the full workspace merely to feel safer; run only uncovered focused checks and state why.

Step 3: Commit the prep, prove packaging, then carry it through the ruleset-gated PR

Two ordering facts the flow depends on: cargo package refuses a dirty tree (commit the prep first, then package from the clean release commit), and main is protected by the repository ruleset (Protect main: pull-request rule + required CI Gate); the SHA-pinned independent verdict is additionally bound by scripts/merge-reviewed-pr.sh. Direct pushes are declined, so the prep travels on a branch.

git checkout -b chore/release-prep-v<VERSION>
git commit -m "chore(release): prepare v<VERSION>"    # hooks run L0
cargo package --workspace --locked --no-verify
cargo publish --dry-run --workspace --locked          # must reach "Uploading edda"
python .claude/skills/edda-release/scripts/test_crates_release_plan.py
python .claude/skills/edda-release/scripts/crates_release_plan.py \
  --version <VERSION> --package-dir target/package --expected-sha <FULL_SHA>

The skill-local helper proves each generated .crate carries the clean release commit in .cargo_vcs_info.json. Later, publish-crates.py plan --tag proves tag shape, package-version parity, metadata, and dependency order; neither proof substitutes for the other.

Run repository-root REVIEW.md top to bottom for the prep PR. It and .claude/CLAUDE.md exclusively own issue/spec acceptance, Decision lines, reviewer independence, gate selection, §7 comments, response rounds, and merge authority; do not restate or weaken those rules here. After the final current-head §7 LGTM is visible, settle its union and run the merge check:

edda review deliver --pr <PR> --sha <FULL_SHA>
sh scripts/merge-reviewed-pr.sh <PR>             # check only
# only with explicit operator merge authority:
sh scripts/merge-reviewed-pr.sh <PR> --merge

Use a freshly built edda that contains the current review deliver surface; a stale global binary fails closed with an unknown-subcommand or unreadable union. Record <EDDA_BIN> --version and put its directory first on PATH for the merge helper when necessary.

After merge, freeze the squash/merge commit and wait for that exact main push CI to go green. That run is the tag target's receipt. If origin/main advances again, do not silently include the later commits or move the frozen target: keep the reviewed SHA only when it is still an ancestor and the release scope was already frozen; otherwise ask the operator.

Create the annotated tag locally, then run the plan gate inside a detached tag worktree. This avoids failure when the primary checkout has advanced beyond the frozen tag. The gate requires HEAD to equal the tag commit on a clean tree, validates the tag shape, and prints dependency-first order (python instead of python3 on Windows):

git fetch origin main --tags
git merge-base --is-ancestor <FULL_SHA> origin/main
git tag -a "v<VERSION>" <FULL_SHA> -m "Release v<VERSION>"
git rev-list -n 1 "v<VERSION>"                  # receipt SHA
git worktree add --detach <TEMP_WORKTREE> "v<VERSION>"
(
  cd <TEMP_WORKTREE>
  python3 scripts/publish-crates.py plan --tag "v<VERSION>"
  python3 scripts/publish-crates-test.py
)

Use the detached worktree for later publish-crates.py verify too. Use its default target/; do not invent timestamped Cargo target lanes.

preflight stops here and reports evidence. Remove only the exact disposable worktree after verifying its resolved path.

Operation: publish

Step 1: Push the tag — the single mutation point

The tag push is what publishes crates.io. Everything before it (preflight) is the only chance to catch package defects; publication itself is irreversible.

git push origin "refs/tags/v<VERSION>"
gh run list --workflow release.yml --branch "v<VERSION>" --limit 5
gh run watch <RUN_ID> --exit-status

Step 2: Verify every CI job did its job

Require all five logical stages green — currently nine concrete jobs because build-linux-release and build-non-linux-release expand to five legs total. A green aggregate with a skipped required stage or leg is BLOCKED. Read conclusion and each job result; do not classify arbitrary warning/error-looking lines from gh run watch output as a workflow failure:

gh run view <RUN_ID> --json conclusion,jobs \
  --jq '.conclusion, (.jobs[] | [.name,.conclusion] | @tsv)'
StageRequirement
prepare-cratesenabled=true (secret present); tag/plan validation passed
publish-cratesSUCCESS: all <N> workspace versions verified
create-releaseparity gate verify --tag passed; draft release created from the CHANGELOG section
build-linux-release + build-non-linux-release (5 jobs total)every platform leg green; Linux x86_64/aarch64 built in Ubuntu 22.04, ABI cap and critical CLI canaries passed; all five archives + .sha256 uploaded to the draft
publish-releaseexact 10-asset set, no empty assets, each checksum sidecar is exact ASCII+LF and matches its archive, native binary canary without credentials (version core after stripping the optional build identity suffix), release published --latest

Never repair a failed run by moving the tag.

Step 3: Prove the README Cargo path

Use a fresh Cargo home and install root. Run exactly the public command without --version, --git, --path, or --locked:

cargo install edda --root <FRESH_ROOT>
<FRESH_ROOT>/bin/edda --version
<FRESH_ROOT>/bin/edda dispatch --help
<FRESH_ROOT>/bin/edda verdict --help

The version core must equal <VERSION>; a registry build may legitimately print an optional identity suffix such as (unknown). On Windows, retry once with --jobs 1 only when rustc itself exits with an OS crash/resource signature such as 0xc0000005. A Rust compiler diagnostic, test failure, missing native library, or wrong CLI behavior is a product failure and must not be relabeled flaky.

Do not declare DONE until this unversioned install canary passes.

Step 4: Prove install.sh and Homebrew

Run the one-line installer twice in disposable directories: once pinned and once through its default “latest” path. The option is --to, not --prefix. The installer supports Linux/macOS shells, not Windows MINGW; on a Windows workstation use Ubuntu WSL and perform install plus all canaries in the same invocation so a WSL restart cannot clear /tmp between steps.

curl -sSf https://raw.githubusercontent.com/fagemx/edda/v<VERSION>/install.sh \
  | sh -s -- --version v<VERSION> --to <PINNED_DIR>/bin
<PINNED_DIR>/bin/edda --version
<PINNED_DIR>/bin/edda dispatch --help
<PINNED_DIR>/bin/edda verdict --help
curl -sSf https://raw.githubusercontent.com/fagemx/edda/main/install.sh \
  | sh -s -- --to <LATEST_DIR>/bin
<LATEST_DIR>/bin/edda --version
<LATEST_DIR>/bin/edda dispatch --help
<LATEST_DIR>/bin/edda verdict --help

Both binaries must report the intended version. The release-asset compatibility baseline is Ubuntu 22.04: CI builds both Linux architectures inside that userspace and rejects a highest readelf --version-info requirement above GLIBC_2.35. Post-publication verification must still download the public asset, run it on Ubuntu 22.04, and report its observed highest GLIBC_x.y; checking the build directory or trusting the runner label is insufficient. An asset that fails there is a product failure, never an environmental retry.

Download all ten public assets and run GNU sha256sum -c against every sidecar. A sidecar containing CRLF, a missing final LF, extra lines, a non-ASCII payload, or anything other than <64 lowercase hex><two spaces><archive>\n is a distribution failure even when the digest value itself is correct.

After crates.io publication is verified, generate the Homebrew formula from the immutable crates.io source package. The generator downloads and hashes the .crate itself and emits a source-build formula; do not point Linuxbrew back at a GitHub binary built on ubuntu-latest, because its glibc floor can exceed the Homebrew host's:

sh scripts/test-update-homebrew.sh
./scripts/update-homebrew.sh <VERSION> <HOME_BREW_TAP_CHECKOUT>
brew audit --strict fagemx/tap/edda
brew install fagemx/tap/edda       # required before reinstall in a fresh verifier
edda --version
edda dispatch --help
edda verdict --help
brew reinstall fagemx/tap/edda
brew test fagemx/tap/edda

The generated formula must use the static crates.io .crate URL and declare pkgconf/Rust build dependencies plus openssl@3; the crates.io API redirect may return HTTP 403 to Homebrew curl, so do not replace the static URL with /api/v1/crates/.../download.

On Windows, the official disposable homebrew/brew:latest Docker image is a valid Linuxbrew verifier. Tap the remote public tap, pin its Git HEAD in the receipt, and run strict audit, install, reinstall, both CLI help canaries, and brew test in one container:

docker run --rm homebrew/brew:latest bash -lc '
  set -euo pipefail
  brew tap fagemx/tap
  brew audit --strict fagemx/tap/edda
  brew install fagemx/tap/edda
  edda --version && edda dispatch --help >/dev/null && edda verdict --help >/dev/null
  brew reinstall fagemx/tap/edda
  brew test fagemx/tap/edda
'

A local formula mount is suitable while iterating but is not the final public-channel proof.

Commit and push the tap formula only after its diff names the intended static crates.io URL, source hash, and build dependencies. If neither a native macOS/Linux verifier nor the official Docker verifier is available, report DONE_WITH_CONCERNS with the missing public canary.

Step 5: Record the release receipt

Pin every claim to the tag's full SHA. Use this exact output structure:

## Edda Release v<VERSION>

Status: DONE | DONE_WITH_CONCERNS | BLOCKED
Tag SHA: <40-hex>

| Surface | Evidence | Result |
|---|---|---|
| Workspace packages | <N>, version parity (plan ORDER) | PASS/FAIL |
| Preflight package proof | dry-run publish + local provenance SHA | PASS/FAIL |
| Release workflow | run URL, 5 stages / 9 concrete jobs green, none required skipped | PASS/FAIL |
| crates.io | <N> visible and unyanked | PASS/FAIL |
| crates.io provenance | CI VERIFIED lines / verify --tag SHA match | PASS/FAIL |
| cargo install edda | resolved version + critical help canaries | PASS/FAIL |
| GitHub Release | latest endpoint == tag, 10 assets, checksums, native canary | PASS/FAIL |
| install.sh | pinned + latest version canaries | PASS/FAIL |
| Linux asset ABI | documented/minimum baseline + observed glibc floor | PASS/FAIL/NOT RUN |
| Homebrew | remote tap commit + strict audit/install/reinstall/test canaries | PASS/FAIL/NOT RUN |

Failures/retries: <exact command, classification, result>
Remaining action: <none or one concrete next action>

Persist the receipt on the release tracking issue (or the strongest PR-visible carrier when no release issue exists), then write an edda note containing the status, tag commit, workflow run, tap commit, and remaining action. A chat-only receipt is not durable evidence.

Operation: verify

Run the public half of the workflow without changing remote state:

  1. From the tag worktree, python3 scripts/publish-crates.py verify --tag "v<VERSION>" — read-only all-crate registry and provenance proof.
  2. Repeat the fresh unversioned Cargo canary.
  3. Inspect the exact GitHub Actions run (five stages / nine concrete jobs, none required skipped), release assets, and checksums; require gh api repos/fagemx/edda/releases/latest --jq .tag_name to equal the tag.
  4. Repeat pinned/latest install.sh and Homebrew canaries.
  5. Emit the release receipt. Do not say DONE when any README channel is stale.

Operation: recover

First inventory immutable public state; do not repeat successful mutations. CI publication is idempotent — publish-crates.py publish prints NO-OP for every already-verified crate — so resuming is usually just rerunning failed jobs:

git ls-remote --tags origin \
  "refs/tags/v<VERSION>" "refs/tags/v<VERSION>^{}"
gh run list --workflow release.yml --branch "v<VERSION>" --limit 5
gh run view <RUN_ID> --json jobs,conclusion
gh release view "v<VERSION>" --repo fagemx/edda --json isDraft,assets
gh api repos/fagemx/edda/releases/latest --jq .tag_name
# from the detached tag worktree:
python3 scripts/publish-crates.py verify --tag "v<VERSION>"

Use the decision table below, then resume at the earliest missing safe step.

Observed stateAction
No tag pushed, nothing publishedReturn to preflight
prepare-crates reports enabled=falseBLOCKED until the operator configures CARGO_REGISTRY_TOKEN, then rerun the whole run (gh run rerun <id> without --failed — nothing failed; downstream jobs were skipped)
Tag pushed, run failed at publish-cratesRerun failed jobs (gh run rerun <id> --failed); verified crates are NO-OP
Run failed at create-release (parity)Inspect registry with verify --tag; rerun only after the cause is gone
Run failed at create-release (CHANGELOG section missing)BLOCKED; repair means a new commit and tag — operator decision, never move the tag
Run failed at build-linux-release/build-non-linux-release/publish-releaseRerun failed jobs; draft uploads are clobber-safe and re-verified
Registry provenance differs from tag SHABLOCKED; do not yank or move tag without operator decision
Public release exists but a channel is staleRepair that channel without changing immutable crate/tag identity

Registry propagation is handled inside publish-crates.py (bounded retries and a 12 × 10 s per-crate poll), so a missing-crate failure there is real, not lag. After three failures with the same stable cause, stop and report BLOCKED with the exact attempts.

Anti-patterns

  1. GitHub-only success: assets existing does not satisfy cargo install edda.
  2. Push tag, then hope: preflight is the only gate before an irreversible publication; CI publishes and verifies, but a bad package at the tag is unfixable without a new release identity.
  3. Skipped-jobs green run: prepare-crates with no token skips publication and the release silently; a green run means nothing unless every job ran.
  4. Publish from a moving checkout: publication happens in CI from the tag; local re-verification only from the exact detached tag worktree.
  5. Root crate only: all publishable workspace crates must reach crates.io in dependency order — enforced by publish-crates.py and the parity gate.
  6. Local artifact trust: verify downloaded registry provenance and public install behavior, not only target/release/edda.
  7. Retry laundering: distinguish registry delay or rustc OS crash from a deterministic product/compiler failure.
  8. Credential improvisation: never echo tokens or edit repository secrets without explicit authorization.
  9. Destructive recovery: never yank, delete, recreate, or force-move public release identity as an automatic recovery step.
  10. Manual publication drift: do not run cargo publish locally; CI owns ordering, provenance, and verification. Local helpers only prove packaging and verify public state.
  11. Bump the workspace version only: crate manifests pin internal dependencies explicitly; an unmatched pin fails cargo update -w at prep time — catch it there, not at the tag.
  12. Package a dirty tree: cargo package and cargo publish --dry-run refuse uncommitted changes; commit the prep, then prove packaging from the clean release commit.
  13. Assume a direct push to main: the ruleset declines it; budget the prep PR, its PR-visible review round, review deliver, and merge-gate check into the release timeline.
  14. Race toward 1.0: do not bump 0.x minor merely because the range contains feat: commits. Default to patch; reserve minor for a named milestone/breaking contract and 1.0 for an explicit stability decision.
  15. Empty Unreleased means empty release: a non-empty tag range with an empty [Unreleased] requires reconstructed, cross-checked notes.
  16. Stale warm CLI binary: the CLI-doc gate must use a binary built after the version bump; otherwise the documented-version mismatch stays hidden.
  17. Tag object equals release SHA: annotated tags have a tag-object hash and a peeled commit hash. Receipts and provenance use the peeled commit.
  18. Tag from a checkout that moved: freeze the reviewed merge SHA and use a detached tag worktree; never retarget silently when main advances.
  19. Watch-log diagnosis: trust run/job conclusions and required success markers, not an alarming tail line from gh run watch.
  20. Newest-runner Linux means portable Linux: the host CPU label does not define the userspace. Keep both Linux builds in the Ubuntu 22.04 container, enforce the GLIBC_2.35 cap before upload, and run the downloaded asset on that baseline after publication.
  21. Fresh brew reinstall: install first, then reinstall; final proof reads the remote tap, not only a locally mounted formula.
  22. Normalize checksum files only in the verifier: accepting CRLF by stripping \r hides a broken public sidecar. Producers emit ASCII+LF and publish-release rejects any other byte shape before publishing.

References

  • crates.io publication mechanics: references/crates-io.md
  • release automation: .github/workflows/release.yml (five stages, nine concrete jobs, tag-triggered)
  • publication dry-run gate: .github/workflows/publish-crates-check.yml
  • publish plan/publish/verify script: scripts/publish-crates.py (+ its test scripts/publish-crates-test.py)
  • consumer promises: README.md
  • Homebrew formula generator and regression: scripts/update-homebrew.sh, scripts/test-update-homebrew.sh
  • CLI reference drift gate: scripts/check-cli-docs.sh (GH-650/GH-795)
  • verification ladder and build lanes: .claude/CLAUDE.md

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.