/bedrock:healthcheck — Vault Health Report
Plugin Paths
Entity definitions and templates are in the plugin directory, not the vault root. Use the "Base directory for this skill" provided at invocation to resolve paths:
- Entity definitions:
<base_dir>/../../entities/ - Templates:
<base_dir>/../../templates/{type}/_template.md - Plugin CLAUDE.md:
<base_dir>/../../CLAUDE.md(already injected automatically into context)
Where <base_dir> is the path provided in "Base directory for this skill".
Vault Resolution
Resolve which vault to diagnose. This skill can be invoked from any directory.
Step 1 — Parse --vault flag:
Check if the input arguments include --vault <name>. If found, extract the vault name.
Step 2 — Resolve vault path:
-
If
--vault <name>was provided: Read the vault registry at<base_dir>/../../vaults.json. Find the entry matching the name. If not found: error — "Vault<name>is not registered. Run/bedrock:vaultsto see available vaults." If found: setVAULT_PATHto the entry'spathvalue. -
If no
--vaultflag — CWD detection: Read<base_dir>/../../vaults.json. Check if the current working directory is inside any registered vault path (CWD starts with a registered vault's absolute path). If multiple match, use the longest path (most specific). If found: setVAULT_PATHto the matching vault'spath. -
If CWD detection fails — default vault: From the registry, find the vault with
"default": true. If found: setVAULT_PATHto the default vault'spath. -
If no resolution: Error — "No vault resolved. Available vaults:" followed by the registry listing. "Use
--vault <name>to specify, or run/bedrock:setupto register a vault."
Step 3 — Validate vault path:
test -d "<VAULT_PATH>" && echo "exists" || echo "missing"
If missing: error — "Vault path <VAULT_PATH> does not exist on disk. Run /bedrock:setup to re-register."
Step 4 — Read vault config:
cat <VAULT_PATH>/.bedrock/config.json 2>/dev/null
Extract language and other relevant fields for use in later phases.
From this point forward, ALL vault file operations use <VAULT_PATH> as the root.
- Entity directories:
<VAULT_PATH>/actors/,<VAULT_PATH>/people/, etc. - Graphify output:
<VAULT_PATH>/graphify-out/
Overview
This skill produces a diagnostic report of vault health without modifying any files. It scans the vault once, runs 5 checks against the scan data, and prints the results.
You are a read-only agent. You do NOT write files, commit, push, invoke other skills, or spawn subagents. Your only output is the diagnostic report printed to the terminal.
Five health checks
| # | Check | What it verifies |
|---|---|---|
| 1 | graphify-out | Graph.json exists, is valid, is fresh |
| 2 | Setup | Directories, templates, entity definitions, plugin manifest |
| 3 | Orphan entities | Entities with zero inbound wikilinks |
| 4 | Dangling content | Entities fully disconnected (no inbound, no outbound, no relations) |
| 5 | Old content | Entities with updated_at older than 15 days |
Status values
Each check reports one of:
- OK — no issues found
- WARN — issues found (with details)
- MISSING — prerequisite not met (e.g., graphify-out absent)
Phase 1 — Scan the Vault
Read all entity files once and store the data for use across all 5 checks.
1.1 Enumerate entity files
For each entity directory (<VAULT_PATH>/actors/, <VAULT_PATH>/people/, <VAULT_PATH>/teams/, <VAULT_PATH>/concepts/, <VAULT_PATH>/topics/, <VAULT_PATH>/discussions/, <VAULT_PATH>/projects/, <VAULT_PATH>/fleeting/):
- List all
.mdfiles using Glob, excluding_template.mdand_template_node.md- For actors: include both
<VAULT_PATH>/actors/*.md(flat) and<VAULT_PATH>/actors/*/*.md(folder) - Include code entities:
<VAULT_PATH>/actors/*/nodes/*.md
- For actors: include both
- Record the directory and filename for each entity
1.2 Read entity data
For each entity file found in 1.1:
- Read the file
- Extract from frontmatter:
typename(or derive from filename)aliases(array)updated_at(date string)- All frontmatter array fields that contain wikilinks (e.g.,
actors,people,teams,related_to, etc.)
- Extract from body:
- All wikilinks
[[target]](regex:\[\[([^\]]+)\]\])
- All wikilinks
- Compute:
outbound_wikilinks: union of all wikilinks from body + frontmatter arrayshas_frontmatter_relations: true if any frontmatter array field contains at least one wikilink valueentity_slug: the filename without extension (used as the canonical identifier)
Output: vault_entities map: entity_slug → {type, name, aliases[], updated_at, outbound_wikilinks[], has_frontmatter_relations, file_path}
Also collect: all_entity_slugs — set of all entity slugs in the vault (for resolving wikilinks).
Phase 2 — Run Checks
2.1 Check 1 — graphify-out
-
Check if directory
<VAULT_PATH>/graphify-out/exists:ls -d <VAULT_PATH>/graphify-out/ 2>/dev/null && echo "EXISTS" || echo "MISSING" -
If MISSING:
- Status: MISSING
- Details: "graphify-out/ directory not found. Run
/bedrock:learnon an actor repository to generate." - Skip remaining sub-checks.
-
If EXISTS, check
<VAULT_PATH>/graphify-out/graph.json:test -f <VAULT_PATH>/graphify-out/graph.json && echo "EXISTS" || echo "MISSING" -
If graph.json MISSING:
- Status: MISSING
- Details: "graph.json not found in graphify-out/. Run
/bedrock:learnto generate." - Skip remaining sub-checks.
-
If graph.json EXISTS, validate and extract stats:
python3 -c " import json, os, time from pathlib import Path g = json.loads(Path('<VAULT_PATH>/graphify-out/graph.json').read_text()) nodes = g.get('nodes', []) code_nodes = [n for n in nodes if n.get('file_type') == 'code'] mtime = os.path.getmtime('<VAULT_PATH>/graphify-out/graph.json') mod_date = time.strftime('%Y-%m-%d', time.localtime(mtime)) days_old = (time.time() - mtime) / 86400 print(f'total_nodes={len(nodes)}') print(f'code_nodes={len(code_nodes)}') print(f'mod_date={mod_date}') print(f'days_old={int(days_old)}') print(f'stale={\"yes\" if days_old > 30 else \"no\"}') " 2>/dev/null || echo "INVALID_JSON" -
If INVALID_JSON:
- Status: WARN
- Details: "graph.json exists but is not valid JSON."
-
If valid:
- If stale (>30 days): Status: WARN, Details: "Graph.json is stale (>30 days). Last updated: {mod_date}. Run
/bedrock:learnor/bedrock:syncto update." - If fresh: Status: OK, Details: "{total_nodes} nodes ({code_nodes} code). Last updated: {mod_date}."
- If stale (>30 days): Status: WARN, Details: "Graph.json is stale (>30 days). Last updated: {mod_date}. Run
Store: graphify_status, graphify_details, graphify_node_count
2.2 Check 2 — Setup
Verify the vault structure and plugin dependencies.
2.2.1 Entity directories
Check that each expected directory exists:
<VAULT_PATH>/actors/,<VAULT_PATH>/people/,<VAULT_PATH>/teams/,<VAULT_PATH>/concepts/,<VAULT_PATH>/topics/,<VAULT_PATH>/discussions/,<VAULT_PATH>/projects/,<VAULT_PATH>/fleeting/
For each directory, check if _template.md exists inside it.
Record: list of missing directories, list of directories missing templates.
2.2.2 Entity definitions
Check that entity definitions exist in the plugin directory:
<base_dir>/../../entities/
Expected files: actor.md, person.md, team.md, concept.md, topic.md, discussion.md, project.md, fleeting.md
Record: list of missing entity definitions.
2.2.3 Plugin manifest
Check that .claude-plugin/plugin.json exists and is valid JSON:
python3 -c "import json; json.loads(open('.claude-plugin/plugin.json').read()); print('VALID')" 2>/dev/null || echo "INVALID"
Record: manifest status.
2.2.4 Result
- If ev