Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Generate NOTICE files with third-party attributions for all packages in the monorepo.
.claude/skills/tetherto-qv-notice-generate/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 100% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 30% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 9% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 40% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 4% | 0% |
Generate deterministic, sorted NOTICE files for individual packages or all packages at once, covering model, JS, Python, and C++ dependency attributions.
As of QVAC-21554, license/compliance enforcement on Tier-1 PRs is primarily a CI gate — .github/workflows/license-compliance.yml, delegating to the org reusable workflow public-reusable-license.yml (design: tetherto/qvac-actions/docs/license-compliance-ci.md). The gate deterministically classifies newly added PR dependencies against the org policy (allow/deny/review), honours .github/license-allowlist.yml, and posts a PR comment.
This SKILL is now the human fallback for the long tail the gate cannot decide:
check-forbidden-licenses.js to investigate, then record the decision in .github/license-allowlist.yml (CODEOWNERS-reviewed) or remove/replace the dependency. The gate is deterministic from then on.check-forbidden-licenses.js does a real npm install + license-checker (plus Python/C++/model scans) and is the tool for a complete audit — e.g. before a release, or when the gate's coverage is insufficient.generate-notice.js job.Use when:
/qv-notice-generateBefore running, ensure .env is sourced and contains:
GH_TOKEN -- GitHub token (access to private repos and GitHub API)HF_TOKEN -- HuggingFace token (model license verification)NPM_TOKEN -- npm registry token (private package resolution)System requirements for Python scanning:
python3 and pip available in PATH (for pip-licenses)--all for all packages).env in the shell--dry-run if the user explicitly asks for itDo NOT commit changes. The user will review and commit manually.
bashsource .env node .cursor/skills/qv-notice-generate/scripts/generate-notice.js <package-dir-name>
Example: node .cursor/skills/qv-notice-generate/scripts/generate-notice.js sdk
For registry sub-packages use the full path:
registry-server/clientregistry-server/sharedbashsource .env node .cursor/skills/qv-notice-generate/scripts/generate-notice.js --all
bashsource .env node .cursor/skills/qv-notice-generate/scripts/generate-notice.js --all --dry-run node .cursor/skills/qv-notice-generate/scripts/generate-notice.js sdk --dry-run
In dry-run mode:
bashsource .env node .cursor/skills/qv-notice-generate/scripts/check-forbidden-licenses.js --all --dry-run node .cursor/skills/qv-notice-generate/scripts/check-forbidden-licenses.js --all
Uses an allowlist approach. The ALLOWED_LICENSES array in config.js controls which licenses pass:
License strings from all sources (npm, PyPI, GitHub, models) are normalized to canonical SPDX ids before comparison, so adding apache-2.0 to the list automatically covers Apache 2.0, Apache Software License, Apache License 2.0, etc.
If violations are found, writes FORBIDDEN_LICENSES.txt to the repo root and exits with code 1.
Important: The agent should NOT edit ALLOWED_LICENSES directly. Present the scan results to the user and let them decide which licenses to allow. The allowlist and normalization map live in .cursor/skills/qv-notice-generate/scripts/constants.js.
bashnode .cursor/skills/qv-notice-generate/scripts/generate-report.js
Reads existing NOTICE files across all packages (no scanning, no tokens needed) and produces NOTICE_FULL_REPORT.txt with:
NOTICE file inside each scanned package directory (from generate-notice.js)NOTICE_FULL_REPORT.txt license overview report (from generate-report.js, gitignored)NOTICE_LOG.txt at the repo root with errors/warnings (gitignored)| Type | What | Tool | |------|------|------| | Models | Model attributions from models.prod.json | Direct JSON parsing | | JS | Production npm dependencies | license-checker (auto-installed via npx) | | Python | Benchmark/script Python deps | pip-licenses (auto-installed in temp virtualenv) | | C++ | vcpkg native dependencies | GitHub API + local portfile parsing |
sdk, bare-sdk, inference, registry-server/clientpackage.jsonrequirements.txt or pyproject.toml in benchmarks/scriptsvcpkg.json| Package directory | Engine | |---|---| | embed-llamacpp | @qvac/embed-llamacpp | | llm-llamacpp | @qvac/llm-llamacpp | | translation-nmtcpp | @qvac/translation-nmtcpp | | tts-onnx | @qvac/tts-onnx | | asr-ggml | @qvac/transcription-whispercpp, @qvac/asr-ggml | | diffusion-cpp | @qvac/diffusion-cpp |
asr-ggml carries two engine keys because the whisper + parakeet packages were unified: models.prod.json still names the retired @qvac/transcription-whispercpp engine until the SDK/registry repoint lands.
All entries within every NOTICE file section are sorted deterministically using locale-independent collation. Re-runs on identical input always produce identical output, resulting in clean git diffs.
npm run verify:licenses in packages/registry-server -- verifies model licenses in models.prod.json against HuggingFace/GitHub APIs (dry-run only, console output, fails on unverifiable)..cursor/skills/qv-notice-generate/scripts/constants.js.cursor/skills/qv-notice-generate/scripts/lib/config.js.cursor/rules/sdk/sdk-pod-packages.mdc| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 2,704 | 5,324 | +97% | 1 | 1 | 0% | 284 | 2,308 | +713% | 0 | 0 | — |
case-02 | fail→fail | 6,445 | 3,101 | -52% | 1 | 1 | 0% | 1,035 | 2,287 | +121% | 0 | 0 | — |
case-03 | fail→fail | 8,835 | 2,241 | -75% | 1 | 1 | 0% | 1,441 | 2,353 | +63% | 0 | 0 | — |
case-04 | fail→pass | 36,561 | 11,120 | -70% | 1 | 1 | 0% | 1,491 | 2,989 | +100% | 0 | 0 | — |
case-05 | fail→fail | 10,184 | 5,792 | -43% | 1 | 1 | 0% | 1,620 | 2,820 | +74% | 0 | 0 | — |
case-06 | fail→pass | 11,021 | 2,484 | -77% | 1 | 1 | 0% | 1,842 | 2,392 | +30% | 0 | 0 | — |
case-11 | fail→pass | 12,617 | 1,670 | -87% | 1 | 1 | 0% | 2,044 | 2,227 | +9% | 0 | 0 | — |
case-07 | fail→pass | 11,281 | 4,203 | -63% | 1 | 1 | 0% | 1,902 | 2,661 | +40% | 0 | 0 | — |
case-08 | fail→pass | 15,708 | 3,117 | -80% | 1 | 1 | 0% | 2,432 | 2,531 | +4% | 0 | 0 | — |
case-09 | fail→fail | 10,760 | 3,666 | -66% | 1 | 1 | 0% | 1,867 | 2,401 | +29% | 0 | 0 | — |
case-10 | pass→pass | 9,421 | 2,098 | -78% | 1 | 1 | 0% | 1,335 | 2,322 | +74% | 0 | 0 | — |
case-21 | fail→pass | 12,507 | 2,622 | -79% | 1 | 1 | 0% | 2,047 | 2,437 | +19% | 0 | 0 | — |
case-12 | pass→pass | 9,826 | 2,837 | -71% | 1 | 1 | 0% | 1,560 | 2,329 | +49% | 0 | 0 | — |
case-13 | pass→pass | 10,507 | 1,855 | -82% | 1 | 1 | 0% | 1,671 | 2,253 | +35% | 0 | 0 | — |
case-14 | pass→pass | 14,063 | 1,621 | -88% | 1 | 1 | 0% | 2,195 | 2,219 | +1% | 0 | 0 | — |
case-15 | fail→pass | 15,237 | 5,088 | -67% | 1 | 1 | 0% | 2,400 | 2,739 | +14% | 0 | 0 | — |
case-16 | fail→pass | 11,375 | 2,886 | -75% | 1 | 1 | 0% | 1,697 | 2,377 | +40% | 0 | 0 | — |
case-17 | fail→pass | 7,806 | 1,907 | -76% | 1 | 1 | 0% | 1,263 | 2,289 | +81% | 0 | 0 | — |
case-18 | pass→pass | 9,243 | 3,587 | -61% | 1 | 1 | 0% | 1,537 | 2,500 | +63% | 0 | 0 | — |
case-19 | fail→pass | 11,254 | 2,772 | -75% | 1 | 1 | 0% | 1,898 | 2,383 | +26% | 0 | 0 | — |
case-20 | pass→pass | 14,845 | 5,510 | -63% | 1 | 1 | 0% | 2,504 | 2,928 | +17% | 0 | 0 | — |
case-22 | fail→pass | 12,987 | 1,620 | -88% | 1 | 1 | 0% | 2,008 | 2,201 | +10% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 20 counted toward the lift figure. The other 2 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +50 percentage points is the difference between those two pass rates over the 20 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.