diff --git a/.gitignore b/.gitignore index ff12716..69499b4 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ Chat*.txt .claude/ # Local agent guidance — not shipped with the catalogue -CLAUDE.md # Upstream inputs and build tooling — not shipped with any skill bundle # (includes elixir-erlang/ — cloned Elixir/Erlang reference repos + a copyrighted diff --git a/AGENTS.md b/AGENTS.md index b813587..55d78ca 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,25 +1,408 @@ # AGENTS.md — Construct skill catalogue -Tool-agnostic guidance for any agent (Claude, Codex, Gemini, Grok, …) editing -skills in this repo. The full, version-controlled workflow lives in -[`CONTRIBUTING.md`](CONTRIBUTING.md); this file is the committed digest of the -rules that bite. (A maintainer-local `CLAUDE.md` overlay adds host-specific notes -— Home Manager fan-out, local config — and is gitignored.) - -## Hard rules - -- **`SKILL.md` frontmatter `description` — hard cap 1000 characters.** The loader's - absolute limit is 1024 (`field 'description' in SKILL.md must be at most 1024 - characters`), but this repo caps the *rendered* description at **1000** — it - MUST NOT exceed 1000 chars. Folded `description: >` blocks render by joining - lines with spaces (blank lines → newlines, plus a trailing newline); that - rendered length is what counts, not the raw line count. Re-check after any edit. - Normative as Standard §5.6, and gated in CI (`SKILL.md description cap` step, - every `SKILL.md` in the tree) and by `construct skill ship`, which refuses to - stage or ship an over-cap skill (exit 5, `CONFLICT`). The `.githooks/pre-commit` - hook is the fast local signal only — it is opt-in per clone - (`git config core.hooksPath .githooks`), so trim *before* packing rather than - relying on it. +Authoritative agent context (Standard §5.7). Every agent reads this file — +Claude, Codex, Gemini, Grok, Cursor, opencode. `CLAUDE.md` imports it and adds +only Claude-Code-only notes. The full, version-controlled procedure (bundling +commands, drift sweep, branch/PR flow) lives in +[`CONTRIBUTING.md`](CONTRIBUTING.md). + +## What this repo is + +A catalogue of agent skills loaded by Claude Code, Gemini CLI, and Codex from +`~/.claude/skills/`, `~/.gemini/skills/`, `~/.codex/skills/`, plus Grok-specific +skills in [`grok-skills/`](grok-skills/) loaded from `~/.grok/skills/` and +vendored Android skills in [`android-skills/`](android-skills/). Skill content +is markdown plus a small number of templates/JSON — there is no build system, +runtime, or test suite for it; edits there are content edits, shipping is +rezipping. The one exception is [`construct-cli/`](construct-cli/), a real +Rust binary (see below) with its own build/test/lint surface. + +Current skills (authoritative list is `README.md §2`; run `ls -d spacecraft-* +gnu-* microsoft-*` or check the README table if this drifts) span three +groups: infra/tooling (`spacecraft-agentic-cli`, `spacecraft-brand-guidelines`, +`spacecraft-cli-preference`, `spacecraft-cli-shell`, `spacecraft-cli-standard`, +`spacecraft-document-format`, `spacecraft-markdown-document`, +`spacecraft-missing-pkg`, `spacecraft-standard-constitution`, +`spacecraft-texinfo-document`, `spacecraft-theme-factory`, `gnu-coding-standards`, +`gnu-free-software`), the governing Standard skill +(`spacecraft-standard-constitution`), and one `spacecraft--guidelines` +skill per supported language (currently: ada, carbon, chez, clang, clojure, +commonlisp, cpp, dartflutter, elixir, erlang, gleam, golang, guile, java, +kotlin, lua, nickel, nim, nix, nu, ocamel, python, rust, swift, typescript, +zig — plus `microsoft-rust-guidelines`, the mandatory Rust base skill). New +language/skill directories land here often; treat the inline list as a rough +map, not ground truth — `README.md §2` and the directory listing are. + +The repo is also a Nix flake (`flake.nix` + `flake.lock`). The flake exposes +each detected skill as `packages.${system}.${skill-name}` (each Grok skill as +`packages.${system}.grok-${skill-name}`, each Android skill similarly +namespaced) and ships `homeManagerModules.default` that wires up the canonical +`~/.agents/skills/` location plus per-harness symlinks. **`flake.lock` is +tracked and must be committed.** Skill auto-detection is by `SKILL.md` +presence — adding a new skill directory is enough; no flake edit needed. +`grok-skills`, `android-skills`, `Excluded`, `.claude`, `.git`, and +`construct-cli` are explicitly excluded from top-level skill auto-detection +(see `excludedDirs` in `flake.nix`). + +The authoritative governance document for everything produced in this repo is +[`spacecraft-standard-constitution/SKILL.md`](spacecraft-standard-constitution/SKILL.md), which encodes +The Steelbore Standard — it carries the current version in its own masthead, so +none is repeated here to go stale. Load it before any non-trivial edit — its §14 checklist is the +audit gate. The skill is the upstream of the published `standard/` document; +changes flow skill → published standard, so this `SKILL.md` may lead it. + +## Skill layout (per top-level directory) + +``` +/ +├── SKILL.md # frontmatter (name, description, license, maintainer, website) + body +├── LICENSE | LICENSE.md # optional in-dir copy; GPL-3.0-or-later (microsoft-rust-guidelines is dual `GPL-3.0-or-later OR MIT`, shipping a LICENSE-GPL + LICENSE-MIT pair — Microsoft upstream is MIT). About half the skills omit it and fall back on the repo-root LICENSE. +├── CREDITS.md # required when the skill builds on third-party work (Standard §15.3); currently microsoft-rust-guidelines, gnu-coding-standards, spacecraft-cli-preference, spacecraft-rust-guidelines, spacecraft-ada-guidelines +├── references/ # optional; loaded on demand by the agent +└── assets/ # optional; only spacecraft-agentic-cli has one today +``` + +Skill IDs (directory and frontmatter `name`) are **functional identifiers**, +not codenames — Standard §2.2 reserves codenames for projects/modules/utilities/ +releases, not for skill identifiers. The README catalogue and the directory list +must stay in sync. + +## Bundling (.zip and .skill) + +Each skill ships as two bundles at the repo root: `.zip` and +`.skill`. They contain only `SKILL.md`, `LICENSE`, `CREDITS.md`, and +`references/` (plus `assets/` where present) — never tooling, generator +scripts, or raw upstream sources. Auxiliary inputs that don't belong in the +shipped skill live in `Excluded/` (e.g., `Rust-Guidelines.{md,txt}`, +`skill.ps1`). + +Rebuild pattern (from `.claude/settings.local.json`): + +```sh +rm -f .zip .skill +zip -qr .zip /SKILL.md /LICENSE /CREDITS.md /references +zip -qrD .skill /SKILL.md /LICENSE /CREDITS.md /references +``` + +Include each argument only when that file/dir exists in the skill. LICENSE may +be entirely absent from the directory (about half are — repo-root `LICENSE` +covers them); when present, the filename varies (`LICENSE` vs `LICENSE.md`). +`CREDITS.md` appears only where §15.3 triggers fire (currently +`microsoft-rust-guidelines`, `gnu-coding-standards`, `spacecraft-cli-preference`, +`spacecraft-rust-guidelines`, `spacecraft-ada-guidelines`). `references/` and `assets/` are optional. +Run `ls /` first whenever you're unsure. + +The `.skill` bundle uses `-D` to drop directory entries; the `.zip` keeps them. +Verify with `unzip -l .zip` before committing. After editing any file +inside a skill directory, **rebuild both bundles in the same commit** — a stale +bundle ships broken content to every agent that installs from the zip. + +## Workflow: every skill-directory change + +The bundles are the install surface. A bundle that lags its `SKILL.md` / +`references/` / `assets/` ships broken content to every consumer. The contract +is mechanical — apply it after **any** edit inside a `/` directory: + +1. **Rebuild both bundles** for the changed skill: + ```sh + rm -f .zip .skill + zip -qr .zip /SKILL.md /LICENSE /CREDITS.md /references + zip -qrD .skill /SKILL.md /LICENSE /CREDITS.md /references + ``` + Add `/assets` to both lines if the skill has an `assets/` dir + (today only `spacecraft-agentic-cli` does). Omit any argument the skill + doesn't have — `spacecraft-standard-constitution` is SKILL.md-only; many skills omit + the in-directory LICENSE entirely; `CREDITS.md` exists only where §15.3 + applies (`microsoft-rust-guidelines`, `gnu-coding-standards`, + `spacecraft-cli-preference`, `spacecraft-rust-guidelines`, + `spacecraft-ada-guidelines`). Run `ls /` + first when in doubt. +2. **Stage** the skill directory **and** both bundles in the same commit — + never separately. Always stage by explicit name: + ```sh + git add /SKILL.md .zip .skill + ``` + Never use `git add -A` or `git add .` — other `.skill` files at the + repo root carry pre-existing uncommitted changes from prior normalization + passes and must not be swept into unrelated commits. +3. **Commit with UTC timestamps**: + ```sh + TZ=UTC GIT_COMMITTER_DATE="$(TZ=UTC date)" \ + git commit --date "$(TZ=UTC date)" -m "..." + ``` + The Steelbore Standard §14.2 forbids offset notation (`+0300`, `+00:00`); only + `Z` / `+0000` is permitted. Signing is on globally + (`commit.gpgsign=true`, `gpg.format=ssh`, `user.signingkey=~/.ssh/id_ed25519.pub`) + — no extra flag needed. Assistant-driven commits end with a + `Co-Authored-By: Claude …` trailer; human commits do not. +4. **Branch + PR — never push to `main`.** Every change, including a one-line + version bump, goes through a feature branch → pull request → squash-merge → + delete branch. This matches `/spacecraft-software/standard/AGENTS.md`, which + states the rule for **both** the Standard and Construct repos, and matches + this repo's own recent history (#11, #21, #22 are all squash-merged PRs). + ```sh + git switch -c + # …rebuild bundles, stage by name, commit (steps 1–3)… + git push -u https://github.com/Spacecraft-Software/Construct.git + gh pr create --repo Spacecraft-Software/Construct --base main --head \ + --title "…" --body "…" + ``` + Use HTTPS on this host — the SSH remote + (`git@github.com:Spacecraft-Software/Construct.git`) is intermittently + unreachable here. The HTTPS push still carries the locally-made signed + commit, so GitHub's "Verified" status is preserved. + + There is **no auto-push pre-authorisation.** A prior note in this file + claimed skill-directory changes could be pushed straight to `main` without a + prompt; that contradicted the Standard repo's cross-repo rule and is + withdrawn. Opening the PR is where the assistant stops — **merging is the + maintainer's call**, and the assistant never merges its own PR. + +The assistant's responsibility ends at opening the PR. **Local agent install dirs +refresh only after Home Manager rebuilds** — see *Local agent fan-out* below. +That rebuild is a user-initiated action; the assistant must not run it. + +If multiple skills changed in one turn, rebuild **all** of their bundles in the +same commit. Never let `git status` show a skill-dir change without its +matching bundle change. + +**Detecting already-committed drift.** A clean working tree does *not* prove the +bundles are current: a past commit can bump `SKILL.md` while forgetting the +bundle, leaving a committed `.zip`/`.skill` that silently lags its source (this +has happened — `spacecraft-standard-constitution` shipped v1.12 against a v1.18 `SKILL.md`). +`git status` can't see it. Before trusting the install surface, sweep: + +```sh +for d in */; do n="${d%/}"; [ -f "$n/SKILL.md" ] || continue + case "$n" in grok-skills|android-skills|Excluded|construct-cli) continue;; esac + inzip="$(unzip -Z1 "$n.zip" 2>/dev/null | grep -v '/$')" + # (a) content drift: every file inside the bundle must match the working tree + printf '%s\n' "$inzip" | while read -r f; do [ -n "$f" ] || continue + unzip -p "$n.zip" "$f" 2>/dev/null | diff -q - "$f" >/dev/null \ + || echo "DRIFT (content): $n.zip :: $f" + done + # (b) missing from bundle: every shippable file on disk must be in the bundle + find "$n" -type f \( -name SKILL.md -o -name 'LICENSE*' -o -name CREDITS.md \ + -o -path "$n/references/*" -o -path "$n/assets/*" \) 2>/dev/null | while read -r f; do + printf '%s\n' "$inzip" | grep -qxF "$f" \ + || echo "DRIFT (missing): $n.zip lacks $f" + done +done +``` + +Any `DRIFT:` line means rebuild that skill's bundles and commit. The sweep now +walks the **whole** bundle: `(a)` content-diffs every file the `.zip` contains +(`SKILL.md`, `references/**`, `LICENSE`, `CREDITS.md`, `assets/**`) against the +working tree, and `(b)` flags any shippable file on disk that the bundle is +missing — so adding a `references/` file (e.g. `spacecraft-standard-constitution`'s +`CHANGELOG.md`) without rebuilding is caught too. It checks `.zip` as the +canonical surface; `.skill` is built in lockstep from the same args in the same +commit, so a drifted `.zip` implies a drifted `.skill`. + +`git log -1 --show-signature` may report "No signature" locally because +`~/.ssh/allowed_signers` isn't populated; this is a verifier-side gap, not a +signing failure. GitHub validates the SSH signature independently and shows +"Verified" if the public key is registered as a **Signing** key in GitHub +account settings (Authentication-only keys won't validate signatures). + +## `construct-cli/` — the `construct` Rust binary + +[`construct-cli/`](construct-cli/) is a separate, real Rust project (its own +`Cargo.toml`/`Cargo.lock`, `src/`, `tests/`, and per-directory context files) — +the Spacecraft Software Construct skills package manager, conforming to the +Dual-Mode Self-Documenting CLI Standard. It is excluded from the flake's skill +auto-detection (`excludedDirs`) but is itself buildable via `nix build +.#construct`. Standard commands: + +```sh +cd construct-cli +cargo build --release +cargo test +cargo clippy --all-targets -- -D warnings +cargo fmt --check +``` + +Currently implemented: `construct skill sync` (runs `nix flake update +construct` in a consumer flake, default `/spacecraft-software/bravais`), +`construct skill ship`, `construct describe`, `construct schema`. Planned +phases add an imperative installer across ~70 agent registries, general git +sources, and a `--format explore` TUI. + +`construct skill ship` implements the branch+PR workflow above end-to-end: +it enforces bundle-drift and the §5.6 description cap, switches to a feature +branch (generated from the shipped skills, or `--branch`), stages by explicit +name, makes the signed UTC commit, pushes the branch, and opens the PR with +`gh`. It **never** pushes to the default branch, and it never merges — that +stays the maintainer's call. `--dry-run` reports the whole plan, including the +branch it would use, without touching anything. + +Because nothing lands on `main`, `ship` no longer runs `skill sync`; run +`construct skill sync` after the PR merges. `--no-sync` is retained as a hidden +no-op so existing invocations keep working. Read `construct-cli/AGENTS.md` before working inside +this subdirectory — it governs that subtree, not this file. + +## Vendored Android skills (`android-skills/`) + +`android-skills/` is Google's official [android/skills](https://github.com/android/skills) +catalogue, vendored **verbatim and unmodified** (Apache-2.0, third-party — +Standard §4.2 upstream-preservation). Never hand-edit content inside it; +upstream changes come in via re-vendoring, not local patches. It is flattened +one level from upstream (`//SKILL.md` → `/SKILL.md`) +to match how Construct's loader and flake discover skills, and its own +`README.md`/`CREDITS.md` track provenance and the flattening rule. It is +excluded from the root flake's `excludedDirs` and packaged separately. + +## Grok skills (`grok-skills/`) + +Grok uses a **flat** bundle format — `SKILL.md` and any `assets/` / `references/` +live at the **root** of the `.zip`, not inside a `/` directory. +Grok-specific skills therefore live under `grok-skills/` with their own +catalogue (`grok-skills/README.md`) and their bundles ship **inside** +`grok-skills/`, not at the repo root. + +Source layout is the same as cross-platform skills: + +``` +grok-skills// +├── SKILL.md +├── assets/ (optional) +└── references/ (optional) +``` + +Bundle layout is **flat** (different from root skills): + +``` +grok-skills/.zip +├── SKILL.md +├── assets/... +└── references/... +``` + +Build from inside the skill directory so the paths land at the zip root: + +```sh +cd grok-skills/ +rm -f ../.zip ../.skill +zip -qr ../.zip SKILL.md [assets] [references] +zip -qrD ../.skill SKILL.md [assets] [references] +``` + +Verify the zip top level is `SKILL.md` (not `/SKILL.md`) before +committing — a nested layout will break Grok's loader. + +The same workflow contract applies as for root skills: rebuild both bundles +whenever any file inside a Grok skill changes, stage the directory and both +bundles in the same commit, never use `git add -A`. The +`grok-skills/README.md` catalogue table must stay in sync with the +subdirectory listing. + +Frontmatter is also minimal for Grok — just `name` and `description`. No +`license`, `maintainer`, `website` fields (Grok's loader does not consume +them). License compliance still tracks the repo-root `LICENSE` per +Standard §4 — the canonical GPL-3.0-or-later text as a regular file, with +`LICENSES/GPL-3.0-or-later.txt` a symlink back to it (§4.3, v1.38 direction). + +## Local agent fan-out (Home Manager hosts) + +Local fan-out is managed by **Home Manager**, not by the assistant. Each +per-harness skill path is a real directory provisioned by Home Manager with +per-skill symlinks that chain through the Nix store to this repo: + +``` +~/.claude/skills/ + → /nix/store/-home-manager-files/.claude/skills/ + → /nix/store/-hm_ + → /spacecraft-software/construct/ +``` + +Paths populated by Home Manager: `~/.claude/skills/`, `~/.codex/skills/`, +`~/.ai/skills/`, `~/.agent/skills/`. Gemini CLI's scan path is Home Manager's +responsibility on this host as well — the assistant does not provision it. + +The Nix flake's `homeManagerModules.default` (in `flake.nix`) provides a +unified path layout for new consumers: install once to `~/.agents/skills/` and +symlink every per-harness path (`~/.claude/skills`, `~/.gemini/skills`, +`~/.codex/skills`, `~/.ai/skills`, `~/.agent/skills`) to that canonical +location. Grok skills install separately to `~/.grok/skills/` because of +their different bundle layout. The hand-written per-skill HM config currently +in use on this host predates the flake and should be migrated to +`spacecraft.construct.enable = true` at the maintainer's convenience. + +**After a PR merges, Home Manager must be rebuilt** before per-harness paths +resolve to the new content. The maintainer runs the rebuild manually +(`home-manager switch …` or the equivalent flake command); the assistant +does **not** invoke it. + +Verify after rebuild: + +```sh +readlink -f ~/.claude/skills/spacecraft-standard-constitution +# → /spacecraft-software/construct/spacecraft-standard-constitution +``` + +If the symlink still resolves into a stale `/nix/store/-hm_*` path +(for example after a repo rename), the Home Manager config has not yet been +rebuilt against the new repo path. Until it is, agents read the previous +generation's content even though `origin/main` is current. + +The assistant performs no `rsync`, no symlink setup, and no +`home-manager switch`. Its responsibility ends at opening the PR. + +## Editing rules specific to this repo + +- **`SKILL.md` frontmatter `description` — hard cap 1000 characters.** The skill + loader's absolute limit is 1024 (`field 'description' in SKILL.md must be at + most 1024 characters`), but this repo caps the *rendered* `description` at + **1000** — a description MUST NOT exceed 1000 chars, full stop. The 24-char + margin absorbs loader/encoding edge cases and the trailing newline YAML adds. + YAML folded scalars (`description: >`) join lines with spaces, turn blank lines + into newlines, and add one trailing newline — so the rendered length is what + counts, not the raw line count. Re-check after any description edit; every + skill is currently ≤1000 (closest: `gnu-coding-standards` and + `spacecraft-guile-guidelines`, just under). + Folded-aware check before committing: + ```sh + python3 - "$skill/SKILL.md" <<'PY' + import sys + L=open(sys.argv[1]).read().splitlines(); i=L.index('---',1); fm=L[1:i] + j=[k for k,l in enumerate(fm) if l.startswith('description:')][0] + body=[fm[k].strip() for k in range(j+1,len(fm)) if fm[k].startswith(' ') or not fm[k].strip()] + out=[]; buf=[] + for b in body: + (out.append(' '.join(buf)),buf.clear()) if b=='' else buf.append(b) + if buf: out.append(' '.join(buf)) + print(len('\n'.join(out))+1) + PY + ``` + The cap is normative (**Standard §5.6**) and enforced at three points, in + descending authority: + 1. **CI** — the `SKILL.md description cap` step in `.github/workflows/ci.yml` + runs `.githooks/check-description-length.py` over every `SKILL.md` found in + the tree (`find`, so `grok-skills/` and `android-skills/` are covered). This + is the gate; it cannot be skipped. + 2. **`construct skill ship`** — refuses to stage, commit, or open a PR for a skill whose + rendered description exceeds 1000 (exit 5, `CONFLICT`, with an + `oversized_skills` array naming each offender and its overage). This is the + pre-pack gate §5.6 requires. + 3. **Pre-commit hook** — `.githooks/pre-commit` runs the same checker against + the *staged* `SKILL.md` blobs (root + Grok, block *and* single-line forms). + Tracked hooks aren't auto-honoured; this host is already activated + (`git config core.hooksPath .githooks`), a fresh clone needs that once. + Convenience, not the gate. + + Run the checker over everything by hand exactly as CI does: + ```sh + find . -name SKILL.md -not -path './.git/*' -print0 \ + | xargs -0 python3 .githooks/check-description-length.py + ``` +- **`microsoft-rust-guidelines` is intentionally `user-invocable: false`.** It is + the mandatory auto-load Rust base — `spacecraft-standard-constitution` mandates loading it + before any Rust, `spacecraft-rust-guidelines` defers to it as "load first," and + `gnu-coding-standards` / `spacecraft-cli-standard` / `spacecraft-agentic-cli` + chain to it. It fires automatically from its own description and those chains, + so it's hidden from the `/` menu on purpose (Claude Code docs: "background + knowledge users shouldn't invoke directly"). Do **not** remove the field to + "fix" a perceived load failure — its absence from the menu is by design. - **Rebuild BOTH bundles after any skill-dir edit**, in the same commit: `.zip` (`zip -qr`, keeps dir entries) and `.skill` (`zip -qrD`, drops them). A bundle that lags its `SKILL.md`/`references/` ships broken @@ -37,9 +420,42 @@ rules that bite. (A maintainer-local `CLAUDE.md` overlay adds host-specific note the maintainer's call**, and an agent never merges its own PR. `construct skill ship` implements this end-to-end — branch, signed commit, push, `gh pr create` — and never pushes to the default branch. -- **Keep the README §2 catalogue row in sync** when adding, removing, or - re-scoping a skill. +- **README §2 catalogue is load-bearing.** When adding a skill directory, add a + matching alphabetical row to the table in `README.md`. When removing one, + delete the row. +- **Dates are ISO 8601 UTC** anywhere they appear in SKILL.md, references, or + changelogs (Standard §12). No AM/PM, no local-time strings. +- **Don't import skill content into a memory file or a context file.** The + skills are the source of truth and are already loaded on demand. +- `Chat.txt` / `Chat2.txt` / `Chat3.txt` are session exports and are gitignored + (`Chat*.txt`) — never commit them. +- `Excluded/` is the holding pen for inputs that produce skill content but must + not ship with it. Don't reference it from inside any `SKILL.md`. +- **This file is the single agent-facing source of truth** (Standard §5.7). + There is no second copy to keep in sync: `CLAUDE.md` imports it, and the full + procedure lives in [`CONTRIBUTING.md`](CONTRIBUTING.md). +- **REUSE compliance** (`LICENSES/` + `REUSE.toml`) applies repo-wide per + Standard §4.3 — every shipped file needs SPDX tags or `REUSE.toml` coverage. + `reuse lint` should pass before pushing if you touched licensing metadata. + +## Installation (what consumers do) + +```sh +git clone git@github.com:Spacecraft-Software/Construct.git ~/.claude/skills +git clone git@github.com:Spacecraft-Software/Construct.git ~/.gemini/skills +git clone git@github.com:Spacecraft-Software/Construct.git ~/.codex/skills +git clone git@github.com:Spacecraft-Software/Construct.git ~/.grok/skills +``` + +Or, via Nix flake: + +```nix +inputs.construct.url = "github:Spacecraft-Software/Construct"; +# then in HM modules: +construct.homeManagerModules.default +{ spacecraft.construct.enable = true; spacecraft.construct.enableGrok = true; } +``` + +`nix flake update construct` in the consumer flake bumps to the latest commit. -See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the bundling commands, the drift -sweep, and the branch/PR procedure. The maintainer-local `CLAUDE.md` adds the -Home Manager local fan-out (host-specific). +The SSH remote is configured for [Gitway](https://github.com/Spacecraft-Software/Gitway). diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..5663924 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,14 @@ +# CLAUDE.md + +@AGENTS.md + +> Record project knowledge in `AGENTS.md`, not here. This file holds only +> Claude-Code-only context (Standard §5.7). + +## Claude Code specifics + +- `microsoft-rust-guidelines` is `user-invocable: false` on purpose — it is the + mandatory auto-load Rust base and is hidden from the `/` menu by design. See + the editing rules in `AGENTS.md`; do not "fix" its absence from the menu. +- Skills reach Claude at `~/.claude/skills/`, one of the per-harness paths + Home Manager provisions (see "Local agent fan-out" in `AGENTS.md`). diff --git a/construct-cli/AGENTS.md b/construct-cli/AGENTS.md index 112e2ed..87554b0 100644 --- a/construct-cli/AGENTS.md +++ b/construct-cli/AGENTS.md @@ -1,9 +1,10 @@ -# construct — AI Coding-Agent Context +# AGENTS.md — construct `construct` is the Spacecraft Software **Construct** skills package manager (Rust CLI + TUI) — the first executable in the Construct catalogue repository. It conforms to the Spacecraft Software Dual-Mode Self-Documenting CLI Standard -(v1.0.0). This file and `CLAUDE.md` are peers; keep them identical. +(v1.0.0). This is the authoritative agent context file (Standard §5.7); `CLAUDE.md` +imports it and adds only Claude-Code-only notes. ## Build / test / lint diff --git a/construct-cli/CLAUDE.md b/construct-cli/CLAUDE.md new file mode 100644 index 0000000..2e3a3b9 --- /dev/null +++ b/construct-cli/CLAUDE.md @@ -0,0 +1,6 @@ +# CLAUDE.md + +@AGENTS.md + +> Record project knowledge in `AGENTS.md`, not here. This file holds only +> Claude-Code-only context (Standard §5.7). diff --git a/spacecraft-agentic-cli/SKILL.md b/spacecraft-agentic-cli/SKILL.md index 89b74f5..8d06177 100644 --- a/spacecraft-agentic-cli/SKILL.md +++ b/spacecraft-agentic-cli/SKILL.md @@ -82,8 +82,8 @@ repository root, on day one, before business logic: | File | Primary consumer | Contents | |------|------------------|----------| -| `AGENTS.md` | Generic agents (Codex CLI, Cursor, Aider, OpenCode) | Coding conventions, test/build commands, forbidden patterns, repository invariants | -| `CLAUDE.md` | Claude Code agent | Same as AGENTS.md, plus Claude Code–specific context (skills referenced, MCP servers expected, tool preferences) | +| `AGENTS.md` | **Every** agent (Codex CLI, Cursor, Aider, OpenCode, and Claude Code via the import) | **Authoritative.** Coding conventions, test/build commands, forbidden patterns, repository invariants | +| `CLAUDE.md` | Claude Code agent | An `@AGENTS.md` import plus Claude-only context (skills, `.claude/`, slash commands, MCP client) — never a restatement of AGENTS.md | | `SKILL.md` | Spacecraft Software Skills + CLI-Anything + `gws` | YAML frontmatter (name, description, license) + capability surface for the CLI itself | | `CONTRIBUTING.md` | Human contributors | Onboarding, dev environment setup, PR conventions | @@ -97,6 +97,15 @@ Drop-in templates live in `assets/agents-md.template.md` and `assets/claude-md.template.md`. Never copy them blindly — each file must be specialized for the project. +**Standard §5.7 is binding here.** `AGENTS.md` is the single source of +truth and every project must ship one; `CLAUDE.md` is an `@AGENTS.md` +import plus Claude-only content and must not restate it. Both are tracked +— a gitignored `AGENTS.md` makes the import dangle on a fresh clone — and +neither carries credentials, private hostnames, or personal filesystem +paths. Tooling that renders managed blocks into context files targets +`AGENTS.md` only. A "keep these two files in sync" instruction is not a +solution to drift; it is evidence the split is wrong. + **No-clobber: read before you write.** Scaffolding these files is the one durable change this skill triggers on the user's own machine, and a repo often already has an `AGENTS.md` or `CLAUDE.md` with real project context. **Read any diff --git a/spacecraft-agentic-cli/assets/agents-md.template.md b/spacecraft-agentic-cli/assets/agents-md.template.md index 76b9e3a..0b4c7c5 100644 --- a/spacecraft-agentic-cli/assets/agents-md.template.md +++ b/spacecraft-agentic-cli/assets/agents-md.template.md @@ -1,9 +1,18 @@ # AGENTS.md — - - - -## Project identity - - - -## Build, test, lint - - - -## Architectural invariants - - + Do NOT copy, symlink, summarize, or mirror AGENTS.md here. If you find + yourself writing "keep these two files in sync," the split is wrong. -## Forbidden patterns - - + Do NOT duplicate the CLI Standard here either — those rules live in the + spacecraft-cli-standard and spacecraft-agentic-cli skills. -## Environment expectations + CLAUDE.md is REQUIRED even when it holds nothing else. Claude Code reads + CLAUDE.md, not AGENTS.md — a project with only an AGENTS.md gives a + Claude session no project context at all. With nothing Claude-only to + say, the heading + @AGENTS.md + the blockquote is the whole file. - + Both AGENTS.md and CLAUDE.md are tracked. Neither may be gitignored, and + neither carries credentials, private hostnames, or personal filesystem + paths. +--> -## Where to look for ___ +@AGENTS.md - +> Record project knowledge in `AGENTS.md`, not here. This file holds only +> Claude-Code-only context (skills, `.claude/`, slash commands, MCP client). - + -## Skills referenced +## Skills to load -The following Spacecraft Software skills apply to this project. Claude should -consult them when their triggers match: +The following Spacecraft Software skills apply to this project. Consult them +via the Skill tool when their triggers match: - `spacecraft-standard-constitution` — master Steelbore Standard - `spacecraft-cli-standard` — structural CLI Standard rules - `spacecraft-agentic-cli` — agent-facing UX for the CLI -- `spacecraft-brand-guidelines` — Steelbore 2 color palette (values from `steelbore-color-palette`) +- `spacecraft-brand-guidelines` — brand look-and-feel +- `steelbore-color-palette` — canonical palette values (§11) - `microsoft-rust-guidelines` — Microsoft Pragmatic Rust Guidelines - `spacecraft-cli-preference` — preferred external CLI tools (rg, fd, bat) - `spacecraft-cli-shell` — shell syntax for generated commands @@ -56,29 +49,19 @@ consult them when their triggers match: ## MCP servers expected -This project may coexist with the following MCP servers in agent -sessions: - - ` mcp` — this project's own MCP surface (when implemented) - -## Tool preferences - -- Use `rg` over `grep`, `fd` over `find`, `bat` over `cat` (per - spacecraft-cli-preference). -- Use `cargo nextest` over `cargo test` if available; fall back if not. -- Use `jaq` over `jq` for JSON filtering. -- +## Claude Code specifics -## Notes for Claude specifically - -- Inline TODOs use `// TODO(claude):` to distinguish from human TODOs. -- Commit messages use the format `(): ` with - conventional-commits types. +- - -## Standards compliance - -This project follows the Spacecraft Software Dual-Mode Self-Documenting CLI Standard (v1.0.0). The CLI Standard skills -are authoritative on structural and agentic conventions. This file -documents project-specific deviations and supplements only. + diff --git a/spacecraft-agentic-cli/references/agents-md-authoring.md b/spacecraft-agentic-cli/references/agents-md-authoring.md index be758c1..3e0cdc2 100644 --- a/spacecraft-agentic-cli/references/agents-md-authoring.md +++ b/spacecraft-agentic-cli/references/agents-md-authoring.md @@ -25,8 +25,8 @@ does NOT belong, and provides anti-pattern catalogs. | File | Reader | Lifetime | Authoritative on | |------|--------|----------|------------------| -| `AGENTS.md` | Generic agents (Codex CLI, Cursor, Aider, OpenCode, Goose) | Loaded each session | Coding conventions, build/test commands, project invariants | -| `CLAUDE.md` | Claude Code | Loaded each session | Same as AGENTS.md, plus Claude-specific tool/skill/MCP context | +| `AGENTS.md` | **Every** agent, Claude included (via the import below) | Loaded each session | **Authoritative.** Coding conventions, build/test commands, project invariants | +| `CLAUDE.md` | Claude Code | Loaded each session | An `@AGENTS.md` import plus Claude-only tool/skill/MCP context — nothing else | | `SKILL.md` | Spacecraft Software Skills, CLI-Anything, `gws`-style skill systems | Loaded by skill loader | The CLI's own capability surface and triggering description | | `CONTRIBUTING.md` | Human contributors | Read once during onboarding | Dev environment setup, PR conventions | @@ -123,13 +123,29 @@ Cargo workspace. It targets POSIX shell environments first and PowerShell ## §3 — CLAUDE.md: how it differs from AGENTS.md -CLAUDE.md MUST be a strict superset of AGENTS.md. Start by symlinking or -copying AGENTS.md, then add Claude-specific sections: +**Standard §5.7 governs this file.** CLAUDE.md is an `@AGENTS.md` import +plus Claude-only content — it MUST NOT restate, summarize, or mirror +AGENTS.md. Copying or symlinking AGENTS.md into it is non-compliant: the +two copies are edited in different sessions, drift, and the agent reading +the stale one is never told it is stale. + +> **This rule was inverted at Standard v1.46.** Earlier revisions of this +> reference told authors to make CLAUDE.md a strict superset by symlinking +> or copying. That produced duplication by construction. If you find a +> project still arranged that way, or a file carrying a "keep these two in +> sync" instruction, that instruction is the bug — fold the content into +> AGENTS.md and reduce CLAUDE.md to the shape below. + +Anything that is true of the *project* goes in AGENTS.md. Only what a +non-Claude harness cannot act on belongs here: ```markdown # CLAUDE.md — - +@AGENTS.md + +> Record project knowledge in `AGENTS.md`, not here. This file holds +> only Claude-Code-only context. ## Skills referenced - `spacecraft-standard-constitution` — master Standard @@ -158,6 +174,27 @@ The Claude-specific sections matter because Claude Code has features Mentioning them in AGENTS.md would mislead a Codex CLI session into expecting capabilities it doesn't have. +**The test for where a fact belongs:** would a Codex CLI or Cursor session +be worse off without it? If yes, it goes in AGENTS.md. `CLAUDECODE=1` is +the classic false positive — a CLI that detects it alongside `CURSOR_AGENT` +and `GEMINI_CLI` is documenting its own product behavior, which every +harness needs to know, so it belongs in AGENTS.md. + +**CLAUDE.md is mandatory, even when it holds nothing else.** Claude Code +reads `CLAUDE.md`, not `AGENTS.md` — a project with only an AGENTS.md +gives a Claude session *no* project context at all. When there is nothing +Claude-only to say, the file is still four lines: the heading, the +`@AGENTS.md` import, and the blockquote. + +Both files are tracked (§5.7). Neither may be gitignored: an ignored +AGENTS.md makes the import dangle on a fresh clone. Because they are +published artifacts, keep credentials, private hostnames, and personal +filesystem paths out of both — and review a previously-ignored context +file for sensitive content *before* un-ignoring it. + +Tooling that renders managed blocks into context files (rule +synchronizers, task systems) targets AGENTS.md only. + --- ## §4 — SKILL.md: the CLI's own skill manifest @@ -295,7 +332,7 @@ are inline in `#[cfg(test)] mod tests {}` blocks." | File | Target length | Hard cap | |------|---------------|----------| | AGENTS.md | 80–200 lines | 400 lines | -| CLAUDE.md | 100–250 lines | 500 lines | +| CLAUDE.md | 5–40 lines | 80 lines | | SKILL.md | 50–150 lines | 300 lines | | CONTRIBUTING.md | (no agent-loaded budget) | — | diff --git a/spacecraft-standard-constitution/SKILL.md b/spacecraft-standard-constitution/SKILL.md index 1f112f7..6e8ada0 100644 --- a/spacecraft-standard-constitution/SKILL.md +++ b/spacecraft-standard-constitution/SKILL.md @@ -8,7 +8,7 @@ description: > Spacecraft Software-umbrella project — even if the user doesn't explicitly mention the Standard. If the user mentions "Spacecraft Software", a Spacecraft Software subproject name, or asks you to work on anything in the Spacecraft Software ecosystem, consult this skill immediately. It encodes - The Steelbore Standard v1.45 (§13 design systems; §3.1.1 TypeScript over JS; §6.4 contribution targets; §5.6 skill packaging; §11 palettes + §11.6 system theme; §18 accessibility; §17 progress reporting; §3.2 compiler flags; concurrency; §3.3 security-by-design) so + The Steelbore Standard v1.46 (§13 design systems; §3.1.1 TypeScript; §5.7 AGENTS.md; §6.4 contribution targets; §5.6 skill packaging; §11 palettes + §11.6 system theme; §18 accessibility; §17 progress reporting; §3.2 compiler flags; concurrency; §3.3 security-by-design) so you never need to ask for it or have it attached to a prompt again. license: GPL-3.0-or-later maintainer: Mohamed Hammad @@ -17,7 +17,7 @@ website: https://Construct.SpacecraftSoftware.org/ # The Steelbore Standard — Compliance Reference -**Version:** 1.45 | **Date:** 2026-08-06 | **Author:** Mohamed Hammad +**Version:** 1.46 | **Date:** 2026-08-08 | **Author:** Mohamed Hammad **Maintainer:** Mohamed Hammad | **Contact:** [Mohamed.Hammad@SpacecraftSoftware.org](mailto:Mohamed.Hammad@SpacecraftSoftware.org) **Copyright:** Copyright (C) 2026 Mohamed Hammad & Spacecraft Software | **License:** GPL-3.0-or-later **Website:** [https://Construct.SpacecraftSoftware.org/](https://Construct.SpacecraftSoftware.org/) @@ -451,6 +451,61 @@ limits are therefore enforced **before packing**, not after a failure. | Machine-enforced | The cap MUST be checked by an automated gate that runs both in the skill repository's CI on every pull request and push to the default branch, and in whatever command produces the distributable bundle. A developer-installed git hook is a convenience, never the gate — hooks are opt-in per clone and cannot be relied on. | | Over-limit skills do not ship | A skill whose description exceeds the cap MUST NOT be packed, committed, or published. Trim the description; do not raise the cap. | +### §5.7 — Agent Context Files + +Coding agents load a project's root context file into their window at the start +of every session. Different harnesses read different filenames — `AGENTS.md` is +the cross-vendor convention (Codex CLI, Cursor, Aider, OpenCode, Goose, Gemini +CLI), while Claude Code reads `CLAUDE.md`. Maintaining both as parallel prose +guarantees drift: the two copies are edited in different sessions, diverge, and +the agent that reads the stale one is misinformed. This section fixes a single +source of truth. + +**`AGENTS.md` is the authority.** Every project **must** ship an `AGENTS.md` at +its root, in addition to the §5.2 posture files. It is harness-neutral: it +carries the project's build, test, and lint commands, architectural invariants, +forbidden patterns, repository layout, and any fact an agent cannot infer from +the code itself. + +**`CLAUDE.md` is a thin overlay, and is also required.** Claude Code reads +`CLAUDE.md` and does *not* read `AGENTS.md`, so a project shipping only an +`AGENTS.md` gives a Claude session no project context at all. The file **must** +consist of an `@AGENTS.md` import followed only by content that is meaningless +to a non-Claude harness — Skill-tool invocations, `.claude/` paths, Claude Code +slash commands, and Claude-client MCP configuration. It **must not** restate, +summarize, or mirror `AGENTS.md`. Where there is nothing Claude-only to say, the +import and its note are the whole file: + +```markdown +# CLAUDE.md + +@AGENTS.md + +> Record project knowledge in `AGENTS.md`, not here. This file holds +> only Claude-Code-only context. +``` + +**Mandatory rules:** + +| Rule | Detail | +|------|--------| +| Write to `AGENTS.md` | New project knowledge — a build command, an invariant, a gotcha — MUST be written to `AGENTS.md`. An agent or maintainer adds to `CLAUDE.md` only when the fact is meaningless to a harness that is not Claude Code. "Update the context file" always means `AGENTS.md`. | +| No duplication | A rule stated in `AGENTS.md` MUST NOT be restated in `CLAUDE.md`. Instructions of the form "keep these two files in sync" are evidence the split is wrong and MUST be removed rather than honored. | +| Both tracked | Both files are version-controlled artifacts, not agent-local scratch, and both are required. A `.gitignore` entry for either one breaks the `@AGENTS.md` import on a fresh clone and hides project knowledge from every contributor who did not author it. | +| No secrets | Because they are tracked and published, context files are subject to the same hygiene as any other repository file: no credentials, tokens, keys, private hostnames or network topology, or personal filesystem paths. A context file that was previously ignored MUST be reviewed for sensitive content **before** it is un-ignored. | +| Generated blocks | Tooling that renders managed regions into context files (rule synchronizers, task systems) MUST target `AGENTS.md` only. Writing the same block into both files reintroduces the duplication the import exists to remove. | + +A relative import resolves against the file containing it, never against the +working directory, so each project's `CLAUDE.md` reaches its own `AGENTS.md`. +Claude Code walks up the directory tree and concatenates every `CLAUDE.md` it +finds, so a project nested under another inherits the ancestor's context in +addition to its own — which is why an ancestor file must not restate what a +child already says. + +Other harness-specific files (`GEMINI.md`, `.cursorrules`, and similar) follow +the `CLAUDE.md` pattern: import or reference `AGENTS.md`, then add only what is +specific to that harness. + --- ## §6 — Platform & Systems Requirements @@ -1653,6 +1708,7 @@ Before finalising **any** Spacecraft Software artifact, mentally verify: - [ ] **§5** Project Posture: README/NOTICE/CONTRIBUTING present; default personal-hobby stance applied; general-use carve-outs declared in project README - [ ] **§5.5** Package distribution: `packaging/guix.scm`, `packaging/default.nix`, and `packaging/PKGBUILD` present, buildable, and carrying correct version + SHA-256 checksum (in each package manager's native format) before any release tag is pushed - [ ] **§5.6** Skill packaging: every `SKILL.md` `description` measures ≤ 1000 rendered characters (folded scalars counted as the loader sees them, not as raw lines); the cap is enforced by CI *and* by the command that produces the bundle, not only by a local git hook — N/A for projects that ship no skills +- [ ] **§5.7** Agent context files: `AGENTS.md` and `CLAUDE.md` both present at the repository root and version-controlled; `CLAUDE.md` is an `@AGENTS.md` import plus Claude-only content and restates nothing; neither file is gitignored; no credentials, private hostnames, or personal filesystem paths in either; managed blocks rendered into `AGENTS.md` only - [ ] **§6.1** POSIX-compliant CLI/system tools - [ ] **§7** Shell scripts are POSIX-compatible; Nushell/Ion native variants provided where shell-native idioms are required; no Bashisms in shared scripts - [ ] **§8** Texinfo manual present for user-facing programs (`doc/.texi`); builds to `.info`, `.html`, and `.pdf`; `install-info` hook present in all three package manifests (§5.5) — N/A for scripts and internal tooling @@ -1689,6 +1745,7 @@ for a pure Rust library), note it as N/A rather than silently skipping it. | Creating IDE / terminal themes | `spacecraft-theme-factory` | | Resolving or declaring the system theme (§11.6) | `steelbore-color-palette` | | Implementing or auditing accessibility (§18) | `spacecraft-accessibility-support` | +| Authoring `AGENTS.md` / `CLAUDE.md` (§5.7) | `spacecraft-agentic-cli` | | All other Spacecraft Software work | `spacecraft-standard-constitution` | --- diff --git a/spacecraft-standard-constitution/references/CHANGELOG.md b/spacecraft-standard-constitution/references/CHANGELOG.md index 6ad5113..12dcc78 100644 --- a/spacecraft-standard-constitution/references/CHANGELOG.md +++ b/spacecraft-standard-constitution/references/CHANGELOG.md @@ -12,6 +12,7 @@ activation. The canonical record is the published Standard's own `standard/CHANGELOG.md` (extracted from §1 of the document itself in v1.37); this file mirrors it and must be synced to the same version and date. +- **v1.46 (2026-08-08):** **§5.7 added — Agent Context Files.** §5.2 has enumerated the required root files since the standard's early versions and never named the one file every coding agent actually reads. That silence was not neutral: in its absence each project invented its own arrangement, and a survey of the umbrella found five incompatible conventions running simultaneously across ~39 repositories — byte-identical twins, a symlink, a declared superset, a thin pointer in one direction, and genuinely divergent files each holding facts the other lacked. The failure mode is specific and silent. `AGENTS.md` is the cross-vendor convention (Codex CLI, Cursor, Aider, OpenCode, Goose); Claude Code reads `CLAUDE.md`. When both exist as parallel prose they are edited in different sessions and drift, and **the agent reading the stale copy is never told it is stale** — it proceeds confidently on a build command that changed six weeks ago. Several files had already noticed and responded with the wrong remedy, carrying explicit "whenever you update CLAUDE.md, update AGENTS.md in the same pass" instructions: a maintenance tax paid manually, forever, that the drift proves was not being paid. §5.7 makes **`AGENTS.md` the single authority** — required at every project root alongside the §5.2 files, harness-neutral, carrying build/test/lint commands, architectural invariants, forbidden patterns, layout, and every fact an agent cannot infer from the code. `CLAUDE.md`, where a project ships one, becomes an **`@AGENTS.md` import plus only what is meaningless to a non-Claude harness** — Skill-tool invocations, `.claude/` paths, slash commands, Claude-client MCP configuration — and MUST NOT restate, summarize, or mirror it. Five rules attach. **Write to `AGENTS.md`**: new project knowledge goes there by default, and "update the context file" always means `AGENTS.md`; this is the rule that keeps the overlay from re-growing into a second copy one session at a time. **No duplication**, with the corollary that a "keep these in sync" instruction is evidence the split is wrong and MUST be removed rather than honored. **Both tracked** — a `.gitignore` entry for either breaks the `@AGENTS.md` import on a fresh clone and hides project knowledge from every contributor who did not author it; 15 of the surveyed repositories were ignoring one or both. **No secrets**, which is the clause that makes the tracking rule safe rather than merely tidy: context files become published artifacts, so credentials, tokens, keys, private hostnames or network topology, and personal filesystem paths are out, and a file that was previously ignored MUST be reviewed for sensitive content *before* it is un-ignored — a file that was safe as a local scratchpad has not thereby been cleared for publication, and un-ignoring is effectively irreversible once pushed. **Generated blocks target `AGENTS.md` only**: tooling that renders managed regions into context files — rule synchronizers, task systems — reintroduces exactly the duplication the import removes if it writes both, so the obligation is placed on the tooling rather than left for a human to notice. Other harness files (`GEMINI.md`, `.cursorrules`) follow the `CLAUDE.md` pattern rather than earning clauses of their own. This section **inverts the guidance previously carried only in the `spacecraft-agentic-cli` skill**, which instructed authors to make `CLAUDE.md` a strict superset of `AGENTS.md` and to start by symlinking or copying it — a rule that produced the duplication by construction and that every new scaffold reproduced; that skill's `references/agents-md-authoring.md` §1 and §3 and both `assets/` templates are rewritten to match in the same pass. The Skill Cross-References table gains a `spacecraft-agentic-cli` row for context-file authoring, which had never appeared there despite the skill being the implementation layer for it. §16 gains a §5.7 checklist bullet. Nothing in §5.2 changes: `AGENTS.md` is added to the required set, and no existing required file is relaxed or removed. This skill's own frontmatter `description` measures 988 characters under the §5.6 cap (the §3.1.1 highlight shortened to "§3.1.1 TypeScript" to make room for §5.7). - **v1.45 (2026-08-06):** **§11.6 added — System Theme Declaration & Resolution.** §11 has been a palette *family* since v1.35 and §11.1 has required every palette reference to go through a named theme since v1.34, yet nothing said what an application does when the *machine* has an opinion. The gap was invisible from both ends: §11.1 answers "how do I reference a color", §11.4 answers "which palette is mine", and neither question is "which member of the family renders on this system, right now" — so an application could satisfy every clause in §11 while shipping one hard-wired theme, deaf to the desktop it runs on. Steelbore OS has had a theme declaration for months (Bravais's `theme.nix` is a single word that re-themes every terminal, both bars, the TTY and greetd), which made the omission look like it did not exist; it ends at a rebuild, because that machinery resolves at build time and exports per-role hex but never the slug, so a *running* application can see individual colors and still not learn which theme is active. **Applications register the family, not a theme.** §11.6.1 separates two obligations §11.4 had conflated: a project *authors* against one palette and *registers* thirteen — the six conforming palettes (`steelbore`, `steelbore-blue`, `steelbore-blackpinkpanther`, `steelbore-matrixgreen`, `steelbore-navywhite`, `tokyonight`), each with its `-high-contrast` sibling, plus `steelbore-mono`. Three were already required by §11.4 and §11.1.1, so this adds ten, all already written out in `steelbore.toml`; every one binds the same eleven role tokens, so a theme layer that reads that file registers them in a loop. `steelbore-classic` is deliberately **not** in the mandatory set: it keeps the legacy six-role contract (§11.2), defines no surface class, and carries an `info` token that is not one of §11.1's eleven roles at all. **Resolution is two-stage, and that is the load-bearing decision.** Stage 1 picks a base palette from five sources — in-app selection, `SPACECRAFT_THEME`, the system declaration, the platform's light/dark preference, then the project's §11.4 default. Stage 2 picks a *variant of that palette* — a pinned `-high-contrast`/`-mono` slug, then `NO_COLOR` ⇒ `steelbore-mono`, then §18.1 accessible mode, then the platform's high-contrast preference under §18.3's existing precedent. Keeping the stages apart is what makes the section composable: an accessibility signal chooses a *sibling*, never a palette, so it can never silently change the brand — exactly the promise §11.1.1 has made since v1.33. §18.1's four-source precedence is consumed, not restated and not modified. An unknown or unregistered slug **falls through and is never fatal**, so a typo in `/etc` cannot leave a machine without a working interface (§3.1), and the resolved theme plus the deciding source are reported under `--verbose`. **Light and dark needed §11.4 read precisely.** `steelbore-navywhite` is the family's only light-canvas member, so a platform light preference can only be answered by rendering a different palette. §11.6.2 states that §11.4 forbids *combining* tokens from two palettes and that a switch combines nothing: the entire token set is replaced at once, the new canvas comes with it unaltered, and no frame ever carries a token from two palettes. **Switching is compliant; mixing remains forbidden** — the switch must be atomic and whole-surface (an application that cannot re-theme atomically resolves once at startup and holds), and the canvas travels with the palette. The family pair is `steelbore` ⇄ `steelbore-navywhite`; a project may declare its own or declare `light = none` with a stated reason on the §14.2.1 footing, which buys it nothing under §18. Solarized Dark and Light are a natural pair upstream and §11.5 bars both from adoption, so neither is ever a source-4 target. **The declaration is a file, deliberately** — `/etc/steelbore/theme.toml`, overridden per user by `$XDG_CONFIG_HOME/steelbore/theme.toml`, carrying `active` (required), an optional `light`/`dark` pair, `follow-color-scheme`, and `high-contrast`. A file, not a bus: the contract has to work for a CLI in a text console, where there is no session bus, no portal, and no portable way to ask the terminal what color its background is — which is why the platform color-scheme source is graphical-only. Absence of the file is *no declaration*; a file saying `active = "steelbore"` is a declaration *of Modern*, and the distinction matters because a system may need to pin Modern rather than inherit whatever the default later becomes. **The declaration carries slugs and never colors** — the same division §13 draws for component systems; an OS-installed registry is advisory and the application's own `steelbore.toml` governs, so per-role color environment variables are explicitly *not* a Standard interface. The variable is **`SPACECRAFT_THEME`**, in the `SPACECRAFT_` namespace §18.1 established with `SPACECRAFT_A11Y`; `STEELBORE_THEME` is named as **not** a Standard interface, because it is already a boolean shell flag and giving it slug semantics would make `STEELBORE_THEME=true` resolve to a nonexistent theme and fall through in silence. **§11.6.5** puts the symmetrical obligation on Steelbore OS in every flavor: render the declaration from its own selection rather than maintain it by hand, export the slug so it reaches graphical sessions and system services rather than login shells alone, keep the platform color-scheme preference in agreement with the declared polarity, and validate the slug at evaluation time so an unknown theme fails the build rather than the boot. **Scope is both §6.4 namespaces** and all three interface classes: a CLI is not exempt, because it already honors `NO_COLOR` and already emits ANSI. Artifacts with no user-facing output record §11.6 as N/A. Registered games are **not** exempt — §18.5 carves out §18 and §10, never §11 — but a game satisfies it in its menus, HUD and settings chrome, not in the world it simulates. Three things are unchanged: **`steelbore` is still the sole default** (§11.6 changes what an application *can* render, never what it renders when nothing is declared); **§11.4's mixing prohibition is unchanged** and is now precise enough to be enforceable; and **§18 is unchanged** — a declaration's `high-contrast` key selects a theme sibling and is explicitly barred from being read as enabling accessible mode. §11.4 gains two bullets and three amended ones; §16 gains a §11.6 bullet rather than lengthening the §11 one; the Skill Cross-References table gains a `steelbore-color-palette` row, closing a smaller gap — the skill has been the normatively cited canonical source in §11.4 since v1.39 and had never appeared in the table that tells a reader which skill to load. Recorded as a factual correction in the same entry: the §11 chapter-head palette-family table listed six slugs where `[meta] palette-family` and §11.4.1 both list seven — **`tokyonight` was missing** from the one table a reader consults first. It is added, and the table gains a canvas-polarity column, which §11.6.2 makes normative content. `assets/steelbore.toml` → v3.2.0: `[meta]` gains `default-dark-theme`, `default-light-theme`, `mono-theme`, and `registered-set` (the §11.6.1 thirteen), plus new `[resolution]`, `[resolution.polarity]`, and `[resolution.pair]` tables — slugs only, no color value, with every polarity value verified against the WCAG relative luminance of its own canvas. `spacecraft-theme-factory` now emits the registered set rather than one palette and its variants; `spacecraft-accessibility-support` gains the §11.6.3 stage-2 composition rules. This skill's own frontmatter `description` measures 980 characters under the §5.6 cap (the §11.5 fidelity highlight rotated out to make room for §11.6). - **v1.44 (2026-08-05):** **The published Standard's cross-reference table named a skill that does not exist.** Its accessibility row pointed at `spacecraft-accessibility`; the skill has been `spacecraft-accessibility-support` since it was added. **This skill's own table has always been correct**, so the drift was one-directional and only the published document needed fixing — but the failure mode it created was silent: a missing skill does not announce itself, it simply never loads, so §18 work directed by the Standard would have proceeded without its implementation layer. Corrected upstream; every other skill name the Standard cites was verified against the catalogue in the same pass, and this was the only bad one. A cross-reference is normative content like any other clause, and renaming a skill is a two-repo edit. Only the masthead and frontmatter version move here — no rule changes and no section text was touched. - **v1.43 (2026-08-05):** **§3.2.1 published to the Standard — no change to this skill's rules.** §3.2.1 (Platform-Specific Compiler & Linker Flag Caveats) has been in this skill for some time and was **never in the published document**: no version carried it, and neither changelog recorded it. It entered here during a rename commit rather than a normative one, so the bump-and-record step was skipped, and the gap was invisible from both sides — this skill looked complete, and the Standard had nothing to be missing. A section-by-section comparison of the `.texi` against this file surfaced it as the single structural difference across 88 sections. **The rule itself is unchanged and its text here is untouched** — agents loading this skill have been applying §3.2.1 all along; what changed is that the document that is supposed to be normative now contains it. For the record, the section holds that compiler and linker optimization flags are **not universally portable** across operating systems and distributions (systemd-specific settings do not apply to GNU Guix System, Void Linux, or Gentoo with OpenRC; linker and LTO flags likewise track the target's toolchain layout), with **NixOS / Steelbore OS Bravais** as the concrete case: `/nix/store` isolation keeps GCC's LTO plugin off the standard linker search path, so `-flto` **must** be paired with `-fuse-ld=mold` (preferred) or `-fuse-ld=bfd` (fallback) or the build fails to link — generalizing to a requirement that any use of `-flto`, `-march=native`, or PGO be checked against the target OS and the OS-specific requirement documented alongside the flag. It is the platform-specific companion to §3.2: §3.2 says record the flag state, §3.2.1 says the correct state is not the same everywhere. §16 gains no bullet, because its §3.2 item already requires flags to be "applied/disabled with explicit notation." Only the masthead and frontmatter version move here; this skill's `description` measures 976 characters under the §5.6 cap.