Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ lint-secrets: ## Scan for committed secrets
check: ## Run repo self-consistency scripts (skips scripts not yet added)
@if [ -x scripts/check-skills.sh ]; then scripts/check-skills.sh; else echo "skip: scripts/check-skills.sh not present yet"; fi
@if [ -x scripts/check-local-md.sh ]; then scripts/check-local-md.sh; else echo "skip: scripts/check-local-md.sh not present yet"; fi
@if [ -x scripts/check-license-marker.sh ]; then scripts/check-license-marker.sh; else echo "skip: scripts/check-license-marker.sh not present yet"; fi

lint: lint-docs lint-actions lint-secrets check ## L0 - aggregate all lint/consistency checks

Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,8 @@ The template is released and verified end to end (create from template → boots

## License

[MIT](LICENSE)
The template is [MIT](LICENSE). **Your repository does not have to be.**
Bootstrap phase 9 makes you choose — MIT under your own name, a proprietary /
all-rights-reserved notice for client and commissioned work, or decide later —
and records the scaffolding's MIT attribution in `NOTICE`, which you keep
either way. See [docs/setup/licensing.md](docs/setup/licensing.md).
42 changes: 42 additions & 0 deletions docs/adr/ADR-0004-adopter-licence-choice.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# ADR-0004: The adopter's licence is an explicit bootstrap decision

- **Status**: Accepted
- **Date**: 2026-09-02

## Context

A repository created from this template starts out carrying the template's own `LICENSE`: MIT, copyright the template author. De-templating rewrote `README.md`, `CHANGELOG.md` and the release-please manifest, and removed `docs/template/` — but never touched `LICENSE`. Nothing in the script mentioned licensing at all.

For an open-source adopter that is a wrong copyright line. For an adopter doing client or commissioned work it is considerably worse: MIT is an irrevocable, written grant of the right to use, modify, publish, distribute, sublicense and sell, made to the whole world. A commission agreement typically transfers copyright on final payment; an MIT file in the delivered repository grants far more than that, to more people, before payment, and cannot be withdrawn. It removes the leverage the payment clause was built on. The field report that prompted this ADR came from an adopter who shipped four private client repositories that way.

The obvious fix — rewrite the copyright line to the adopter — is itself a defect. Substantial portions of the template ship verbatim in every adopted repository, and MIT requires its copyright and permission notice to be included with them. Rewriting that line deletes the only copy of the notice from the repository, trading a licensing mistake for a licence violation.

## Decision

Bootstrap gains **phase 9 — Licence**, before de-template, forcing an explicit choice: MIT under the adopter's name, a proprietary all-rights-reserved notice, or an explicit defer.

1. **The phase runs before de-template and is not gated by `--keep-template-docs`.** De-template returns early for three unrelated reasons; folding the licence step into it would let any of them silently swallow the decision. Running first also means an aborted run fails into the safe state.
2. **There is no default, and a closed stdin defers.** `confirm()` treats a closed stdin as "take the default", which here would mean silently shipping the template author's MIT — the original bug with extra steps.
3. **`--yes` never writes a licence.** It defers and files the decision as the first remaining manual step, visually marked. This is the one place where the script declines to act on `--yes`.
4. **Attribution is unconditional.** Every answer that writes `LICENSE` also writes `NOTICE`, carrying the template's MIT notice. The MIT-keep path needs it exactly as much as the proprietary path.
5. **Attribution goes in `NOTICE`, never inside `LICENSE`.** A `LICENSE` containing both an all-rights-reserved notice and a verbatim MIT grant is ambiguous about what a client is receiving, and a client's counsel reads `LICENSE` and nothing else.
6. **The script ships exactly two licence bodies.** Anything else is the defer answer with a pointer to SPDX.
7. **`LICENSE` is regenerated from a seed, not patched with `sed`.** Holder names legitimately contain `&` and `/`, both `sed` replacement metacharacters.

## Consequences

- One more interactive prompt in an already long run, and it is the one prompt that cannot be safely skimmed.
- Adopters carry a `NOTICE` file. Licence scanners find it, which is useful when a client runs an open-source audit on delivery.
- The template must keep `TEMPLATE_COPYRIGHT_HOLDER` and `TEMPLATE_COPYRIGHT_YEAR` in sync with its own `LICENSE`. If they drift, the phase stops recognising its own licence and silently does nothing — the original defect, with no symptom. `scripts/check-license-marker.sh` turns that into a red build.
- The proprietary body is an example and says so on its face, with a self-removing trailer the adopter deletes after counsel review.
- The template now takes a position on adopters' licensing. It is a prompt, not a policy: every answer including "leave it alone" is available.

## Alternatives considered

- **Rewrite only the copyright line.** Manufactures an MIT violation by deleting the notice. Rejected outright.
- **Delete `LICENSE` during de-templating.** An unlicensed repository is "all rights reserved" by default in most jurisdictions, which is arguably the safest state — but it reads as an oversight rather than a decision, and breaks GitHub's licence detection. Rejected.
- **Ship more licence bodies (Apache-2.0, GPL, MPL).** Kilobytes of legal text the maintainer cannot meaningfully maintain, and any set of three is arbitrary. Rejected in favour of pointing at SPDX.
- **Attribution as a comment block inside the new `LICENSE`.** Creates grant ambiguity in the one file people actually read. Rejected.
- **Attribution in the README.** Does not survive editorial churn, and phase 10 replaces the file wholesale. Rejected.
- **A `docs/template/LICENSE.proprietary.example` file.** Under `--yes` the phase writes nothing and files a manual step, and phase 10 then removes `docs/template/` — deleting the example in the very run that told the adopter to read it. The text lives as a script constant and in `docs/setup/licensing.md` instead. Rejected.
- **Do nothing; document it in the README.** The failure mode is silent and the cost is legal. A paragraph nobody reads is not a mitigation. Rejected.
1 change: 1 addition & 0 deletions docs/adr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ Routine choices (a library patch bump, a wording tweak) do not get ADRs. When in
| [ADR-0001](ADR-0001-adopt-adr.md) | Adopt Architecture Decision Records | Accepted |
| [ADR-0002](ADR-0002-release-flow.md) | Release flow: release-please with human-gated release PRs | Accepted |
| [ADR-0003](ADR-0003-metadata-single-home.md) | Metadata single-home policy | Accepted |
| [ADR-0004](ADR-0004-adopter-licence-choice.md) | The adopter's licence is an explicit bootstrap decision | Accepted |
51 changes: 49 additions & 2 deletions docs/setup/bootstrap.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ below), then re-run.
| `--yes` | No prompts; accept defaults for every phase. |
| `--prune` | Delete undeclared repo labels without prompting (the default answer is already yes; use this to skip the prompt in scripts/CI). |
| `--skip-project` | Skip Project creation and field setup (phase 4). |
| `--keep-template-docs` | Skip de-templating (phase 9); keep `docs/template/` and the starter README. |
| `--license MODE` | Answer phase 9 non-interactively: `mit`, `proprietary` or `defer`. Without it, `--yes` defers and files the decision first. |
| `--keep-template-docs` | Skip de-templating (phase 10); keep `docs/template/` and the starter README. |
| `--help` | Show usage and exit. |

