Files
reliquary/docs/workpad/plans/2026-09-18-adept-discovery-plan.md
g4borg 9e6deea36e 📝 Add adept discovery design pipeline artifacts and harness investigation goal
Design, plan, fact-check report, and athanor implementation report for
the adept discovery and tiered knowledge folders feature. Also captures
the harness behavior investigation as an open goal.
2026-09-18 15:56:01 +02:00

223 lines
11 KiB
Markdown

# Plan: Adept discovery and tiered knowledge folders
**Design**: `designs/2026-09-18-adept-discovery.md`
**Date**: 2026-09-18
---
## Decisions
### Q1: Journal relocation — worth the churn?
**Decision: Move journals to `journal/` subfolder.** No existing adept folders exist in this repo, so there is zero churn here. The design's lazy migration path (next adept into a legacy folder does the `git mv`) is sound for other projects. The clean `ls` benefit is real and permanent; the migration cost is one-time and bounded.
### Q2: Doc vocabulary — fixed or free?
**Decision: Suggested vocabulary, free additions, index rule enforces discoverability.** A fixed vocabulary would be over-prescriptive for domains that don't map cleanly to `key-files / conventions / architecture / gotchas`. The index rule ("if it is not listed in CLAUDE.md, it does not exist") is the enforcement mechanism — it makes free naming safe. The `_template/CLAUDE.md` should list the suggested names as comments so a founding adept sees the vocabulary without being constrained by it.
### Q3: `## Adepts` in journal — grepping enough, or add a counter?
**Decision: Grepping is enough.** A counter is exactly the hand-maintained metadata the design principle forbids. The `## Adepts` section in the journal provides a grep-friendly surface (`grep -l 'auth —' journals/`). If someone ever wants counts, a one-liner over journal files derives them.
### Q4: `roster.sh` location — skill folder vs. Justfile recipe
**Decision: Skill folder (`${CLAUDE_SKILL_DIR}/roster.sh`).** This avoids a Justfile dependency that the design otherwise does not introduce. The Justfile in this repo is currently unstaged and minimal. Adding a `just adepts` recipe would couple a plugin-internal concern to the consuming project's build tool. The skill folder is the natural home — `spire:project` already uses the same `${CLAUDE_SKILL_DIR}` mechanism for `cat`.
### Q5: Parallel sessions — acceptable conflict risk?
**Decision: Acceptable for now; document the worktree in `handoff.md`.** The conflict surface is `handoff.md`, which is short and human-resolvable. The adept should record its worktree/branch in `handoff.md`'s frontmatter `branch:` field (already in the design). Rare enough that engineering a lock or merge protocol would be premature.
---
## Implementation Phases
### Phase 1 — New `spire:adepts` skill (the roster)
**Dependencies**: None. Foundational new component.
#### 1.1 Create `plugins/spire/skills/adepts/SKILL.md`
Content per design §D. Frontmatter:
```yaml
---
name: adepts
description: Lists the adept domains in the workpad — what each covers, when it was last active, its status. Loaded by Igor at boot; any agent may invoke it for a fresh listing.
allowed-tools: Bash(bash:*)
---
```
Body: the shell-injection line `` !`bash "${CLAUDE_SKILL_DIR}/roster.sh"` `` followed by the empty-roster comment.
#### 1.2 Create `plugins/spire/skills/adepts/roster.sh`
Implement the script from design §D. Key implementation details:
- Workpad resolution: `WORKPAD_FOLDER` env var → `just workpad-folder 2>/dev/null` → `docs/workpad` → `.workpad`. Also grep `.claude/spire/project.md` for the `Workpad:` line as fallback for the external-tickets-folder case.
- Iterate `"$WP"/adepts/*/`, skip `_template`.
- Parse frontmatter from each domain's `CLAUDE.md` using `sed` (extract lines between opening and closing `---`).
- Derive `newest` and `sessions` from `journal/` filenames (also check the domain root for legacy `YYYY-MM-DD-HH-journal-*` files for backward compatibility with unmigrated folders).
- Output one `- **slug** — summary ...` line per domain.
- Make the script executable (`chmod +x`).
#### Verification
- `bash plugins/spire/skills/adepts/roster.sh` in a repo with no `adepts/` folder produces the "none" fallback line.
- Frontmatter parsing handles values with colons, and files with no frontmatter produce empty output (not errors).
---
### Phase 2 — Update `agents/adept.md` (tiered layout + handoff protocol)
**Dependencies**: None (parallel with Phase 1).
#### 2.1 Rewrite domain folder structure section
Replace current `## Domain folder structure` (lines 62-66) with new layout from design §A (showing `journal/` subfolder, `handoff.md`, knowledge docs).
#### 2.2 Split genesis into founding and successor protocols
Replace current `## Genesis` section (lines 18-31) with two subsections:
- **Successor genesis** (design §E): nine numbered steps — read `adepts/CLAUDE.md`, read domain `CLAUDE.md` (index), read `handoff.md`, run drift check, read Must-read docs, read only named journal entries, verify-and-correct if drift found, write genesis journal, rewrite `handoff.md`.
- **Founding genesis** (design §E): copy `_template/CLAUDE.md` and `_template/handoff.md`, fill frontmatter during orientation, create at minimum `key-files.md`, write `handoff.md` before first consultation with `verified-at` = current HEAD, write genesis journal entry.
#### 2.3 Add handoff.md duties
New section `## Handoff` after genesis: rolling, overwritten, short (≤40 lines). Written early, refreshed after significant consultations. Frontmatter fields: `updated`, `session`, `branch`, `verified-at`. The drift check mechanism.
#### 2.4 Update consultation section
Add after existing point 5: refresh `handoff.md` after state-changing consultations; use `Skill("spire:adepts")` for sibling discovery; update index when adding docs.
#### 2.5 Add index maintenance rules
`CLAUDE.md` stays under ~60 lines. Tiers are conditional (state the condition). Docs split at ~200 lines. Siblings introspected on demand, not preloaded. Every root file must appear in the index.
#### 2.6 Update end-of-life and knowledge tiers
Make "wrap up" concrete (refresh handoff, closing journal). Add four-tier table from design §A.
#### Verification
- No reference to flat `YYYY-MM-DD-HH-journal-<topic>.md` at root level remains.
- Both founding and successor genesis protocols present as distinct subsections.
- `handoff.md` mentioned with overwrite-not-append rule.
---
### Phase 3 — Update `skills/igor/SKILL.md` (roster integration + spawning)
**Dependencies**: Phase 1 (skill must exist to be referenced).
#### 3.1 Rewrite `## Adepts` section
Remove "Check the workpad's `adepts/` folder before spawning." Replace with: roster is loaded by `spire:adepts` at boot; Igor does not read adept folders directly. Two brief shapes (successor vs. founding). Roster matching uses the gravity-well rule. Shell-disabled fallback: Haiku subagent runs `roster.sh`.
#### 3.2 Update session start steps
After creating journal: seed `## Adepts` from roster rows relevant to topic. May name a matching adept in the greeting.
#### 3.3 Add wrap-up step for adepts
In session lifecycle wrap-up: `SendMessage` each live adept to close, wait via `ListAgents`, journal final state per adept.
#### Verification
- No reference to "Check the workpad's `adepts/` folder" remains.
- Both brief shapes present. Fallback documented.
---
### Phase 4 — Update `agents/igor.md` (add skill)
**Dependencies**: Phase 1.
Add `spire:adepts` to `skills:` list after `spire:workpad`.
---
### Phase 5 — Update journal template
**Dependencies**: None (parallel with other phases).
Add `## Adepts` section between `## Log` and `## Artifacts` in `skills/igor/references/journal-template.md`.
---
### Phase 6 — Update `skills/init/SKILL.md` (new templates)
**Dependencies**: Phases 1-2 (references the new layout).
- Rewrite Phase 4 `adepts/CLAUDE.md` content to match design §G.
- Rewrite `_template/CLAUDE.md` to be an index template with frontmatter and tiered reading list.
- Add `_template/handoff.md` template.
- Update Phase 7 commit file list.
---
### Phase 7 — Update supporting files
**Dependencies**: None (logically last).
- `skills/workpad/SKILL.md`: add `adepts/` to optional-folders list.
- `skills/igor/references/project.md`: update `Adepts:` line to reference roster.
- `skills/curator/SKILL.md`: add scope note distinguishing knowledge docs (curator targets) from handoff/journal (not targets).
---
## Commit Strategy
**Commit 1** — `✨ Add spire:adepts roster skill`
- `plugins/spire/skills/adepts/SKILL.md`, `plugins/spire/skills/adepts/roster.sh`
**Commit 2** — `🤖 Update adept agent for tiered layout and handoff protocol`
- `plugins/spire/agents/adept.md`
**Commit 3** — `🤖 Wire Igor to use adept roster for discovery and spawning`
- `plugins/spire/skills/igor/SKILL.md`, `plugins/spire/agents/igor.md`, `plugins/spire/skills/igor/references/journal-template.md`
**Commit 4** — `🤖 Update init templates and supporting files for adept discovery`
- `plugins/spire/skills/init/SKILL.md`, `plugins/spire/skills/workpad/SKILL.md`, `plugins/spire/skills/igor/references/project.md`, `plugins/spire/skills/curator/SKILL.md`
---
## Fact-Check Items
### From the design (questions 6-10)
**FC-1 (Q6)**: Nested `CLAUDE.md` auto-loading — does the harness load `<dir>/CLAUDE.md` when a subagent reads files under `<dir>` via Read? Underpins the "keep CLAUDE.md short" length pressure.
**FC-2 (Q7)**: Skill shell injection with a script path — does `` !`bash "${CLAUDE_SKILL_DIR}/roster.sh"` `` work with `allowed-tools: Bash(bash:*)`? Does `${CLAUDE_SKILL_DIR}` resolve for plugin skills at agent-startup preload time? Behavior under `disableSkillShellExecution`?
**FC-3 (Q8)**: Workpad resolution in the script — does the resolution chain cover the external-tickets-folder case?
**FC-4 (Q9)**: `Skill("spire:adepts")` from a subagent — can an adept invoke a plugin skill on demand?
**FC-5 (Q10)**: `git log` with glob pathspecs — does `git log --oneline <sha>..HEAD -- src/middleware/auth*` work correctly, or does shell expansion interfere? Should the handoff template quote the paths?
### Additional items from planning
**FC-6**: `sed` frontmatter parsing robustness — handles values with colons? Multiline arrays? Files with no frontmatter?
**FC-7**: `ls` vs. `find` for journal enumeration — behavior when `journal/` doesn't exist? Does `2>/dev/null` on `ls` swallow both arguments' output?
**FC-8**: `CLAUDE_SKILL_DIR` for the adepts skill — resolves to `plugins/spire/skills/adepts/` (or cached equivalent), not the invoking skill's directory?
---
## Design Adjustments (from planner)
1. **`roster.sh` should grep `.claude/spire/project.md` for the workpad path** as an additional fallback for the external-tickets-folder case.
2. **Keep `covers:` parsing out of `roster.sh`** — it's consumed by the drift check in `handoff.md`, not by the roster. The roster only needs `summary`, `status`, and `related`.
3. **Phase parallelism**: Phases 1, 2, and 5 have no dependencies and can be worked in parallel. Phase 3 depends on Phase 1. Phase 6 depends on Phase 2.
---
## Risks and Mitigations
1. **`roster.sh` fragility** — shell parsing of YAML frontmatter with `sed` is brittle. Mitigation: only extract four single-line fields; "unmigrated" fallback for unparseable frontmatter; convention note that frontmatter values must be single-line.
2. **`handoff.md` overwrite breaks git merge** — parallel sessions in same domain. Mitigation: accepted (Q5); rare, short file, `branch:` field helps resolution.
3. **Large change surface** — many files change across the plugin. Mitigation: commit strategy isolates additive roster skill from behavior changes; each commit independently verifiable.
4. **Backward compatibility** — existing adept folders see "unmigrated" in roster. Mitigation: by design; lazy migration via next adept spawn.