name: licensing-with-reuse description: Manages REUSE-compliant licensing with the reuse CLI. Use when adding SPDX headers, running reuse annotate or reuse lint, choosing header versus .license sidecar files, working with LICENSES/, LicenseRef custom licenses, or setting up project licensing conventions. user-invocable: true license: LicenseRef-MutuaL-1.2 metadata: author: Amolith amolith@secluded.site
Use the reuse CLI as the source of truth for file licensing. Prefer a small,
verified change over hand-writing SPDX metadata and hoping reuse lint agrees.
First pass
- Inspect existing licensing before changing it:
reuse lint find . -maxdepth 1 -type f \( -iname 'license*' -o -iname 'licence*' -o -iname 'copying*' -o -iname 'notice*' \) -print | sort find LICENSES -maxdepth 1 -type f -print 2>/dev/null | sort rg -n "SPDX-License-Identifier|SPDX-FileCopyrightText|LicenseRef-|\[\[annotations\]\]" . - If the project already has a clear pattern, follow it. Do not offer to re-license existing work unless the user asked for that.
- If the project has no convention, ask whether they want one. Useful defaults to discuss: docs/examples/config are some CC variant like CC0, while meaningful code may use a copyleft license.
- If the user is choosing licenses and wants guidance, point them at https://writefreesoftware.org/.
Everyday commands
Add an SPDX header without a year:
reuse annotate -c "User <user@example.com>" -l 'SPDX-ID' --exclude-year path/to/file.ext # ask the user for name/email
Use more than one copyright holder or license by repeating the flag:
reuse annotate \
-c "Alice <alice@example.com>" \
-c "Example Org" \
-l 'Apache-2.0' \
-l 'MIT' \
--exclude-year \
path/to/file.go
Write a .license sidecar instead of putting a header in the file:
reuse annotate \
-c "User <user@example.com>" \
-l 'CC0-1.0' \
--exclude-year \
--force-dot-license \
AGENTS.md .agents/skills/example/SKILL.md
Use --force-dot-license for files whose literal bytes matter, especially text
that will be read directly as an LLM prompt or embedded into another prompt.
Headers in those files change the prompt; sidecars keep licensing metadata out
of the content. Example: if internal/server/silverbullet.md is embedded and
sent as part of a prompt, license it with --force-dot-license.
For files where reuse cannot infer the comment style, choose one deliberately:
reuse annotate -c "User <user@example.com>" -l 'CC0-1.0' --exclude-year --style python script
reuse annotate -c "User <user@example.com>" -l 'CC0-1.0' --exclude-year --fallback-dot-license unknown.file
reuse annotate -c "User <user@example.com>" -l 'CC0-1.0' --exclude-year --skip-unrecognised some/path
Bulk annotations belong in REUSE.toml when a whole class of files shares the
same metadata and inline headers would be noisy or impossible. Keep those globs
tight.
The reuse annotate gotcha agents miss
Re-running reuse annotate on a file that already has a matching header does
not mean "edit the header I just added". It means add another copyright line to
the existing header. This is correct when a new holder contributed to the file,
but wrong when the previous command had a typo or the wrong holder.
If the first command was wrong, inspect the file and edit or replace the bad
header directly, then run reuse lint. If you are applying metadata to a mixed
tree, use --skip-existing so already-covered files are not changed:
reuse annotate -c "User <user@example.com>" -l 'CC0-1.0' --exclude-year --skip-existing -r docs
When in doubt, test the exact command on a temporary copy first:
tmp=$(mktemp -d)
cp path/to/file.ext "$tmp/"
reuse annotate -c "User <user@example.com>" -l 'CC0-1.0' --exclude-year "$tmp/file.ext"
sed -n '1,20p' "$tmp/file.ext"
rm -rf "$tmp"
License files and custom identifiers
Use SPDX identifiers where possible, like MIT, Apache-2.0, and CC0-1.0, so
reuse download --all pickes them up.
Custom licenses must use a LicenseRef-* identifier and have matching text
under LICENSES/. For example, a custom MutuaL license identifier would look
like LicenseRef-MutuaL-1.2 in headers, sidecars, or REUSE.toml and could go
in LICENSES/LicenseRef-MutuaL-1.2.txt.
If the text already exists locally somewhere else, copy it through reuse download --source or place it at the exact LICENSES/LicenseRef-... path
expected by reuse lint:
reuse download --source /path/to/other/LICENSES LicenseRef-ID
Do not invent an ID without the user's agreement. The identifier becomes part of the project's public metadata and the user may know its ID even if you don't.
reuse lint in development and CI
Run reuse lint after changing file coverage, headers, sidecars, LICENSES/, or
REUSE.toml. In CI, pre-commit hooks, or task runners, keep it boring:
reuse lint
# or
reuse lint --lines
reuse lint failures are usually one of:
- a file has no licensing metadata;
- an ephemeral build artifact needing rm-ing;
- a header names a license missing from
LICENSES/; - a
LicenseRef-...identifier does not match a license text file; - a generated, binary, vendored, or prompt file needs a sidecar or
REUSE.tomlannotation; - an old or broad annotation no longer matches the actual tree.