plugins/personal/skills/obsidian-brain/SKILL.md
Autonomous Obsidian vault management using the PARA + LLM Wiki pattern. Three operations: ingest (inbox to wiki + PARA routing), query (cross-vault synthesis), lint (health check). Scheduled via CronCreate 4x/day. Filesystem-only -- no Obsidian app dependency. Activate when the user mentions 'ingest', 'vault', 'wiki page', 'obsidian brain', 'vault lint', 'inbox', 'wiki index', 'knowledge base query', or wants to process, organize, query, or audit their Obsidian vault.
npx skillsauth add anton-abyzov/vskill obsidian-brainInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Autonomous vault management skill implementing the Karpathy LLM Wiki pattern. Teaches the agent to manage an Obsidian vault as a folder of markdown files using three operations: ingest, query, and lint.
The vault has three layers:
This skill operates entirely via filesystem tools. No Obsidian app, CLI, or Sync dependency.
All paths are user-configured. Replace placeholders before first use.
vault_path: "{{VAULT_PATH}}" # Absolute path to Obsidian vault root
para_folders:
projects: "{{PROJECTS_FOLDER}}" # e.g. "001 Projects"
areas: "{{AREAS_FOLDER}}" # e.g. "002 Areas"
resources: "{{RESOURCES_FOLDER}}" # e.g. "003 Resources"
archive: "{{ARCHIVE_FOLDER}}" # e.g. "004 Archive"
wiki_dir: "{{WIKI_DIR}}" # e.g. "wiki"
inbox_dir: "{{INBOX_DIR}}" # e.g. "raw/inbox"
log_file: "{{LOG_FILE}}" # e.g. "wiki/log.md"
index_file: "{{INDEX_FILE}}" # e.g. "wiki/index.md"
credentials_folder: "{{CREDENTIALS_FOLDER}}" # e.g. "003 Resources/credentials"
Resolved paths: All operations resolve relative paths against vault_path. For example, inbox_dir resolves to {{VAULT_PATH}}/{{INBOX_DIR}}/.
This skill supports three operations, each described below. For scheduled autonomous execution, see Scheduled Operation.
Processes new files from the inbox into wiki pages and routes originals to PARA folders.
Trigger: Files present in {{VAULT_PATH}}/{{INBOX_DIR}}/.
Before processing any file, scan its content for sensitive material:
Patterns (case-insensitive):
password\s*[:=]
api[_-]?key\s*[:=]
secret[_-]?key\s*[:=]
token\s*[:=]
aws_access_key_id\s*[:=]
aws_secret_access_key\s*[:=]
AKIA[0-9A-Z]{16}
private[_-]?key\s*[:=]
bearer\s+[a-zA-Z0-9\-._~+/]+=*
On credential match: STOP wiki ingestion for that file (never create a wiki page from credentials).
Credential value preservation (MANDATORY): When routing a credential file, the file's contents (key/secret/token/password values) MUST be preserved verbatim. Do NOT:
nvapi-**********c-e, sk-...x4y)actual secret NOT recorded, key-missing, *** redacted ***)The {{CREDENTIALS_FOLDER}}/ tree IS the user's credential store: siloed, locally-synced, and only readable by the user's own machine. Masking inside it defeats retrieval — the user cannot use a key they cannot read. Never overwrite an existing full value with a masked one. If updating a stale file that has both a masked entry and a full value (legacy inconsistency), reconcile in favor of the full value and remove the masked artefact.
Frontmatter status: must reflect the actual state — active, expired, revoked, or superseded. Never key-missing if the value is in fact recorded in the file.
Exception: banking PANs / credit-card numbers follow industry standard (last-4 + issuer + expiry, never full PAN). Don't change those.
User-specific overrides (additional patterns, exceptions) live in references/user-preferences.md § Credentials, when present.
{{CREDENTIALS_FOLDER}}/ (Email-Accounts/, Social-Media/, Cloud-Providers/, etc.){{CREDENTIALS_FOLDER}}/ root (last resort only)YYYY-MM-DD HH:MM | !cred | <filename> | credential detected, routed to <destination>Before processing any files, scan the vault structure to build a routing map:
{{PROJECTS_FOLDER}}/, {{AREAS_FOLDER}}/, {{RESOURCES_FOLDER}}/, {{ARCHIVE_FOLDER}}/For each non-credential file in the inbox:
{{WIKI_DIR}}/ for the entity name, key identifiers, and primary topics from the sourcetitle or aliases in frontmatter), extend it instead of creating a duplicate:
## Update YYYY-MM-DD)tags and aliases if the source reveals new onesYYYY-MM-DD HH:MM | ~merge | page-name | merged content from <source> (dedup){{VAULT_PATH}}/{{WIKI_DIR}}/ (only if no existing page was extended in step 3):
slugified-name.md (lowercase, hyphens, max 60 chars)YYYY-MM-DD-slug.md[[wikilinks]] to related existing pages(part N) suffix and cross-references[[new-page]]) to existing wiki pages that share topics{{VAULT_PATH}}/{{INDEX_FILE}}
- [[page-name]] -- one-line summary{{VAULT_PATH}}/{{LOG_FILE}}:
YYYY-MM-DD HH:MM | +page | page-name | created from <source>YYYY-MM-DD HH:MM | ~page | page-name | added cross-ref to <new-page>YYYY-MM-DD HH:MM | >ingest | <source> | N pages created/updatedYYYY-MM-DD HH:MM | @link | page-a -> page-b | bidirectional cross-refBash to move: the source file is read-only during ingest, then moved (not copied)A single source should touch 5-15 wiki pages. The wiki compounds with every ingest.
Synthesizes answers from across the vault, with source citations via wikilinks.
Trigger: User asks a question about vault contents.
Tools used: Read, Glob, Grep only. No Obsidian app or CLI dependency.
{{VAULT_PATH}}/{{INDEX_FILE}} to identify candidate pages{{VAULT_PATH}}/{{WIKI_DIR}}/ and PARA folders[[wikilinks]] (by filename, no folder path){{VAULT_PATH}}/{{WIKI_DIR}}/synthesis-slug.md with frontmatter type: synthesis{{INDEX_FILE}} with the new synthesis pageYYYY-MM-DD HH:MM | ?query | synthesis-slug | query: "<summary of question>"YYYY-MM-DD HH:MM | ?query | - | query: "<summary of question>", N pages consultedWhen a query spans multiple knowledge domains, search across all configured vaults. Vault paths are defined in the user's global CLAUDE.md (typically personal-docs, engineering-docs, and ai-power vaults).
Cross-vault search procedure:
{{VAULT_PATH}}) -- this is always the default[engineering-docs] [[page-name]]Cross-vault search is opt-in by context -- only expand beyond the primary vault when the query clearly spans domains. Single-domain queries stay within the primary vault for speed.
Periodic health check that catches organizational issues before they compound.
Trigger: Manual request, or scheduled run when threshold/cadence is met.
Run scripts/lint-check.sh with Bash:
bash scripts/lint-check.sh "{{VAULT_PATH}}" "{{WIKI_DIR}}" "{{INDEX_FILE}}" "{{INBOX_DIR}}" 10
The script checks:
{{INDEX_FILE}}{{INBOX_DIR}} vs threshold (default: 10)[[wikilinks]] but not existing as filesAfter running the script, perform LLM-driven analysis on flagged pages:
Categorize findings by severity:
| Severity | Meaning | Examples | |----------|---------|---------| | error | Broken structure, must fix | Orphan page, missing wikilink target | | warning | Quality issue, should fix | Inbox backlog > threshold, stale content | | info | Suggestion, nice to fix | Missing concept page, potential cross-ref |
Each finding includes an actionable fix suggestion (e.g., "Add [[page-name]] to index.md").
Log the lint run summary:
YYYY-MM-DD HH:MM | !lint | - | E errors, W warnings, I info findingsLog individual error-severity findings:
YYYY-MM-DD HH:MM | !lint | <page> | <finding description>Autonomous 4x/day execution via CronCreate. See references/cron-setup.md for full configuration.
CronCreate({
schedule: "0 8,12,16,20 * * *",
prompt: "Run obsidian-brain scheduled maintenance on vault at {{VAULT_PATH}}",
description: "Obsidian Brain: scheduled vault maintenance (ingest, lint, index)"
})
Adjust the cron expression to match your timezone and preferred schedule.
Before executing any operation, verify:
test -d "{{VAULT_PATH}}/{{WIKI_DIR}}" -- abort with !error log if failsls "{{VAULT_PATH}}/{{INBOX_DIR}}/" | wc -l -- determines whether ingest runs{{LOG_FILE}} -- skip if last run was < 2 hours ago to prevent duplicate processingIf pre-flight fails:
YYYY-MM-DD HH:MM | !error | - | pre-flight failed: <reason>Each scheduled run executes operations in this order:
scripts/update-index.sh to regenerate {{INDEX_FILE}}Every scheduled run logs start and completion:
YYYY-MM-DD HH:MM | >ingest | - | scheduled run startedYYYY-MM-DD HH:MM | >ingest | - | scheduled run complete: N ingested, L lint findings, index rebuiltYYYY-MM-DD HH:MM | !error | - | <error description>No silent failures -- every run produces at least a start + completion/error log entry.
(part N) suffix if exceededCommon issues and their resolutions, organized by operation.
| Symptom | Cause | Fix |
|---------|-------|-----|
| File stays in inbox after ingest | Move failed (permissions or path with special chars) | Check file permissions with ls -la; ensure target PARA folder exists; escape special characters in path |
| Wiki page created but not in index | Index update step was skipped or errored | Run bash scripts/update-index.sh manually to rebuild the full index |
| Duplicate wiki pages for same entity | Dedup check missed due to alias mismatch | Merge pages manually: keep the older page, append content from the newer one under ## Update YYYY-MM-DD, add aliases from both to frontmatter, delete the duplicate, update index |
| Credential guard false positive | Content contains patterns like token: "explanation" in documentation | Review the file manually; if safe, temporarily rename the matching line, ingest, then restore. Never disable the credential guard entirely |
| Source routed to wrong PARA folder | Domain signals were ambiguous or folder structure changed | Move the file to the correct folder with mv; update the log entry; re-scan vault structure on next ingest |
| Symptom | Cause | Fix |
|---------|-------|-----|
| Query returns no results | Index is stale or search terms don't match wiki page content | Rebuild index with scripts/update-index.sh; try broader search terms; check if content is in a different vault |
| Cross-vault query misses pages | Secondary vault path not configured or inaccessible | Verify vault paths in global CLAUDE.md; check directory exists with test -d |
| Synthesis contradicts source pages | LLM hallucination during synthesis | Always verify synthesis claims against the cited source pages; flag contradictions explicitly |
| Symptom | Cause | Fix |
|---------|-------|-----|
| lint-check.sh reports false orphans | Page exists but uses a different slug format than index expects | Standardize the page filename to match the index entry, or update the index |
| Lint finds hundreds of missing cross-refs | Wikilinks use display names instead of filenames | Use [[filename\|Display Name]] format; never use display-only wikilinks |
| Scheduled lint never runs | CronCreate not configured or last-run check is too aggressive | Verify cron exists; check {{LOG_FILE}} last entry timestamp; reduce the 2-hour dedup window if needed |
| Symptom | Cause | Fix |
|---------|-------|-----|
| Vault path not found | Drive not mounted, cloud sync incomplete, or path changed | Verify the path with test -d "{{VAULT_PATH}}"; check if Obsidian Sync is active; update config if vault moved |
| Log file growing unbounded | No log rotation configured | Periodically archive old log entries: move lines older than 90 days to wiki/log-archive-YYYY.md |
| Scripts fail with permission denied | Shell scripts lost execute bit after sync | Run chmod +x scripts/*.sh in the skill's scripts directory |
| Non-ASCII filenames garbled | Terminal or filesystem encoding mismatch | Ensure locale supports UTF-8 (locale should show UTF-8); Obsidian vaults on macOS use NFD normalization |
Bulk vault maintenance operations for reorganizing, auditing, or migrating content at scale.
Move all files from one PARA folder to another based on changed domain ownership:
Procedure:
1. Glob for all files in the source folder
2. For each file, read frontmatter to confirm domain
3. Move to target folder, preserving subfolder structure
4. Update any wiki pages that reference the old path
5. Log each move: YYYY-MM-DD HH:MM | >batch | filename | re-routed from <source> to <target>
Use case: A project completes and all its files should move from Projects to Archive.
Standardize inconsistent tags across the vault:
Procedure:
1. Grep all frontmatter `tags:` fields across wiki/ and PARA folders
2. Build a frequency map of all tags
3. Identify near-duplicates (e.g., "js" vs "javascript", "k8s" vs "kubernetes")
4. Present a normalization plan to the user for approval
5. Apply approved renames across all affected files
6. Log: YYYY-MM-DD HH:MM | >batch | - | normalized N tags across M files
Systematically resolve all orphan wiki pages:
Procedure:
1. Run lint-check.sh to get the orphan list
2. For each orphan, determine if it should be:
a. Added to index (legitimate page, just missing from index)
b. Merged into an existing page (duplicate content)
c. Deleted (stale or empty page with no value)
3. Execute the chosen action for each orphan
4. Rebuild the index after all changes
5. Log: YYYY-MM-DD HH:MM | >batch | - | resolved N orphans (A indexed, B merged, C deleted)
Generate a health summary of the entire vault:
Procedure:
1. Count files per PARA category and wiki/
2. Count total wikilinks and calculate average links per page
3. Identify the 10 most-linked pages (hub pages)
4. Identify pages with zero inbound links (isolated pages)
5. Calculate inbox throughput (files ingested per week from log)
6. Report wiki growth rate (pages created per month from log)
Output as a wiki page: {{WIKI_DIR}}/vault-statistics-YYYY-MM.md with type: synthesis.
Detailed documentation for each subsystem (loaded on demand):
Shell scripts for deterministic operations (POSIX-compatible):
| Operation | Trigger | Frequency |
|-----------|---------|-----------|
| Ingest | New files in raw/inbox/ | 4x/day via CronCreate |
| Query | User asks about vault content | On-demand |
| Lint | Health check request | Weekly or on-demand |
Emergency ingest: If inbox has 50+ files, process in batches of 10 with a ~batch log tag.
tools
Hand off your in-flight work to ANY other AI coding tool so you can continue exactly where you left off — works in 8+ tools (Claude Code, Codex, OpenCode, Gemini, Antigravity, Cursor, Aider, Cline/Roo, Windsurf). Writes one portable, secret-scrubbed handoff document plus a full diff of your uncommitted edits, then prints the absolute path, a clickable link, and a copy-paste resume prompt. Use this skill whenever the user is running out of subscription tokens, wants to switch tools mid-task, says 'handoff', 'continue elsewhere', 'continue on another machine', 'switch to Codex/OpenCode/Gemini/Cursor', or 'I'm out of tokens'. Self-contained: needs only git and a shell; uses 'specweave handoff' as an optional accelerator if it is on PATH.
tools
Bootstrap or update project AI-agent instruction files (AGENTS.md for Codex, CLAUDE.md for Claude Code, or both) from the current project's structure. Triggers on: write AGENTS.md, write CLAUDE.md, generate AGENTS.md, agent instructions, project conventions for AI, bootstrap agent docs, set up project memory for Codex/Claude, document dev/test/build commands for AI coding tools, single-source project instructions for any AI agent.
development
This skill should be used whenever the user asks Claude to perform any action, task, or operation — including "create X", "fix Y", "run Z", "build", "edit", "search", "deploy", or any other request involving Claude taking an action. Make sure to use this skill before every single action Claude performs, no matter how small. Activate on every action request without exception.
development
Meta-skill for creating new skills from natural language. Trigger phrases: "new skill", "create a skill", "build a skill", "make a skill", "generate a skill", "author a skill", "skill builder".