Skip to content
Apothem
Reference

Authorship Header — Per-File SPDX License Line

Define and enforce per-file SPDX license identifier markers using canonical single-line headers in the appropriate comment syntax for each filetype.

Canonical normative reference for downstream contributors. This document mirrors the project specification's Authorship & File-Header sections (Spec §0.5 + §4.6); it is the standalone reference that ships with the published repo. The architectural rationale is recorded in ADR-0002.


1. The Canonical Header Line

Every applicable file in the ecosystem MUST begin with a single canonical SPDX license-identifier line, in the comment syntax of its filetype family; only a shebang or, on Markdown files, YAML frontmatter may precede it (§5). The line is the file's machine-readable license marker; its presence is non-negotiable for non-exempt files, and its content is governed by a single source of truth, not improvised per file. The full copyright instrument lives once at the repository-root LICENSE file — it is not duplicated into every source file.

1.1 Information Content (Invariant)

The canonical content is exactly one line:

  1. SPDX-License-Identifier: MIT — the machine-readable license marker per the REUSE specification maintained by the FSFE; parsed without ambiguity by the SPDX toolchain (reuse lint, scancode), Linux-kernel tooling, and downstream license-scanners. It carries no visual border and no per-file copyright, website, email, or GitHub lines — per-file provenance is the single SPDX line by design (see §4).

