CI Gates - alexherrero/crickets GitHub Wiki

CI gates

"Is it green" has one answer in crickets: the local gate battery passes. This page lists every gate in it, the CI matrix that mirrors it, and where to look when one fails.

A pull request whose full diff is confined to wiki/** and/or *.md files skips the wait for the full matrix inside ci-all.yml's aggregate job β€” a job-level classifier (scripts/ci_diff_classifier.py), not a trigger-level paths-ignore (pull_request deliberately carries none, since a required check a trigger filter could skip would block a docs-only PR's merge forever). A plain push to main does still carry paths-ignore on wiki/**/*.md, but push no longer runs the full battery at all (worktree-native flow, 2026-07-06) β€” it only ever triggers tests-linux.yml's lightweight syntax job.

⚑ Quick Reference

One command runs every deterministic gate locally:

bash scripts/check-all.sh
Gate What it checks
lint_src src/ source of truth β€” group.yaml + every primitive's frontmatter (incl. the standalone ⟺ requires: [] invariant and enhances: cross-references)
capability naming check-capability-naming.py β€” plugin and capability names obey the AG naming rule
no-dangling-name check-no-dangling-name.py β€” repo-wide gate against dangling references to a retired/renamed plugin or capability name
no-duplicate-diagnosis check-no-duplicate-diagnosis.py β€” the "no two diagnosis engines" regression net; bespoke failure-classification logic must delegate to diagnose.py, never re-grow its own inline category/confidence judgment
no-harness-paths check-no-harness-paths.py β€” no plugin names the vault's retired harness directory, tests included: a project's homes are its own tasks/, designs/ and desk/, and a plugin asks agentm for them. A line may keep the word with a harness-deprecation: marker. The script's EXEMPT list names the files the in-flight part 15 landings still clear, and a listed file with no hits left fails the gate, so the list only shrinks. --inventory prints every hit by plugin. agentm runs the same gate under the same name
conventions conformance check_conventions_conformance.py β€” a plugin that consults a conventions domain (an explicit <!-- consults-conventions-domain: <domain> --> marker) must declare it; checks declaration, not content correctness
unit tests the scripts/ test suite (test_*.py β€” lint, model, generator, plus the CI-consistency check that enforces the both-places rule)
vault-content tests test_voice_kernel.py, asserting facts about a real MemoryVault: the voice kernel is locatable and small, the three heavy genre files stayed demoted out of the always-load tier and resolvable on demand, and the kernel still reaches at least one live consumer. Runs without the AGENTM_INSTALL_PREFIX / MEMORY_ROOT (and its deprecated alias MEMORY_VAULT_PATH) isolation the unit tests gate uses, because that scratch prefix makes these skip themselves into silence. Skips cleanly when no vault resolves, so it is a no-op in CI and on any machine without one. test_voice_kernel_layouts.py, part of unit tests, runs the suite against scratch vaults on every layout the kernel has lived on, so CI still catches the suite drifting from prose_pass.
evidence-tracker self-test evidence_tracker.py --mode self-test β€” the evidence-tracker hook's own embedded self-test suite (67 tests) covering the default-FAIL evidence contract, named- and singleton-plan aware
generate drift generate.py check β€” committed dist/ matches a fresh generation, byte-for-byte
dist-references check-dist-references.py β€” every emitted plugin payload's relative links + ${CLAUDE_PLUGIN_ROOT} paths resolve inside its own dist tree (grandfathers known pre-existing gaps)
version bump each plugin whose src/<slug>/** changed must bump its group.yaml version: (compares against origin/main; graceful-skips when that ref is unresolvable)
check-wiki the wiki linter, --strict (DiΓ‘taxis modes, links, sidebars, basename collisions)
check-slop the deterministic anti-slop voice gate, --strict (blocking on error- or warning-tier findings since 2026-07-10, CONS-3 β€” the verdict's ruling 2; suggestion-tier findings, e.g. term-of-art words with a documented carve-out, never fail by the gate's own design) against the versioned rule pack (src/wiki/skills/diataxis-author/style/voice-rules.json)
voice-floor-parity check-voice-floor-parity.py --report — the overlay→floor promotion parity gate: keeps base-style-guide.md's banned: line honest against the rule pack; report-only, same posture as the opinion-parity gates below
check-syntax bash -n every .sh (CI also AST-parses every .ps1)
check-hook-parity Asserts every developer-safety hook keeps its .sh/.ps1 twins behaviorally paired β€” neither twin may reference a workspace-relative .harness/… path without first resolving the workspace from the host's hook-input contract (workspacePaths + a cd/Set-Location).
check-no-pii the PII regex scanner over the whole tree (crickets is public)
opinion-snapshot-parity check-opinion-snapshot-parity.py --report β€” keeps the committed scripts/opinion-snapshots/<name>.md snapshots (what generate.py bakes into dist/ for cross-plugin opinion consumers) honest against agentm's live opinions/<name>.md; graceful-skip (exit 0) when no agentm sibling is checked out to diff against. Report-only: drift is surfaced, not blocking, until an automated refresh exists.
opinion-self-provider-drift check-opinion-self-provider-drift.py --report — for a self-provider opinion binding (the caller IS the opinion's implements: artifact, e.g. code-review→good), flags agentm's opinions/<name>.md stub if it drifts from curated anchor phrases in the caller's own shipped prose (adversarial-reviewer.md), checking only in that direction; graceful-skip (exit 0) when no agentm sibling is checked out. Report-only, same posture as opinion-snapshot-parity.
cross-repo-script-parity check-cross-repo-script-parity.py --report β€” keeps crickets' canonical src/privacy/scripts/check-no-pii.sh + src/wiki/scripts/check-wiki.py honest against agentm's independently-maintained scripts/check-no-pii.sh + scripts/check-wiki.py. Not a byte-diff β€” compares the PII "kind" names and the lettered check-wiki rule identifiers each copy declares, since the two pairs carry legitimate one-sided content (crickets' check-wiki.py has 3 component-overview rules β€” m/n/o β€” agentm's wiki has no page-type for, documented in the script's own ALLOWED_CRICKETS_ONLY_RULES). Graceful-skip (exit 0) when no agentm sibling is reachable locally; runs for real in CI inside the obsidian-vault-conformance job, the one job that already checks out the agentm kernel. Report-only, same posture as the two opinion gates above.
board sync check_project_sync.py β€” the vault==board drift oracle: computes the expected GitHub Project board state from board-items.json and diffs it against the live board (read-only gh issue list), failing on any drift; graceful-skip (exit 0) when there's no project.json or no gh
tag-reachability all git tags must point to commits reachable from main β€” concurrent-release coordination backstop; graceful-skip when main doesn't resolve (fresh repos, non-main default-branch names)
conformance-suite Active. A dedicated obsidian-vault-conformance CI job (Linux + Windows) runs the obsidian-vault plugin backend's conformance / discovery / doctor suites against a checked-out agentm kernel, on every pull request (also on the nightly main-HEAD backstop workflow); local discovery rides check-all.sh's unit-test gate with graceful-skip when the kernel isn't checked out.

It prints a PASS/FAIL table and exits non-zero on any failure. Run it before every commit.

The CI matrix

Three OS workflows run their full battery on every pull request. A plain push to main only runs tests-linux.yml's lightweight syntax job (the one job with no if: gate) β€” the other jobs (validate, pii-guardrails, obsidian-vault-conformance) all gate on github.event_name == 'pull_request' (worktree-native flow, ratified 2026-07-06 β€” main only merges a PR whose checks already passed). All three run the toolchain gates (source lint Β· unit tests Β· drift Β· wiki lint) on pull_request; the syntax checks follow each OS's shell surface, and gitleaks rides the Linux leg:

OS Workflow What it runs
Linux (ubuntu-latest) tests-linux.yml toolchain gates Β· .sh + .ps1 syntax Β· PII scan Β· gitleaks
macOS (macos-latest) tests-mac.yml toolchain gates Β· .sh + .ps1 syntax Β· PII scan
Windows (windows-latest, PowerShell 7+) tests-windows.yml toolchain gates (under PYTHONUTF8: 1) Β· .ps1 syntax Β· PII scan

The single CI badge on the README + wiki Home points at ci-all.yml, an aggregate workflow that waits for all three OS workflows and reports a combined result. To drill into a failure, click the badge, open the Actions tab, and pick the failing OS; the failing step names the gate.

What CI adds beyond the local battery

  • gitleaks β€” the industry-standard secret scanner, alongside check-no-pii.sh (two independent PII/secret layers; the pre-push git hook is the third, on your machine).
  • PowerShell syntax β€” check-syntax.ps1 AST-parses every .ps1 (locally this runs only where pwsh is installed).
  • claude plugin validate β€” runs in tests-linux.yml's validate job, which installs @anthropic-ai/claude-code via npm first, then validates dist/claude-code/.claude-plugin/marketplace.json and every dist/claude-code/plugins/*/ directory non-strict (the marketplace capabilities:/enhances: fields are soft-composition metadata outside Claude's schema, and --strict would flag them as errors instead of the harmless warnings they are).
  • (Not in CI:) agy plugin validate β€” agy has no npm/CI-installable distribution, so Antigravity plugin loadability stays proven at dogfood time only.
  • Wiki publish β€” wiki-sync.yml ([W] Update Wiki) rsyncs wiki/ to the GitHub wiki on every push to main (after lint-wiki passes), with a case-sensitive duplicate-basename check on the emitted tree (sort | uniq -d, no lowercasing). The case-insensitive collision rule lives separately in check-wiki --strict's own basename-collision rule, which runs first as the lint-wiki job and would already block a case-only collision.

Adding a gate

When a new check earns its keep, add it in both places: a run line in scripts/check-all.sh and a step in tests-linux.yml β€” the battery stays the single source of truth for "is it green," and scripts/test_ci_consistency.py's TestBatteryMatchesLinuxWorkflow fails the battery if they drift (only the Linux leg is held to the full both-places rule; a narrower subset β€” lint_src, the unit suite, generate-drift, check-wiki β€” is separately required on all three OSes via TestPortabilitySubset).

Related

  • Compatibility β€” supported hosts + the per-plugin/hook support matrices.
  • Modify a plugin β€” the edit β†’ generate β†’ dogfood loop the gates protect.
  • Manifest schema β€” the contract lint_src enforces.
  • PII Guardrail β€” the interactive layer of the PII defense the gates back-stop.
  • Obsidian vault backend β€” the vault backend plugin (sole vault-backend implementation since V5-3) whose conformance-suite gate is described above.
⚠️ **GitHub.com Fallback** ⚠️