## Phases, and their manual equivalent
Expand Down Expand Up @@ -247,7 +248,53 @@ select `.github/rulesets/main-branch.json`. Review the imported rules (branch
deletion/force-push blocked, PR required, `ci` status check required) and
click **Create**.

### 9. De-template
### 9. Licence

**The one phase you cannot safely skim.** Until you answer it, your repository
carries the *template's* licence — MIT, copyright the template author — and
that is almost certainly not what you want.

MIT is an irrevocable grant: anyone who obtains a copy may use, modify,
publish, distribute, sublicense and **sell** it, and publishing it once cannot
be undone. For client or commissioned work that usually conflicts with your
contract, which typically transfers copyright on final payment — an MIT file in
the delivered repository grants the client, and everyone else, far more than
that, before you have been paid. And even if you do want MIT, the copyright
line has to name you.

Three answers, with no default — a bare Enter re-asks:

1. **MIT under your name.** Keeps the MIT terms, rewrites the copyright line.
2. **Proprietary / all rights reserved.** For client, commissioned and
closed-source work. Replaces `LICENSE` with an all-rights-reserved notice
that defers to your commission agreement rather than pretending to be one.
3. **Decide later.** Leaves `LICENSE` untouched and puts the decision at the
**top** of the remaining manual steps, marked `!`.

Anything else — Apache-2.0, GPL, BUSL — is answer 3: supply the text yourself.
The script ships no other licence bodies.

**Both writing answers also create `NOTICE`, and this is not optional.**
Substantial parts of this template ship verbatim in your repository
(`scripts/bootstrap.sh` alone is over 900 lines, plus the workflows, the
Makefile, and every skill), and MIT requires its copyright and permission
notice to travel with them. Rewriting `LICENSE` without writing `NOTICE` would
delete the only copy of that notice from your repository — swapping a licensing
mistake for a licence violation. `NOTICE` is where the attribution lives, and
it stays even if you relicense everything else.

Under `--yes` the phase writes **nothing** and files the decision as the first
manual step, because silently keeping the template author's MIT is the bug this
phase exists to prevent. `--license mit|proprietary|defer` answers it
non-interactively. Re-running after you have decided is a no-op: the phase
recognises that `LICENSE` no longer carries the template's copyright line and
leaves it alone. If `LICENSE` or `NOTICE` have uncommitted changes the phase
skips entirely, even under `--yes`.

Manual: see `docs/setup/licensing.md`, which carries both file bodies verbatim
and the reasoning behind them.

### 10. De-template

One-time conversion from the template product to your project:

Expand Down
Loading