PR #607 shipped '188 skills, 30 agents, 3 personas, 30 marketplace plugins'
based on a stale codex-sync output that I trusted without verifying. The
actual file-system counts are:
Skills: 246 (250 SKILL.md files; 4 deduped because chaos-engineering,
feature-flags-architect, kubernetes-operator and
slo-architect each ship as both an umbrella entry and
a standalone plugin)
Tools: 359 .py files under */scripts/* (unchanged, was correct)
Refs: 485 .md files under */references/* (unchanged, was correct)
Agents: 27 (20 canonical cs-*-prefixed + 7 personas; excludes
agents/CLAUDE.md, personas/README.md, personas/TEMPLATE.md)
Commands: 33 .md files under commands/ (unchanged, was correct)
Plugins: 33 in .claude-plugin/marketplace.json (was '30' in the
Status line and README badge area)
Every number now reproduces from a single deterministic command:
find . -name SKILL.md -not -path './.gemini/*' -not -path './.codex/*' \
-not -path './site/*' -not -path './docs/*' \
-not -path './.git/*' | wc -l # -> 250 raw
find agents -name 'cs-*.md' | wc -l # -> 20 cs-* agents
ls agents/personas/*.md | grep -v -E 'README|TEMPLATE' | wc -l # -> 7
python3 -c "import json; print(len(json.load(open('.claude-plugin/marketplace.json'))['plugins']))" # -> 33
Surgical edits only: changed the number, left every other word in place.
Files touched: CLAUDE.md (7 lines), README.md (5 lines), docs/index.md
(4 lines), docs/getting-started.md (2 lines), mkdocs.yml (1 line).
Security scanners legitimately reference dangerous patterns (eval, os.system,
subprocess shell=True, etc.) inside their own regex pattern definitions and
human-readable risk/fix descriptions. Auditing the auditor itself produced
17 CRITICAL false positives — all from its own pattern table. ship-gate had
the same issue (2 CRITICALs on a check description and a variable name
called eval_findings).
Fix:
- Add 'noqa: SEC-AUDITOR' / 'auditor:ignore-line' line-suppression directive
to all three scan loops (code patterns, prompt-injection markdown,
pip/npm runtime install detection).
- Annotate the 179 pattern-definition lines in skill_security_auditor.py
(regex, risk, fix entries) and 4 cleanup shutil.rmtree calls.
- Annotate ship-gate's two flagged lines (SEC-13 check description and
eval_findings variable usage).
- Annotate SKILL.md and references/threat-model.md tables that document
attack patterns for human readers (HTML comment <!-- noqa: SEC-AUDITOR -->).
Verified end-to-end:
skill-security-auditor self-audit: 17 CRITICAL -> 0 (PASS)
ship-gate self-audit: 2 CRITICAL -> 0 (PASS)
slo-architect: PASS (0/0)
project-management WARN unchanged (no top-level SKILL.md, expected)
Auto-regenerated by scripts/generate-docs.py after the post-restructure
fix. Covers slo-architect, ship-gate, chaos-engineering, kubernetes-operator,
feature-flags-architect, llm-wiki, tc-tracker, and 185 other skills now
properly surfaced under their domain index pages.
After PR #593 restructured umbrella plugins, every sub-skill landed at
<domain>/skills/<name>/SKILL.md. The doc generator's is_sub_skill heuristic
treated len(parts) > 2 as nested, so all 188 skills got flagged as 'children
of "skills"' (a non-existent parent) and were never written to docs/.
Recognise <domain>/skills/<name>/ as the canonical top-level layout.
Backwards-compatible with playwright-pro/skills/<sub>/ standalone-plugin
sub-skills (those legitimately have a real parent at parts[1]).
Result: 0 -> 192 skill pages emitted.
PR #527 (@rx4u) submitted a pre-production audit skill that was based on the
pre-#593 layout (skills directly under engineering/). After #593 landed, the
diff would have undone the entire restructure (4500+ rename ops). Re-applying
the actual new content at the correct post-restructure path.
What landed:
- engineering/skills/ship-gate/SKILL.md
- engineering/skills/ship-gate/references/checks.md
- engineering/skills/ship-gate/references/patterns.md
- engineering/skills/ship-gate/scripts/ship_gate_scanner.py
Verified:
- python3 ship_gate_scanner.py --help → OK
- python3 ship_gate_scanner.py --version → ship-gate 1.0.0
- 1671 tests pass (was 1666; +5 for ship-gate smoke + integrity)
- engineering/.claude-plugin/plugin.json: 48 → 49 skills, v2.4.2 → v2.4.3
- marketplace.json: engineering-advanced-skills entry updated to match
Closes#527.
Co-authored-by: Rajaraman Arumugam <rx4u@users.noreply.github.com>
https://claude.ai/code/session_01Dq12xJakFRxwaoU8Pqejdm
chore: resolve 4 open PRs (#596, #597, #582, #517) on clean dev base
Consolidates four ready-to-merge PRs that had become dirty against the
post-restructure dev branch. Conflict in tests/test_skill_integrity.py
resolved by keeping the broader script_globs version (includes .ps1).
Closes#517, #582, #596, #597.
test_scripts_dirs_have_python_files was asserting every scripts/ dir
contains at least one .py file. The full-page-screenshot skill ships
a .mjs (Node ESM) script and triggered a false-positive failure.
Broadens the check to accept any of .py, .mjs, .js, .ts, .sh while
keeping the same intent: scripts/ dirs must not be empty.
Verified: full pytest suite goes from 1 failed / 1611 passed to
725 passed in tests/test_skill_integrity.py alone.
https://claude.ai/code/session_01Dq12xJakFRxwaoU8Pqejdm
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
`engineering/skills/full-page-screenshot/scripts/full-page-screenshot.mjs` is
a legitimate 35KB JavaScript module, but the test only matched `*.py` and
asserted the dir was empty. This caused `test_skill_integrity` to fail on
dev's HEAD (pre-existing breakage, surfaced when CI ran on PR #601).
Broadens the check to accept any common script extension:
.py, .mjs, .js, .ts, .sh, .ps1. The test's intent — "scripts/ shouldn't be
empty" — is preserved; the implementation no longer over-restricts language.
Adds toprank (https://github.com/nowork-studio/toprank) — open-source MIT
plugin with 9 SEO and Google Ads skills (107 GitHub stars).
Co-authored-by: ununununium <43973612+ununununium@users.noreply.github.com>
Closes-PR: #517
- Adds project-management/.mcp.json registering Atlassian's official Remote
MCP server (https://mcp.atlassian.com/v1/sse) as a plugin-bundled SSE MCP.
- Updates project-management/README.md Setup section to reflect bundled-MCP
reality (OAuth handled automatically; no API tokens in the repo).
- Closes the doc/code drift between CLAUDE.md's "Atlassian MCP integration"
claim and the previously absent .mcp.json file.
Co-authored-by: FreyaFujo <172978998+FreyaFujo@users.noreply.github.com>
Closes-PR: #597
`.mcp.json` is the canonical filename Claude Code expects for plugin-bundled
MCP server configuration. The auditor's hidden-file rule was flagging it as
HIGH severity, blocking the `--strict` quality gate documented in CLAUDE.md.
Co-authored-by: FreyaFujo <172978998+FreyaFujo@users.noreply.github.com>
Closes-PR: #596
Karpathy-style review of commit 3806b9b (the prior PR commit) caught real
issues that I missed: agents weren't fully equipped per the optional but
recommended fields in the official sub-agents spec.
Changes:
- engineering/agenthub/agents/hub-coordinator.md: narrow Bash(node *) (too
broad per defense-in-depth) -> moved node into disallowedTools; add
maxTurns: 100 (orchestrators run long); add skills: agenthub:agenthub
(preload the plugin's own guidance into agent context)
- engineering-team/self-improving-agent/agents/memory-analyst.md:
add maxTurns: 30 to bound runaway analysis loops
- engineering-team/self-improving-agent/agents/skill-extractor.md:
add disallowedTools (rm/curl/wget) — agent has Write+Edit so defense-in-
depth applies; add maxTurns: 30
- engineering/karpathy-coder/agents/karpathy-reviewer.md: fix skills field
format from path-style "engineering/karpathy-coder" to spec-correct
namespaced name "karpathy-coder:karpathy-coder" (the path syntax is the
cs-* orchestrator template convention; the official sub-agents spec uses
skill names per code.claude.com/docs/en/sub-agents); add maxTurns: 30
All 6 plugin agents (4 here + 2 in playwright-pro from prior commit) +
the 1 user agent (tech-ingester) now have name + description + tools +
disallowedTools (where write-capable) + model + maxTurns. The skills:
field is set on agents that benefit from preloaded domain skill content.
Functional smoke tests post-fix:
- memory-analyst: PASS (2 turns, 25s, 24K tokens, found 1 real orphan)
- skill-extractor: PASS (0 tool uses, 34s, 17K tokens, generated correct
plan staying read-only with new disallowedTools in effect)
- karpathy-reviewer: PASS (verified in prior session, 28 tool uses)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per https://code.claude.com/docs/en/sub-agents, agents require YAML
frontmatter with name + description, and the field is `tools:` not
`allowed-tools:` (deprecated). Bare `Bash` allows any command including
curl/wget/rm, which violates defense-in-depth.
Changes:
- engineering/agenthub/agents/hub-coordinator.md: add full frontmatter
(name, description, tools allowlist for git/python/node/Agent,
disallowedTools for rm -rf / curl / wget / git push --force, model)
- engineering-team/self-improving-agent/agents/memory-analyst.md:
add frontmatter, read-only tools (Read, Glob, Grep)
- engineering-team/self-improving-agent/agents/skill-extractor.md:
add frontmatter, write tools (Read, Write, Edit, Glob, Grep)
- engineering-team/playwright-pro/agents/test-architect.md:
rename allowed-tools to tools, add model: inherit
- engineering-team/playwright-pro/agents/migration-planner.md:
same rename
- engineering-team/playwright-pro/agents/test-debugger.md:
rename + narrow bare Bash to npx playwright / node / npm patterns,
add disallowedTools for rm / curl / wget / destructive git
- engineering/karpathy-coder/agents/karpathy-reviewer.md:
narrow bare Bash to git read-ops + python, add disallowedTools
All registered agents now load cleanly under the sub-agents spec rather
than falling through to permissive registration.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR #593 moved every skill from <plugin>/<name>/ to <plugin>/skills/<name>/
to satisfy Claude Code's runtime loader. That broke two CI jobs that
hardcoded the old paths:
1. **9 test files** had `sys.path.insert(0, ".../<domain>/<skill>/scripts")`
pointing at the pre-restructure location. Inserted `"skills"` between
the domain and skill segments so imports resolve again.
2. **scripts/sync-codex-skills.py** scanned `<domain>/<skill>/SKILL.md`
and emitted "No skills found in repository". Updated `find_skills` to
prefer `<domain>/skills/<name>/` and fall back to `<domain>/<name>/`
so it works with both layouts (in case any domain hasn't been
restructured yet).
Verified locally:
- `python3 scripts/sync-codex-skills.py --dry-run` finds 178 skills
- `pytest tests/` collects all modules; 3216 tests pass
- 4 pre-existing failures remain (3 argparse duplicates in an
`integrations/` script, 1 strict "must have .py" check on a JS-only
skill) — out of scope for this fix.
Same root cause as #587/#591 — Claude Code's runtime loader rejects
array-form skills paths like ["./content-production", "./ai-seo", ...]
even when each entry is a valid subdirectory containing SKILL.md.
`claude plugin validate` accepts them but the loader does not.
The proven canonical layout (used by self-improving-agent in #536):
<plugin>/
├── .claude-plugin/plugin.json skills: "./skills"
└── skills/
├── <skill-1>/SKILL.md
├── <skill-2>/SKILL.md
└── ...
Restructured 9 multi-skill domain plugins:
- business-growth (4 skills moved)
- c-level-advisor (28)
- engineering (36)
- engineering-team (32)
- finance (2)
- marketing-skill (43)
- product-team (12)
- project-management (8)
- ra-qm-team (13)
Also fixed standalone plugins that had root SKILL.md + ./skills/ subdir
(agenthub, autoresearch-agent, executive-mentor, playwright-pro). The
loader rejected them despite skills="./skills" because of the conflicting
root SKILL.md (compare self-improving-agent which works because PR #536
moved its root SKILL.md). Moved each root SKILL.md into ./skills/<name>/.
Restored standalone plugin folders to their original paths after the
multi-skill restructure swept them into parent skills/ directories
(marketplace.json source paths require original locations).
Removed 7 orphaned marketplace entries that pointed to skill folders
without their own plugin.json (content-creator, demand-gen,
fullstack-engineer, aws-architect, product-manager, scrum-master,
skill-security-auditor) — these were already non-functional.
Bumped patch versions on every changed plugin and synced
marketplace.json. Marketplace now lists 29 working plugins (down
from 36).
After merge: users run `/plugin marketplace update claude-code-skills`
followed by `/plugin update --all` to pick up the working layout.
Claude Code v2.1.126 rejects "skills": ["./"] (array form) at runtime
with the same "Path escapes plugin directory: ./" error as the bare
string form, despite the official plugins reference docs explicitly
showing ["./"] as a valid example. `claude plugin validate` accepts it,
so the bug is in the runtime loader, not the manifest validator.
The proven workaround (already used for self-improving-agent in #536)
is to follow the canonical layout:
<plugin>/
├── .claude-plugin/plugin.json skills: "./skills"
└── skills/<plugin-name>/
├── SKILL.md
├── scripts/
├── references/
└── ...
Applied to 21 single-skill plugins:
- engineering-team/a11y-audit, google-workspace-cli, snowflake-development
- engineering/behuman, code-tour, data-quality-auditor, demo-video,
docker-development, helm-chart-builder, karpathy-coder, llm-cost-optimizer,
llm-wiki, prompt-governance, statistical-analyst, terraform-patterns
- finance/business-investment-advisor
- marketing-skill/video-content-strategist
- product-team/agile-product-owner, apple-hig-expert, code-to-prd,
research-summarizer
Moved with each SKILL.md: scripts/, references/, assets/, templates/,
expected_outputs/. Kept at plugin root (per Claude Code requirements):
agents/, commands/, hooks/, settings.json, README.md.
Bumped patch version on each restructured plugin so /plugin update
picks up the new layout.
Refs #539
PR #587 fixed `"skills": "./"` in 35 plugin.json files but did not bump
versions. Claude Code uses version as the cache key — same version string
means /plugin update is a no-op and users keep loading the cached
plugin.json with the broken path. The /plugin UI shows "1 error" on
every plugin from this marketplace because the installed cache is stale.
Per the official version-management docs:
> If you set `version` in `plugin.json`, you must bump it every time
> you want users to receive changes. Pushing new commits alone is not
> enough.
Bump every plugin.json by one patch using max(plugin_version,
marketplace_version) as the base so no version moves backward. Sync the
new versions back into .claude-plugin/marketplace.json.
After this lands, users run `/plugin marketplace update claude-code-skills`
followed by `/plugin update --all` to pull the fixed manifests.
Claude Code v2.1.107+ rejects bare "skills": "./" with "Path escapes
plugin directory: ./". This blocks every plugin in the marketplace from
loading. Replace with the layout-appropriate form per the official
plugins reference:
- Single-skill plugin (SKILL.md at root):
"skills": ["./"] array form (per docs example)
- Plugin with skills/ subdir:
"skills": "./skills" standard subdir layout
- Multi-skill domain plugin (skills are subfolders at root):
"skills": ["./sub1", "./sub2"] explicit list of skill dirs
The multi-skill case omits "./" from the array so the index SKILL.md
at the plugin root does not register as a skill — that would create
a redundant `marketing-skills:marketing-skills` namespace.
Verified by running `claude plugin validate` against all 35 manifests.
Closes#539