425 plugins, 2,810 skills, 200 agents for Claude Code. Open-source marketplace at tonsofskills.com with the ccpi CLI package manager.
# Repository Guidelines
## Project Structure
This is the Tons of Skills Claude Code plugin marketplace. Author plugins under `plugins/<category>/<plugin-name>/`; a plugin commonly contains `skills/`, `commands/`, `.claude-plugin/plugin.json`, and a README. The editable catalog is `.claude-plugin/marketplace.extended.json`; its `marketplace.json`, generated plugin `package.json` files, and the README table of contents are derived. Shared tooling lives in `scripts/`, workspace packages in `packages/`, Python regression tests in `tests/`, and the Astro site in `marketplace/`.
## Build, Test, and Development
Use Node 20+ and pnpm 9.15.9+ at the repository root; `marketplace/` deliberately uses npm.
```bash
pnpm install
./scripts/quick-test.sh # fast repository sanity check
pnpm test && pnpm typecheck && pnpm lint
pnpm run verify # CI-equivalent verification pipeline
pnpm run sync-marketplace # regenerate catalog-derived files
cd marketplace && npm run dev # local Astro site, port 4321
cd marketplace && npx playwright test # website end-to-end tests
```
Do not hand-edit generated catalog artifacts. Run `pnpm run sync-marketplace` before committing catalog or plugin changes. Validate skill metadata with `python3 scripts/validate-skills-schema.py --marketplace --verbose`; use `python3 scripts/validate-unicode-hygiene.py` for changed skill content.
## Style and Naming
Follow the existing fileβs style; use Prettier for JavaScript, TypeScript, JSON, YAML, and Markdown (`pnpm run format:check`) and ESLint (`pnpm lint`) for code. Use two-space indentation in JS/TS and JSON. Name plugin folders lowercase kebab-case (for example, `plugins/mcp/example-plugin`) and skills as `skills/<skill-name>/SKILL.md`. Keep frontmatter compliant with the schema validator rather than inventing local variants.
## Tests
Add or update focused tests beside the affected package or in `tests/`; Python tests use `test_*.py` and TypeScript tests commonly use `*.test.ts`. Run the narrowest relevant test first, then the commands above. Changes to validators, schemas, or catalog generation require their targeted regression suite plus the marketplace schema validation.
## Commits and Pull Requests
Use Conventional Commit-style subjects visible in history, such as `fix(ci): harden validation` or `docs(contributing): clarify workflow`. Keep each commit scoped. PRs should explain the user-facing change, link the beads issue, include screenshots for visual site changes, and include regenerated derived files when applicable. Use `bd` for task tracking: run `bd ready`, claim the issue, and close it when complete. Before finishing, commit, pull/rebase, run `bd sync`, push, and confirm `git status` is up to date.
## Merge gates (do not weaken)
Required branch-protection contexts on `main`: **`ci-required`**, **`gitleaks`**, **`skill-conform`**.
- `skill-conform` is a **separate** always-report workflow (`audit-harness conform --strict`). Never add it (or any path-scoped / provider-dependent job) to `ci-required`'s `needs:`.
- Behavioral skill eval (`skill-eval-advisory.yml`) is **advisory only** until explicitly graduated.
- Full gate architecture, validator SSoT rules, and non-negotiables: see `CLAUDE.md`.
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Repository Overview
Tons of Skills β Claude Code plugins marketplace. Live at https://tonsofskills.com
**Runtime:** Node `>=20.0.0`, pnpm `>=9.15.9`. Node 18 causes silent workspace-resolution failures.
**Package manager:** `pnpm` everywhere **except** `marketplace/` which uses `npm` (CI-enforced).
**Contributor guidelines live in `AGENTS.md`** β project structure, build/test/dev commands, style and naming, test conventions, commit/PR expectations, and the merge gates. Read it before starting work. (Session protocol lives in this file: the beads workflow in Β§ Beads Issue Tracker β where `bd prime` is also the post-compaction context-recovery step β and the end-of-session push checklist in Β§ Session Completion.)
## Cross-session coordination β another Claude session may be in this repo
This repo is frequently worked in **parallel** with the `intent-eval-platform` umbrella session (that platform's CCPI validator + jrig-cli + kernel reach into this repo). Sessions are separate processes that share only the filesystem, so stay in sync via the shared surfaces:
- **Read + append the shared journal** on cross-repo work: `~/000-projects/CROSS-SESSION-LOG.md` (append a dated line: what / branch or PR# / status).
- **Durable cross-cutting tasks:** umbrella beads `~/000-projects/.beads/`, label `cross-session` (`bd list --label cross-session`).
- **Guard the working tree:** this repo has ONE checkout; a concurrent session can `git checkout`/`reset` it out from under you and **wipe UNCOMMITTED work** (happened 2026-07-01). Commit early, or do multi-step file work in a `git worktree`.
Full protocol (loaded by every session under `/home/jeremy`): `/home/jeremy/CLAUDE.md` Β§ "Cross-session coordination".
## Essential Commands
```bash
# Before ANY commit β regenerates marketplace.json, plugin package.jsons, README TOC
pnpm run sync-marketplace
# Quick sanity check (~30s)
./scripts/quick-test.sh
# Build & test
pnpm install && pnpm build
pnpm test && pnpm typecheck
pnpm lint
pnpm run verify # Full pipeline β what CI's `verify` job runs
# Validator (schema 4.0.0 β see 000-docs/SCHEMA_CHANGELOG.md)
python3 scripts/validate-skills-schema.py --verbose
python3 scripts/validate-skills-schema.py --marketplace --verbose
python3 scripts/validate-skills-schema.py --marketplace --populate-db freshie/inventory.sqlite
python3 scripts/validate-skills-schema.py --agents-only --verbose # agents only (kernel-strict gate)
# Unicode hygiene gate β Trapdoor / Trojan Source defense for SKILL.md /
# plugin.json / agent / command files. Default mode blocks on tag chars
# (U+E0000-E007F) + bidi overrides (CVE-2021-42574). --strict also blocks
# on zero-width / format chars outside the BOM position.
python3 scripts/validate-unicode-hygiene.py
python3 scripts/validate-unicode-hygiene.py --strict # tighter
python3 scripts/validate-unicode-hygiene.py path/to/file.md # one file
python3 -m unittest tests.test_validate_unicode_hygiene -v # regression suite
# Marketplace website
cd marketplace/ && npm run dev # localhost:4321
cd marketplace/ && npm run build
cd marketplace/ && npx playwright test
# Single test
cd packages/cli && pnpm test -- --grep "pattern"
# JRig behavioral eval β the published @intentsolutions/jrig-cli (bin `j-rig`),
# pinned as a root devDep. Invoke via `pnpm exec j-rig` so it resolves the
# repo's pinned version (node_modules/.bin/j-rig), NOT a global shim.
pnpm exec j-rig --version # β 0.1.2 (the real 7-layer CLI)
pnpm exec j-rig check <skill-dir> # Tier 3A: deterministic (~seconds, free, no API key, no DB)
# Real behavioral eval (opt-in, ~$2-5/skill) β needs the native better-sqlite3
# build (run `pnpm rebuild better-sqlite3` once; the build script is not
# auto-run on install). ALWAYS route through the wrapper β it runs j-rig
# against a /dev/shm scratch DB and records the verdict into forge_proofs via
# scripts/record-jrig-proofs.mjs. NEVER pass freshie/inventory.sqlite to
# `j-rig eval --db` directly: j-rig writes its own run tables into whatever
# --db it is given, which contaminates the tracked CMDB (and, pre-allowlist,
# leaked those tables to the public DoltHub record).
scripts/run-jrig-eval.sh --skill-dir <skill-dir> --plugin <catalog-name> \
--inventory-db freshie/inventory.sqlite
# DEEPSEEK_API_KEY is SOPS-decrypted in-process by the wrapper
# (intent-eval-lab/.env.sops; see the IEP umbrella CLAUDE.md credential
# table). Defaults: --provider deepseek --models deepseek-v4-flash β a real
# behavioral provider, this is ground truth; other providers (haiku/sonnet/
# opus via Anthropic, etc.) remain available via --provider/--models.
```
## Two Catalog System β Critical
| File | Purpose | Edit? |
| ------------------------------------------ | ------------------------------ | --------- |
| `.claude-plugin/marketplace.extended.json` | Source of truth | **Yes** |
| `.claude-plugin/marketplace.json` | CLI-compatible, auto-generated | **Never** |
`pnpm run sync-marketplace` regenerates all three derived artifacts: `marketplace.json`, any missing `plugins/**/package.json` files, and the `README.md` AUTO-TOC block. The pre-commit hook runs this automatically when `marketplace.extended.json` is staged.
CI fails if any derived file is out of sync. Never hand-edit auto-generated files.
## Marketplace Build Pipeline
`npm run build` in `marketplace/` runs 7 sequential steps via `scripts/build.mjs`: discover-skills β extract-readme-sections β sync-catalog β enrich-jrig-data β generate-unified-search β build-cowork-zips β astro build.
`discover-skills.mjs` emits two artifacts (schema 3.4.0+): `skills-index.json` (L0, ~97 KB gzipped, metadata only β for trigger-match / browse) and `skills-catalog.json` (L1, ~5.5 MB gzipped, full body HTML). Both carry top-level `schemaVersion` + `level` fields. CLI flag `--level=metadata|full|file` (default `full`).
**Gotcha:** `compressHTML` is disabled in `astro.config.mjs` β iOS Safari fails on lines > 5000 chars. CI enforces this.
Performance budgets (CI-enforced): 40 MB total gzipped, 1 MB largest file, < 30s build, 2,800β4,000 routes.
## Auto-cowork contract
**Author flow.** Add a plugin to `.claude-plugin/marketplace.extended.json` and run `pnpm run sync-marketplace`. That is the entire authoring step. The pre-commit hook regenerates `marketplace.json`, plugin `package.json`s, and the README AUTO-TOC. There is no separate "update the cowork page" step.
**Pipeline (deterministic from the catalog).** `cd marketplace && npm run build` runs `scripts/build.mjs`, which on every invocation:
1. `cowork:zips` (`scripts/build-cowork-zips.mjs`) β wipes `marketplace/public/downloads/{plugins,bundles}` and rebuilds them from `marketplace.extended.json`. Produces individual plugin zips, category bundle zips, the mega-zip, `downloads/manifest.json`, and the Astro-consumed `marketplace/src/data/cowork-manifest.json`. Skips `category: mcp` entries (MCP plugins do not appear in cowork).
2. `cowork:validate` (`scripts/validate-cowork-manifest.mjs`) β drift gate. Fails the build if catalog β manifest β disk fall out of alignment (orphan zips, missing entries, or stale manifest rows). Runs again in CI as a discrete step in `.github/workflows/validate-plugins.yml` so the failure signal is clearly named.
3. `astro build` β copies `marketplace/public/` β `marketplace/dist/`. The `/cowork/` page reads `cowork-manifest.json` at build time and renders the download grid.
**Deploy propagates the wipe.** The VPS force-command script `/usr/local/sbin/deploy-tonsofskills` ends with `rsync -a --delete /srv/tonsofskills/build/marketplace/dist/ /srv/tonsofskills/dist/`, so orphan files removed by the cowork build are also pruned from the served `dist/`. Current deployment authority is `intent-os/ops/deploy/`.
**Don't commit downloads/.** `marketplace/public/downloads/` is gitignored (see `.gitignore:146`). CI checks out fresh and rebuilds from scratch β local state cannot leak to prod. Never commit or hand-edit anything under that directory.
**Don't wire cowork build into `sync-marketplace`.** `sync-marketplace` is the fast (<2s) per-commit hook; `cowork:zips` is the slow (~30s) per-build step. They run on different cadences by design.
## External Plugin Sync (mirror-by-default)
Adopted model: **mirror by default Β· upstream improvements Β· never clobber.** Decision record: `000-docs/694-AT-DECR-external-sync-mirror-by-default-model.md`; pipeline audit + hardening: `000-docs/691-AT-AUDT-sync-external-pipeline-audit-and-hardening.md`.
**Scale first β external is a minority augment, not the core.** ~470 plugins total (per `marketplace.extended.json`), but only 63 are externally synced (57 third-party sources + 6 of Jeremy's own repos, per `sources.yaml`). The other ~407 (~87%) are in-repo Intent Solutions work. The sync is a curated side-channel, not the marketplace β treat external contributors as a respected minority augment, never the center of gravity.
**How sync works.** `sources.yaml` registers each external source. `.github/workflows/sync-external.yml` runs weekly (Mondays 06:00 UTC) and on demand (`workflow_dispatch` / `repository_dispatch`), invoking `scripts/sync-external.mjs` to mirror a source's files into `plugins/` and open an automated PR. A human reviews every auto-PR β historically ~1 in 10 sync PRs merges. The contributor's own repo is the source of truth; we do NOT locally edit a pure-mirror plugin.
**Mirror vs curate.** Default is a pure mirror β the upstream repo governs, and improvements flow by upstreaming (see below), so the mirror becomes A-grade naturally with nothing to revert. Only when we deliberately harden a plugin past its upstream do we mark it `curated:` and freeze it.
**Never-clobber guard (`curated:` freeze).** A source with `curated: true` in `sources.yaml` is FROZEN: `sync-external.mjs` logs `Curated β mirror frozen`, writes no files (no clone, no overwrite, no orphan-prune), and only keeps the catalog entry current β so even a `--force` sync can never revert our edits. `tonone`, `servicegraph`, and `schedule-after-usage-reset` carry `curated: true` today; `hyperflow` does NOT β it is the completed off-ramp example (its frontmatter hardening merged upstream, so the flag was dropped in #1008). This guard exists because a prior `--force` run reverted ~100 A-graded agents back to 3-field upstream stubs β the ~18.9k-line deletion that motivated the whole model. Note `curated:` (we hardened it locally) and `verified:` (a maintainer vetted quality/trust) are orthogonal: all three curated sources are `curated: true` but `verified: false`, an honest state and exactly why the two flags are separate.
**Pileup auto-close (β€1 open sync PR).** `sync-external.yml` runs a "Close superseded sync PRs" step before Create-PR: it closes older open `automation/sync-external-*` PRs (with `--delete-branch`), keeping at most one open sync PR. The safe unique-per-run-branch model (from the 691 audit, which fixed an earlier shared-branch clobber) is preserved β this only prunes the pileup that model produced.
**How we upstream respectfully.** Want a plugin at our A-grade bar? We bring THEIR plugin to standard on THEIR repo: a friendly issue first ("we featured your plugin and hardened its frontmatter to our A-grade bar β would you be open to a PR upstreaming it?"), then a PR the contributor owns and merges. No surprise PRs; credit preserved; they decide. Once merged upstream, the mirror is A-grade naturally and `curated:` can be dropped. **Any contributor-facing post (issue or PR body) gets Jeremy's wording sign-off BEFORE posting.**
## Plugin Structure
**AI instruction plugins** (`plugins/[category]/[name]/`): `.claude-plugin/plugin.json` + `README.md` + optional `commands/*.md`, `agents/*.md`, `skills/[name]/SKILL.md`.
**MCP server plugins** (`plugins/mcp/[name]/`): TypeScript source in `src/`, built to `dist/index.js` (must be executable: shebang + `chmod +x`).
**Forge-generated plugins** include a `.forge/` audit trail dir (`research.md`, `ecosystem.md`, `proofs.md`) β build-time only, not used at runtime. Canonical example: `plugins/productivity/plane/`.
### SKILL.md Required Frontmatter (marketplace tier β all 8 fields)
```yaml
---
name: skill-name
description: |
Capability summary. Use when ... Trigger with "...".
allowed-tools: Read, Write, Edit, Bash(npm:*), Glob
version: 1.0.0
author: Name <email>
license: MIT
compatibility: Designed for Claude Code
tags: [devops, ci]
---
```
Beyond the 8 required fields, schema 3.5.0+ adds optional visibility-gating fields, 3.6.0+ adds self-declared config fields, and 3.7.0+ adds `disallowed-tools` β see the Optional frontmatter section below.
`compatible-with` is deprecated. Migrate with: `python3 scripts/batch-remediate.py --migrate-compatible-with`
**Agents use `disallowedTools` (camelCase denylist).** Skills use `allowed-tools` (allowlist) AND optionally `disallowed-tools` (kebab-case denylist, schema 3.7.0+). The two field names are intentionally different β do NOT use camelCase on skills or kebab-case on agents; the validator rejects either mismatch. Agent-only fields: `effort`, `maxTurns`.
**Agent gate is kernel-strict (schema 3.10.0, NOT tier-gated).** Every authored agent must carry the kernel-floor 8 (`name, description, tools, model, color, version, author, tags`) plus the enterprise live set (`disallowedTools`, `skills`, `background`; + `hooks`, `mcpServers`, `permissionMode` on standalone agents) β all **errors** at every tier. Banned fields (`capabilities`, `expertise_level`, `activation_priority`, `type`, `category`, `compatible-with`, `when_to_use`) are errors; `fable` is an accepted model. **Corpus status (measured 2026-08-11, doc 721):** the advisory `--agents-only` lane recorded a baseline of **253 errors** across the agent corpus β the earlier "all agents A-grade" claim is retired until the lane is re-baselined clean; treat A-grade as the bar, not the current state. **Schema 3.11.0** added a body-vs-allowlist check: an agent whose body invokes `mcp__server__tool` not in its `tools` allowlist is an error (it would runtime-block). Validate with `--agents-only`.
### Optional frontmatter (schema 3.5.0 / 3.6.0 / 3.7.0 β all default to off)
- **Visibility gating (3.5.0):** `requires_env` / `requires_tools` / `fallback_for_env` / `fallback_for_tools` β list-of-strings. Skill hidden unless deps met; fallback form is the inverse. Cross-field overlap (`requires_X` + `fallback_for_X` of same value) is an ERROR.
- **Self-declared config (3.6.0):** `required_environment_variables` (top-level list, each entry needs `name` + `prompt`) and `metadata.intent-solutions.config` (nested list, each entry needs `key` + `description` + `default`). Full reference: `000-docs/264-DR-GUID-skill-config-pattern.md`.
- **Defense-in-depth disallow list (3.7.0):** `disallowed-tools` β kebab-case string or YAML list of tool patterns. Removes those tools from the model while the skill is active. Parallel to (not a replacement for) `allowed-tools`. Cross-field overlap with `allowed-tools` is an ERROR (mirrors the 3.5.0 visibility-gating overlap rule). Defense-in-depth for skills that legitimately need broad `allowed-tools` but should never reach for specific high-risk operations (`rm`, `curl`, `wget`, `.env` writes). Full reference: `000-docs/681-AT-ADEC-claude-code-platform-changelog-impact.md` Β§ Change 1.
- **NON-NEGOTIABLE:** these are optional. `ALWAYS_REQUIRED` is still the 8-field set above. See issue #612 + `000-docs/681-AT-ADEC-claude-code-platform-changelog-impact.md` Β§ Implementation directives before proposing any change to required fields β the 8-field set is preserved; `disallowed-tools` is additive, not required.
## CI gate architecture β three required checks (rebuilt 2026-07; skill-conform added 2026-07-23)
**Branch protection on `main` requires THREE always-reporting contexts: `ci-required` + `gitleaks` + `skill-conform`** (GitHub Actions app; `strict:false`, `enforce_admins:false`, 1 approving review).
- **`ci-required`** is the final job in `.github/workflows/validate-plugins.yml` β `if: always()`, `needs:` all 19 gate jobs (validate, verify, test, check-package-manager, marketplace-validation, cli-smoke-tests, shellcheck-skills, skill-codeblock-syntax, typescript-coverage-audit, eslint-check, format-check, ruff-check, ruff-format-check, markdownlint, scan-synced-content, promote-curated-check, check-submission-docs). It fails if any needed job ended `failure`/`cancelled`; a `skipped` result counts as PASS β legitimate **only** for a designed job-level `if:`.
- **`gitleaks`** comes from `secret-scan.yml` (also unfiltered).
- **`skill-conform`** is its **own** workflow (`.github/workflows/skill-conform.yml`) β `pnpm exec audit-harness conform --strict` over the full marketplace corpus. Always-reports (no path filter). **Never** folded into `ci-required`'s `needs:` (doc 110 Β§ 5: a skippable/path-scoped job must not green the aggregate). Baseline after #1108/#1118: thousands PASS / 0 FAIL; remaining ADVISORY is the harness-side missing marketplace schema only.
- **Advisory (never required):** `.github/workflows/skill-eval-advisory.yml` β j-rig behavioral eval on changed skills that already carry `eval-spec.yaml`. Kill-switch `vars.ENABLE_SKILL_EVAL=true` + same-repo guard + `MINIMAX_API_KEY`. Graduation to required needs Jeremy + β₯4-week clean flap window (doc 110).
- **Ruff pin:** `validate-plugins.yml` installs **`ruff==0.15.22`** for both ruff-check and ruff-format-check. Unpinned install pulled 0.16.0 mid-2026-07-23 and treated SKILL.md fenced Python as format targets (~1132 files). Do not unpin without a deliberate corpus reformat.
**Why, and the rules that keep it fixed (do not regress):** the previous 10-context required set sourced checks from path-filtered workflows, so a PR without matching files left them "Expected" forever and could never merge (the #778/#964 stuck-PR class).
1. `validate-plugins.yml` runs on **every** `pull_request` β never add a `paths:` filter to it.
2. **Never add a path-filtered workflow's context to the required-status set.** To make a new check blocking: add it as a job in `validate-plugins.yml` and list it in `ci-required`'s `needs:`.
3. A job in the aggregate's `needs:` may only skip via a _designed_ `if:` β an undesigned skip silently passes the gate.
4. The five split lint workflows (`lint-markdown/python/shell/typescript/skill-codeblocks.yml`) were retired 2026-07; their identically-named jobs live in `validate-plugins.yml`. Do not re-split them. `tests/ci/test_path_routing.py` pins this invariant.
**Supply-chain gate:** `scan-synced-content` (the REFUSE/CHALLENGE/FLAG scanner over `plugins/**`, `scripts/scan-synced-content.mjs`) blocks via the aggregate. A `sources.yaml`-only PR scans zero files and deliberately fails with a **waivable** `sources-change-unscanned` CHALLENGE β a reviewer clears it with a `sources.yaml:sources-change-unscanned <reason>` line in `scripts/scan-allowlist.txt` after confirming the source is vetted and pinned in `sources.lock.json`. REFUSE is never waivable.
**Submission-docs intake gate:** `check-submission-docs` (`scripts/check-submission-docs.mjs`) blocks via the aggregate. A PR that adds a NEW plugin directory (its `.claude-plugin/plugin.json` is an added file in the diff) must ship the tiered submission documents per the matrix in `templates/skill-docs/README.md` (micro β `docs/PRD.md`; standard β + `docs/ADR.md`; pack, 2+ skills β + `docs/ONE-PAGER.md`; `CFO-ONE-PAGER.md` stays review-enforced β "money is the pitch" isn't deterministic). External mirror plugins (dir contains `.source.json`) are exempt β their docs live upstream. A PR adding no new plugin passes clean INSIDE the script (the designed skip), so the job always reports. Standard: `000-docs/700-DR-GUID-skill-submission-standard.md`.
**Advisory lanes (report, never block β never promote into the required set from a side PR):** the two kernel lanes (next section); agent frontmatter (`validate-skills-schema.py --agents-only`, report-only with a tracked `REPORT-ONLY-UNTIL:` marker β corpus unbaselined); `.mcp.json` (`scripts/validate-mcp-config.mjs`, never `--strict` β that promotion belongs to the DR-049 soak checklist); CodeQL (PR trigger scoped to `packages/**` + `marketplace/src/**` so it adds no fan-out to plugin PRs); and the PR pre-screen (below).
### AI review β Greptile is active and advisory; CI is the only merge gate
**As of 2026-07-23 Greptile is active through the GitHub App and has reviewed recent CCPI PRs.** Its version-controlled policy lives under `.greptile/`; treat its findings as advisory semantic-review input, not a merge signal. Gemini Code Assist consumer product is **sunset** (bot posts a sunset notice only; `.gemini/config.yaml` has `code_review.disable: true`). Fully removing Apps is a UI/admin action. Optional future path: SHA-pinned MiniMax review (`MINIMAX_API_KEY` + `ENABLE_MINIMAX_REVIEW`) as already patterned in `minimax-review.yml`.
**Operationally: never block a merge waiting for an AI review.** Required contexts are **`ci-required` + `gitleaks` + `skill-conform`**.
### PR pre-screen (advisory respond leg)
`pr-prescreen.yml` (`pull_request_target`; kill switch `vars.ENABLE_PR_PRESCREEN`) grades changed plugins with the pinned validator and responds in two low-noise ways: a **`prescreen-grade` commit status** on every run (advisory forever β never a required context) and **one upserted marker comment** only on `CHANGES_REQUESTED`/`HARD_BLOCK` (silent on PASS; re-runs edit the same comment). Two hard-won invariants:
- **The validator anchors its scan root to its own script location** (`Path(__file__).resolve().parents[1]`), not the cwd. Prescreen therefore copies the BASE-authored validator into the PR tree and runs the copy β invoking `../base/scripts/β¦` directly grades **main's** tree and false-PASSes every frontmatter change (the 2026-07 bug, fixed in #980). Do not "simplify" this back.
- **Never checkout or execute PR-authored code in a `pull_request_target` workflow.** Applies equally to `plane-sync.yml` (which runs on `pull_request_target` so fork-PR close-outs get secrets β it reads event context only).
## Validation & the kernel SSoT β CI/CD posture
Two things grade frontmatter in this repo today, and the relationship between them is the load-bearing context to preserve.
### The two validators
- **Prose-spec validator (authoritative):** `scripts/validate-skills-schema.py`. This is the canonical gate. It runs at standard and marketplace tiers, it grades both frontmatter AND markdown body sections, and at marketplace tier a missing required field is an **ERROR** (not a warning). Its CI jobs block merges through the `ci-required` aggregate (see "CI gate architecture" above). `ALWAYS_REQUIRED` (the IS 8-field set) is hand-authored here and stays **AUTHORITATIVE** β read `000-docs/SCHEMA_CHANGELOG.md` Β§ NON-NEGOTIABLES before touching it. The IS rubric sits on top of Anthropic's permissive spec; the marketplace tier is intentionally strict. Do not reduce the 8-field set, do not demote marketplace errors to warnings, and do not "realign" to Anthropic's floor β any change to required-fields / tier model / error-vs-warning semantics is approval-gated per that doc.
- **Kernel machine-spec (the SSoT being migrated to):** `@intentsolutions/core` β its `schemas/authoring/v1` family (byte-frozen) plus the strict fork `authoring/v2` β is the single internal source of truth for "what is a valid agent-native artifact." The kernel's `skill-frontmatter` schema encodes the **same** IS 8-field required set as a pure `allOf` of upstream-base + universal folds + the IS overlay. The plan of record is for `validate-skills-schema.py` to **consume the kernel folds** instead of its hand-rolled rule sets. That migration is in progress; the kernel pin is **exactly `0.9.0`** in `package.json` (no `^`/`~`) β currently **behind** the published `0.10.0`, see the staleness note below. The `authoring/v1` schema family is byte-frozen across kernel package versions, so a pin bump tracks the latest published kernel without changing the `authoring/v1` contract the shadow lane reads. Contract semantics for `authoring/v1` fields are canonical in the kernel's own changelog β cite it, do not duplicate it (see `000-docs/SCHEMA_CHANGELOG.md` Β§ "Kernel changelog citation").
### Two advisory lanes (never block) running the soak
Both are `continue-on-error: true`, neither is in the required-status set, and neither mutates anything:
- **kernel-shadow soak** β `.github/workflows/kernel-shadow-validation.yml` + `scripts/kernel-shadow-validation.mjs`. Runs the kernel-pinned `skill-frontmatter` schema (from `@intentsolutions/[email protected]`) over the same SKILL.md corpus the prose-spec validator grades and logs per-file AGREE / DISAGREE deviation to `scripts/.kernel-shadow/report.json`. This is the DR-049 shadow soak (the "zero-on-corpus shadow signal"). The cutover-relevant number is the **frontmatter-scoped** deviation β a file that fails the prose-spec on missing `[body]` sections but has valid frontmatter is a scope difference, not a kernel gap, and is excluded.
- **kernel-vendor-hash gate** β `.github/workflows/kernel-vendor-hash.yml` + `scripts/kernel-vendor-hash.mjs`. Enforces the version-coupling invariant **V β€ C β€ K** (vendored β€ CCPI-declared β€ kernel-latest) plus a β€7-day staleness bound. Soak-aware: it reads the `0.9.0` pin, polices ordering/staleness only, and must never pressure a pin bump or change validator authority.
The validator itself does a kernel-loaded **shadow read** of `ALWAYS_REQUIRED` (`load_kernel_required()` / `--kernel-shadow`) β it compares the kernel's effective required set against the hand-authored one and reports drift. The hand-authored `ALWAYS_REQUIRED` stays authoritative; the shadow read is observational only.
### Do-not-flip soak discipline (do not lose this)
**The kernel pin and the authority flip are two SEPARATE axes β do not conflate them.** The pin is _intended_ to track the latest published kernel; bumping it keeps the shadow lane reading a current, byte-frozen `authoring/v1` contract and is a routine governance/coupling update, not an authority change.
> β οΈ **The pin is currently BEHIND (as of 2026-07-26).** Root pin is exactly `0.9.0` (no `^`/`~`) but `@intentsolutions/[email protected]` published 2026-07-09 β so the β€7-day staleness bound has been breached since roughly 2026-07-16, and the `kernel-vendor-hash` daily sweep has been reporting `β VIOLATION: STALENESS` on every run. It is ADVISORY (exit 0), which is why it went unnoticed. Catching this up is a **lockstep** change: `@intentsolutions/[email protected]` depends on `[email protected]` _exactly_, so core must move together with jrig-cli (`0.2.0`, published 2026-07-10) or the two resolve to separate un-hoisted copies of the kernel. Do not read the staleness report as pressure to flip authority β the two axes remain separate, and re-baselining the shadow-soak agreement numbers is part of the bump.
What stays frozen is the **authority**: do **NOT** flip the kernel-shadow lane from advisory to authoritative (blocking) until ALL of these hold:
1. β₯99.5% corpus agreement (deterministic folds must be 100%; the 0.5% band is reserved for non-deterministic surfaces only);
2. β₯30 days of advisory soak;
3. zero open P0 blockers;
4. the Rekor superseding-event rollback protocol implemented and tested;
5. governance sign-off from the CTO + CISO + VP-DevRel triple; and
6. a β₯14-day public deprecation-window notice to affected skill authors.
As of now the soak has **not** met the bar β agreement sits below 99.5%, and the open disagreements are real tool-safety / shell-substitution security cases that the prose-spec validator correctly blocks (so flipping early would weaken a real gate). Until every condition above is satisfied, validator authority stays with `validate-skills-schema.py` and both kernel lanes stay advisory. Promotion to blocking is a separate, later cutover step gated by these conditions β never a side effect of an unrelated PR.
**Alignment note (`@intentsolutions/jrig-cli`).** The `j-rig` behavioral-eval CLI is a root devDep pinned to **exactly `@intentsolutions/[email protected]`**, which depends on **`@intentsolutions/[email protected]` (exact)** β the same version the **root** `@intentsolutions/core` pin carries β so they resolve to one shared root-hoisted copy and the kernel-shadow + kernel-vendor lanes read it directly. (The `0.1.2` cut carries the evalβEvidence-Bundle bridge `j-rig eval --emit-bundle` [jrig #172], a functional-exec `max_tokens` / length-truncation fix [jrig #173], `j-rig scaffold-spec` from a `SKILL.md` [jrig #174], and a judge-verdict recovery from truncated / fenced JSON that had inflated NO-SHIP [jrig #175]; it also retains the per-test-case `criteria_ids` scoping fix [jrig #162], so `pnpm exec j-rig eval` scopes each criterion to its own test case. A transitive dep, `@intentsolutions/[email protected]`, still peer-wants `core@^0.8.0`; pnpm surfaces that as a non-fatal warning until refiner-core widens its peer range.) The pin bump is a coupling update only; the authority flip and the root-pin cutover to `authoring/v2` remain the separate, gated steps above.
### Validator consolidation (already landed)
A recent cleanup removed 74 dead duplicate `validation.sh` stubs, collapsed previously-diverged secondary validators into delegating wrappers around the canonical `validate-skills-schema.py`, and added the kernel-loaded shadow read described above. There is now one canonical validator; secondary entry points delegate to it.
### auto-bump posture for contributors
`.github/workflows/auto-bump-on-pr.yml` auto-bumps changed plugins' patch versions on PRs (only on `plugins/**` / `packages/**` changes). For a docs-only or otherwise non-release PR, put **`[skip auto-bump]`** in the PR title or body so the auto-bumper steps aside. Minor/major bumps stay a deliberate human choice β hand-edit the version in the same PR. It stays on `pull_request` (not `pull_request_target`) by design β the bump needs a write token, which must never be handed to fork code; fork PRs are skipped cleanly, and a first-time fork contributor's queued "Approve and run" entry just no-ops when approved.
## Adding a New Plugin
**Hand-authored:** copy from `templates/`, add catalog entry to `marketplace.extended.json`, run `pnpm run sync-marketplace`, validate with `--marketplace`.
**Forge-generated:** `/skill-creator --forge <api-name>` β runs 8-gate workflow, requires a NOI (Name of Identity), produces Grade-A skill + `.forge/` audit trail + catalog entry.
To regenerate against a current API: `/skill-creator --reforge <plugin-name>`.
## Design System
Constitution: `marketplace/DESIGN.md` (Data-Dense Pro family, locked 2026-05-06). If a component disagrees with it, the component is wrong.
Key tokens (`marketplace/src/styles/tokens.css`): `--bg`, `--panel`, `--rule`, `--ink`, `--signal`. Old aliases (`--primary`, `--surface`, `--text`, `--border`) remain mapped for back-compat. CSS colors: **OKLCH only, never hex/rgb**.
Reject: gradients on cards, glassmorphism, drop-shadow stacks, `hover:scale-105` on whole cards.
## Killer Skill of the Week
Editorial β Jeremy picks manually. Tooling only syncs two render surfaces.
```bash
# Promote a new spotlight
node scripts/promote-spotlight.mjs path/to/new-spotlight.json
# Sync README block only (no rotation)
node scripts/render-spotlight.mjs
```
Source of truth: `marketplace/src/data/spotlights.json`.
## Key Identifiers β Do Not "Normalize"
- **GitHub repo (canonical):** `jeremylongshore/claude-code-plugins-plus-skills`
- **Marketplace catalog id:** `claude-code-plugins-plus`
- **Public install slug:** `jeremylongshore/claude-code-plugins` (legacy, GitHub 301s to canonical β hardcoded in CLI, Hero snippet, hundreds of READMEs β renaming is a breaking API change)
## Freshie Inventory
CMDB with a hybrid storage model: `freshie/inventory.sqlite` is the **local
runtime format** every tool reads/writes (UNTRACKED β the blob is out of git);
the **versioned system of record is Dolt**, exported by
`freshie/scripts/dolt-sync.py` into `freshie/dolt/` (gitignored) and pushed to
public DoltHub `jeremylongshore/freshie-inventory` with a `run-N` tag per
inventory run. The tracked compact export (`freshie/grades.csv` +
`freshie/grade-histogram.json`) is regenerated by every sync β its git diff is
the "skill X went BβA" story.
The full cycle:
```bash
python3 freshie/scripts/rebuild-inventory.py # 1. New discovery run
python3 scripts/validate-skills-schema.py --marketplace --populate-db freshie/inventory.sqlite # 2. Compliance
python3 freshie/scripts/dolt-sync.py # 3. Dolt commit + tag + DoltHub push
python3 freshie/scripts/promote-to-curated.py # 4. Refresh skills/.curated/ (skills.sh mirror)
sqlite3 freshie/inventory.sqlite "SELECT grade, COUNT(*) FROM skill_compliance GROUP BY grade;" # runtime queries
python3 freshie/scripts/batch-remediate.py --dry-run && python3 freshie/scripts/batch-remediate.py --all --execute
```
**skills.sh curated mirror** (`freshie/scripts/promote-to-curated.py`): rebuilds
`skills/.curated/` as a generated mirror of the repo's best **A+B** plugin skills (our own;
external `.source.json` mirrors excluded β ~1,881) so skills.sh can index them β it only
crawls root `skills/` / `.curated/`, never `plugins/**/skills/`. The plugin skill stays the
source of truth; the mirror is wipe-and-rebuilt from the tracked `grades.csv` (not the
git-ignored `inventory.sqlite`, so the CI drift gate is reproducible), copies only
git-tracked files, and re-grades each candidate in-process (promote iff fresh grade still
A/B). Audit trail: `skills/.curated/MANIFEST.json`. It is excluded from the README count
(`generate-readme-toc.mjs`) and the inventory scan (`validate-skills-schema.py`
`find_skill_files`) so a mirror copy is never double-counted. Self-maintaining:
`promote-curated.yml` refreshes it weekly (PR on change, Slack-on-fail); the
`promote-curated-check` gate in `ci-required` fails a PR that edits a promoted source
without regenerating. Repo-page branding: root `skills.sh.json`.
History queries go to Dolt (`cd freshie/dolt/freshie`): `WHERE run_id = N`,
`AS OF 'run-N'`, `dolt diff run-7 run-8 --stat` β the run_id model is
append-only, so diffs between run tags show added rows, not cell changes.
Clone-free check: `curl "https://www.dolthub.com/api/v1alpha1/jeremylongshore/freshie-inventory/main?q=SELECT+COUNT(*)+FROM+skill_compliance"`.
**Interactive/MCP history β the in-repo `dolt-mcp-vcs` plugin** (`plugins/mcp/dolt-mcp-vcs/`,
registered as this project's MCP server β freshie Dolt on `127.0.0.1:3308`). Use it to query the
run-over-run history conversationally instead of hand-writing `dolt sql`:
- **Start the sql-server first** β the MCP client connects to a _running_ server; it is NOT
auto-started. From `freshie/dolt/freshie`: `dolt sql-server -H 127.0.0.1 -P 3308` (run
detached; log to a scratch path). Do NOT pass `-u`/`-p` β dolt β₯2 removed them from
`sql-server`; the default `root` is passwordless, matching the MCP config's `DOLT_PASSWORD=""`.
Then load tools with `ToolSearch
query="select:mcp__dolt-mcp-vcs__query,mcp__dolt-mcp-vcs__list_dolt_commits,mcp__dolt-mcp-vcs__list_dolt_diff_changes_by_table_name"`
β `query` for `AS OF 'run-N'` reads, the diff tools for per-run deltas; expert agents
`dolt-sync-advisor` / `bead-epic-auditor` / `dolt-mcp-vcs:beads-guru` are also available.
- **β οΈ Stop the sql-server before `freshie/scripts/dolt-sync.py`** β both write
`freshie/dolt/freshie`; a live server holds the lock and the sync will clobber/deadlock. `kill
<server-pid>`, sync, then restart if you still need it.
- **Mutation gate**: destructive verbs (`push`/`merge`/`reset`/`branch-delete`) are
**recommend-only** β the plugin surfaces them but won't execute, so DoltHub pushes still go
through the one-way `dolt-sync.py` exporter, never the MCP.
**Rules:** local is the sole writer β never merge DoltHub PRs or web-edit the
public database (the exporter is one-way and will clobber them). A failed
DoltHub push exits non-zero on purpose: until pushed, Dolt history is
single-copy on this box. Exporter unit tests: `python3 -m unittest
tests.test_dolt_sync`. Full details + restore path: `freshie/README.md`.
Key tables: `skill_compliance` (scores, grades, JRig columns), `forge_proofs` (drives JRig-Verified badges on plugin detail pages β `enrich-jrig-data.mjs` preserves the committed `jrig-data.json` when the local DB is absent, e.g. in CI).
## npm Publish Pipeline
Patch version bumps happen automatically on PR (via `auto-bump-on-pr.yml`). For minor/major bumps, hand-edit the version in the same PR. Merge to main triggers publish + tag + GitHub Release via `publish-changed-packages.yml`. See `RELEASING.md` for the full operator flow.
<!-- BEGIN BEADS INTEGRATION v:1 profile:minimal hash:7510c1e2 -->
## Beads Issue Tracker
This project uses **bd (beads)** for issue tracking. Run `bd prime` to see full workflow context and commands.
### Quick Reference
```bash
bd ready # Find available work
bd show <id> # View issue details
bd update <id> --claim # Claim work
bd close <id> # Complete work
```
### Rules
- Use `bd` for ALL task tracking β do NOT use TodoWrite, TaskCreate, or markdown TODO lists
- Run `bd prime` for detailed command reference and session close protocol
- Use `bd remember` for persistent knowledge β do NOT use MEMORY.md files
**Architecture in one line:** issues live in a local Dolt DB; sync uses `refs/dolt/data` on your git remote; `.beads/issues.jsonl` is a passive export. See https://github.com/gastownhall/beads/blob/main/docs/SYNC_CONCEPTS.md for details and anti-patterns.
## Session Completion
**When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds.
**MANDATORY WORKFLOW:**
1. **File issues for remaining work** - Create issues for anything that needs follow-up
2. **Run quality gates** (if code changed) - Tests, linters, builds
3. **Update issue status** - Close finished work, update in-progress items
4. **PUSH TO REMOTE** - This is MANDATORY:
```bash
git pull --rebase
git push
git status # MUST show "up to date with origin"
```
5. **Clean up** - Clear stashes, prune remote branches
6. **Verify** - All changes committed AND pushed
7. **Hand off** - Provide context for next session
**CRITICAL RULES:**
- Work is NOT complete until `git push` succeeds
- NEVER stop before pushing - that leaves work stranded locally
- NEVER say "ready to push when you are" - YOU must push
- If push fails, resolve and retry until it succeeds
<!-- END BEADS INTEGRATION -->
Discover similar high-velocity repositories, agent skills, and OpenAPI specifications across the ecosystem.
Topic hubs, agent specifications, and quick tools