بنقرة واحدة
vault
Generate an Obsidian LLM wiki vault from a project's source code and any static documents in raw/
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Generate an Obsidian LLM wiki vault from a project's source code and any static documents in raw/
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
| name | vault |
| description | Generate an Obsidian LLM wiki vault from a project's source code and any static documents in raw/ |
| argument-hint | [project-dir] [--workspace <dir>] [--lang <code>] |
Analyzes a project's source code and any static documents the user has placed under raw/, then generates a Karpathy-style Obsidian wiki vault where every page is self-contained and useful as either human documentation or LLM context.
| Argument | Default | Description |
|---|---|---|
project-dir | current directory | Source code to analyze |
--workspace | <project>/vault-anything/ | Where raw/ and vault/ are written |
--lang | en | Vault page output language (must match a file in locales/) |
Run the resolvers to get plugin and workspace paths. Save the outputs into shell variables you'll use throughout:
set -e
PLUGIN_ROOT=$(node "$CLAUDE_SKILL_DIR/resolve-plugin-root.mjs")
WORKSPACE=$(node "$PLUGIN_ROOT/skills/vault/resolve-workspace.mjs" "$@")
Parse $WORKSPACE (it's a JSON object) into shell variables with jq:
PROJECT_DIR=$(echo "$WORKSPACE" | jq -r '.projectDir')
PROJECT_NAME=$(echo "$WORKSPACE" | jq -r '.projectName')
WORKSPACE_DIR=$(echo "$WORKSPACE" | jq -r '.workspaceDir')
RAW_DIR=$(echo "$WORKSPACE" | jq -r '.rawDir')
VAULT_DIR=$(echo "$WORKSPACE" | jq -r '.vaultDir')
EXISTS=$(echo "$WORKSPACE" | jq -r '.exists')
VAULT_LANG="en" # parse from --lang argument if user provided one
Decision:
$EXISTS is "true", this project has been analyzed before. Ask the user which path to take:
/vault-anything:vault-update instead, then STOP.raw/ (jump to Phase 3).$EXISTS is "false", proceed with full analysis.Before running the phases, use the TaskCreate tool to create a top-level task list the user can watch. The tasks are:
If the user picked option (c) above (regenerate from existing raw/), mark tasks 1 and 2 as completed immediately (they're being skipped, but recorded as already done so the user sees what's happening).
At the start of every subsequent phase, call TaskUpdate to mark the task in_progress. At the end of each phase, mark it completed.
Mark "Phase 1" as in_progress. Report to the user: [Phase 1/5] Scanning project files...
Run the analyzer script. It scans files, detects frameworks and entry points deterministically, builds an import map, and produces batch plans for the file-analyzer agents:
SCAN=$(node "$PLUGIN_ROOT/skills/vault/run-analyze.mjs" \
"$PROJECT_DIR" "$RAW_DIR" "$PROJECT_NAME")
Extract counts to report to the user:
FILE_COUNT=$(echo "$SCAN" | jq -r '.files')
LANGUAGES=$(echo "$SCAN" | jq -r '.languages | join(", ")')
BATCH_COUNT=$(echo "$SCAN" | jq -r '.batches | length')
Check whether a commit hash was captured:
COMMIT_HASH=$(echo "$SCAN" | jq -r '.commitHash')
SUBREPO_COUNT=$(echo "$SCAN" | jq -r '.subRepos | length')
If $COMMIT_HASH is the string "null", the root isn't under git (or has no commits yet). This is fine — analysis proceeds — but mention it to the user, and distinguish the multi-project case:
If $SUBREPO_COUNT is greater than 0, the root is a parent directory holding several git repos (a multi-project run). The repos may be flat (parent/service) or grouped under a folder (parent/apps/sms, parent/packages/core) — both are detected, and each sub-repo's name is its path relative to the root. List them from echo "$SCAN" | jq -r '.subRepos[].name' and print:
Note: The workspace root isn't a git repo, but <SUBREPO_COUNT> sub-repositories
were detected (<names>). Each one's HEAD is recorded as a baseline, so
/vault-anything:vault-update diffs each sub-repo against its own last commit
(plus its working tree) — per-project incremental updates work. Static-file
changes in raw/ are tracked too.
Otherwise (no sub-repos either) print:
Note: No git repository was found at the root or nested within it. Code change
detection won't be available for incremental updates; only static-file changes
in raw/ will be tracked. If your repos are grouped deeper than 3 levels, list
them in .vault-anything.json → "repoRoots": ["apps/sms", "packages/core"].
Now print a short plan summary for the user:
Plan
Project: <PROJECT_NAME> (<FILE_COUNT> files, languages: <LANGUAGES>)
Workspace: <WORKSPACE_DIR>
Will dispatch <BATCH_COUNT> file-analyzer agent(s) and (after clustering) one page-writer agent per category.
If $FILE_COUNT is greater than 200, warn the user this may take a while and ask them to confirm before continuing.
Mark "Phase 1" as completed.
Mark "Phase 2" as in_progress. Report: [Phase 2/5] Analyzing files...
For each batch (batch-1, batch-2, ...) add a sub-task under "Phase 2" so the user can watch individual batches complete. Use TaskCreate with parentId set to the Phase 2 task id, or use a single TaskUpdate that lists batch progress in the description — whichever your runtime supports.
For each batch in $SCAN.batches, dispatch a vault-anything:file-analyzer subagent via the Agent tool. Run up to 5 agents concurrently — in a single message with multiple Agent tool calls.
For each batch, the Agent tool call uses:
subagent_type: vault-anything:file-analyzerdescription: Analyze batch <batchIndex>/<totalBatches>prompt: described belowIterate the batches with jq to get each batch's data:
echo "$SCAN" | jq -c '.batches[]'
For each batch, build the agent prompt. Substitute the batch-specific values into this template:
Inputs:
- projectRoot:
<PROJECT_DIR>- projectName:
<PROJECT_NAME>- batchIndex:
<batch.batchIndex>- totalBatches:
<total>- outputPath:
<RAW_DIR>/<PROJECT_NAME>/file-summaries/batch-<batchIndex>.jsonFiles to analyze (read each one and produce a
FileSummary):<batch.files>Intra-batch imports (project-internal imports between files in this batch):
<batch.importData>Cross-batch imports (files outside this batch that are referenced — for context, do not re-analyze):
<batch.crossBatchImports>Write a JSON array of
FileSummaryobjects tooutputPath. Follow the schema and rules in your agent definition.
As each batch's subagent completes, mark its sub-task completed. After all batches complete, mark "Phase 2" as completed. Report: Phase 2 complete. <FILE_COUNT> files analyzed.
Mark "Phase 3" as in_progress. Report: [Phase 3/5] Clustering concepts and generating vault skeleton...
GEN=$(node "$PLUGIN_ROOT/skills/vault/run-generate.mjs" \
"$RAW_DIR" "$VAULT_DIR" "$PROJECT_NAME")
Extract counts:
PAGE_COUNT=$(echo "$GEN" | jq -r '.pagesWritten')
CATEGORIES=$(echo "$GEN" | jq -r '.categories | join(", ")')
USER_FILES=$(echo "$GEN" | jq -r '.userFiles | length')
If $USER_FILES is greater than 0, report: Note: <USER_FILES> static file(s) from raw/ will be included.
Report: <PAGE_COUNT> pages planned across categories: <CATEGORIES>
Mark "Phase 3" as completed.
Mark "Phase 4" as in_progress. Report: [Phase 4/5] Writing vault pages...
For each category in $GEN.categories, add a sub-task under "Phase 4" so the user can track progress per category (e.g. "Phase 4: write 02-Architecture (3 pages)").
Load the locale guide and the type templates. If the user asked for a language that isn't bundled, fall back to English and warn them:
LOCALE_FILE="$PLUGIN_ROOT/locales/$VAULT_LANG.md"
if [ ! -f "$LOCALE_FILE" ]; then
echo "Note: no locale guide for '$VAULT_LANG' at $LOCALE_FILE — falling back to English." >&2
VAULT_LANG="en"
LOCALE_FILE="$PLUGIN_ROOT/locales/en.md"
fi
LOCALE_GUIDE=$(cat "$LOCALE_FILE")
# Load all type templates (map page type → template content)
TPL_FLOW=$(cat "$PLUGIN_ROOT/templates/flow.md")
TPL_CONCEPT=$(cat "$PLUGIN_ROOT/templates/concept.md")
TPL_CROSS=$(cat "$PLUGIN_ROOT/templates/cross-cutting.md")
TPL_REFERENCE=$(cat "$PLUGIN_ROOT/templates/reference.md")
TPL_SERVICE=$(cat "$PLUGIN_ROOT/templates/service-overview.md")
TPL_API=$(cat "$PLUGIN_ROOT/templates/api.md") # used by type: api_index
TPL_TOPIC=$(cat "$PLUGIN_ROOT/templates/topic.md") # used by type: topic_index
TPL_CONFIG=$(cat "$PLUGIN_ROOT/templates/config.md") # used by type: config_index
TPL_DATA_MODEL=$(cat "$PLUGIN_ROOT/templates/data-model.md") # used by type: data_model_index
TPL_INTEGRATIONS=$(cat "$PLUGIN_ROOT/templates/integrations.md") # used by type: integration_index
TPL_JOBS=$(cat "$PLUGIN_ROOT/templates/jobs.md") # used by type: job_index
TPL_PERMISSIONS=$(cat "$PLUGIN_ROOT/templates/permissions.md") # used by type: permission_index
For each category in $GEN.categories, dispatch one vault-anything:page-writer subagent via the Agent tool. Run all categories concurrently — in a single message with multiple Agent tool calls.
For each category, get the pages that belong to it:
echo "$GEN" | jq -c --arg CAT "$CATEGORY" '.pages[] | select(.category == $CAT)'
Build the agent prompt with these substitutions. Include only the templates for page types that actually appear in this category's pages (most categories use exactly one type — flows use flow, architecture uses concept, etc.):
Inputs:
- category:
<CATEGORY>- vaultDir:
<VAULT_DIR>/<CATEGORY>/- outputLanguage:
<VAULT_LANG>Templates for the page types in this category:
For type
<type>:<template content for this type, e.g. $TPL_CONCEPT>(Include one template block per unique page type present in this category's pages.)
Locale guide:
<LOCALE_GUIDE>wikilinkMap (use these page titles for [[wikilinks]]):
<GEN.wikilinkMap>Pages to write (skeleton files already exist at vaultDir — read them for context, then overwrite with finished prose):
<pages for this category>User-provided static files that contribute to this category (read these for additional context):
<userFiles relevant to this category, or empty array>Follow the writing rules in your agent definition and the section structure in the template for each page's type. Produce one finished markdown page per entry in
pages.
As each category's subagent completes, mark its sub-task completed. After all category agents finish, mark "Phase 4" as completed. Report: Phase 4 complete.
Mark "Phase 5" as in_progress. Report: [Phase 5/5] Running quality checks...
REVIEW=$(node "$PLUGIN_ROOT/skills/vault/run-review.mjs" "$VAULT_DIR" "$RAW_DIR")
SCORE=$(echo "$REVIEW" | jq -r '.qualityScore')
ISSUES=$(echo "$REVIEW" | jq -r '.issues | length')
WARNINGS=$(echo "$REVIEW" | jq -r '.warnings | length')
Report Quality score: <SCORE>/100.
If $ISSUES is greater than 0:
$REVIEW | jq '.issues'.If $WARNINGS is greater than 0, list the top 5 (informational only — does not block).
Mark "Phase 5" as completed.
Output to the user:
✓ Vault generated
Project: <PROJECT_NAME>
Workspace: <WORKSPACE_DIR>
Pages: <PAGE_COUNT> across <CATEGORIES>
Quality: <SCORE>/100
Open in Obsidian → <VAULT_DIR>
Run updates → /vault-anything:vault-update <PROJECT_DIR>
If the workspace is inside the project directory (default <project>/vault-anything/), suggest the user version it. Print:
Versioning vault-anything:
The vault and its raw layer are designed to be committed alongside your code,
so your team shares the same documentation. Add this single line to your
project's .gitignore:
vault-anything/raw/vault-review.json
(vault-review.json changes on every run and is noise; everything else is
meant to be committed.)
Only print this if (a) the workspace lives inside the project directory and
(b) the project has a .git directory. Skip it for separate-workspace setups.
Multi-project case: if the root has no .git of its own but $SUBREPO_COUNT
(from Phase 1) is greater than 0, the combined vault can't be committed to the
parent because it isn't a repo. Print this instead:
Versioning this multi-project vault:
The workspace root isn't a git repo, so the combined vault has nowhere to be
committed. Two options:
- git init the parent directory and commit the vault there, or
- re-run with --workspace pointing at a dedicated docs/wiki git repo.
vault-update tracks each sub-repo's HEAD independently, so incremental
updates work either way.