fix(import): treat each SKILL.md as one skill #59

Merged
clawdie merged 1 commit from fix/import-skill-md into main 2026-06-14 02:08:23 +02:00
2 changed files with 12 additions and 16 deletions

View file

@ -11,10 +11,10 @@ Reviewed **skills** import into Colibri's existing `skills` catalog:
scripts/import-layered-soul.sh <layered-soul-dir> <colibri.sqlite>
It reads `skills/**/*.md` (frontmatter `name` / `description`; category derived
from the skill's parent dir), and `INSERT OR IGNORE`s rows into the `skills`
table. Same mechanism and table as `clawdie-iso/scripts/import-clawdie-skills.sh`;
idempotent, safe to re-run.
It reads each `skills/**/SKILL.md` (frontmatter `name` / `description`; category
`soul`) and `INSERT OR IGNORE`s a row into the `skills` table. `references/` and
`templates/` under a skill are supporting material, not separate skills. Same
table as `clawdie-iso/scripts/import-clawdie-skills.sh`; idempotent, safe to re-run.
## What's deferred (planned, not built)
@ -25,7 +25,7 @@ only a single flat `skills` table exists; the rest is **design only**
| Layered Soul source | Target (planned) | Status |
| ---------------------------- | ---------------- | ---------------------------------------------------------- |
| `skills/**/*.md` | `system_skills` | imported into the flat `skills` table today |
| `skills/**/SKILL.md` | `system_skills` | imported into the flat `skills` table today |
| `memories/curated/**/*.md` | `system_brain` | NOT imported — no store yet (the importer reports a count) |
| converted task/job manifests | `system_ops` | NOT implemented |

View file

@ -36,26 +36,22 @@ sqlite3 "$DB" "CREATE TABLE IF NOT EXISTS skills (
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
# Reviewed skills: skills/**/*.md (skip READMEs). find|while runs in a subshell,
# so keep the counters + summary together inside one { } group.
find "$SOUL/skills" -type f -name '*.md' ! -iname 'README.md' 2>/dev/null | sort | {
# Reviewed skills: each skills/**/SKILL.md is one skill. Its references/ and
# templates/ are supporting material, not separate skills. find|while runs in a
# subshell, so keep the counters + summary together inside one { } group.
find "$SOUL/skills" -type f -name 'SKILL.md' 2>/dev/null | sort | {
imported=0
skipped=0
while IFS= read -r skill_md; do
[ -f "$skill_md" ] || continue
frontmatter=$(sed -n '/^---$/,/^---$/p' "$skill_md" | sed '1d;$d')
name=$(printf '%s\n' "$frontmatter" | grep -m1 '^name:' | sed 's/^name: *//' | tr -d '"')
# Fall back to the file's basename when there is no frontmatter name.
[ -n "$name" ] || name=$(basename "$skill_md" .md)
# Fall back to the skill directory name when there is no frontmatter name.
[ -n "$name" ] || name=$(basename "$(dirname "$skill_md")")
[ -n "$name" ] || { skipped=$((skipped + 1)); continue; }
description=$(printf '%s\n' "$frontmatter" | grep -m1 '^description:' | sed 's/^description: *//' | tr -d '"')
[ -n "$description" ] || description="Layered Soul skill: $name"
# Category = the skill's parent dir under skills/, else "soul".
rel=${skill_md#"$SOUL"/skills/}
case "$rel" in
*/*) category=$(printf '%s' "$rel" | cut -d/ -f1) ;;
*) category="soul" ;;
esac
category="soul"
id=$(uuidgen 2>/dev/null || python3 -c 'import uuid;print(uuid.uuid4())' 2>/dev/null || echo "soul-skill-$name")
if sqlite3 "$DB" "INSERT OR IGNORE INTO skills (id, name, description, category, created_at)
VALUES ('$id', '$(printf '%s' "$name" | sed "s/'/''/g")', '$(printf '%s' "$description" | sed "s/'/''/g")', '$(printf '%s' "$category" | sed "s/'/''/g")', '$NOW');" 2>/dev/null; then