$npx -y skills add PolicyEngine/policyengine-claude --skill policyengine-plugin-maintenanceMaintaining the policyengine-skills source repo and its generated policyengine-claude wrapper — adding or editing skills, bundles, and the Claude/Codex targets, and keeping the verification harness green. For maintaining the catalog, not for using PolicyEngine. Triggers: "update
| 1 | # Maintaining the PolicyEngine skills catalog |
| 2 | |
| 3 | > This skill is for maintaining the skills SOURCE repo and the Claude wrapper — not for using |
| 4 | > PolicyEngine. |
| 5 | |
| 6 | ## Repository shape (rebuilt) |
| 7 | |
| 8 | Flat, category-tagged skills compiled into install profiles, then rendered into per-target |
| 9 | wrappers. |
| 10 | |
| 11 | - `skills/<name>/SKILL.md` — one flat directory per skill (no `domain-knowledge/`, |
| 12 | `tools-and-apis/` nesting). Frontmatter is `name` (equal to the dir name), a `description:` |
| 13 | block that carries trigger phrases and stays under 1024 characters (hard Codex limit), and |
| 14 | `metadata.category`. Supporting files sit beside SKILL.md — e.g. |
| 15 | `skills/policyengine-content/templates/social-image.html`. |
| 16 | - `bundles/*.json` — install profiles. Each lists the skills, commands, and agents it ships by |
| 17 | path. `complete.json` is the recommended everything bundle; the rest are scoped (essential, |
| 18 | country-models, analysis-tools, app-development, api-development, data-science, |
| 19 | dashboard-builder, content). |
| 20 | - `targets/claude/` — the Claude wrapper source: `marketplace.template.json`, `agents/`, |
| 21 | `commands/`, `hooks/hooks.json`, `lessons/`. `targets/codex/` is the Codex target. |
| 22 | - `scripts/build_claude_wrapper.py` — compiles the bundles and marketplace template into the |
| 23 | generated `policyengine-claude` marketplace, validating that every referenced skill, command, |
| 24 | and agent path exists (and normalizing plugin entries for the current Claude Code schema). |
| 25 | - `presets/`, `analyses/`, `dashboard/`, `mcp/` — analysis infrastructure consumed by the |
| 26 | commands and agents. |
| 27 | |
| 28 | ## Build and publish |
| 29 | |
| 30 | CI (`.github/workflows/test.yml`) runs `uv run pytest` and smoke-builds the wrapper on every PR. |
| 31 | On merge to main, `sync-claude.yml` builds the wrapper and rsyncs it into |
| 32 | `PolicyEngine/policyengine-claude` — the marketplace repo users actually install — committing as |
| 33 | the sync bot. Build and test locally with: |
| 34 | |
| 35 | ```bash |
| 36 | uv run pytest # full lint + unit suite |
| 37 | python3 scripts/build_claude_wrapper.py --source-root . --output-root build/policyengine-claude |
| 38 | ``` |
| 39 | |
| 40 | ## The verification harness (do not defeat it) |
| 41 | |
| 42 | The rebuild exists because the old catalog shipped API claims nothing had ever executed — |
| 43 | some deleted upstream, some never real. Two tests hold the line; treat them as the |
| 44 | definition of "done", not as obstacles. |
| 45 | |
| 46 | ### Executable examples — `tests/test_skill_examples.py` |
| 47 | |
| 48 | A ```python fence whose immediately preceding non-empty line is exactly the verify marker |
| 49 | `<!-- verify -->` is a **fast** example: self-contained, household-tier, and it must assert |
| 50 | something. The harness executes every such block in a subprocess (300s timeout) and fails if it |
| 51 | exits non-zero. The `<!-- verify: slow -->` variant marks population-scale examples (multi-GB |
| 52 | data, tens of GB of RAM); those run only when `PE_SKILLS_RUN_SLOW=1` is set — at authoring time |
| 53 | and on demand, not in PR CI. The module skips entirely when `policyengine` is not installed, so |
| 54 | it runs in a dedicated CI job that installs the stack (the default job passes |
| 55 | `--ignore=tests/test_skill_examples.py`). A guard test also fails if zero fast examples are found, |
| 56 | so the harness cannot silently go blind. |
| 57 | |
| 58 | **Discipline: never place a verify marker on a block you have not actually run successfully.** A |
| 59 | green marker on an unrun block is precisely the failure the rebuild removed. Run it in a |
| 60 | policyengine venv first, watch it assert, then add the marker. |
| 61 | |
| 62 | ### Anti-rot lint — `tests/test_no_stale_references.py` |
| 63 | |
| 64 | Scans `skills/`, `targets/`, `docs/`, `bundles/`, and `presets/` (`.md`, `.json`, `.yaml`, |
| 65 | `.yml`, `.py`, `.sh`, `.html`) for a table of regexes that each name a dead API, path, dataset, |
| 66 | or package the pre-rebuild catalog leaked: the archived us-data Hugging Face URI, per-state and |
| 67 | per-district H5 filenames, the retired enhanced-CPS/FRS dataset names, the deprecated per-entry |
| 68 | changelog YAML, v1 app source paths, legacy UI libraries app-v2 no longer uses, deleted |
| 69 | household-impact functions from policyengine.py, the old design-system package as an install |
| 70 | target, and non-uv pip installs. The authoritative pattern-and-reason list |
| 71 | lives in the test's `FORBIDDEN` table — read it there rather than duplicating it. Any hit fails |
| 72 | CI. A line opts out when the marker `<!-- stale-ok -->` sits on it or on the line directly above, |
| 73 | reserved for a deliberate "this is the superseded thing" history o |