1.2 The Reference Form (#-Comment Family)

The canonical text — written here in its #-comment-syntax form — is the source of truth at src/apothem/schemas/authorship-header.txt:

# SPDX-License-Identifier: MIT

This text is the only authoritative source. The file-header validator (§8) checks files against this byte-exact fixture. Any drift between a file's header line and this fixture (under syntax substitution per §2) is reported as a finding. The validator is blocking: under --strict, as CI and the pre-commit hook run it, a finding fails the run (§8).


2. Per-Filetype Variants (Byte-Exact)

The line's information content is invariant; only its comment syntax varies per filetype. The full per-filetype variant table:

Filetype familyComment syntaxVariant rendering
# family — .sh, .bash, .zsh, .py, .rb, .pl, .ps1, .yml, .yaml, .toml, .cff, .cfg, .gitignore, .gitattributes, .editorconfig, .shellcheckrc, .env.example, Makefile, Dockerfile, Procfile, CODEOWNERS, PKGBUILD, extensionless shell entrypoints such as scripts/apothem# line-comment# SPDX-License-Identifier: MIT
// family — .js, .jsx, .mjs, .cjs, .ts, .tsx, .go, .rs, .java, .kt, .swift, .cs, .scala, .dart, .jsonc// line-comment// SPDX-License-Identifier: MIT
Block-comment family — .html, .htm, .md, .markdown, .xml, .vue (template region), .php (template region)<!-- ... --><!-- SPDX-License-Identifier: MIT -->
MDX (.mdx){/* ... */} (JSX expression comment){/* SPDX-License-Identifier: MIT */}
C-block family — .c, .cc, .cpp, .h, .hpp, .css, .scss, .less (/* */)/* ... *//* SPDX-License-Identifier: MIT */
; family — .ini, some .lisp/.scm; line-comment; SPDX-License-Identifier: MIT
-- family — .sql, .lua, .hs, .elm, .ada-- line-comment-- SPDX-License-Identifier: MIT
Lockfile / generated / JSONnone / not applicableExempt. See §3 Exception List.

Markdown variant (canonical rendering):

<!-- SPDX-License-Identifier: MIT -->

The HTML-comment (or MDX {/* */}) wrapper renders invisibly, so the rendered surface stays clean while the in-source license marker remains machine-readable across filetypes.


3. Exception List (Categorically Exempt)

The following classes are exempt from the SPDX header line. The file-header validator passes these files without checking them. The classes below match the glob list in header-exceptions.txt:

  • Legal and version files — LICENSE, LICENSE.md, LICENSE.txt, NOTICE, and VERSION. LICENSE carries the authoritative copyright line, which the license-author-consistency validator confirms is present.
  • The canonical fixture — schemas/authorship-header.txt. Injecting the header into the fixture would produce a header of the header.
  • *.svg assets — XML comments are brittle for line-comment markers, so SVG provenance is carried by the asset README and generated raster outputs.
  • JSON files (.json) — JSON has no comment syntax. Where attribution is required for a JSON config, place a sibling <file>.NOTICE.md.
  • Lockfiles — every *.lock file, package-lock.json, yarn.lock, pnpm-lock.yaml, and go.sum. These files are machine-managed.
  • Generated and minified files — any file under a generated/ directory, and minified bundles (*.min.js, *.min.css).
  • Vendored third-party content — files under _vendor/, vendor/, third_party/, and node_modules/. These carry the upstream's own license or notice. Injecting our marker over upstream attribution is a license violation.
  • Audit, planning, and harness state — everything under .audit/ and .apothem/, which holds plans, memory, learning data, and contexts. Also projects/ and memory/ at the working-tree root, which the harness owns. These trees are gitignored or operator-owned and out of scope of the published tree. Plan files are provenance-tracked by their frontmatter (see plans-discipline.md §3).
  • Test data fixtures — .yaml, .yml, .txt, and .json files under tests/fixtures/. Test source files in that tree still carry the header.
  • Injector smoke-test inputs — the files under tests/conformity-scenarios/fixtures/F-13-injector-smoke/. They stay header-less because the injector test checks that the injector adds the header to them.
  • Packaging and empty markers — .SRCINFO, which a packaging parser reads strictly, and the zero-byte markers .keep, .gitkeep, and py.typed.
  • Binary files — the image, font, archive, media, and compiled-object suffixes listed in the fixture. A suffix that the validator's variant table does not map is exempt by default.

The exception list is itself encoded as a regex/glob list at src/apothem/schemas/header-exceptions.txt and is the input to the validator's applicability check. Amendments require a structured inquiry and a new ADR.


4. License Interaction

The SPDX line declares the project's license machine-readably; the LICENSE file declares it authoritatively:

  • SPDX-License-Identifier: MIT — the machine-readable license marker per the REUSE specification and SPDX standard. Automated license scanners parse this line directly; the SPDX expression syntax is cross-compatible with reuse lint, scancode-toolkit, FOSSology, and Linux-kernel license-tooling.
  • Repository-root LICENSE — the authoritative legal instrument carrying the full MIT terms and the copyright holder. It is the single home for the copyright statement; per-file headers reference it implicitly through the shared SPDX identifier rather than restating copyright in every file.

Single-line form. Per-file provenance is the single SPDX line; the copyright instrument lives once at the root LICENSE. Bordered multi-line banner boxes (copyright, website, email, contact lines wrapped in a ruled frame) are rejected by the validator: they duplicate contact and copyright metadata in every file without adding anything the machine-readable license marker does not already provide to REUSE/SPDX/SBOM tooling. The byte-exact fixture at src/apothem/schemas/authorship-header.txt carries the single-line form; the validator runs against this fixture.

Cross-references. LICENSE file (MIT) — the legal instrument controls in case of conflict. ADR-0006 documents the banner-narrowing ratification rationale.


5. Insertion Position

  • The SPDX line is the first content of the file, with two exceptions. A shebang line (#!/usr/bin/env bash, #!/usr/bin/env python3, etc.) always remains line 1, and the SPDX line begins on line 2. On Markdown / MDX files with YAML frontmatter, the frontmatter comes first (next bullet).
  • For Markdown / MDX files with YAML frontmatter, the frontmatter stays at byte 0 so tooling can parse it, and the SPDX comment follows the closing ---, then the body, which opens with the H1 on files that carry one. scripts/inject-header.py places the comment this way.
  • A single blank line separates the SPDX line from the next content (the H1, the body, etc.).

6. Header Visibility Policy

For Markdown and MDX files, the SPDX line is always written inside its comment wrapper (<!-- ... --> or {/* */}). It is source-visible only and does not appear in the rendered page. The injector has no visible rendering and no per-file override. No tool in the repository reads the fixture src/apothem/schemas/header-visibility.yaml.


7. The Injector — scripts/inject-header.{sh,py}

A deterministic CLI that:

  • Takes one or more file paths (or globs).
  • Determines applicability via the exception list (§3).
  • Detects the existing header state (canonical / malformed / absent), stripping any non-canonical banner block it finds so re-runs are idempotent.
  • Renders the correct SPDX variant per filetype (§2).
  • Inserts at the correct position (§5), respecting shebangs and frontmatter.
  • Adds the missing blank line to an SPDX line that sits at the insertion site without one, instead of inserting a second copy above it.
  • Operates in three modes: fix-in-place (writes), emit-patch (prints unified diff), check (exit-non-zero on any divergence; no CI job runs it over the tracked tree).
  • Idempotent: running twice is a no-op.

The injector is invoked by the make headers-fix target, which runs scripts/inject-header.py --mode fix-in-place.


8. The Validator — file-header

Lives at src/apothem/conformity/file_header_grep.py. For every file in the working tree, the validator looks up its applicability (per §3) and, if applicable, asserts the canonical SPDX line is present at the insertion site. For most families that site is the file's head, after an optional shebang. For Markdown and MDX files, a YAML frontmatter block is skipped first, so the canonical line may follow the closing fence, as §5 requires. MDX files resolve to the {/* */} form (§2) and are checked against it. The validator and the injector place the canonical block at the same index.

Backed by the byte-exact fixture at src/apothem/schemas/authorship-header.txt. The corpus run reports a finding count and a sample of flagged files for this matcher. It prints no per-file diff and no coverage percentage. The matcher is blocking: under --strict, which CI and the pre-commit hook use, a finding fails the run. Without --strict the gate reports the finding and exits 0.


9. Self-Enforcement Mechanisms

The discipline must survive every future session and every future contributor. Mandatory enforcement surfaces:

  1. src/apothem/schemas/authorship-header.txt — the byte-exact canonical fixture; one source of truth.
  2. scripts/inject-header.{sh,py} — the mechanical injector (§7).
  3. file-header validator (§8) — reports divergence as a blocking finding, which fails a --strict run.
  4. Pre-commit hook — the conformity-corpus-perwrite hook runs every per-Write matcher, including the file-header validator (§8), over the tracked tree with --strict. The file-header matcher is blocking, so a finding blocks the commit. The hook only checks. It has no fix mode and never runs the injector (§7), which runs through make headers-fix.
  5. CLAUDE.md mandatory-behavior block — instructs the assistant to inject the canonical SPDX line whenever creating an applicable file.
  6. The GitHub Copilot instructions file at .github/copilot-instructions.md — instructs Copilot to do the same on file generation.
  7. PreToolUse hooks at src/apothem/hooks/messages/pretooluse-{write,edit}-header-guard.md — intercept Write/Edit tool calls on applicable paths so the SPDX line is injected at file creation rather than discovered later as a validator finding. The guard's checker, src/apothem/hooks/lib/header_check.py, uses the standard library alone and reads the fixture and the exemption list from the schemas/ directory beside hooks/, so it also works under the Claude Code plugin, where the apothem package is not importable. It applies the injector's variant tables and insertion-site rules to files inside the project, and only in a git project that carries the header fixture (src/apothem/schemas/authorship-header.txt), since the SPDX line is this repository's convention and not a default for every project the plugin opens.
  8. PR template checkbox — contributor-facing assertion that every new file carries the canonical SPDX line.
  9. This document (site/content/docs/reference/authorship-header.mdx) — canonical, normative explainer.

See Also

On this page