AGENT SKILL

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

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 as DOTBABEL_ATTEST_CHANGED_FILES, plus a per-leg DOTBABEL_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 recorded skipped. 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-attest config 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.
  • gh authenticated as a user whose author_association is in your config's trustedAssociations list (default: ["OWNER"]).
  • Docker running if your config sets requireDocker: true.
  • auditLogPath gitignored (default .local-attest-log.jsonl). Every run appends to it — including --dry-run — so with requireClean on, 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

  1. Preconditions. Branch exists, worktree clean (if requireClean), local HEAD == PR head, gh authed, Docker available (if requireDocker), and the running toolchain matches config.toolchain pins (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 GitHub author_association on the repo (OWNER / MEMBER / COLLABORATOR, etc.) is not in the config's trustedAssociations list — the attestation will post but CI will ignore it.

  2. Run matrix. Legs sharing a lane run 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 a scope: true leg 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 recorded not run, never as passes.

  3. 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").

  4. Re-check HEAD. First, restoreFiles snapshots 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.

  5. 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 via gh 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 criteria already 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.

  6. Push (if pushAfterAttest and not --no-push). A failed push records result: "push-fail"; the comment is already in place, so a bare git push retry completes the attestation.

  7. Apply label (default ci/local-verified). Best-effort; failure warns but does not abort.

  8. Append audit log line to the configured auditLogPath (default .local-attest-log.jsonl). Every run whose matrix executes writes exactly one line, tagged result: 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 no result field and imply attested. 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's if: 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 lastEditedAt stays 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

kaiohenricunha
kaiohenricunha/dotbabel

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.

开发工程师
★ 0
kaiohenricunha
kaiohenricunha/dotbabel

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?".

律师与法务Skill与智能体开发
★ 0
kaiohenricunha
kaiohenricunha/dotbabel

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.

★ 0
kaiohenricunha
kaiohenricunha/dotbabel

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".

运维与部署
★ 0
kaiohenricunha
kaiohenricunha/dotbabel

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".

测试与质量运维与部署
★ 0
kaiohenricunha
kaiohenricunha/dotbabel

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/.

设计师视觉设计
★ 0