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.
377 lines
25 KiB
Markdown
377 lines
25 KiB
Markdown
# Design: Adept discovery and tiered knowledge folders
|
||
|
||
**Date**: 2026-09-18
|
||
**Touches**: `plugins/spire/agents/adept.md`, `plugins/spire/agents/igor.md`, `plugins/spire/skills/igor/SKILL.md`, `plugins/spire/skills/igor/references/journal-template.md`, `plugins/spire/skills/init/SKILL.md`, `plugins/spire/skills/workpad/SKILL.md`, new skill `plugins/spire/skills/adepts/`
|
||
**Builds on**: `designs/spire-project-override-and-init.md` (which shipped the `_template` scaffolding this design replaces)
|
||
|
||
## The problem
|
||
|
||
Three gaps, all downstream of the same fact — the adept folder is opaque from outside:
|
||
|
||
1. **No discovery.** Igor is told to "check the workpad's `adepts/` folder before spawning." In practice that means `ls`, then reading each `CLAUDE.md` to learn what a folder covers and whether anyone has been there lately. That is exactly the kind of inline work Igor is not supposed to do, and it scales linearly with the number of domains. Nothing records which domains were recently active.
|
||
2. **Monolithic CLAUDE.md.** The current template puts scope, key files, conventions, and open questions in one file. Every adept appends to it; every successor loads all of it. Because the harness auto-loads a directory's `CLAUDE.md` when files beneath it are read, a fat one is paid for repeatedly. There is no tiering — a successor cannot tell what it must read from what it may read.
|
||
3. **Weak handoff.** A successor "reads the CLAUDE.md and journals." Journals are append-only and grow without bound; the successor has no cheap way to know what the predecessor's last state was, what is in flight on a branch, or whether the code has moved since the predecessor last verified anything.
|
||
|
||
The design principle for all three: **adepts write knowledge; tooling derives metadata.** An adept should never maintain an index, a counter, or a timestamp by hand. Everything the roster needs is either declared once in frontmatter or derived from files that already exist (journal filenames, git).
|
||
|
||
## Design
|
||
|
||
### A. Domain folder layout
|
||
|
||
```
|
||
<workpad>/adepts/
|
||
CLAUDE.md # directory conventions (init-scaffolded; rewritten by this design)
|
||
_template/ # init-scaffolded starter; copied on founding
|
||
CLAUDE.md
|
||
handoff.md
|
||
<domain-slug>/
|
||
CLAUDE.md # INDEX — frontmatter + tiered reading list. Short. Auto-loaded.
|
||
handoff.md # rolling state-of-the-domain for the successor. Overwritten, not appended.
|
||
key-files.md # solid knowledge docs — as many as the domain needs
|
||
conventions.md
|
||
architecture.md
|
||
gotchas.md
|
||
... # any other doc, provided it is listed in CLAUDE.md
|
||
journal/
|
||
YYYY-MM-DD-HH-genesis.md
|
||
YYYY-MM-DD-HH-<topic>.md
|
||
```
|
||
|
||
Changes from today:
|
||
|
||
- Journals move into `journal/` and drop the `journal-` infix (the folder says it). The domain root then reads as a knowledge base: index, handoff, docs. `ls` alone tells a successor what exists.
|
||
- `handoff.md` is new and is the one file that is *overwritten* rather than appended.
|
||
- Knowledge docs are plural. The names above are a suggested vocabulary, not a fixed schema — but **any file in the domain root must appear in `CLAUDE.md`'s reading list.** If it is not in the index, it does not exist.
|
||
|
||
Where the two knowledge tiers from `adept.md` land:
|
||
|
||
| Content | Lives in | Update rule |
|
||
|---|---|---|
|
||
| Solid knowledge (verified on main) | `key-files.md`, `conventions.md`, `architecture.md`, `gotchas.md`, … | Correct on contact; dated refinement sections when disputing a predecessor; curator compresses |
|
||
| Experiences (branch work, observations, dead ends) | `journal/` | Append-only, one file per topic or session |
|
||
| Current state, open threads, in-flight branch notes | `handoff.md` | Overwritten by the living adept; written early, refreshed often |
|
||
| Scope, boundaries, what to read when | `CLAUDE.md` | Rarely changes; edited when docs are added or the domain splits |
|
||
|
||
### B. `CLAUDE.md` as index
|
||
|
||
Frontmatter carries the only hand-declared metadata. Everything temporal is derived (see D).
|
||
|
||
```markdown
|
||
---
|
||
domain: Authentication
|
||
summary: Login flow, session tokens, the auth middleware chain, and the permission model.
|
||
covers:
|
||
- src/auth/
|
||
- src/middleware/auth*
|
||
- tests/auth/
|
||
related: [api-gateway, user-profile]
|
||
status: active # active | split | merged
|
||
---
|
||
# Authentication
|
||
|
||
Everything between "a request arrives with credentials" and "a request carries a
|
||
verified principal." Permission *checks* inside feature code are not this domain —
|
||
that is whoever owns the feature. Token *issuance* for service accounts is
|
||
api-gateway's.
|
||
|
||
## Must-read
|
||
|
||
Every genesis, before answering anything. Keep this list to three or four entries.
|
||
|
||
- `handoff.md` — where the previous adept left things. Always first.
|
||
- `key-files.md` — the files that matter, what each does, where the seams are.
|
||
- `conventions.md` — rules here that differ from the project-wide ones.
|
||
|
||
## Good-to-read-if
|
||
|
||
- `architecture.md` — if asked how the pieces fit, or where a new thing should go.
|
||
- `gotchas.md` — if asked why something behaves oddly, or before recommending any change to the middleware order.
|
||
- `journal/` — if `handoff.md` points at a specific entry, or a question touches a dead end noted there. Do not read the whole journal.
|
||
|
||
## Optional
|
||
|
||
- `history.md` — how the domain got this way. Read for "why" questions only.
|
||
- `../api-gateway/CLAUDE.md` — read only when a question crosses into token issuance.
|
||
|
||
## Open questions
|
||
|
||
Carried forward by predecessors. Try to resolve one before adding one.
|
||
|
||
- Why does `AdminService` bypass the standard middleware? (since 2026-08-30)
|
||
```
|
||
|
||
Rules the adept agent enforces:
|
||
|
||
- **Length.** `CLAUDE.md` stays under ~60 lines. It is auto-loaded by the harness whenever an adept reads any file in the folder, so every line costs repeatedly. If it grows, something in it belongs in a doc.
|
||
- **Tiers are conditional, not ranked.** "Good-to-read-if" entries state the *condition*. A successor answering a "why is this weird" question reads `gotchas.md`; one answering "where do I add X" reads `architecture.md`. Neither reads both at boot.
|
||
- **Docs split at ~200 lines.** When a doc passes that, the adept splits it and updates the index in the same edit.
|
||
- **Siblings are introspected, not preloaded.** `related:` names sibling slugs. The adept reads a sibling's `CLAUDE.md` (index only) when a consultation crosses a boundary, and may `grep` across `../*/journal/` when hunting a dead end. Nothing sibling-shaped is read at genesis.
|
||
|
||
### C. `handoff.md` — the successor's first read
|
||
|
||
Rolling, overwritten, short (≤ ~40 lines). Written *early* in an adept's life and refreshed after every significant consultation — sessions end abruptly; an adept that writes its handoff "at the end" often never does.
|
||
|
||
```markdown
|
||
---
|
||
updated: 2026-09-16-14
|
||
session: journals/2026-09-16-14-auth-refactor.md
|
||
branch: main
|
||
verified-at: 4886539 # HEAD when the solid docs were last checked against code
|
||
---
|
||
# Handoff — Authentication
|
||
|
||
## State
|
||
Middleware chain is documented and verified. Permission model doc is complete
|
||
except for the admin bypass (open question). Nothing in flight on main.
|
||
|
||
## In flight (experiences, not solid)
|
||
- Branch `feat/oauth-pkce` adds a third token type. Observed, journaled in
|
||
`journal/2026-09-16-14-pkce-branch.md`, NOT in key-files.md until it merges.
|
||
|
||
## Open threads
|
||
- Admin bypass still unexplained. Explore agent found no comment, no commit message. Next: `git log -S AdminService --follow`.
|
||
- User asked whether refresh-token rotation is enforced; answer pending a test run.
|
||
|
||
## Successor: read first
|
||
1. This file.
|
||
2. `key-files.md` §Middleware chain — most likely to have drifted.
|
||
3. `journal/2026-09-16-14-pkce-branch.md` if the OAuth branch is still open.
|
||
|
||
## Drift check
|
||
git log --oneline 4886539..HEAD -- src/auth/ src/middleware/auth* tests/auth/
|
||
```
|
||
|
||
`verified-at` is the mechanism that makes continuity cheap. The successor runs the drift check (paths come from `covers:`) and knows in one command whether any solid knowledge could be stale — and which files to re-verify before trusting `key-files.md`. Without it the successor either trusts blindly or re-reads the domain.
|
||
|
||
### D. The roster — discovery without reading
|
||
|
||
A new skill, `spire:adepts`, shell-injects a derived roster at load time — same mechanism `spire:project` uses.
|
||
|
||
```markdown
|
||
---
|
||
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:*)
|
||
---
|
||
|
||
!`bash "${CLAUDE_SKILL_DIR}/roster.sh"`
|
||
|
||
<!-- Empty roster: no adepts/ folder yet, or /spire:init has not been run. -->
|
||
```
|
||
|
||
`roster.sh` (sketch — the planner decides the exact implementation):
|
||
|
||
```bash
|
||
#!/usr/bin/env bash
|
||
# Resolve workpad the same way spire:workpad does, minus the "ask" step.
|
||
WP="${WORKPAD_FOLDER:-$(just workpad-folder 2>/dev/null)}"
|
||
[ -z "$WP" ] && { [ -d docs/workpad ] && WP=docs/workpad || WP=.workpad; }
|
||
[ -d "$WP/adepts" ] || { echo "## Adept roster — none (no $WP/adepts/)"; exit 0; }
|
||
|
||
echo "## Adept roster — $WP/adepts/ ($(date +%F))"
|
||
for dir in "$WP"/adepts/*/; do
|
||
slug=$(basename "$dir"); [ "$slug" = "_template" ] && continue
|
||
fm=$(sed -n '2,/^---$/p' "$dir/CLAUDE.md" 2>/dev/null)
|
||
summary=$(echo "$fm" | sed -n 's/^summary: *//p')
|
||
status=$(echo "$fm" | sed -n 's/^status: *//p')
|
||
related=$(echo "$fm" | sed -n 's/^related: *//p')
|
||
# Recency and session count derive from journal filenames — nothing to maintain.
|
||
newest=$(ls "$dir"/journal/ "$dir" 2>/dev/null | grep -E '^[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{2}' | sort | tail -1 | cut -c1-13)
|
||
sessions=$(ls "$dir"/journal/ "$dir" 2>/dev/null | grep -Eo '^[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{2}' | sort -u | wc -l)
|
||
if [ -z "$summary" ]; then
|
||
echo "- **$slug** — (unmigrated: no frontmatter) · last active ${newest:-never}"
|
||
else
|
||
echo "- **$slug** — $summary · last active ${newest:-never} · $sessions session(s) · ${status:-active}${related:+ · related: $related}"
|
||
fi
|
||
done
|
||
```
|
||
|
||
Output Igor sees at boot:
|
||
|
||
```
|
||
## Adept roster — docs/workpad/adepts/ (2026-09-18)
|
||
- **auth** — Login flow, session tokens, the auth middleware chain, and the permission model. · last active 2026-09-16-14 · 4 session(s) · active · related: [api-gateway, user-profile]
|
||
- **billing** — Stripe integration and the invoice pipeline. · last active 2026-08-02-09 · 1 session(s) · active
|
||
- **legacy-importer** — (unmigrated: no frontmatter) · last active 2026-07-02-11
|
||
```
|
||
|
||
Properties:
|
||
|
||
- **Never stale.** There is no index file to forget to update. Frontmatter is declared once; recency and session counts fall out of the journal naming convention that already exists.
|
||
- **No shared mutable file.** Two adepts in parallel sessions each touch only their own folder.
|
||
- **Tolerates legacy.** A folder without frontmatter still appears, flagged.
|
||
- **Cheap.** One line per domain. Twenty domains is twenty lines. If a project ever has enough domains for this to matter, the roster can gain a `--recent N` mode; not needed now.
|
||
- **Available on demand.** Adepts (and athanor) can `Skill("spire:adepts")` when a question crosses a boundary, instead of `ls`-ing and reading.
|
||
|
||
Fallback when skill shell execution is disabled: the skill body's comment tells Igor to dispatch a Haiku subagent with the one-liner `bash <plugin>/skills/adepts/roster.sh`. Igor never reads the folders itself.
|
||
|
||
Dormancy is *derived*, not declared: Igor reads "last active" and judges. `status:` exists only for the states an adept must declare because tooling cannot infer them — `split` (with successor slugs in `related:`) and `merged` (target in `related:`). A split or merged folder stays on disk; its `CLAUDE.md` shrinks to a pointer.
|
||
|
||
### E. Flows
|
||
|
||
#### Igor boot
|
||
|
||
1. `spire:project` loads `project.md` (unchanged).
|
||
2. `spire:adepts` injects the roster (new — `agents/igor.md` adds it to `skills:`).
|
||
3. Igor creates the session journal. The template gains an `## Adepts` section; Igor seeds it with the roster rows relevant to the topic.
|
||
4. Greet, ask what the user wants (unchanged).
|
||
5. If the topic clearly matches a roster entry, Igor names it in the greeting — "there's an auth adept, last active two days ago; I'll wake it once I know what we're doing" — and spawns it as soon as the direction is clear. One flourish, then the dispatch.
|
||
|
||
#### Spawning — founding vs. successor
|
||
|
||
The brief changes shape depending on whether the slug is in the roster:
|
||
|
||
```
|
||
# Successor (slug in roster)
|
||
Agent(subagent_type: "adept", name: "auth-adept", model: "opus",
|
||
prompt: "Your domain is Authentication. Your folder is docs/workpad/adepts/auth/ — you are a
|
||
successor; it has a handoff.md. We are on branch main. Session journal:
|
||
docs/workpad/journals/2026-09-18-10-oauth-pkce.md.
|
||
Orient per your genesis protocol and be ready for consultation.")
|
||
|
||
# Founding (slug not in roster)
|
||
Agent(subagent_type: "adept", name: "billing-adept", model: "opus",
|
||
prompt: "Your domain is Billing (Stripe integration, invoices). Your folder is
|
||
docs/workpad/adepts/billing/ — it does not exist; you are the founding adept.
|
||
We are on branch main. Session journal: <path>.
|
||
Orient and be ready for consultation.")
|
||
```
|
||
|
||
Igor picks the slug from the roster when one fits *strictly* (the gravity-well rule from `adept.md` §4 stays; the roster just makes it possible to apply without reading folders). The session journal path goes in the brief so the adept's journal can link back.
|
||
|
||
#### Adept genesis — successor
|
||
|
||
```
|
||
1. Read adepts/CLAUDE.md (conventions, short)
|
||
2. Read <slug>/CLAUDE.md (index — auto-loaded anyway)
|
||
3. Read <slug>/handoff.md
|
||
4. Run the drift check from handoff.md (git log <verified-at>..HEAD -- <covers>)
|
||
5. Read the Must-read docs
|
||
6. Read only the journal entries handoff.md names (usually one or two)
|
||
7. If step 4 showed changes under a key path: verify those claims before anything else;
|
||
correct on contact; note corrections in the genesis journal entry
|
||
8. Write journal/<now>-genesis.md — short for a successor: drift found, corrections made,
|
||
orientation trace. Link the session journal.
|
||
9. Rewrite handoff.md: bump `updated`, `session`, `verified-at` (if step 7 verified), note "successor active"
|
||
```
|
||
|
||
Steps 1–6 are bounded: two short files, one short handoff, three or four docs, one or two journal entries. A successor never reads the whole journal.
|
||
|
||
#### Adept genesis — founding
|
||
|
||
As today (`adept.md` §Genesis), plus: copy `_template/CLAUDE.md` *and* `_template/handoff.md`; fill frontmatter (`domain`, `summary`, `covers`, `related`) during orientation; create the docs the orientation produces — at minimum `key-files.md`; write `handoff.md` *before* the first consultation, with `verified-at` = current HEAD. The genesis journal entry keeps its orientation-trace duty.
|
||
|
||
#### During consultation
|
||
|
||
Unchanged in spirit. Additions:
|
||
|
||
- After a consultation that changes state (new open thread, a branch observation, a resolved question), refresh `handoff.md` in the same turn. It costs a few lines; it is the file that survives an abrupt end.
|
||
- When a question crosses the domain boundary: `Skill("spire:adepts")` for the roster, read the sibling's `CLAUDE.md` index, and — if warranted — tell Igor "this is api-gateway's; consider waking that adept." Do not absorb the sibling's domain.
|
||
- When adding a doc: add it to the index in the same edit.
|
||
|
||
#### Session wrap-up (Igor)
|
||
|
||
1. `SendMessage` each live adept: "Session closing. Refresh handoff.md, write your closing journal entry, reply with one line of state." Wait via `ListAgents`, read the `<result>`s.
|
||
2. Journal `## Adepts`: final state per adept, path to its `handoff.md`.
|
||
3. Close the journal (existing steps 3–4 of the lifecycle continue unchanged).
|
||
|
||
#### Compression mid-session
|
||
|
||
Already in `adept.md`: an adept whose context compresses wraps up and asks for a successor. With this design "wrap up" is concrete — refresh `handoff.md`, closing journal entry — and the successor's genesis is the bounded protocol above, so replacement is cheap enough to do without hesitation.
|
||
|
||
### F. Journal template changes
|
||
|
||
`references/journal-template.md` gains one section between Log and Artifacts:
|
||
|
||
```markdown
|
||
## Adepts
|
||
|
||
<!-- Roster rows relevant to this session at boot; then one line per adept as
|
||
spawned/consulted/closed. Path to handoff.md on close. -->
|
||
|
||
- auth — successor (5th session) — spawned 10:12 — consulted 3× — closed 11:40, handoff refreshed
|
||
```
|
||
|
||
This is the "cross-session memory of what was useful": the next Igor grepping `journals/` for `auth —` finds every session that used the adept and what it did. The roster gives recency; the journals give usefulness. Neither requires the adept to keep score.
|
||
|
||
### G. `adepts/CLAUDE.md` (directory conventions) — rewritten
|
||
|
||
Init writes this; the content changes to describe the layout above. The conventions section becomes:
|
||
|
||
```markdown
|
||
## Conventions
|
||
|
||
- **One domain per folder.** Overlap → pick the stricter scope. Broad names are gravity wells.
|
||
- **CLAUDE.md is an index, not a document.** Frontmatter + tiered reading list + open questions. Under ~60 lines. It is auto-loaded whenever anything in the folder is read — keep it cheap.
|
||
- **Every file in the domain root is listed in CLAUDE.md.** Unlisted files do not exist.
|
||
- **handoff.md is overwritten, never appended.** Write it early, refresh it after anything significant. `verified-at` is the commit the solid docs were last checked against.
|
||
- **journal/ is append-only.** One file per topic or session, `YYYY-MM-DD-HH-<topic>.md`. Recency and session counts are derived from these names — keep the prefix exact.
|
||
- **Solid knowledge goes in docs; experiences go in the journal.** Branch observations stay in the journal (and handoff.md's "In flight") until the code is on main.
|
||
- **Don't hoard.** Findings that belong in the project's docs or a workpad report go there; link from here.
|
||
- **Metadata is derived.** Never hand-maintain counts, dates, or an index file. Declare `domain`, `summary`, `covers`, `related`, `status` once in frontmatter; the roster does the rest.
|
||
```
|
||
|
||
### H. Integration summary
|
||
|
||
| Component | Change |
|
||
|---|---|
|
||
| `skills/adepts/SKILL.md` + `roster.sh` | **New.** Shell-injected roster; invocable on demand. |
|
||
| `agents/igor.md` | Add `spire:adepts` to `skills:`. |
|
||
| `skills/igor/SKILL.md` §Adepts | Replace "check the workpad's `adepts/` folder" with "the roster is in context; spawn as successor when the slug exists." Add the founding/successor brief shapes. Add wrap-up step 1 (close-out message). Add shell-disabled fallback (Haiku runs `roster.sh`). |
|
||
| `skills/igor/SKILL.md` §Session start | Step 1 seeds the journal's `## Adepts` from the roster; step 2 may name a matching adept in the greeting. |
|
||
| `skills/igor/references/journal-template.md` | Add `## Adepts` section. |
|
||
| `agents/adept.md` | Genesis splits into founding/successor protocols; folder structure updated; handoff.md duties added (write early, refresh often, drift check); index-maintenance rule; sibling introspection rule; doc-split threshold. |
|
||
| `skills/init/SKILL.md` Phase 4 | Rewrite `adepts/CLAUDE.md` content (§G). `_template/` gains `handoff.md`; `_template/CLAUDE.md` becomes the index template (§B with placeholders). Phase 7 commit list gains `_template/handoff.md`. |
|
||
| `skills/workpad/SKILL.md` | Add `adepts/` to the optional-folders list ("adept domain folders — see `spire:adepts`"). Today it is an unknown folder the skill says to ignore. |
|
||
| `skills/igor/references/project.md` | `Adepts:` line points at the roster: "listed by `spire:adepts` at boot." |
|
||
| `skills/curator/SKILL.md` | Scope note: knowledge docs in adept folders accrete refinement sections and are curator targets; `handoff.md` and `journal/` are not. |
|
||
| `agents/athanor.md` | No change. If athanor ever consults adepts, it invokes `spire:adepts` on demand. |
|
||
|
||
## Migration path
|
||
|
||
### This repo
|
||
|
||
No adept folders exist under `docs/workpad/`. Migration here is template-only: update init, re-run `/spire:init` (templates are `status: generated`, so they regenerate).
|
||
|
||
### Projects with existing adept folders
|
||
|
||
Lazy migration, done by the next adept spawned into each domain — not a bulk job. The roster flags unmigrated folders so Igor knows to include the instruction in the brief:
|
||
|
||
```
|
||
… Your folder is <workpad>/adepts/legacy-importer/ — it predates the tiered layout
|
||
(no frontmatter, journals at the root). Migrate it during genesis per adepts/CLAUDE.md,
|
||
then orient.
|
||
```
|
||
|
||
Migration steps the adept performs, in one commit-sized change:
|
||
|
||
1. `git mv` each `YYYY-MM-DD-HH-journal-<topic>.md` → `journal/YYYY-MM-DD-HH-<topic>.md`.
|
||
2. Split the monolithic `CLAUDE.md`: `## Key files` → `key-files.md`; `## Conventions` → `conventions.md`; remaining prose → `architecture.md` or `gotchas.md` by judgment. Preserve dated refinement sections in whichever doc their parent section landed.
|
||
3. Write the new `CLAUDE.md` index: frontmatter (`domain`, `summary`, `covers` from the key-files table, `related` from any cross-references found), tiered list of the docs just created, carried-over open questions.
|
||
4. Write `handoff.md` from the newest journal entry's "what's unclear" plus the open questions. `verified-at` = HEAD *after* the adept has verified `key-files.md` against current code — or, if it has not yet, omit the field and say so in `## State`; the next successor will set it.
|
||
5. Journal entry `journal/<now>-migration.md`: what moved where, what was verified, what was not.
|
||
|
||
If a project has many legacy domains and the user wants them done at once, this is a natural athanor job: one brief, one subagent per domain, same five steps.
|
||
|
||
### Plugin update for existing installs
|
||
|
||
Re-run `/spire:init`. `adepts/CLAUDE.md` and `_template/*` regenerate if `status: generated`. If a project authored either, init skips it and the summary tells the user which files to merge by hand. `roster.sh` ships with the plugin, so discovery works immediately, including over unmigrated folders.
|
||
|
||
## Open questions
|
||
|
||
For the planner:
|
||
|
||
1. **Journal relocation — worth the churn?** Moving journals to `journal/` is the one change that touches history in existing projects. Alternative: keep them flat with the `journal-` infix and have `roster.sh` match both. The clean `ls` is the argument for moving; zero migration is the argument against. This design says move; the planner may overrule.
|
||
2. **Doc vocabulary — fixed or free?** `key-files.md` is the only doc this design requires. The rest are suggestions. A fixed vocabulary makes cross-domain grepping predictable; free naming fits odd domains better. Current answer: suggested vocabulary in `_template/CLAUDE.md` comments, free additions, index rule enforces discoverability either way.
|
||
3. **`## Adepts` in the session journal — is grepping journals enough** for "which adept was useful," or is there appetite for a counter? This design says grep is enough and counters are exactly the hand-maintained metadata the principle forbids.
|
||
4. **`roster.sh` location.** Inside the skill folder (resolved via `${CLAUDE_SKILL_DIR}`) is the obvious spot. If the planner prefers a `just adepts` recipe scaffolded by init, the skill can call that with the script as fallback — but that adds a Justfile dependency this design otherwise avoids.
|
||
5. **Parallel sessions in the same domain.** Two Igors in two worktrees could each spawn an `auth-adept`; both would overwrite `handoff.md`. Worktrees mean separate files until merge, where `handoff.md` conflicts. Acceptable for now (rare; the conflict is short and human-resolvable), but the adept should mention its worktree in `handoff.md`'s `branch:` so the loser of the merge knows what it is looking at.
|
||
|
||
For the fact-checker:
|
||
|
||
6. **Nested `CLAUDE.md` auto-loading.** The design leans on the claim that the harness loads `<dir>/CLAUDE.md` when an agent reads files under `<dir>`. Confirm this holds for subagents and for files read via the Read tool (not just cwd). If it does not, the "keep CLAUDE.md short because it is auto-loaded" argument weakens — the index design still stands on its own, but the length pressure is less acute.
|
||
7. **Skill shell injection with a script.** `spire:project` injects `cat`. Confirm `!`bash "${CLAUDE_SKILL_DIR}/roster.sh"`` works with `allowed-tools: Bash(bash:*)`, that `${CLAUDE_SKILL_DIR}` resolves for plugin-cached skills at agent-startup preload (not only on `/skill` invocation), and what the behaviour is under `disableSkillShellExecution`.
|
||
8. **Workpad resolution inside the script.** `roster.sh` cannot ask the user. Confirm `WORKPAD_FOLDER` / `just workpad-folder` / `docs/workpad` / `.workpad` covers every configuration the `spire:workpad` skill supports — the external tickets-folder case (`<tickets>/workpad/`) may need `.claude/spire/project.md` to record the resolved path, which init already knows at scaffold time.
|
||
9. **`Skill("spire:adepts")` from a subagent.** Confirm adepts can invoke a plugin skill on demand and receive the injected output, so sibling discovery does not fall back to `ls`.
|
||
10. **`git log <sha>..HEAD -- <paths>` with glob entries in `covers:`.** `src/middleware/auth*` needs the shell to expand or git's pathspec to handle it; confirm which, and whether the handoff should store the literal command (as drafted) or just the paths.
|