Operate the ai-agents generation and release machinery, covering the seven build_all.py generators, generate_agents.py, the drift gates, the version-free plugin manifests, and the npm publish path. Use when you say `regenerate the mirrors`, `run the drift checks`, `why is the plugin version gate red`, `release the npm cli`. Do NOT use for environment setup (use `ai-agents-build-and-env`) or architecture rationale (use `ai-agents-architecture-contract`).
Installs into .claude/skills of the current project.
Are you the author of Ai Agents Generation And Release?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/rjmurillo-ai-agents-generation-and-release)
---
name: ai-agents-generation-and-release
description: Operate the ai-agents generation and release machinery, covering the seven build_all.py generators, generate_agents.py, the drift gates, the version-free plugin manifests, and the npm publish path. Use when you say `regenerate the mirrors`, `run the drift checks`, `why is the plugin version gate red`, `release the npm cli`. Do NOT use for environment setup (use `ai-agents-build-and-env`) or architecture rationale (use `ai-agents-architecture-contract`).
version: 1.0.0
license: MIT
metadata:
routing:
role: conditional-adjunct
invoker: ai-agents-build-and-env
trigger: build-and-env redirects release work here
user-facing: false
---
# ai-agents Generation and Release
<!-- vendor-portability: contributor-facing knowledge pack for the rjmurillo/ai-agents repo itself. It intentionally references .project-toolkit/architecture, .project-toolkit/retrospective, .claude/lib, scripts/hook_utilities, scripts/github_core, scripts/ai_review_common, scripts/validation, build/generate_agents.py, build/scripts, templates/agents, templates/platforms, and AGENTS.md because its audience is repo contributors, not plugin consumers. Issue #2050. -->
Runbook for the build, generation, mirroring, versioning, and release machinery. Every command below was run or read from source on 2026-07-02/03 and re-verified on 2026-07-29; re-verify with the one-liners in Provenance before trusting a volatile number.
Jargon, defined once:
- Generator: a Python function or script that reads a canonical tree and writes a derived (generated) tree.
- Drift: the generated tree no longer matches what the generators would produce from the canonical tree.
- Canonical: the tree you are allowed to edit. Generated trees are outputs; you never hand-edit them.
- Semver: semantic version string MAJOR.MINOR.PATCH. The plugin manifests carry no version at all (ADR-092); the npm package still does.
## Triggers
- `regenerate the mirrors`
- `run the drift checks`
- `why is the plugin version gate red`
- `release the npm cli`
- `why is the drift gate red`
## When NOT to Use This Skill
| You want | Use instead |
|----------|-------------|
| Set up the dev environment, uv, hooks | `ai-agents-build-and-env` |
| WHY the seam is shaped this way, invariants | `ai-agents-architecture-contract` |
| Triage a red CI gate you do not understand | `ai-agents-debugging-playbook` |
| Change classification, commit caps, review gates | `ai-agents-change-control` |
| Escape hatches like the drift allowlist | `ai-agents-config-catalog` |
## Process
### Phase 1: Know the Seam Before You Edit
The generation seam is ASYMMETRIC (ADR-072 is PROPOSED and refines this; the running system is what follows). Find your file in this table BEFORE editing. Editing a generated tree is the classic failure (see Anti-Patterns).
| Tree | Role | Canonical source | Regenerated by |
|------|------|------------------|----------------|
| `templates/agents/*.shared.md` | CANONICAL for agents | itself | n/a |
| `src/vs-code-agents/` | generated | templates/agents | `build/generate_agents.py` |
| `src/copilot-cli/agents/` | generated | templates/agents | `build/generate_agents.py` |
| `docs/agent-catalog.md` | generated | templates/agents | `build_all.py` (agent-catalog) |
| `.claude/` | MIXED per subtree, see Facts below | mixed | binplace, template-owned parts only |
| `templates/skills/*.SKILL.md.tmpl` | CANONICAL for all 111 skills' SKILL.md (ADR-108, ADR-109 B3) | itself | renders `src/claude/skills/`, binplaces `.claude/skills/`, mirrors `src/copilot-cli/skills/` |
| `src/copilot-cli/{skills,instructions,hooks}` | generated | `.claude/` trees | `build/scripts/build_all.py` |
| `.github/instructions/` | generated | `.claude/rules/` | `build_all.py` (rules) |
| `scripts/{hook_utilities,github_core,ai_review_common}` | CANONICAL for shared Python | itself | n/a |
| `src/claude/lib/`, `src/copilot-cli/lib/` | generated direct | `scripts/` packages | `build_all.py` lib step (B5) |
| `.claude/lib/` | binplaced from `src/claude/lib/` | `src/claude/lib/` | `build_all.py` binplace |
| `src/claude/{agents,rules,hooks,hooks.json,settings.json}` | generated (ADR-109 B1, B2, B4; supersedes the pre-ADR-109 hand-synced model) | `templates/{agents,rules,hooks}/` | `build_all.py`, then binplaced to `.claude/` |
All 111 skills are template-owned (ADR-108, ADR-109 B3): edit `templates/skills/<name>.SKILL.md.tmpl`; it renders `src/claude/skills/<name>/SKILL.md` first, binplace copies that to `.claude/skills/<name>/SKILL.md`, then the Copilot copy step mirrors it (plus the skill's hand-maintained `scripts/`, `references/`, `tests/`) into `src/copilot-cli/skills/<name>/SKILL.md`.
Generator inventory inside `build/scripts/build_all.py` (the `GENERATORS` list; order is load-bearing per the `Order matters` comment above it; seven since ADR-064 retired `commands`):
| # | Generator | Reads | Writes |
|---|-----------|-------|--------|
| 1 | agents | `templates/agents/*.shared.md` + `templates/platforms/*.yaml` | `src/copilot-cli/agents/*.agent.md`, `src/vs-code-agents/*.agent.md` |
| 2 | agent-catalog | `templates/agents/*.shared.md` | `docs/agent-catalog.md` |
| 3 | adr-index | the ADR corpus under `.project-toolkit/architecture/` | `.project-toolkit/architecture/README.md` |
| 4 | lib | `scripts/` packages | `src/claude/lib/`, `src/copilot-cli/lib/`; binplaced `.claude/lib/` |
| 5 | skills | `.claude/skills/*/SKILL.md` (template-owned skills compile first; ADR-108, ADR-109) | `src/copilot-cli/skills/` |
| 6 | rules | `.claude/rules/*.md` | `.github/instructions/*.instructions.md` AND `src/copilot-cli/instructions/` |
| 7 | hooks | `.claude/settings.json` + `.claude/hooks/` | `src/copilot-cli/hooks/` + `src/copilot-cli/hooks/hooks.json` |
Facts that prevent confusion:
- `build_all.py` enforces a no-write invariant on `.claude/` (REQ-003-010): if any generator writes there, the run exits 2 with `REQ-003-010 VIOLATION`, except a `binplace.yaml` row's `.claude/`-rooted `install_tree` (agents, skills, rules, hooks, settings, lib; ADR-109). `.claude/` is otherwise input only.
- Generated-tree ownership is exactly `OWNED_PREFIXES = ("src/", ".github/instructions/", "docs/agent-catalog.md", ".project-toolkit/architecture/README.md")`, four entries, in the `OWNED_PREFIXES` tuple. `--check` only flags staleness inside those prefixes, and the adr-index generator is why the last one is there.
- The hooks generator maps Stop, SubagentStop, PermissionRequest, and
PreCompact to their PascalCase compatibility names. Stop and SubagentStop
remain direct host registrations because their structured decisions require
host-level merging. A reported drop needs an identified source registration;
never assume it is normal.
- Every run overwrites the generation audit log in the gitignored build audit directory. Read it to see what each generator did.
### Phase 2: Regenerate After Editing a Canonical Surface
Always commit the canonical edit and the regenerated output TOGETHER, in the same commit set, or the drift gates go red.
Interpreter note: `build/generate_agents.py` and `build/scripts/build_all.py` both import PyYAML through `build/scripts/yaml_loader.py`. Run them as `uv run python <script>` locally so the project venv supplies it. CI can invoke bare `python3` because `.github/actions/setup-code-env` installs the locked dependencies system-wide first.
| You edited | Run | Then |
|------------|-----|------|
| `templates/agents/*.shared.md` | `uv run python build/generate_agents.py` then `uv run python build/scripts/build_all.py` (refreshes docs/agent-catalog.md) | commit template + all regenerated files, including `src/claude/agents/` (generated, ADR-109 B1; never hand-edit it). |
| `.claude/skills/<name>/SKILL.md` (hand-maintained) or `templates/skills/<name>.SKILL.md.tmpl` (template-owned; ADR-108, ADR-109), plus `.claude/rules/` | `uv run python build/scripts/build_all.py` | commit source or template, plus both rendered copies for a template-owned skill. No manifest edit (Phase 4) |
| `.claude/hooks/` or `.claude/settings.json` | `uv run python build/scripts/build_all.py` | same as above. The `build-all-check` pre-push job in `lefthook.yml` re-runs `build_all.py --check` at `git push` time and blocks if any generated output (including shims under `src/copilot-cli/hooks/`) drifts, so regenerate BEFORE pushing. |
| `scripts/hook_utilities/`, `scripts/github_core/`, `scripts/ai_review_common/` | `uv run python build/scripts/build_all.py` (writes both lib trees, binplaces `.claude/lib/`, B5) | One command; no manifest edit. |
| `src/claude/AGENTS.md`, `src/claude/claude-instructions.template.md` (root-level, hand-maintained; no template) | nothing to regenerate | commit directly; not an agent stem |
Useful flags, verified against source:
- `build/generate_agents.py`: `--validate` (CI compare mode), `--what-if` (dry run, writes nothing), `--templates-path`, `--output-root`. Exit codes: 0 ok, 1 logic error or drift, 2 config error (docstring, generate_agents.py:13-16).
- `build/scripts/build_all.py`: `--check` (staleness gate; snapshots and restores owned trees), `--clean`, `--audit-format json`, `--platform copilot-cli`. Exit codes: 0 ok, 1 generator error, 2 config error or staleness or (under `--check`) a path under `OWNED_PREFIXES` that cannot be read or redirects (symlink or junction) or holds a nested git repository, or a generator write under `.claude/` (REQ-003-010), 3 audit blocklist violation or (under `--check`) unreadable git state (the `EXIT CODES` block in this script's module docstring). Only the staleness producer of exit 2 is cleared by regenerating and committing; the REQ-003-010 producer is a generator policy violation, so regenerating reproduces it. Git is external, so every git-read failure (launch, timeout, nonzero exit) is 3 per the `AGENTS.md` contract, which keeps "you are missing git" out of the same code as "your tree is stale" (issue #4632).
- `build/scripts/lib_mirror.py`: the lib copy, run by `build_all.py` (B5). `build_all.py --check` is the dry run (exit 2 when out of sync); do not "fix" `.claude/lib/` imports by hand.
### Phase 3: Run the Drift Gates Locally Before Pushing
Drift-gate matrix (all local commands verified runnable, all green on 2026-07-29):
| Gate | Catches | Local command | CI enforcement |
|------|---------|---------------|----------------|
| Agent template drift | templates edited without regen (or vice versa) | `uv run python build/generate_agents.py --validate` | `validate-generated-agents.yml`, `agent-drift-detection.yml` |
| Full pipeline staleness | any canonical edit not mirrored to owned prefixes | `uv run python build/scripts/build_all.py --check` | `validate-generated-agents.yml`; named pre-push job in `lefthook.yml` |
| Lib mirror drift | `scripts/` package edited without regen | `uv run python build/scripts/build_all.py --check` | `validate-generated-agents.yml` |
| Install parity | plugin install layout broken | `python3 scripts/validation/run_install_parity_ci.py` | `validate-generated-agents.yml` |
| Manifest description parity | `.claude` vs `src/copilot-cli` plugin descriptions carry component counts | `python3 build/scripts/check_plugin_manifest_parity.py` | `validate-generated-agents.yml`, `agent-drift-detection.yml` (the version half was retired with ADR-092) |
| Plugin version field present | a manifest or marketplace entry carries `version` | `pre-pr-validation` job in `lefthook.yml` (`scripts/validation/pre_pr.py`) | `validate-plugin-version-bump.yml` |
| Semantic agent drift (src/claude) | hand-synced tree diverging in meaning | `python3 build/scripts/detect_agent_drift.py` | `drift-detection.yml`, weekly cron Monday 09:00 UTC (line 15); similarity threshold default 80 (detect_agent_drift.py:666-668), with a recorded-baseline floor so a clean checkout does not fail |
When a drift gate is red, the output shows the DIFFERENCE, not the DIRECTION. Ask "which side is canonical?" using the Phase 1 table before touching anything. The 2025-12-15 incident (retro: `.project-toolkit/retrospective/2025-12-15-drift-detection-disaster.md`) happened because an agent edited the SOURCE to match the GENERATED tree; the commit was reverted. Fix is always: edit canonical, rerun generator, commit both.
An emergency bypass marker for the drift gate exists but requires a reason and approval; see `ai-agents-config-catalog`. Route the decision through `ai-agents-change-control`.
Run the installed Copilot hook E2E in an isolated home. This executes the
marketplace layout and generated hook scripts without changing live plugin state:
```bash
E2E_HOME="$(mktemp -d)"
HOME="$E2E_HOME" COPILOT_HOME="$E2E_HOME/.copilot" \
copilot plugin marketplace add "$PWD"
HOME="$E2E_HOME" COPILOT_HOME="$E2E_HOME/.copilot" \
copilot plugin install project-toolkit@ai-agents
HOME="$E2E_HOME" COPILOT_HOME="$E2E_HOME/.copilot" \
RUN_INSTALLED_PLUGIN_HOOK_E2E=1 uv run pytest \
tests/e2e/test_installed_plugin_hook_e2e.py -q
```
Do not run this setup in the live Copilot home. Copilot CLI 1.0.72-1 was observed
removing the marketplace registration for `copilot plugin uninstall
project-toolkit` while leaving the `_direct/project-toolkit` cache. The active
session then lost its hook scripts and denied matching tools until the
marketplace plugin was reinstalled.
### Phase 4: Plugin Manifests Carry No Version
Two plugin manifests exist (verify:
`find . -name plugin.json -path "*claude-plugin*"`); a third,
`.claude/.claude-plugin/plugin.json`, is retired. `.claude/` is not a
marketplace-listed root; its template-owned files (SKILL.md, agents,
rules, hooks, settings) are binplaced from `src/claude/`, but skill
`scripts/`, `references/`, and `tests/` stay hand-maintained there:
| Tree | Manifest | Plugin name |
|------|----------|-------------|
| `src/claude/` | `.claude-plugin/plugin.json` | project-toolkit (Claude) |
| `src/copilot-cli/` | `.claude-plugin/plugin.json` | project-toolkit (Copilot) |
The rule (docstring of `build/scripts/validate_plugin_version_bump.py`): none of
those manifests may carry a `version` field, and neither may an entry in either
`marketplace.json`. Claude Code then resolves freshness from the git commit SHA,
which moves on every merge. ADR-092 records the reversal of ADR-079's
hand-bumped rule after issue #4080 measured 14 of 22 conflicting PRs conflicting
on that one line.
Practical consequences:
- Any `.claude/` content edit regenerates `src/copilot-cli/` too, but neither manifest changes: both are version-free, and `check_plugin_manifest_parity.py` now checks description component counts only.
- `src/claude/` is the same: no version to move.
- `.github/instructions/` and `src/vs-code-agents/` carry no plugin.json.
- Marketplace: `.claude-plugin/marketplace.json` lists one Claude-side plugin, `project-toolkit`, sourced at `./src/claude` (the retired `claude-agents` entry used `./.claude`). The old count validator is retired; keep counts honest by hand.
### Phase 5: npm Release Path
The npm surface is `packages/ai-agents-cli` (package
`@rjmurillo/ai-agents`; read `package.json` for the current version). It vendors
the Claude kit into consumer repos. Release procedure (source: `RELEASING.md`,
repo root):
1. Bump `packages/ai-agents-cli/package.json` version. Tag/version mismatch is a listed failure mode.
2. Local sanity: `cd packages/ai-agents-cli && bun run build` (runs `bun build src/cli.ts --outdir dist --target node`), `bun test`, `tsc --noEmit` via `bun run typecheck`. As of 2026-07-29 `bun run typecheck` exits 1 on this package with 38 errors (36 `TS2591`, 2 `TS2503`). `@types/node` 26.0.0 is installed, but the package `tsconfig.json` sets no `types` field, and TypeScript 7.0.2 no longer auto-includes it the way 5.9.3 does, so Node builtins are absent from the compilation. Issue #3865 tracks the fix: add `"types": ["node"]` and a CI job that runs typecheck and `bun test`. Before blaming your change for a red typecheck, check whether that fix landed: `grep -q '"types"' packages/ai-agents-cli/tsconfig.json`.
3. Commit to main via normal PR flow (branch discipline still applies; see `ai-agents-change-control`).
4. `git tag vX.Y.Z` then `git push origin main --tags`.
5. `.github/workflows/publish.yml` fires on `v*` tags: validates package metadata, publishes with OIDC provenance (`id-token: write`; `NPM_TOKEN` is fallback only). `workflow_dispatch` offers a dry-run input defaulting to `true`.
6. Verify: registry version, provenance badge on npmjs.com, clean-environment install (commands in RELEASING.md Verification section).
Rollback is roll-FORWARD: npm unpublish is restricted; fix, bump patch, retag (RELEASING.md Rollback procedures).
## Anti-Patterns
| Anti-pattern | Why it burns you | Do instead |
|--------------|------------------|------------|
| Hand-editing `src/copilot-cli/`, `src/vs-code-agents/`, `.github/instructions/`, `.claude/lib/` | Next regen silently overwrites your edit; ruff deliberately exempts generated Python (`pyproject.toml [tool.ruff.lint.per-file-ignores]` ignores all selected rule families under `src/copilot-cli/{hooks,skills}/**/*.py`), so lint will not even look at it | Edit the canonical tree (Phase 1 table), regenerate |
| Editing source to make a drift gate green | The 2025-12-15 disaster; drift output shows difference, not direction | Identify canonical side first, regenerate outward |
| Editing `.claude/lib/` or `src/copilot-cli/lib/` by hand | Both are generated; the next `build_all.py` run reverts you | Edit `scripts/{hook_utilities,github_core,ai_review_common}`, run `build_all.py` |
| Bumping the two project-toolkit manifests in lockstep to satisfy version parity | Version parity retired with the field (ADR-092); `check_plugin_manifest_parity.py` no longer compares versions, and the bump itself now fails the gate | Nothing to bump; leave both manifests version-free |
| Re-adding a `version` to a manifest to clear a red gate | The gate fails on the field's presence, so the red is permanent | Delete the field; freshness already tracks the commit SHA |
| Treating `Dropped: N` as normal without checking the source | Current source registrations all map to Copilot events; an unexplained drop means contract drift | Read the generation audit log, identify the source registration, and require an explicit `eventDrop` decision |
| Running `build_all.py` with bare `python3` in a fresh shell | PyYAML lives in the venv; import fails | `uv run python build/scripts/build_all.py` |
| Running installed-plugin E2E against live `~/.copilot` | Version skew and ambiguous uninstall mutate active hooks; a missing hook root can deny every matching tool | Set both `HOME` and `COPILOT_HOME` to one isolated directory and register the worktree marketplace there |
| Treating `src/claude/` as generated | It is the manual exception (ADR-036); no generator will save you | Hand-apply changes there; its manifest carries no version to bump |
## Verification
Run this checklist before pushing any change that touched a canonical or generated surface:
- [ ] `uv run python build/generate_agents.py --validate` exits 0
- [ ] `uv run python build/scripts/build_all.py --check` exits 0 (if it returns 2, read stderr first: regenerate only for staleness, not for an owned path that is unreadable, redirecting, or a nested repository, and not for a REQ-003-010 generator write)
- [ ] `uv run python build/scripts/build_all.py --check` exits 0 (covers the lib trees too; only relevant if `scripts/` packages changed)
- [ ] `python3 build/scripts/check_plugin_manifest_parity.py` exits 0
- [ ] `python3 build/scripts/validate_plugin_version_bump.py` exits 0 (no manifest or marketplace entry carries a `version`)
- [ ] Canonical edit and regenerated output are staged in the same commit set
- [ ] For an npm release: tag matches `packages/ai-agents-cli/package.json` version exactly
## Provenance and Maintenance
Verified 2026-07-29 against the working tree (re-verification pass; the 2026-07-03 pass had rotted for `build/scripts/build_all.py`, `build/generate_agents.py`, `pyproject.toml`, `.github/workflows/publish.yml`, and `.github/workflows/validate-generated-agents.yml`). Volatile facts and how to re-check them:
| Fact | Source | Re-verify |
|------|--------|-----------|
| 7 generators and their order | the `GENERATORS` list in build/scripts/build_all.py | `grep -n -A9 "^GENERATORS" build/scripts/build_all.py` |
| `OWNED_PREFIXES`, four entries | the `OWNED_PREFIXES` tuple in build/scripts/build_all.py | `grep -n "OWNED_PREFIXES" build/scripts/build_all.py` |
| .claude/ no-write invariant | build/scripts/build_all.py: `CLAUDE_GUARD_PREFIX` (rule), the `claude_baseline` snapshot in `run` (snapshot), `assert_no_claude_writes` called from `_run_generators` (enforcement) | `grep -n "REQ-003-010" build/scripts/build_all.py` |
| build_all exit codes 0/1/2/3, four exit-2 producers | the `EXIT CODES` block in the build/scripts/build_all.py module docstring | `grep -n -A20 "^EXIT CODES" build/scripts/build_all.py` |
| generate_agents flags and exit codes | build/generate_agents.py:13-16,460-487 | `uv run python build/generate_agents.py --help` |
| sync pairs scripts to lib trees | lib_mirror.py PACKAGES/PLUGIN_ROOTS | `grep -n PACKAGES build/scripts/lib_mirror.py` |
| Plugin manifest locations, all version-free | the three plugin.json files | `python3 build/scripts/validate_plugin_version_bump.py` |
| Version-field prohibition and the ADR-092 reversal | build/scripts/validate_plugin_version_bump.py docstring | `grep -n "WHY THE FIELD MUST BE ABSENT" build/scripts/validate_plugin_version_bump.py` |
| Parity gate #2222 | build/scripts/check_plugin_manifest_parity.py | `python3 build/scripts/check_plugin_manifest_parity.py` |
| Drift CI wiring | .github/workflows/validate-generated-agents.yml (multiple gates); agent-drift-detection.yml:146,156,159,171 | `grep -n "uv run python" .github/workflows/validate-generated-agents.yml && grep -n "python3 " .github/workflows/agent-drift-detection.yml` |
| Weekly semantic drift cron, threshold 80 | .github/workflows/drift-detection.yml; the drift script's own argparse default (command below) | `grep -n "cron" .github/workflows/drift-detection.yml && grep -n "default=80" build/scripts/detect_agent_drift.py` |
| Git hook jobs, filters, and validators | `lefthook.yml` | `uv run --frozen lefthook validate` |
| Ruff exemption for generated Python | `pyproject.toml [tool.ruff.lint.per-file-ignores]` | `grep -n "src/copilot-cli" pyproject.toml` |
| npm package, bun build, tag flow | packages/ai-agents-cli/package.json; RELEASING.md; .github/workflows/publish.yml:13-16 | `grep -n '"build":' packages/ai-agents-cli/package.json && grep -n "Rollback" RELEASING.md && grep -n "tags" .github/workflows/publish.yml` |
| Marketplace count validator retired | no dedicated count validator or marketplace counter YAML should exist | `find . -name "*marketplace*count*" -not -path "./.venv/*"` |
| Audit log path, gitignored | .gitignore:70 | `grep -n "build/audit" .gitignore` |
| 2025-12-15 direction story | .project-toolkit/retrospective/2025-12-15-drift-detection-disaster.md | `python3 -c "import pathlib;print([p.name for p in pathlib.Path('.project-toolkit/retrospective').glob('*drift*')])"` |
| ADR-036 superseded by ADR-052, ADR-052 superseded by ADR-109, ADR-108 and ADR-109 accepted | the ADR-036, ADR-052, ADR-108, and ADR-109 records | `[ "$(grep -Ec -e '^status: superseded$' -e '^superseded-by: ADR-052$' .project-toolkit/architecture/ADR-036-two-source-agent-template-architecture.md)" = 2 ] && [ "$(grep -Ec -e '^status: superseded$' -e '^superseded-by: ADR-109$' .project-toolkit/architecture/ADR-052-template-strategy.md)" = 2 ] && [ "$(grep -Ec '^status: accepted$' .project-toolkit/architecture/ADR-108-template-owned-skill-files.md)" = 1 ] && [ "$(grep -Ec -e '^status: accepted$' -e '^supersedes: \[ADR-052\]$' .project-toolkit/architecture/ADR-109-template-first-plugin-distribution.md)" = 2 ]` (`-e` counts each named field; a changed status or supersession drops the count; `&&` fails on any file; re-verified 2026-09-14) |
Maintenance: when a generator is added or removed from `GENERATORS`, when a fourth plugin.json appears, or if a marketplace count validator is reintroduced to replace the retired one, update Phase 1/4 tables and re-run every re-verify command above.