agentskills.codes
SP

Session-start vault scanner. Auto-fixes broken wikilinks, missing tags, and orphan docs. Detects coverage gaps from recent commits. Runs automatically at session start.

Install

mkdir -p .claude/skills/spine-scan && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/16389" && unzip -o skill.zip -d .claude/skills/spine-scan && rm skill.zip

Installs to .claude/skills/spine-scan

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Session-start vault scanner. Auto-fixes broken wikilinks, missing tags, and orphan docs. Detects coverage gaps from recent commits. Runs automatically at session start.
168 charsno explicit “when” trigger

About this skill

Spine Scan — Session-Start Vault Scanner

Automatically scan the Spine vault for decay and coverage gaps. Auto-fixes low-risk issues, reports findings as a non-blocking banner.

Tier 3 Gate

Before doing anything, check if Tier 3 is enabled:

  1. Read ~/.spine/config.json
  2. Check the tier3 field
  3. If tier3 is false or missing, skip silently — do not scan, do not print a banner, do nothing.

This skill only runs when the user has opted into Tier 3 autonomous behavior.

Vault Path Resolution

Resolve the vault path using this config chain:

  1. $SPINE_VAULT_PATH environment variable
  2. ~/.spine/config.json → read the vaultPath field
  3. Default: ~/Documents/SpineVault/

If no vault is found, or the vault directory doesn't exist, skip silently — no banner, no output contract, nothing. Not every repo uses Spine. The output contract is only emitted when the scan actually runs.

Detect Current Repo

basename "$(git remote get-url origin 2>/dev/null)" .git

Fall back to the current directory name if no git remote. If {vault}/{repo}/ doesn't exist, skip silently — this repo isn't tracked by Spine.

Phase 1: Auto-Fixes

Scan the vault for mechanical issues and fix them silently. Log every action to {vault}/.spine/curator-log.md.

Ensure {vault}/.spine/ directory exists before writing.

Conflict Guard

Before reading each file for auto-fix analysis, record its modification time and file size (size catches same-second edits on filesystems with only second-resolution timestamps). Before writing the fix back:

  1. Re-check mtime and size against the recorded values
  2. If either changed, skip the fix for that file and log: **Skipped:** \{file}` — modified by another process during scan`
  3. Proceed with the next file

This prevents overwriting concurrent edits from Obsidian, Obsidian Sync, or parallel sessions. The dual check (mtime + size) handles HFS+/ext4 second-resolution timestamps where a sub-second edit would otherwise be invisible.

1a. Broken Wikilinks

For each markdown file in {vault}/{repo}/:

  1. Find all [[wikilinks]] in the file content
  2. Check if each linked note exists anywhere in the vault (search by filename without extension)
  3. If a linked note doesn't exist:
    • Search for notes with similar names (typos, renamed docs)
    • If a close match is found, update the wikilink to the correct name
    • If no match, remove the broken wikilink and log it
  4. Log: **Auto-fixed:** Broken wikilink in \{file}` → `[[{corrected}]]``

1b. Missing or Wrong Type Tags

