From 1c4ec764f9274ed4a55b8076ed8a99bf673bead5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabor=20K=C3=B6rber?= Date: Fri, 18 Sep 2026 15:03:01 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20spire:adepts=20roster=20skill?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shell-injected skill that derives an adept domain roster from workpad frontmatter and journal filenames. Loaded by Igor at boot; any agent may invoke it on demand for fresh discovery. --- plugins/spire/skills/adepts/SKILL.md | 14 ++++++++ plugins/spire/skills/adepts/roster.sh | 47 +++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 plugins/spire/skills/adepts/SKILL.md create mode 100755 plugins/spire/skills/adepts/roster.sh diff --git a/plugins/spire/skills/adepts/SKILL.md b/plugins/spire/skills/adepts/SKILL.md new file mode 100644 index 0000000..1ad107c --- /dev/null +++ b/plugins/spire/skills/adepts/SKILL.md @@ -0,0 +1,14 @@ +--- +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"` + + diff --git a/plugins/spire/skills/adepts/roster.sh b/plugins/spire/skills/adepts/roster.sh new file mode 100755 index 0000000..fe6ccd8 --- /dev/null +++ b/plugins/spire/skills/adepts/roster.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +# Roster generator for spire:adepts — derived metadata from adept domain folders. +# Called via skill shell injection: !`bash "${CLAUDE_SKILL_DIR}/roster.sh"` +# +# Design principle: adepts write knowledge; tooling derives metadata. This +# script reads frontmatter declared once and journal filenames that already +# exist. No adept ever maintains an index, a counter, or a timestamp by hand. + +# Resolve workpad — same chain as spire:workpad, minus interactive steps. +WP="${WORKPAD_FOLDER:-$(just workpad-folder 2>/dev/null)}" +if [ -z "$WP" ]; then + # Try .claude/spire/project.md for an explicit Workpad: line + if [ -f .claude/spire/project.md ]; then + WP=$(sed -n 's/^- \*\*Workpad\*\*: *`\{0,1\}\([^` ]*\).*/\1/p' .claude/spire/project.md | head -1) + fi +fi +[ -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 + [ -d "$dir" ] || continue + slug=$(basename "$dir") + [ "$slug" = "_template" ] && continue + + # FC-6: Skip files without frontmatter early — avoid full-file reads through sed. + if ! head -1 "$dir/CLAUDE.md" 2>/dev/null | grep -q '^---$'; then + 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) + echo "- **$slug** — (unmigrated: no frontmatter) · last active ${newest:-never}" + continue + fi + + 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 derived 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