- #954: strip non-spec source/attribution keys from all 39 plugin.json
manifests so Claude Code's validator accepts them; metadata preserved in
new .claude-plugin/authoring-notes.json sidecars; check_plugin_json.py now
hard-fails manifests carrying those keys and sanity-checks the sidecar;
CLAUDE.md ClawHub schema section updated to the new rule.
- #949: move the c-level-agents plugin out of c-level-advisor/ to a
top-level directory so the two marketplace sources no longer overlap;
updated marketplace.json source, homepage, descriptions, all
cross-references, docs, harness manifest, mirror-tree symlinks/indexes,
and rebased the moved files' relative links; domain counters trued up
(18 -> 19 domains).
- #933: replace dead links to the gitignored maintainer-local megaprompts/
tree with annotated plain-text references (44 files: SKILL.md, READMEs,
agents, commands).
- #931: DynamoDB on-demand pricing updated to post-Nov-2024 rates
($0.625/M writes, $0.125/M strongly consistent reads).
- #969: skill_security_auditor.py and the three dossier scripts reconfigure
stdout/stderr to UTF-8 (errors=replace) so legacy Windows codepages no
longer crash at print time; PYTHONUTF8=1 documented.
- #968: Windows Notes section in INSTALLATION.md + README pointer for the
core.symlinks mirror-tree checkout caveat.
- #924/#885 residuals: hook commands quote "${CLAUDE_PLUGIN_ROOT}" paths in
all plugin hooks.json/settings.json (space-safe roots); removed the stale
pre-rename status/review mirror symlinks and index entries left over from
the memory-status/memory-review rename.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qgc6RYXWJPr5oW9DHU7zR4
Resolves#712 and #714.
Claude Code's plugin spec (code.claude.com/docs/en/plugins-reference) requires
"All paths must be relative to the plugin root and start with ./". CC 2.1.144+
rejects the bare "skills" form with `Validation errors: skills: Invalid input`,
breaking plugin installs from this repo.
Changes:
- 47 plugin.json manifests migrated from "skills": "skills" → ["./skills"]
(canonical post-CC 2.1.144 form, also accepts string "./skills")
- scripts/check_plugin_json.py rewritten to enforce the live spec:
* Hard-fails on non-"./"-prefixed strings (except the legacy "skills" literal)
* Hard-fails on empty strings/arrays and non-string array entries
* Emits WARN (non-fatal) on the legacy "skills" literal as a safety net
for copied templates — the WARN tolerance can be removed later
* Tested against all four canonical forms + 3 garbage forms
- CLAUDE.md §5 rewritten to document the live spec, including the historical
context of the v2.1.107 → v2.1.144 regression window that's now closed
- 15 stale broken symlinks under .gemini/skills/ removed (orphans from older
reorgs that the sync script didn't prune because its cleanup is disabled)
Verification:
- scripts/check_plugin_json.py --all → 0 FAIL, 0 WARN, exit 0 (69 files OK)
- pytest tests/ → 2103 passed
- find . -type l ! -exec test -e {} \; → 0 broken symlinks
- Live spec forms tested: ["./"], ["./skills"], "./skills", ["./a","./b"] all pass
- Garbage forms rejected: bare "./", empty array, non-string entries, plain strings
Issue #686 was the second round of the same Claude Code path-validator
tightening: v2.1.107 rejected bare "./" (fixed in #539 by moving to
"./skills"), then v2.1.133 also rejected "./skills". The validator that
codified the #539 fix was still recommending "./skills" verbatim — so a
future round 3 would have hit the same trap.
This commit makes the validator catch the regression and runs it in CI:
- scripts/check_plugin_json.py
- Reject any "skills" string starting with "./" (catches both
"./skills" and "./skills/sub" patterns)
- Update docstring + error message to point at the layout-correct
forms instead of the now-broken "./skills"
- Recognize "source" and "attribution" as approved extension fields
(already documented in CLAUDE.md but not in the validator), so the
21 pre-existing false-positives go away and CI can run blocking
- Drop the "./" rejection inside arrays — CLAUDE.md says ["./"] is
the correct single-skill-at-root form
- .github/workflows/ci-quality-gate.yml
- Add blocking "Validate plugin.json manifests" step that runs the
validator on every PR
- CLAUDE.md
- Add an Enforcement note pointing at the validator and the lockstep
rule: when CC tightens its path validator again, update validator
rules and CLAUDE.md together
Verified: 69/69 manifests pass; 6-case smoke test confirms validator
rejects all three known-broken forms ("./skills", "./", "./skills/sub")
and accepts all three documented-valid forms ("skills", ["./"],
explicit array).
Phase 0 of the multi-skill build: ship the two stdlib-only tools that
the rest of the work depends on.
- scripts/sync_skill_bundles.py: mirror a standalone plugin's
SKILL.md + scripts/ + references/ + assets/ into its domain-bundled
location. --check exits 1 on drift; --sync rewrites the mirror.
- scripts/check_plugin_json.py: validate plugin.json against the
strict ClawHub schema (exactly the 8 allowed fields, semver version,
author{name,url}, skills as string or array — bare "./" rejected per
Claude Code v2.1.107+).
Verified: --all run reports OK on all 30 existing plugin.json files;
sync --check correctly detects missing mirrors. Karpathy-coder gate:
both files score 85/100 under strict (single nesting-depth WARN, no
FAIL) — better than the canonical karpathy-coder tools themselves.
https://claude.ai/code/session_01Dq12xJakFRxwaoU8Pqejdm