Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Read findings JSONL files from cluster 1-4 skills, deduplicate by fingerprint, group by severity, and compose a deliverable- grade markdown vulnerability report with per-finding sections (title, severity, target, detail, remediation, evidence) and a top-level summary table. The canonical written artifact a customer receives at engagement close; precise, reproducible, machine- checkable against source findings. Use when: closing an engagement, generating an interim report, regenerating after CVE
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | 1062% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 12% | 0% |
| case-04 | ✗→✓ | ▲ Improved | -5% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 94% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 9% | 0% |
After cluster 1-4 scan skills run, each one produces a Findings file. A typical engagement ends up with eight to twenty such files across the different skill categories. The customer wants ONE vulnerability report — comprehensive, deduplicated, organized by severity, with each finding cross-referenced to its source skill and target.
This skill consumes one or more findings files (JSONL preferred, JSON list also accepted), deduplicates entries by the canonical fingerprint defined in lib/finding.py, enriches each finding with a CVSS v3.1 vector when one isn't present (using a deterministic heuristic based on severity + category — explicitly noted as "derived, not assigned by NVD" in the output), and emits a single markdown report with per-finding sections plus a top-level summary table.
The report has a defined structure that downstream tools (next two skills in cluster 6) consume:
LOW, INFO
remediation, evidence, references
| Finding | Severity | Threshold | Affected control | |---|---|---|---| | Source file unparseable | HIGH | JSON/JSONL parse fails | (operational) | | Finding missing required field | HIGH | A finding record is missing title, severity, target, detail, or remediation | (operational) | | Duplicate fingerprint across files | INFO | Same finding appears in N>1 sources; reported as deduplication count | (informational) | | Source file has zero findings | INFO | Empty or all-info-only file; reported but not an error | (informational) | | Report generated cleanly | INFO | Positive confirmation | (informational) |
any cluster 1-4 scan skill (which all share lib/finding.py schema)
By default the skill reads every file matching engagement/findings/*.json and engagement/findings/*.jsonl. Override with --source FILE (repeatable).
bashpython3 ./scripts/compose_report.py engagements/acme-2026-q2/
Options:
Usage: compose_report.py PATH [OPTIONS]
Options:
--source FILE Specific findings file (repeatable; overrides default glob)
--report-output FILE Write the composed report here (default:
PATH/reports/vulnerability-report.md)
--engagement-id ID Override the engagement ID (default: parse from PATH/roe.yaml)
--output FILE Operational findings output (this skill's own findings)
--format FMT json | jsonl | markdown (default: markdown)
--min-severity SEV Filter report to findings at or above this severity
--include-info Include INFO-severity findings in the report (default: omit)The output report has a predictable structure. The header identifies the engagement, the source files, and the generation timestamp. The summary table shows finding counts by severity. Per-severity sections follow.
Each finding subsection includes a stable anchor (the fingerprint) so cross-references from later artifacts (executive summary, OWASP mapping) resolve into the report cleanly.
bashpython3 ./scripts/compose_report.py engagements/acme-2026-q2/ --format json --output /tmp/compose-findings.json jq '.[] | select(.severity == "high")' /tmp/compose-findings.json
If the report references a finding the operator didn't expect, trace back via the finding's skill_id + target to the source file.
bashpython3 ./scripts/compose_report.py engagements/acme-2026-q2/ \ --report-output engagements/acme-2026-q2/reports/vulnerability-report.md
bashpython3 ./scripts/compose_report.py engagements/acme-2026-q2/ \ --min-severity high \ --report-output engagements/acme-2026-q2/reports/interim-2026-06-15.md
--min-severity high produces an interim report covering only HIGH and CRITICAL findings — useful for in-engagement customer syncs.
bashpython3 ./scripts/compose_report.py engagements/acme-2026-q2/ \ --source engagements/acme-2026-q2/findings/all-findings-with-owasp.jsonl \ --report-output engagements/acme-2026-q2/reports/vulnerability-report-v2.md
Re-run after mapping-findings-to-owasp-top10 has enriched each finding with its OWASP category; the regenerated report includes the OWASP tag in each per-finding subsection.
JSON / JSONL / Markdown per lib/report.py for the skill's own operational findings. The PRIMARY output is the composed vulnerability report, written as standalone Markdown to the --report-output path.
Each operational Finding includes:
id — compose::<issue>::<source-file>severity — CRITICAL / HIGH / MEDIUM / INFOcategory — report-compositionsummary — what went wrong (or right) during compositionevidence — source files, finding counts, dedup statsexits 1.
skips the file, continues with remaining sources.
exits 1.
finding, exits 1.
finding, omits that record from the report, continues.
references/THEORY.md — Vulnerability-report structure history(NIST SP 800-115, OWASP Testing Guide), CVSS v3.1 vector composition, severity scoring tradeoffs (CVSS vs intrinsic vs EPSS), finding-deduplication theory, why fingerprint-based dedup beats title-based
references/PLAYBOOK.md — Report-template variants peraudience (technical, executive, regulatory), per-finding remediation phrasing patterns, evidence-redaction patterns for distributed reports, cross-reference protocol with the OWASP-mapping and exec-summary skills
Other measured skills in the registry, with their headline benchmark lift.