The description is the only signal an agent sees at discovery time, so
overlapping descriptions cause misrouting. Nothing in CI checked for that.
- tools/lint-descriptions.py enforces name==folder, description <=1024
chars, terminal punctuation (a truncation canary), a trigger clause, a
negative trigger, and a 500-line body cap. Pre-existing failures are
grandfathered in tools/lint-baseline.json so this blocks new debt only;
the baseline may shrink and never grow.
- tools/detect-collisions.py scores every description pair by TF-IDF
cosine and ratchets the count of unreviewed near-duplicates. It strips
negative-trigger clauses before vectorizing: those name the sibling
skill on purpose, so scoring them would make correct disambiguation
raise a pair's similarity.
- wire both into validate-skills.yml, along with agentskills conformance,
an index.json freshness check, and a guard that fails the build if a
regex frontmatter parser is reintroduced.
- broaden the path filters from tools/validate-skill.py to tools/**, as
noted when #105 merged.
All five gates verified to fail on deliberately broken input.
index.json shipped 604 of 817 descriptions truncated to their first line.
The cause was the inline regex parser in update-index.yml: it reconstructed
multi-line descriptions only for the YAML block-scalar styles ('>' and '|')
and silently dropped continuation lines for every other style.
A census of the corpus explains the blast radius:
block scalar (description: >-) 43
single-quoted multiline 278
plain unquoted multiline 496
single-line 0
So 774 of 817 skills (94.7%) used a style the parser mishandled. Commit
d56fc0a7 had fixed only the 43 block-scalar files, and CONTRIBUTING.md
recommends that one working style, which is why it stayed hidden.
- add tools/skill_frontmatter.py, the single PyYAML-backed loader
- add tools/generate-index.py so generation is testable outside CI, with
a --check mode for use as a gate
- delete the hand-rolled parsers from validate-skill.py (98 lines) and
validate-agentskills.py, routing both through the shared loader
- implement the reserved-word check that agentskills-skill.schema.json
names validate-agentskills.py as the enforcement point for
Verified by a differential harness against yaml.safe_load ground truth:
index-vs-source mismatches 606 -> 0.
The generator's `^description:\s*(.+)$` regex captured the block-scalar
indicator (">-") instead of the wrapped text, corrupting 43 descriptions in
index.json. Parse `>`/`|` block scalars properly and regenerate (0 broken).
Also refresh the count-update comment examples 754 -> 817.
The standard requires only name+description; additional top-level keys are
permitted metadata. Fixes:
- validator no longer counts extra top-level keys as violations (reports them
as informational only).
- angle-bracket check now ignores YAML block-scalar indicators (`>`, `>-`,
`|`), which were false-positiving on multi-line descriptions; no skill has
genuine angle-bracket content.
- schema additionalProperties false -> true to match.
Audit result: 817/817 compliant.
- tools/agentskills-skill.schema.json: strict JSON Schema for the
agentskills.io SKILL.md frontmatter standard (name+description required;
optional license/compatibility/metadata/allowed-tools; no other top-level
keys).
- tools/validate-agentskills.py: read-only compliance validator (also checks
name==directory and the no-angle-brackets rule).
Each rewritten description now states both what the skill does (concrete
capability, named tools/artifacts) and an explicit when-to-use trigger,
improving agent discovery/activation. Grounded in each skill's own body;
changes confined to the `description` field only (bodies and all other
frontmatter untouched). Produced by a gated audit->rewrite->recheck loop
(548 -> 0 flagged) with a sampled anti-invention check (0 ungrounded).
Schema: 817/817 pass. Framework-ID gate: 0 defects.
Deterministic audit against vendored MITRE/NIST oracles (ATT&CK v19.1,
ATLAS 2026.07, NIST CSF 2.0, D3FEND v1.4.0) found and fixed:
- 27 wrong-framework leaks on 12 AI-security skills: ATLAS AML.* IDs were
under `mitre_attack` (-> `atlas_techniques`) and AI-RMF GOVERN/MEASURE IDs
under `nist_csf` (-> `nist_ai_rmf`).
- RS.AN-01 -> RS.AN-03 on 37 forensics/incident-analysis skills (CSF 1.1 ID
retired in CSF 2.0; RS.AN-03 is the incident-analysis successor).
- PR.DS-06 -> PR.DS-01 on the SLSA/Sigstore provenance skill (CSF 1.1 ID
absorbed into PR.DS-01 in CSF 2.0; body prose updated too).
- AML.T0104 -> AML.T0010 on 3 software-supply-chain skills (T0104 is
"Publish Poisoned AI Agent Tool" -- wrong topic; T0010 "AI Supply Chain
Compromise" is correct).
CSF/ATLAS replacements verified against NIST CSWP.29, the official CSF
1.1->2.0 transition workbook, and mitre-atlas/atlas-data.
Framework-ID gate: 0 defects. Schema: 817/817 pass.
Address PR review threads: valid YAML subdomain example, separate
D3FEND list items, NIST CSF ID convention, document tools/validate-skill.py,
and fix Quick Reference backticks.
generate_ioc_report()'s "generated" field used:
datetime.utcnow().isoformat() if "datetime" in dir() else ""
"datetime" is never imported anywhere in this file, and dir() with
no arguments only inspects local scope names -- so this guard is
always False, and every generated report had "generated": "" instead
of a real timestamp.
Fixed by importing datetime/timezone at the top and calling
datetime.now(timezone.utc).isoformat() directly (the non-deprecated
replacement for utcnow(), since Python 3.12 deprecates utcnow()).
Tested: python3 -m py_compile, --help works, and:
python3 agent.py report --file <any file>
now produces a real ISO 8601 UTC timestamp
(e.g. "2026-07-17T14:46:03.178652+00:00") instead of an empty string.
Add AV false-positive guidance for issue #100, move inline YARA rule to
references/yara-fileless-powershell.yar, and replace literal encoded
PowerShell payload with a placeholder in the sample report.
Add tools/validate-skill.py and the workflow file to the push/pull_request
path filters so edits to the validator or workflow re-run validation, and
add workflow_dispatch for manual runs.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add hardware-firmware-security as a canonical subdomain (folding in the
firmware-analysis/firmware-security aliases). The 4 new hardware/firmware
skills failed validation because the subdomain was not in the allowed set.
- Skip skills/*.bak/ backup directories in --all mode; they have no SKILL.md
and were producing 21 false failures.
- Result: validate-skill.py --all now reports 817/817 passing, exit 0.
Added a comprehensive README in French detailing the Anthropic Cybersecurity Skills project, including its features, frameworks, and usage instructions.