/bedrock:compress — Vault Alignment Engine

SkillAI & models

Vault alignment engine. Detects and fixes 5 types of structural misalignments: broken backlinks, concept fragmentation, entity miscategorization, duplicated entities, and misnamed entities. Delegates all writes to /bedrock:preserve. Supports interactive mode (user confirmation) and cron mode (autonomous mechanical fixes + queued semantic proposals). Use when: "bedrock compress", "bedrock-compress", "align vault", "fix backlinks", "fix misalignments", "/bedrock:compress".

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the /bedrock:compress — Vault Alignment Engine skill

What this skill tells your AI

The instructions your AI receives, as published by iurykrieger/claude-bedrock in skills/compress/SKILL.md and read by ahel’s review.

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 compress. 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 and remove it from the arguments before parsing --mode.

Step 2 — Resolve vault path:

  1. 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:vaults to see available vaults." If found: set VAULT_PATH to the entry's path value. Store the resolved vault name as VAULT_NAME.

  2. If no --vault flag — 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: set VAULT_PATH to the matching vault's path. Store its name as VAULT_NAME.

  3. If CWD detection fails — default vault: From the registry, find the vault with "default": true. If found: set VAULT_PATH to the default vault's path. Store its name as VAULT_NAME.

  4. If no resolution: Error — "No vault resolved. Available vaults:" followed by the registry listing. "Use --vault <name> to specify, or run /bedrock:setup to 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, git.strategy, 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.
  • Git operations: git -C <VAULT_PATH> <command>
  • When delegating to /bedrock:preserve, pass --vault <VAULT_NAME>

Overview

This skill scans all entities in the vault, detects 5 types of structural misalignments, proposes fixes to the user, and delegates all writes to /bedrock:preserve.

You are an execution agent. Follow the phases below in order, without skipping steps.

Execution modes

The skill accepts an optional --mode argument:

  • interactive (default): all 5 capabilities prompt the user for confirmation before execution.
  • cron: capabilities 1 and 4 (mechanical, deterministic) execute autonomously without confirmation. Capabilities 2, 3, and 5 (semantic, judgment-dependent) are detected but written as a proposal to a fleeting note for human review — they are NOT executed.

Parse the mode from the invocation arguments. If no --mode is specified, default to interactive.

Five alignment capabilities

#CapabilityTypeCron behavior
1Broken backlinksMechanicalAutonomous — fix without confirmation
2Concept matchSemanticQueued — write proposal to fleeting note
3Entity misalignmentSemanticQueued — write proposal to fleeting note
4Duplicated entitiesMechanicalAutonomous — fix without confirmation
5Misnamed entitiesSemanticQueued — write proposal to fleeting note

Critical rules:

  • NEVER write entity files directly — all mutations go through /bedrock:preserve
  • NEVER execute semantic capabilities (2, 3, 5) without confirmation in interactive mode
  • NEVER execute semantic capabilities (2, 3, 5) autonomously in cron mode — always queue
  • NEVER remove existing wikilinks
  • NEVER delete entities (compress aligns, it does not delete)
  • People/Teams/Concepts/Topics: append-only — never delete content
  • Actors: free merge — may edit body freely

Phase 0 — Sync the Vault

Execute:

git -C <VAULT_PATH> pull --rebase origin main

If it fails:

  • No remote: warn "No remote configured. Working locally." and proceed.
  • Conflict: git -C <VAULT_PATH> rebase --abort and warn the user. Do NOT proceed without resolving.

Phase 1 — Scan and Detect

Scan the entire vault and run all 5 detection algorithms. Store results for Phase 2.

1.0 Load entity definitions and config

Read the entity definitions from the plugin directory to understand classification criteria:

  • <base_dir>/../../entities/concept.md — needed for capability 2 (concept match)
  • <base_dir>/../../entities/*.md — needed for capability 3 (entity misalignment)
  • <base_dir>/../../entities/code.md — needed for capability 1 graph-side detection (§1.2.2)

Store the "When to create", "When NOT to create", and "How to distinguish" sections from each entity definition for use in detection.

Read vault config for graph-side detection:

cat <VAULT_PATH>/.bedrock/config.json 2>/dev/null

Extract code.cluster_threshold (default 0.85, used by §1.2.2 for Scenario A-extended similarity matching and Scenario B clustering) and code.max_per_actor (default 200, used in Phase 5 to surface cap overrun warnings — never enforced as a hard limit). If .bedrock/config.json is missing or has no code block, use the defaults silently.

1.1 Read all entities

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/):

  1. List all .md files, excluding _template.md and _template_node.md
    • For actors: include both <VAULT_PATH>/actors/*.md (flat) and <VAULT_PATH>/actors/*/*.md (folder)
  2. For each entity, read frontmatter + body
  3. Extract:
    • type from frontmatter
    • name from frontmatter (or filename as fallback)
    • aliases from frontmatter (array)
    • All wikilinks [[target]] from body AND frontmatter arrays
    • All proper nouns, service names, team names, person names mentioned in the body (for capabilities 4 and 5)

