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

11 KiB

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:

---
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.