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
In this repository52 other files it gives its agents.
- AGENTS.mdAGENTS.md
- .claude/CLAUDE.mdCLAUDE.md
- agent-browserSkill
- arch-specSkill
- code-qualitySkill
- code-reviewSkill
- commitSkill
- coord-delegateSkill
- coord-handoffSkill
- coord-orchestrateSkill
- coord-requestSkill
- coord-reviewSkill
- coord-runSkill
- coord-syncSkill
- dispatchSkill
- fleet-epic-splitSkill
- fleet-managerSkill
- fleet-orchestrateSkill
- fleet-pr-loopSkill
- fleet-reviewSkill
- fleet-triadSkill
- fleet-workerSkill
- ground-checkSkill
- health-checkSkill
- intel-scanSkill
- issue-actionSkill
- issue-compactSkill
- issue-createSkill
- issue-intakeSkill
- issue-pipelineSkill
- issue-planSkill
- issue-scanSkill
- parallel-waveSkill
- path-forwardSkill
- plan-decomposeSkill
- plan-validateSkill
- pr-checkSkill
- project-planSkill
- Project PrinciplesSkill
- pr-review-loopSkill
- pr-reviewSkill
- pull-requestSkill
- regression-guardSkill
- skill-aliasSkill
- skill-craftSkill
- skill-testSkill
- spec-review-modesSkill
- tech-debtSkill
- testingSkill
- tracking-issueSkill
- verifiable-goal-loopSkill
- fleet-orchestrateSkill
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
- Distinctive: line 41
If the operation or version is missing, ask for it.
- Very specific: line 47
Default compatible fixes and features to the next patch release: after 0.6.0, prefer 0.6.1, 0.6.2, and so on.
- Very specific: line 49
Use a new 0.x minor only for a named cohesive milestone or an intentional breaking public CLI, config, ledger, or migration contract.
- Distinctive: line 55
After 1.0, return to ordinary SemVer: compatible features bump minor and breaking changes bump major.
- Distinctive: line 58
Before proposing a number, read the release range:
- Distinctive: line 73
Treat any version or behavior mismatch among them as a release blocker.
- Very specific: line 94
Never print or read credential contents.
- Very specific: line 102
Read AGENTS.md and .claude/CLAUDE.md completely, then inspect the actual install promises and release automation:
- Distinctive: line 120
Treat an absent secret as BLOCKED before pushing anything.
- Very specific: line 172
Follow the L0/L1/L2 verification ladder in .claude/CLAUDE.md.
- Very specific: line 201
Run repository-root REVIEW.md top to bottom for the prep PR.
- Very specific: line 214
Use a freshly built edda that contains the current review deliver surface.
- Distinctive: line 219
After merge, freeze the squash/merge commit and wait for that exact main push CI to go green.
- Distinctive: line 225
Create the annotated tag locally, then run the plan gate inside a detached tag worktree.
- Very specific: line 244
Use the detached worktree for later publish-crates.py verify too.
- Distinctive: line 285
Never repair a failed run by moving the tag.
- Very specific: line 289
Use a fresh Cargo home and install root.
- Distinctive: line 305
Do not declare DONE until this unversioned install canary passes.
- Very specific: line 309
Run the one-line installer twice in disposable directories: once pinned and once through its default “latest” path.
- Very specific: line 341
After crates.io publication is verified, generate the Homebrew formula from the immutable crates.io source package.
- Distinctive: line 384
Commit and push the tap formula only after its diff names the intended static crates.io URL, source hash, and build dependencies.
- Distinctive: line 423
Run the public half of the workflow without changing remote state:
- Distinctive: line 452
Use the decision table below, then resume at the earliest missing safe step.
- Very specific: line 480
Root crate only: all publishable workspace crates must reach crates.io in dependency order — enforced by publish-crates.py and the parity …
- Very specific: line 482
Local artifact trust: verify downloaded registry provenance and public install behavior, not only target/release/edda.
- Distinctive: line 486
Credential improvisation: never echo tokens or edit repository secrets without explicit authorization.
- Distinctive: line 488
Destructive recovery: never yank, delete, recreate, or force-move public release identity as an automatic recovery step.
- Very specific: line 490
Manual publication drift: do not run cargo publish locally.
- Very specific: line 502
Race toward 1.0: do not bump 0.x minor merely because the range contains feat: commits.
≈ “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.
Files
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 proofpublish: run the preflight, push the tag, watch CI, then prove every advertised channelverify: read-only public consumer canaries and parity reportrecover: 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, prefer0.6.1,0.6.2, and so on. - Use a new
0.xminor only for a named cohesive milestone or an intentional breaking public CLI, config, ledger, or migration contract. Afeat:commit alone does not force a minor bump. 1.0.0requires 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
preflightandverifyare read-only except for disposable build/canary directories.- An explicit
publish <version>request authorizes pushing thev<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_TOKENsecret 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/eddagh 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.shcheck-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 indocs/reference/cli.mdagainst 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 staleDocumented for edda 0.xheading. The oldcheck_cli_reference.pyno longer exists.- Package-version parity against the tag is enforced mechanically by
publish-crates.py planin 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 matchesCrate 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> --mergeUse 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-statusStep 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)'| Stage | Requirement |
prepare-crates | enabled=true (secret present); tag/plan validation passed |
publish-crates | SUCCESS: all <N> workspace versions verified |
create-release | parity 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-release | exact 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 --helpThe 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 --helpBoth 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/eddaThe 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:
- From the tag worktree,
python3 scripts/publish-crates.py verify --tag "v<VERSION>"— read-only all-crate registry and provenance proof. - Repeat the fresh unversioned Cargo canary.
- 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_nameto equal the tag. - Repeat pinned/latest
install.shand Homebrew canaries. - 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 state | Action |
| No tag pushed, nothing published | Return to preflight |
prepare-crates reports enabled=false | BLOCKED 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-crates | Rerun 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-release | Rerun failed jobs; draft uploads are clobber-safe and re-verified |
| Registry provenance differs from tag SHA | BLOCKED; do not yank or move tag without operator decision |
| Public release exists but a channel is stale | Repair 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
- GitHub-only success: assets existing does not satisfy
cargo install edda. - 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.
- Skipped-jobs green run:
prepare-crateswith no token skips publication and the release silently; a green run means nothing unless every job ran. - Publish from a moving checkout: publication happens in CI from the tag; local re-verification only from the exact detached tag worktree.
- Root crate only: all publishable workspace crates must reach crates.io in
dependency order — enforced by
publish-crates.pyand the parity gate. - Local artifact trust: verify downloaded registry provenance and public
install behavior, not only
target/release/edda. - Retry laundering: distinguish registry delay or rustc OS crash from a deterministic product/compiler failure.
- Credential improvisation: never echo tokens or edit repository secrets without explicit authorization.
- Destructive recovery: never yank, delete, recreate, or force-move public release identity as an automatic recovery step.
- Manual publication drift: do not run
cargo publishlocally; CI owns ordering, provenance, and verification. Local helpers only prove packaging and verify public state. - Bump the workspace version only: crate manifests pin internal
dependencies explicitly; an unmatched pin fails
cargo update -wat prep time — catch it there, not at the tag. - Package a dirty tree:
cargo packageandcargo publish --dry-runrefuse uncommitted changes; commit the prep, then prove packaging from the clean release commit. - 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. - Race toward 1.0: do not bump
0.xminor merely because the range containsfeat:commits. Default to patch; reserve minor for a named milestone/breaking contract and 1.0 for an explicit stability decision. - Empty Unreleased means empty release: a non-empty tag range with an
empty
[Unreleased]requires reconstructed, cross-checked notes. - Stale warm CLI binary: the CLI-doc gate must use a binary built after the version bump; otherwise the documented-version mismatch stays hidden.
- Tag object equals release SHA: annotated tags have a tag-object hash and a peeled commit hash. Receipts and provenance use the peeled commit.
- Tag from a checkout that moved: freeze the reviewed merge SHA and use a detached tag worktree; never retarget silently when main advances.
- Watch-log diagnosis: trust run/job conclusions and required success
markers, not an alarming tail line from
gh run watch. - 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.35cap before upload, and run the downloaded asset on that baseline after publication. - Fresh
brew reinstall: install first, then reinstall; final proof reads the remote tap, not only a locally mounted formula. - Normalize checksum files only in the verifier: accepting CRLF by
stripping
\rhides a broken public sidecar. Producers emit ASCII+LF andpublish-releaserejects 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 testscripts/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
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
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.

