diff --git a/docs/workpad/designs/spire-project-override-and-init.md b/docs/workpad/designs/spire-project-override-and-init.md new file mode 100644 index 0000000..6a1e917 --- /dev/null +++ b/docs/workpad/designs/spire-project-override-and-init.md @@ -0,0 +1,99 @@ +# 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