License Attribution Compliance
TT-Studio is Apache-2.0 © Tenstorrent AI ULC and ships under a strict regime.
This skill keeps third-party attribution correct when dependencies or bundled
assets change. There are two layers:
- Deterministic gate —
dev-tools/check_license_attribution.py, meant for CI
on every PR. It catches mechanical drift: a stale frontend license file, or a
newly added dependency that nobody attributed.
- Judgment review (this skill) — classify the actual license, flag
NonCommercial / copyleft / provenance risks, and write the attribution in the
right place using the repo's established patterns.
Run the gate first, then reason about whatever it surfaces.
The repo's attribution surfaces
| Surface |
What it covers |
How it's maintained |
Root LICENSE → "Third-Party Dependencies" list |
Notable / distributed deps + pointers |
Hand-edited bullets: - Name (SPDX) [License available here](url) |
app/frontend/third-party-licenses.txt |
Every frontend production npm dep (full license text) |
cd app/frontend && npm run generate-license |
| SPDX file headers |
Every source file (.py, .sh, Dockerfile, .ts/.tsx/.js/.jsx) |
Enforced by existing CI (check-copyright / ESLint header/header-format); fix with python run.py --add-headers or npm run header:fix:changed |
| (none yet) backend Python deps |
"utilized but not distributed" — covered by the blanket clause in LICENSE |
If a backend dep is ever distributed/bundled, it needs an explicit notice |
Step 1 — run the gate
python3 dev-tools/check_license_attribution.py # both checks
python3 dev-tools/check_license_attribution.py --check-frontend
python3 dev-tools/check_license_attribution.py --check-new-deps --base origin/main
- Frontend freshness FAIL →
cd app/frontend && npm run generate-license, commit
the result. (Needs node; the check SKIPs where node is absent.)
- New-dep attribution FAIL → continue to Step 2 for each named dep.
Tool pin: generate-license-file is pinned to 4.0.0 in
app/frontend/package.json. 4.1.0+ silently drops react/react-dom from the
output. The script regenerates with @4.0.0 explicitly. Do not loosen the pin.
Step 2 — classify the license
Find each dependency's real license (npm: its package.json/repo; pip: PyPI/repo).
Models, datasets, and weights often carry a different, more restrictive license
than the code that loads them — check both.
| Class |
Examples |
Action |
| Permissive |
Apache-2.0, MIT, ISC, BSD-2/3 |
✅ Attribute (link/notice). Apache-2.0 §4 wants the NOTICE text retained, not just a link, for anything distributed. |
| Weak copyleft |
MPL-2.0, LGPL |
⚠️ Usually OK if not modified/static-linked. Flag for review. |
| Strong copyleft |
GPL, AGPL |
🛑 Generally incompatible with shipping Apache-2.0. Escalate before merging. |
| NonCommercial |
CC BY-NC, CC BY-NC-SA, *-NC* |
🛑 Blocker for commercial distribution. Not a paperwork fix. Escalate to IP/legal. |
You are not a lawyer — for anything copyleft, NonCommercial, or of uncertain
provenance, flag it to whoever owns IP/legal rather than silently attributing it.
Step 3 — attribute in the right place
- Frontend prod dep → already handled by regenerating
third-party-licenses.txt.
Add a root-LICENSE bullet too if it's notable/headline.
- Notable / distributed dep (any language) → add a bullet to the
"Third-Party Dependencies" list in the root
LICENSE, matching the existing form:
- <Name> (<SPDX>) [License available here](<upstream-license-url>).
- Runtime-only backend dep, not distributed → acknowledge in
dev-tools/license_attribution_allowlist.txt (one name per line). This is the
"considered, no LICENSE entry needed" escape hatch the gate honors.
Step 4 — bundled binaries / models / weights (the high-risk case)
A checked-in .onnx/.bin/weights file is distributed, so its license travels
with the repo, and you can't put an SPDX header inside a binary. Convention:
- Add a sidecar
README.md next to the file stating exactly how it was produced
(self-trained vs. derived/fine-tuned from an upstream model) and under what
license.
- If it's derived from a NonCommercial-licensed model, it inherits that license
(e.g. ShareAlike) — that's a blocker for commercial use, not a notice you can write
your way out of. Confirm provenance before shipping.
Worked example — Wake mode (the case this skill was built from)
openWakeWord package: Apache-2.0 code ✅ — but its pre-trained models are
CC BY-NC-SA 4.0 (NonCommercial). The Apache link attributes the code only.
Silero VAD (MIT) + @ricky0123/vad-web (ISC) — frontend, permissive ✅, covered
by third-party-licenses.txt + a LICENSE bullet.
hey_quiet_box.onnx (checked in) — needs a sidecar README: self-trained →
Apache-2.0 ✅; derived from an openWakeWord model → inherits CC BY-NC-SA 🛑.
- Smell: code that
download_models([...]) an NC-licensed asset at runtime onto a
deployed box even when only the Apache-2.0 preprocessing models are used — fetch
only what you use, or document it.
Wiring into GitHub Actions (when ready)
Run the gate on pull_request (mirror the triggers in
.github/workflows/backend-license-checker.yml). The runner needs node for the
frontend check:
# license-attribution.yml (sketch)
on:
pull_request:
branches: [main, staging, dev]
types: [opened, reopened, synchronize]
jobs:
attribution:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 } # need base ref for --check-new-deps
- uses: actions/setup-node@v4
with: { node-version: 22 }
- run: cd app/frontend && npm ci # installs pinned generate-license-file@4.0.0
- run: python3 dev-tools/check_license_attribution.py --base "origin/${{ github.base_ref }}"
To "tag this skill to run" in Actions (judgment review on the diff, beyond the
deterministic gate), invoke Claude Code headless in a job step, e.g.
claude -p "/license-attribution-compliance review this PR's dependency changes",
after checkout — keep the deterministic gate as the always-on blocking check.
1---2name: license-attribution-compliance3description: Review third-party license attribution for TT-Studio when dependencies or bundled assets change, and keep the attribution files in sync. Use when a PR adds/updates a dependency (app/backend/requirements.txt, app/agent, inference-api, docker-control-service, or app/frontend/package.json), bundles a binary/model/weights file, or when the user asks to "attribute a license", "update third-party-licenses", "check license compliance", or run the license check. Pairs with the deterministic gate dev-tools/check_license_attribution.py (freshness + new-dependency attribution) that runs on pull requests; this skill does the judgment the script cannot -- classifying licenses and flagging NonCommercial/copyleft/provenance risks.4---56# License Attribution Compliance78TT-Studio is Apache-2.0 © Tenstorrent AI ULC and ships under a strict regime.9This skill keeps third-party attribution correct when dependencies or bundled10assets change. There are two layers:1112- **Deterministic gate** — `dev-tools/check_license_attribution.py`, meant for CI13 on every PR. It catches *mechanical* drift: a stale frontend license file, or a14 newly added dependency that nobody attributed.15- **Judgment review (this skill)** — classify the actual license, flag16 NonCommercial / copyleft / provenance risks, and write the attribution in the17 right place using the repo's established patterns.1819Run the gate first, then reason about whatever it surfaces.2021## The repo's attribution surfaces2223| Surface | What it covers | How it's maintained |24|---|---|---|25| Root `LICENSE` → "Third-Party Dependencies" list | Notable / distributed deps + pointers | Hand-edited bullets: `- Name (SPDX) [License available here](url)` |26| `app/frontend/third-party-licenses.txt` | Every frontend **production** npm dep (full license text) | `cd app/frontend && npm run generate-license` |27| SPDX file headers | Every source file (`.py`, `.sh`, Dockerfile, `.ts/.tsx/.js/.jsx`) | Enforced by existing CI (`check-copyright` / ESLint `header/header-format`); fix with `python run.py --add-headers` or `npm run header:fix:changed` |28| (none yet) backend Python deps | "utilized but not distributed" — covered by the blanket clause in LICENSE | If a backend dep is ever *distributed/bundled*, it needs an explicit notice |2930## Step 1 — run the gate3132```bash33python3 dev-tools/check_license_attribution.py # both checks34python3 dev-tools/check_license_attribution.py --check-frontend35python3 dev-tools/check_license_attribution.py --check-new-deps --base origin/main36```3738- **Frontend freshness FAIL** → `cd app/frontend && npm run generate-license`, commit39 the result. (Needs node; the check SKIPs where node is absent.)40- **New-dep attribution FAIL** → continue to Step 2 for each named dep.4142> **Tool pin:** `generate-license-file` is pinned to **4.0.0** in43> `app/frontend/package.json`. 4.1.0+ silently drops `react`/`react-dom` from the44> output. The script regenerates with `@4.0.0` explicitly. Do not loosen the pin.4546## Step 2 — classify the license4748Find each dependency's real license (npm: its `package.json`/repo; pip: PyPI/repo).49**Models, datasets, and weights often carry a different, more restrictive license50than the code that loads them — check both.**5152| Class | Examples | Action |53|---|---|---|54| Permissive | Apache-2.0, MIT, ISC, BSD-2/3 | ✅ Attribute (link/notice). Apache-2.0 §4 wants the NOTICE text retained, not just a link, for anything distributed. |55| Weak copyleft | MPL-2.0, LGPL | ⚠️ Usually OK if not modified/static-linked. Flag for review. |56| Strong copyleft | GPL, AGPL | 🛑 Generally incompatible with shipping Apache-2.0. Escalate before merging. |57| NonCommercial | CC BY-NC, CC BY-NC-SA, `*-NC*` | 🛑 **Blocker for commercial distribution.** Not a paperwork fix. Escalate to IP/legal. |5859You are not a lawyer — for anything copyleft, NonCommercial, or of uncertain60provenance, flag it to whoever owns IP/legal rather than silently attributing it.6162## Step 3 — attribute in the right place6364- **Frontend prod dep** → already handled by regenerating `third-party-licenses.txt`.65 Add a root-`LICENSE` bullet too if it's notable/headline.66- **Notable / distributed dep (any language)** → add a bullet to the67 "Third-Party Dependencies" list in the root `LICENSE`, matching the existing form:68 `- <Name> (<SPDX>) [License available here](<upstream-license-url>)`.69- **Runtime-only backend dep, not distributed** → acknowledge in70 `dev-tools/license_attribution_allowlist.txt` (one name per line). This is the71 "considered, no LICENSE entry needed" escape hatch the gate honors.7273## Step 4 — bundled binaries / models / weights (the high-risk case)7475A checked-in `.onnx`/`.bin`/weights file is **distributed**, so its license travels76with the repo, and you can't put an SPDX header inside a binary. Convention:7778- Add a sidecar `README.md` next to the file stating **exactly how it was produced**79 (self-trained vs. derived/fine-tuned from an upstream model) and **under what80 license**.81- If it's *derived from* a NonCommercial-licensed model, it **inherits** that license82 (e.g. ShareAlike) — that's a blocker for commercial use, not a notice you can write83 your way out of. Confirm provenance before shipping.8485## Worked example — Wake mode (the case this skill was built from)8687- `openWakeWord` package: **Apache-2.0** code ✅ — but its pre-trained models are88 **CC BY-NC-SA 4.0** (NonCommercial). The Apache link attributes the *code only*.89- `Silero VAD` (MIT) + `@ricky0123/vad-web` (ISC) — frontend, permissive ✅, covered90 by `third-party-licenses.txt` + a LICENSE bullet.91- `hey_quiet_box.onnx` (checked in) — needs a sidecar README: self-trained →92 Apache-2.0 ✅; derived from an openWakeWord model → inherits CC BY-NC-SA 🛑.93- Smell: code that `download_models([...])` an NC-licensed asset at runtime onto a94 deployed box even when only the Apache-2.0 preprocessing models are used — fetch95 only what you use, or document it.9697## Wiring into GitHub Actions (when ready)9899Run the gate on `pull_request` (mirror the triggers in100`.github/workflows/backend-license-checker.yml`). The runner needs node for the101frontend check:102103```yaml104# license-attribution.yml (sketch)105on:106 pull_request:107 branches: [main, staging, dev]108 types: [opened, reopened, synchronize]109jobs:110 attribution:111 runs-on: ubuntu-latest112 steps:113 - uses: actions/checkout@v4114 with: { fetch-depth: 0 } # need base ref for --check-new-deps115 - uses: actions/setup-node@v4116 with: { node-version: 22 }117 - run: cd app/frontend && npm ci # installs pinned generate-license-file@4.0.0118 - run: python3 dev-tools/check_license_attribution.py --base "origin/${{ github.base_ref }}"119```120121To "tag this skill to run" in Actions (judgment review on the diff, beyond the122deterministic gate), invoke Claude Code headless in a job step, e.g.123`claude -p "/license-attribution-compliance review this PR's dependency changes"`,124after checkout — keep the deterministic gate as the always-on blocking check.