# Design: Spire project override + spire:init **Date**: 2026-09-17 **Covers**: Findings 1 (no spire:init), 2 (project.md cannot be overridden), 3 (adept scaffolding not shipped) **Source research**: `research/2026-09-17-project-md-override-mechanics.md` **Goal**: `goals/igor-project-adoption.md` ## The problem Igor and Athanor hard-bind `references/project.md` via `@` directives that resolve into the plugin cache. Every project gets the blank template. There is no init, no override, and no adept scaffolding — three gaps that compound into "every session rediscovers the project from scratch." ## Solution: three new pieces ### 1. `spire:project` skill (the injection vehicle) A tiny skill whose only job is loading the right `project.md` at skill-load time via shell injection: ```markdown --- name: project description: Loads per-project Spire configuration (override or bundled template). allowed-tools: Bash(cat:*) --- !`cat "${CLAUDE_PROJECT_DIR}/.claude/spire/project.md" 2>/dev/null || cat "${CLAUDE_SKILL_DIR}/../igor/references/project.md"` ``` **Igor** (`agents/igor.md`) and **Athanor** (`agents/athanor.md`) add `spire:project` to their `skills:` list and drop their `@` imports. The skill loads at agent startup — same timing as today's `@`, but with fallback. Runtime belt: Igor's skill text keeps a one-line instruction — "if the project block is the blank template, try reading `.claude/spire/project.md` before orienting from scratch" — so it degrades gracefully if `disableSkillShellExecution` is on. ### 2. Shared vs. personal installs `.claude/` is often committed to git. But Spire may be personal — installed via `settings.local.json` or user-level settings — in which case `.claude/spire/` should not leak into the project's history. **The rule**: `spire:init` detects where Spire is enabled: | Spire enabled in | `.claude/spire/` should be | Init action | |---|---|---| | `settings.json` (project-level, committed) | Committed with the project | Write files, commit | | `settings.local.json` or user settings | Gitignored | Write files, add `/spire/` to `.claude/.gitignore`, do not commit | | Not detected / ambiguous | Ask the user | Prompt: "Should the Spire config be shared with the project or personal?" | Detection: check whether `"spire@reliquary"` (or any spire plugin ref) appears in `.claude/settings.json` vs. `.claude/settings.local.json`. If in `settings.json` → shared. If in `settings.local.json` or absent from both → personal/ask. The `.claude/.gitignore` approach (a gitignore inside `.claude/`) keeps the ignore scoped — it only affects `.claude/spire/`, not the rest of `.claude/`. A `project.local.md` sibling can follow later for personal overrides on top of shared config — but that's out of scope for the first pass. ### 3. `spire:init` skill Human-triggered (`disable-model-invocation: true`). Modelled on `tome:init` Phase 2.1. **Phases**: 1. **Detect** — read the project to auto-fill what we can: - Workpad location via the `spire:workpad` resolution chain - Pinned agents from `.claude/agents/*.md` - Verification commands from `Justfile` (recipe names like `check`, `test`, `lint`, `build`), `Makefile`, `package.json` scripts, `Cargo.toml` - Conventions from root `CLAUDE.md` - Tome skill presence (check if a `*-tome:navigate` skill exists or `tome@reliquary` is enabled) 2. **Scaffold** — create the following: - `.claude/spire/project.md` — filled template with `status: generated` front matter (re-init safe: only overwrite while status is `generated`, never clobber `authored`) - `/adepts/_template/CLAUDE.md` — the adept CLAUDE.md template that `agents/adept.md:23,26` references but doesn't ship - `/adepts/` directory (if missing) 3. **Gitignore** (if personal install) — add `spire/` to `.claude/.gitignore` 4. **Alias** (optional) — offer to create `.claude/skills/assistant/SKILL.md` that invokes `spire:igor` as `/assistant`, so the project can use a generic entry point 5. **Commit** (if shared install) — commit the scaffolded files with gitmoji ### 4. Adept template The adept agent (`agents/adept.md`) references `/adepts/_template/CLAUDE.md` and `/adepts/CLAUDE.md` — neither exists. `spire:init` creates both: - `adepts/CLAUDE.md` — root-level orientation for the adepts directory (what it is, how adepts use it) - `adepts/_template/CLAUDE.md` — the default starting CLAUDE.md for a newly spawned adept's domain folder These are `status: generated` and re-init safe. ### 5. Changes to existing files | File | Change | |---|---| | `skills/igor/SKILL.md:32` | Remove `@references/project.md`. Add a one-line runtime fallback instruction. | | `agents/igor.md` | Add `spire:project` to `skills:` list | | `agents/athanor.md:25` | Remove `@skills/igor/references/project.md`. Add `spire:project` to `skills:` list | | `references/project.md` | Add "run `/spire:init`" hint at top. Keep as fallback template. | ### 6. Backward compatibility - No `.claude/spire/project.md` → shell injection falls back to bundled template → same as today - Template gains a hint to run init, turning the dead-end into a prompt - `disableSkillShellExecution` → runtime fallback instruction kicks in - `status: generated` front matter protects hand-edits from re-init