Optimization for large vaults: If the vault has more than 100 entities in a type, use subagents via Agent tool to parallelize reading by entity type.

Output: vault_data map: entity_name → {type, name, aliases[], wikilinks[], body_mentions[], frontmatter, body}

1.2 Capability 1 — Detect broken backlinks

Cap 1 detects backlinks that are broken on either of two layers: markdown wikilinks (§1.2.1, today's behavior) and graph-side back-pointers (§1.2.2, total-binding rule).

1.2.1 Markdown-side backlinks (existing behavior)

For each entity A in vault_data:

  1. For each wikilink [[B]] found in A (body or frontmatter arrays):
    • Skip if B does not exist as an entity file in the vault (wikilinks to non-existent entities are valid in Obsidian)
    • If B exists: check if B contains a wikilink [[A]] (body or frontmatter arrays)
    • If B does NOT link back to A: register as broken backlink with kind: "markdown_backlink"

Output: broken_backlinks[] — list of {kind: "markdown_backlink", source: A, target: B, direction: "A→B exists, B→A missing"}

1.2.2 Graph-side back-pointers (total-binding rule)

Rule: every node in <VAULT_PATH>/graphify-out/graph.json MUST end up with vault_entity_path set. There is NO relevance filter at /compress time — confidence level (EXTRACTED / INFERRED / AMBIGUOUS), trivial labels (Test / Mock / Builder / Stub / Fixture), degree, is_god_node, edge_count do NOT exclude any node from binding.

Best-effort load. If <VAULT_PATH>/graphify-out/graph.json is missing, empty, or invalid JSON, skip §1.2.2 silently and proceed with §1.2.1 results only. The /compress run continues normally.

GRAPH_PATH="<VAULT_PATH>/graphify-out/graph.json"
test -s "$GRAPH_PATH" && python3 -c "import json,sys; json.load(open('$GRAPH_PATH'))" 2>/dev/null && echo "OK" || echo "SKIP"

If OK, also load <VAULT_PATH>/graphify-out/.graphify_analysis.json (best-effort — when missing or stale, fall back to semantically_similar_to-only grouping; same fallback used by /preserve Phase 1.3 step 5).

Build the entity-id index. For each code entity in vault_data (i.e., entities under <VAULT_PATH>/actors/*/nodes/), normalize ids to a set:

ids = set()
fm = entity.frontmatter
if isinstance(fm.get("graphify_node_ids"), list):
    ids.update(fm["graphify_node_ids"])
if isinstance(fm.get("graphify_node_id"), str):  # legacy singular — backward compat
    ids.add(fm["graphify_node_id"])

Build a map entity_id_index: id → entity_path covering every code entity. Build bound_node_ids = set(entity_id_index.keys()).

Walk every node in graph.json. For each node N with id and OPTIONAL vault_entity_path:

  • If vault_entity_path is already set on N → already bound, skip.

  • Otherwise classify in priority order — stop at first matching shape:

    1. Scenario A — back_pointer_missing. If N.id ∈ bound_node_ids: register {kind: "graph_back_pointer", shape: "back_pointer_missing", node_id: N.id, entity_path: entity_id_index[N.id]}.

    2. Scenario A-extended — extend_existing. Find any node M such that:

      • M.id ∈ bound_node_ids (M is bound to some entity E),
      • There is an edge (N, M) or (M, N) of relation: "semantically_similar_to" with confidence_score ≥ code.cluster_threshold,
      • OR (when .graphify_analysis.json is present) community_id(N) == community_id(M) AND (is_god_node(M) OR (edge_count(N) ≥ 2 AND edge_count(M) ≥ 2)).

      If found, pick the M with the highest confidence_score (or highest degree if community-based) and register {kind: "graph_back_pointer", shape: "extend_existing", node_id: N.id, target_entity_path: entity_id_index[M.id], target_node_id: M.id, similarity: <score>}.

    3. Scenario B — orphan_graph_node. Otherwise, mark N as a Scenario B candidate. Do NOT register yet — Scenario B candidates are clustered together first (next step).

Cluster Scenario B candidates using the Part 2 grouping algorithm (mirrors /preserve Phase 1.3 step 5):

  • Two Scenario B nodes are in the same cluster if there is a semantically_similar_to edge between them with confidence_score ≥ code.cluster_threshold, OR they share community_id AND (at least one is is_god_node OR both have edge_count ≥ 2).
  • If .graphify_analysis.json is absent or stale, only the semantically_similar_to rule applies.
  • Singletons form their own cluster of size 1.
  • Each cluster carries: cluster_id (synthetic), member_node_ids[] (the union of node ids — this becomes the graphify_node_ids array of the resulting code entity), representative (highest-degree node in the cluster — used for label, source_file, node_type).

Resolve actor_context for each Scenario B cluster via (b) + (c) from the spec:

  • (b) Mechanical inference: extract the cluster representative's source_file and take the first path segment (e.g., billing-api/src/Foo.cs → candidate slug billing-api). Match (case-insensitive, kebab-case) against existing actor slugs in <VAULT_PATH>/actors/.
    • Single match → set actor_context = <slug>.
    • No match → mark cluster as actor_context: null — it will be classified as concept global / topic / fleeting per the corpus-agnostic branch from /preserve Phase 1.3 step 6.
    • Ambiguous match (2+ candidates) → mark cluster as actor_context: <list-of-candidates> for (c) resolution in Phase 3.
  • (c) Phase 3 fallback (resolved later in this run): in --mode interactive the user picks; in --mode cron the cluster is queued in the compress-proposals fleeting note.

For each Scenario B cluster, register {kind: "graph_back_pointer", shape: "orphan_graph_node", member_node_ids: [...], representative: <node>, actor_context: <slug | null | candidates[]>, node_type: <inferred>}.

Inferring node_type for Scenario B clusters (mirrors /preserve Phase 1.3 step 6):

  • Representative file_type=code AST node (function / class / module / interface) → corresponding node_type.
  • Representative label matches HTTP/RPC pattern → node_type: endpoint.
  • Representative file_type=document/paper and has rationale_for edges OR label markers (ADR / RFC / "decision" / "chose" / "decided") → node_type: decision.
  • Otherwise node_type: concept.

Output: broken_backlinks[] is now a list mixing both kinds:

  • {kind: "markdown_backlink", source, target, direction} — from §1.2.1.
  • {kind: "graph_back_pointer", shape: "back_pointer_missing", node_id, entity_path} — Scenario A.
  • {kind: "graph_back_pointer", shape: "extend_existing", node_id, target_entity_path, target_node_id, similarity} — Scenario A-extended.
  • {kind: "graph_back_pointer", shape: "orphan_graph_node", member_node_ids, representative, actor_context, node_type} — Scenario B.

1.3 Capability 2 — Detect concept fragmentation

Scan all entity bodies for recurring terms or phrases that:

  1. Appear in 3+ different entities (across any types)
  2. Do NOT have a corresponding entity file in <VAULT_PATH>/concepts/ (or any other entity directory)
  3. Are NOT already wrapped in a wikilink [[term]]

For each candidate term, evaluate against the concept entity definition (entities/concept.md):

  • Is it timeless and definitional? (not temporal, not an initiative)
  • Is it actor-independent? (not specific to one system's implementation)
  • Does it match "When to create" criteria?
  • Does it NOT match "When NOT to create" criteria?

Filter out:

  • Common English words and generic terms
  • Terms that are already entity filenames or aliases
  • Terms shorter than 2 words (unless they are well-known patterns like "CQRS", "mTLS")

Output: concept_candidates[] — list of {term, occurrences: [{entity, context_snippet}], meets_concept_criteria: bool}

1.4 Capability 3 — Detect entity misalignment

For each entity in vault_data:

  1. Read the entity's frontmatter type field
  2. Read the corresponding entity definition from entities/<type>.md
  3. Evaluate the entity's content against:
    • "When to create" criteria for the current type → does the entity still qualify?
    • "When NOT to create" criteria for the current type → does the entity violate any?
    • "How to distinguish" table → does the entity look like another type?
  4. If a different type is a better fit:
    • Score the entity against "When to create" criteria of the proposed new type
    • Score the entity against "When NOT to create" criteria of the proposed new type
    • If the new type scores higher: flag as misaligned

Focus on these common misalignments:

  • Fleeting notes that have matured into topics, actors, or concepts (critical mass, corroboration)
  • Topics that are actually concepts (timeless definition vs. temporal initiative)
  • Actors that are actually projects (no repo/deployment yet)

Output: misaligned_entities[] — list of {entity, current_type, proposed_type, reason}

1.5 Capability 4 — Detect duplicated entities

Scan all entity bodies for proper nouns, service names, team names, and person names that:

  1. Are mentioned in 3+ different entity files
  2. Do NOT have a corresponding entity file anywhere in the vault
  3. Are NOT already wrapped in a wikilink [[name]]

Identification heuristics:

  • Capitalized multi-word phrases (e.g., "Payment Gateway", "Alice Smith")
  • Kebab-case or camelCase terms that look like service names (e.g., "billing-api", "notificationService")
  • Terms following patterns like "the X team", "the X service", "X squad"

Filter out:

  • Terms that are already entity filenames or aliases (existing entities)
  • Generic organizational terms ("the team", "the service", "the API")
  • Terms that appear only within wikilinks (already linked)

Output: missing_entities[] — list of {name, inferred_type, mentions: [{entity, context_snippet}]}

1.6 Capability 5 — Detect misnamed entities

Scan for name variants of the same real-world entity:

  1. For each entity, collect all known names: filename (kebab-case), name field, aliases[]
  2. For each proper noun/service name found in body text across the vault:
    • Check if it is a variant of an existing entity name (case-insensitive, with/without hyphens, abbreviated forms)
    • Example matches: "Iury" ↔ "Iury Krieger", "billing-api" ↔ "BillingAPI" ↔ "Billing API"
  3. If a mention is a variant of an existing entity but NOT wrapped in a wikilink AND the variant is NOT in the entity's aliases[]: flag as misnamed
  4. If two distinct entity files refer to the same real-world entity (e.g., iury.md and iury-krieger.md): flag as duplicate entity files requiring merge

Output: misnamed_entities[] — list of {canonical_entity, variant_name, found_in: [{entity, context_snippet}], action: "add_alias" | "merge_entities"}


Phase 2 — Build Proposal

Present all findings to the user in a structured report, grouped by capability.

2.1 Summary table

## /bedrock:compress — Alignment Proposal

| # | Capability | Findings | Mode |
|---|---|---|---|
| 1 | Broken backlinks | N found | Autonomous / Interactive |
| 2 | Concept match | N candidates | Queued / Interactive |
| 3 | Entity misalignment | N misaligned | Queued / Interactive |
| 4 | Duplicated entities | N missing | Autonomous / Interactive |
| 5 | Misnamed entities | N variants | Queued / Interactive |

**Total findings:** N
**Mode:** interactive / cron

2.2 Capability 1 — Broken backlinks

Cap 1 has one or two layers depending on whether graph.json was loaded in §1.2.2.

### Capability 1: Broken Backlinks

#### 1A — Markdown backlinks

| # | Source | Target | Missing direction |
|---|---|---|---|
| 1 | [[entity-a]] | [[entity-b]] | entity-b → entity-a |
| 2 | [[entity-c]] | [[entity-d]] | entity-d → entity-c |

**Fix:** Add missing backlinks in target entities via /bedrock:preserve.

#### 1B — Graph back-pointers (when graph.json was loaded)

##### Shape: back_pointer_missing (mechanical)
| # | Graph node id | Entity that owns it | Action |
|---|---|---|---|
| 1 | `billing_api_processTransaction` | `actors/billing-api/nodes/process-transaction.md` | Re-trigger Phase 6.5 propagation (no-op update) |

##### Shape: extend_existing (mechanical, similarity-based)
| # | Orphan node id | Target entity | Similar to bound node | Score |
|---|---|---|---|---|
| 1 | `billing_api_processTransactionV2` | `actors/billing-api/nodes/process-transaction.md` | `billing_api_processTransaction` | 0.92 |

##### Shape: orphan_graph_node (semantic, materialize new entity)
| # | Cluster repr. | Member ids | Resolved actor_context | node_type |
|---|---|---|---|---|
| 1 | `billing_api_validateAmount` | `[billing_api_validateAmount, billing_api_validateAmountV2]` | `billing-api` | function |
| 2 | `auth_decisions_jwt_choice` | `[auth_decisions_jwt_choice]` | `auth-api` | decision |

#### Cap overrun warnings (when applicable)

| Actor | Existing code entities | Proposed (Scenario B) | Total | Cap |
|---|---|---|---|---|
| `billing-api` | 198 | 12 | 210 | 200 |

**Fix:** /compress will proceed with all proposals — cap is a warning, not a block. Maintainer can raise `code.max_per_actor` in `.bedrock/config.json` afterwards if needed.

If no broken backlinks found across both layers: "No broken backlinks found."

If §1.2.2 was skipped (no graph.json or invalid): "Graph-side detection skipped — graph.json is missing or invalid in <VAULT_PATH>/graphify-out/."

2.3 Capability 2 — Concept match

### Capability 2: Concept Fragmentation

| # | Candidate concept | Occurrences | Entities |
|---|---|---|---|
| 1 | "event sourcing" | 5 | [[actor-a]], [[topic-b]], [[actor-c]], ... |
| 2 | "circuit breaker" | 3 | [[actor-d]], [[actor-e]], [[topic-f]] |

**Fix:** Create concept entities and add wikilinks in referencing entities via /bedrock:preserve.

If no candidates found: "No concept fragmentation found."

2.4 Capability 3 — Entity misalignment

### Capability 3: Entity Misalignment

| # | Entity | Current type | Proposed type | Reason |
|---|---|---|---|---|
| 1 | [[note-about-cqrs]] | fleeting | concept | Meets critical mass: >3 paragraphs, timeless definition |
| 2 | [[new-checkout-system]] | actor | project | No repo or deployment yet |

**Fix:** Recategorize via /bedrock:preserve (create under new type, mark original as promoted/consolidated).

If no misalignments found: "No entity misalignments found."

2.5 Capability 4 — Duplicated entities

### Capability 4: Missing Entities (Mentioned but Not Created)

| # | Name | Inferred type | Mentions |
|---|---|---|---|
| 1 | "Payment Gateway" | actor | 4 mentions in [[topic-a]], [[actor-b]], [[discussion-c]], [[actor-d]] |
| 2 | "Alice Smith" | person | 3 mentions in [[discussion-e]], [[topic-f]], [[discussion-g]] |

**Fix:** Create missing entities and establish backlinks via /bedrock:preserve.

If no missing entities found: "No duplicated entity mentions found."

2.6 Capability 5 — Misnamed entities

### Capability 5: Misnamed Entities

| # | Canonical entity | Variant found | Found in | Action |
|---|---|---|---|---|
| 1 | [[iury-krieger]] | "Iury" | [[discussion-a]], [[topic-b]] | Add alias + wikilink |
| 2 | [[billing-api]] | "BillingAPI" | [[actor-c]] | Add alias + wikilink |
| 3 | [[iury.md]] + [[iury-krieger.md]] | Same person | — | Merge entities |

**Fix:** Add aliases and wikilinks, or merge duplicate entity files via /bedrock:preserve.

If no misnamed entities found: "No misnamed entities found."

2.7 No findings

If ALL 5 capabilities found 0 issues: Report "Vault is aligned. No misalignments detected." and end (skip Phases 3-5).


Phase 3 — Confirmation and Mode Handling

Interactive mode (--mode interactive or default)

Present the full proposal from Phase 2 and ask:

Confirm execution? (yes / no / partial)
- **yes**: execute all findings
- **no**: abort
- **partial**: specify which capabilities or individual findings to execute (e.g., "only capability 1 and 4", "all except finding 3 in capability 5")

STOP HERE and wait for user confirmation.

If the user says "no": report "No changes made." and end. If the user partially confirms: filter the execution list accordingly.

Cron mode (--mode cron)

No user confirmation needed for mechanical capabilities. Split findings:

Autonomous execution (mechanical):

  • Capability 1 markdown backlinks (§1.2.1).
  • Capability 1 graph back-pointers — back_pointer_missing (§1.2.2 Scenario A).
  • Capability 1 graph back-pointers — extend_existing (§1.2.2 Scenario A-extended).
  • Capability 4.
  • Proceed directly to Phase 4 with these findings.
  • When invoking /bedrock:preserve, include in the prompt: "Autonomous mode — do not ask for confirmation, process directly."

Queued proposals (semantic):

  • Capabilities 2, 3, 5.
  • Capability 1 graph back-pointers — orphan_graph_node (§1.2.2 Scenario B), including clusters whose actor_context could not be resolved mechanically (no match) or that have ambiguous candidates.
  • If there are findings of any of the above, compile them into a single fleeting note and delegate creation to /bedrock:preserve:

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
99
Forks
8
Last commit
May 2026
Hacker News mentions
20
Advanced
Catalog kind
skill
Gateway key
compress-iurykrieger
Source
github.com/iurykrieger/claude-bedrock