For each markdown file in {vault}/{repo}/ (skip spine notes):

  1. Read the YAML frontmatter
  2. Determine the expected type/* tag from the filename:
    • Filename starts with date + Fix -type/fix
    • Filename starts with date + Feature -type/feature
    • Filename starts with Architecture -type/architecture
    • Filename starts with Plan -type/plan
    • Filename starts with Decision -type/decision
  3. Check if the frontmatter tags array contains the expected type/* tag
  4. If missing or wrong, add/correct it in the frontmatter
  5. Log: **Auto-fixed:** Missing \{tag}` tag on `{filename}``

1c. Orphan Docs

For each feature folder in {vault}/{repo}/:

  1. Find the spine note ({Feature}.md with type/spine tag)
  2. List all other markdown files in the folder
  3. For each file, check if it's referenced as a [[wikilink]] in the spine note
  4. If not linked, add a wikilink under the appropriate section:
    • type/fix## Fixes
    • type/feature## Features
    • type/architecture## Architecture
    • type/plan## Plans
    • type/decision## Decisions
  5. Log: **Auto-fixed:** Orphan doc \{filename}` linked into `{spine-note}``

1d. Stale and Obsolete Doc Detection

For each doc in {vault}/{repo}/ that has a **Files changed:** section:

  1. Extract the file paths listed
  2. For each file path, run existence check first:
    git ls-files -- {filepath}
    
    • If the command returns empty, the file no longer exists in the repo
  3. Classify the doc based on results:
    • All referenced files missing → the feature was likely removed. Set obsolete: true in frontmatter. Do NOT also set stale.
    • Some referenced files missing → partial removal. Set stale: true and add a removed_files list to frontmatter.
    • All files exist → run activity check: git log --oneline --since="{doc-date}" -- {filepath}. If 3+ commits, set stale: true.
  4. Log accordingly:
    • **Flagged obsolete:** \{doc}` — all referenced files removed from repo (feature likely deleted)`
    • **Flagged stale:** \{doc}` — `{filepath}` removed from repo (partial)`
    • **Flagged stale:** \{doc}` — `{filepath}` has {N} commits since doc date`

Important: Never auto-delete or archive obsolete docs — only flag them. The user decides what to do.

Phase 2: Coverage Gap Detection

Find significant commits that have no corresponding Obsidian doc.

2a. Determine Time Window

  1. Read {vault}/.spine/last-scan-timestamp
    • If the file doesn't exist, default to 2 weeks ago
  2. Also read {vault}/.spine/pending-commits.json for any leftover commits from abrupt session ends

2b. Find Undocumented Commits

  1. Run git log --oneline --since="{last-scan-timestamp}" in the current repo
  2. Filter out trivial commits:
    • Skip commit messages matching ^(style|lint|chore|docs|merge)
    • Skip commits with < 20 total line changes AND <= 1 file
  3. Group remaining commits by feature area:
    • Match changed file paths against existing feature folders in the vault
    • Group commits touching the same feature together
  4. For each group, check if a corresponding doc exists in that feature folder with a date on or after the commit date
  5. Collect any groups with no matching doc as coverage gaps

Phase 3: Banner

Print a single non-blocking summary. Do NOT ask for input or wait for a response.

Format:

🦴 Spine: {N} commits since last session — {fixes summary} (auto). {gaps summary}.

Include obsolete/stale flags in the summary if any were found:

  • Obsolete docs (all files removed): mention by name — user should review these
  • Stale docs (high activity or partial removal): count only, don't list names

Examples:

  • 🦴 Spine: 5 commits since last session — 2 wikilinks fixed, 1 tag corrected (auto). 2 coverage gaps (auth, payments). Run /spine-capture when ready.
  • 🦴 Spine: No new commits. 1 orphan doc linked (auto). Vault is healthy.
  • 🦴 Spine: 3 commits since last session. No issues found. Vault is clean.
  • 🦴 Spine: 4 commits — 1 doc flagged obsolete (TradeIn feature removed?): \2026-03-12 Feature - TradeIn Flow.md`. Review with /spine-health.`
  • 🦴 Spine: 2 commits — 2 docs flagged stale. Vault mostly healthy.

If there are zero commits and zero issues, either print 🦴 Spine: Vault is clean. or skip the banner entirely.

Health Check Reminder

Check {vault}/.spine/last-health-timestamp. If the file doesn't exist or the timestamp is older than 14 days, append a reminder to the banner:

   Last full health check: {N} days ago — consider running /spine-health.

Examples with the reminder:

  • 🦴 Spine: Vault is clean. Last full health check: 18 days ago — consider running /spine-health.
  • 🦴 Spine: 2 wikilinks fixed (auto). 1 coverage gap (auth). Last full health check: 21 days ago — consider running /spine-health.

If the last health check was within 14 days, do not mention it.

Phase 4: Structured Output

After the human-readable banner, emit a structured observation block. This is the contract that downstream skills (especially /spine-capture --batch) rely on.

spine_scan_result:
  status: success | warning | error
  summary: "5 commits since last session — 2 wikilinks fixed, 1 coverage gap"
  auto_fixes:
    - { type: "wikilink", file: "Auth/Login.md", detail: "[[Logn]] → [[Login]]" }
    - { type: "tag", file: "2026-04-10 Fix - Cache Bug.md", detail: "added type/fix" }
    - { type: "orphan", file: "Architecture - API Layer.md", linked_to: "API.md" }
  stale_docs:
    - { file: "2026-03-18 Fix - Session Bug.md", reason: "session.hook.ts has 5 commits since" }
  obsolete_docs:
    - { file: "2026-03-12 Feature - TradeIn Flow.md", reason: "all referenced files removed" }
  coverage_gaps:
    - { feature: "auth", commits: 3, files: ["src/auth/login.ts", "src/auth/session.ts"] }
  next_actions:
    - { action: "/spine-capture", reason: "1 undocumented feature group" }
    - { action: "review obsolete", file: "2026-03-12 Feature - TradeIn Flow.md" }
  recovery_hint: null

Status values:

  • success — scan completed, no issues found
  • warning — scan completed, issues found (gaps, stale, obsolete)
  • error — scan failed (vault missing, git error, etc.) — include recovery_hint

Cross-skill handoff: Write coverage gaps to {vault}/.spine/scan-gaps.json so /spine-capture --batch can pre-populate drafts without re-scanning. Delete this file after capture consumes it.

Phase 5: Update Timestamp

Write the current ISO timestamp to {vault}/.spine/last-scan-timestamp:

2026-04-19T14:30:00Z

Curator Log Format

Append a dated section to {vault}/.spine/curator-log.md (create the file from templates/curator-log.md if it doesn't exist). Newest entries at the top of the file (prepend, don't append).

## {YYYY-MM-DD} — Session Scan
- **Auto-fixed:** {description of each fix}
- **Flagged obsolete:** `{doc}` — all referenced files removed from repo (feature likely deleted)
- **Flagged stale:** {description of each stale doc}
- **Coverage gap:** {description of each gap}

If no actions were taken, do not add an entry.

Search skills

Search the agent skills registry