local-attest
Run the configured CI matrix locally and, on a clean pass, post a SHA-pinned OWNER-authored PR comment that gates downstream GitHub Actions jobs off for that exact commit. Skips the redundant remote run after a maintainer has already verified locally, saving runner minutes without weakening the gate. A new push changes the head SHA, the attestation stops matching, CI runs again. Side-effectful (posts a PR comment, applies a label, optionally pushes) and slow — minutes to tens of minutes, whatever the configured matrix costs. Diagnostic modes (--only, --from) run subsets for the fix-retry loop and can never attest; --fail-fast works in both modes. Invoke only on explicit request.
- License 许可
- MIT
- 最近更新
- 2026-10-26
- Stars
- ★ 0
- Forks
- 0
01 前言 Front Matter
- id
- local-attest
- name
- local-attest
- task
- [ "testing", "runtime-ops" ]
- type
- skill
- owner
- @kaiohenricunha
- tools
- Bash
- domain
- [ "devex", "observability" ]
- created
- 1779494400000
- updated
- 1786665600000
- version
- 1.2.0
- maturity
- draft
- platform
- [ "github-actions" ]
- description
- Run the configured CI matrix locally and, on a clean pass, post a SHA-pinned OWNER-authored PR comment that gates downstream GitHub Actions jobs off for that exact commit. Skips the redundant remote run after a maintainer has already verified locally, saving runner minutes without weakening the gate. A new push changes the head SHA, the attestation stops matching, CI runs again. Side-effectful (posts a PR comment, applies a label, optionally pushes) and slow — minutes to tens of minutes, whatever the configured matrix costs. Diagnostic modes (--only, --from) run subsets for the fix-retry loop and can never attest; --fail-fast works in both modes. Invoke only on explicit request.
- argument-hint
- [--pr <N>] [--no-push] [--dry-run] [--fail-fast] [--only <leg>] [--from <leg>] [--config <path>]
- user-invocable
- true
- disable-model-invocation
- true
02 资源文件 3
- 参考文档references/config.md10.8 KB
- 参考文档references/operator-guide.md9.4 KB
- 参考文档references/workflow-gate.yml.tmpl2.9 KB
03 SKILL.md 正文
/local-attest — Local CI attestation
Run the project's configured CI matrix on your machine. On a clean pass, post
a hidden marker comment to the open PR so the remote Test / Preview jobs
read the marker and skip themselves for that exact commit.
This skill is side-effectful and slow. It runs every leg of your CI matrix — serially within a lane, lanes in parallel; minutes to tens of minutes, whatever the configured matrix costs — posts a PR comment, applies a label, and pushes the current branch. Invoke only when you've decided to attest a specific PR. For the fix-retry loop, use the diagnostic modes below instead: they run subsets, tolerate a dirty tree, and are structurally unable to attest.
Quick start
# In a project root with a .local-attest.config.mjs
dotbabel local-attest --pr 123
# Try a config without posting anything:
dotbabel local-attest --pr 123 --dry-run
# Run + post + label, but do not git push (useful for offline review):
dotbabel local-attest --pr 123 --no-push
# Iterate on a fix: run one leg, dirty tree fine, no PR needed, never attests:
dotbabel local-attest --only lint
# Re-run the matrix from the leg that failed, stopping at the first hard failure:
dotbabel local-attest --from bats --fail-fast
# The on-demand full run: ignore every leg's diff rules and scope:
dotbabel local-attest --pr 123 --full
PR-scoped runs
An attest run verifies the scope of the pull request's changes and nothing
more. The full suite runs only on demand (--full) or on a schedule. Three
config fields decide each leg's scope (schema in
references/config.md):
scope: true— the leg scopes itself. When the runner knows the PR's changed files, it writes them to a JSON file and passes its path asDOTBABEL_ATTEST_CHANGED_FILES, plus a per-legDOTBABEL_ATTEST_SKIP_FILE. The leg runs only what the changes reach. When nothing is in scope, it writes a one-line reason to the skip file and exits 0, and the leg is recordedskipped. A non-zero exit is a failure, skip file or not. Without the file list the leg gets neither variable and must run in full (fail-open).when.changedPaths— the leg runs only when a changed file matches one of its globs; use it for whole-repo invariant checks, listing their inputs.skipWhenDiffOnly— the leg skips when every changed file matches.
--full ignores all three: no file list is passed, every leg runs in full,
and the attestation payload records "full": true.
Diagnostic modes — the fix-retry loop
--only <leg> (repeatable or comma-separated) and --from <leg> run a subset
of the matrix under relaxed preconditions: any git repo state is fine (dirty
tree, detached HEAD, no PR — iterating is the point), Docker and toolchain
problems warn instead of failing. Leg names match exactly and case-sensitively;
an unknown name lists every valid leg. The two flags are mutually exclusive.
A diagnostic run never posts, labels, or pushes. Two mechanisms stack:
the diagnostic branch in execute returns before the publication path even
exists (and the attest branch always runs the full config matrix), and the
shouldAttest predicate that gates publication receives the diagnostic flag
plus the expected leg count, so a subset record is rejected even if the
branch wiring were ever wrong. Exit is 1 when any selected leg fails,
advisory legs included, because there is no attestation gate to grade against
and --only <advisory-leg> exiting 0 on a failure would be useless in a loop.
Subsets get exactly what they name — no dependency injection. --from a leg
that reads a build artifact measures whatever artifact is lying around.
--fail-fast works in both modes: the first hard failure stops launching
further legs, which are recorded not run (fail-fast) — never as passes. A
full run with --fail-fast where nothing failed completed the whole matrix
and attests normally; one that stopped early cannot.
Prerequisites
- A
.local-attestconfig in the project root — see references/config.md for the schema and three example configs (Node-only, Node + Go monorepo, Python). Discovery order:.local-attest.config.mjs→.local-attest.config.json→package.json#local-attest. - A workflow gate wired into your
.github/workflows/test.yml(and any other pipeline you want to skip). Paste the snippet from references/workflow-gate.yml.tmpl. This is a one-time manual setup — auto-injecting YAML across diverse CI layouts is too risky to do for you. - A clean worktree — the skill aborts on any uncommitted change, because
the attestation must certify the exact tree that gets pushed. (Configurable
via
requireClean: false, but generally not recommended.) - Local HEAD must match the PR head — the skill aborts if your local branch tip differs from the remote PR head. Push any local commits first.
ghauthenticated as a user whoseauthor_associationis in your config'strustedAssociationslist (default:["OWNER"]).- Docker running if your config sets
requireDocker: true. auditLogPathgitignored (default.local-attest-log.jsonl). Every run appends to it — including--dry-run— so withrequireCleanon, an untracked log makes the next attest abort on the tool's own output.
How the gate works
The gate input is a PR comment authored by a trusted user (default: the repo OWNER) whose first line is exactly:
<!-- local-attest verified-sha=<full-head-sha> -->
<!-- local-attest-payload <base64url JSON> -->
The CI workflow reads PR comments, applies a jq select(.author_association == "OWNER")
filter, takes the first line of each, and grep -qFxs (exact-line match)
for the marker that matches github.event.pull_request.head.sha. When it matches, every downstream
job's if: evaluates false and skips at zero runner cost.
Line 2 carries the evidence payload the merge gate reads
(schemas/dotbabel.attestation-evidence.schema.json): the head SHA, the merge
base, a hash of the files that govern the run, and each leg's terminal status.
The CI gate ignores it; dotbabel pr-stack gate --gate merge does not. A marker
alone says a matrix passed, which is enough to skip a redundant remote run but
not enough to authorize a merge — it does not say WHICH matrix. The
config_hash closes that: the gate recomputes it from the base ref, so a pull
request that rewrites a leg's command cannot attest its own change.
Freshness is automatic: a new push changes the head SHA, the old comment no
longer matches, CI runs again. Editing or deleting the comment does not
re-trigger CI (the gate only re-evaluates on push/synchronize). If you
need to revoke an attestation, push any new (even empty) commit.
Full operator contract: references/operator-guide.md.
What the skill does, in order
-
Preconditions. Branch exists, worktree clean (if
requireClean), local HEAD == PR head,ghauthed, Docker available (ifrequireDocker), and the running toolchain matchesconfig.toolchainpins (if set) — a matrix run on a different Node or Go than CI uses certifies a run CI would never perform, so a pin mismatch fails closed here. Any failure aborts before a single test runs. The skill also warns (does not fail) if your GitHubauthor_associationon the repo (OWNER / MEMBER / COLLABORATOR, etc.) is not in the config'strustedAssociationslist — the attestation will post but CI will ignore it. -
Run matrix. Legs sharing a
lanerun serially in matrix order; distinct lanes run concurrently; a config without lanes runs fully sequentially. Diff rules (when.changedPaths,skipWhenDiffOnly) mark legs skipped against the PR's changed files, and ascope: trueleg that reports nothing in scope is recorded skipped too — skipped legs still appear in every table, and the comment headline says so rather than claiming a full run. Hard legs must pass to attest; advisory legs are reported but never block. Stdout + stderr are tailed at 10 lines per leg. With--fail-fast, the first hard failure stops launching further legs in every lane; the rest are recordednot run, never as passes. -
Attestation bar. Posting is gated on a run-record predicate: every leg accounted for — executed or diff-skipped — at least one leg actually executed (an all-skipped run has verified nothing and refuses to attest; CI's own path filters already skip the same jobs), zero hard fails, not a diagnostic subset. A run that fails the bar aborts — no comment, no label, no push — and still writes its audit line (
result: "hard-fail"). -
Re-check HEAD. First,
restoreFilessnapshots taken before the matrix are restored byte-exact (a leg that seeds fixture stubs over tracked files would otherwise fail this recheck on its own writes, every run). Then: the matrix takes minutes — long enough for another agent session, another worktree, or you in a second terminal to commit onto the same branch. Step 1's check is stale by now, so HEAD and the worktree are re-asserted against what was actually tested. If either moved, everything aborts (result: "head-moved"): no comment, no label, no push. Without this the skill would attest the pre-matrix SHA and then push whatever HEAD had become — publishing commits it never tested and labelling the PR verified on an unrun head. -
Post comment, minimize older ones. A new comment is POSTed and this tool's own earlier attestation comments are minimized as
OUTDATED— before the push, so the marker is already visible when the push event fires GitHub Actions. Body always goes viagh api --input -so multiline markdown can't be mangled by shell quoting.This never edits a comment, which is a deliberate change from the previous PATCH-in-place behaviour and matches what
dotbabel criteriaalready does (OPS-4). The merge gate refuses an edited comment — text that is not what the tool wrote is not evidence — so under the old model the second attestation on any pull request would have been rejected as untrusted. Comments written by other users are never minimized. -
Push (if
pushAfterAttestand not--no-push). A failed push recordsresult: "push-fail"; the comment is already in place, so a baregit pushretry completes the attestation. -
Apply label (default
ci/local-verified). Best-effort; failure warns but does not abort. -
Append audit log line to the configured
auditLogPath(default.local-attest-log.jsonl). Every run whose matrix executes writes exactly one line, taggedresult: attested | hard-fail | head-moved | push-fail | post-fail | dry-run | diagnostic, with per-leg{name, mode, status, durationS}— failures leave a record too, which is what makes failure and duration distributions measurable. Lines written by older versions have noresultfield and implyattested. Best-effort: an unwritable log warns but never changes the run's outcome.
Flags
| Flag | Effect |
|---|---|
--pr <N> |
Target PR number. Defaults to the open PR for the current branch. |
--no-push |
Run matrix + post + label, but skip git push. |
--dry-run |
Run matrix, render the comment, print it. Post nothing, label nothing, push nothing. Use this to validate a new project's config end-to-end. |
--fail-fast |
Stop launching legs after the first hard failure. Unstarted legs record as not run; a run that stopped early can never attest. |
--only <leg> |
Diagnostic mode — run only the named leg(s). Repeatable or comma-separated. Relaxed preconditions; never attests. Exit 1 on any failure. |
--from <leg> |
Diagnostic mode — run the matrix from the named leg to the end. Mutually exclusive with --only. |
--config <path> |
Override config discovery. |
What this skill never does
- Auto-install the workflow gate. Paste it manually using the template.
- Skip the Secret-scan job (or any other gate you didn't put behind the
attestation
if:). Configure each workflow'sif:explicitly. - Merge or deploy. It only attests and pushes the current branch.
- Edit a comment. Each run posts a new one and minimizes its own older
ones, so at most one attestation is visible per PR and
lastEditedAtstays null — which is what makes it trustworthy to the merge gate. - Auto-unlabel on stale attestation. A new push silently invalidates the prior attestation by SHA mismatch; the label stays as audit decoration.
Trust model
Default trustedAssociations: ["OWNER"]. Only comments from the repo OWNER
will gate CI. A non-trusted user's comment will post (and the label may apply)
but CI will still run. Widen the trust list in your config for multi-maintainer
repos:
trustedAssociations: ["OWNER", "MEMBER", "COLLABORATOR"];
The generated workflow gate snippet (references/workflow-gate.yml.tmpl) automatically matches the configured list.
04 同仓库更多 Skills
yolo
Start temporary autonomy for the current task or an explicit scope with a required --for expiry. Codex permits scoped pushes, merges, deploys, and releases after strict testing and validation; Full access is a separate runtime setting. Claude Code uses a session permission hook with a protected-action denylist.
veracity-audit
Audit a data pipeline for Veracity and Value. Dispatches data-scientist, compliance-auditor, and data-engineer agents with project context injected at dispatch time. All source paths are supplied via flags — no defaults, no project assumptions. Subcommands: audit (full pipeline walk), score-check (scoring math only), gate-check (gate coverage only), source-trace <label> (single source end-to-end). Invoke when: "audit pipeline", "veracity check", "scoring math correct?", "check gates", "trace source", "verify quality gates", "formula correct?".
validate-spec
Audit an already-implemented spec against the codebase. Walks each constraint (ARCH-N, PERF-N, KD-N, etc.) and acceptance criterion, grounds findings in file:line evidence, runs the spec.json acceptance_commands, and writes a single audit doc to docs/audits/. Use whenever the user asks to "validate a spec", "audit a spec", "check if spec is implemented", "verify the spec is done", "is this spec really done", or otherwise wants closure on spec-driven work. Read-only against the spec — produces an audit, never modifies the spec itself.
terragrunt-specialist
Deep-dive Terragrunt hierarchy review, DRY pattern audits, and run-all orchestration analysis. Use for structured investigations of multi-environment Terragrunt layouts, dependency graphs, remote state config, and hook correctness. Triggers on: "Terragrunt audit", "run-all review", "dependency block", "DRY pattern review", "env hierarchy audit", "mock_outputs", "terragrunt hooks".
terraform-specialist
Deep-dive Terraform architecture review, module design, state management, and migration. Use for structured investigations of Terraform workspaces, provider configuration, module coupling, import workflows, and test coverage. Triggers on: "Terraform audit", "module review", "state management", "Terraform import", "workspace design", "provider config review", "Terraform testing".
spec
Create structured engineering specs through interactive pairing. Use when the user wants to create a spec, design doc, technical specification, architecture document, RFC, or engineering plan. Triggers on "let's spec this out", "create a spec", "design doc", "write a technical plan", "plan the architecture". Works for greenfield and brownfield projects. Outputs to docs/specs/.