How claude-obsidian Separates the Product Repository from the User Vault
claude-obsidian enforces strict separation between immutable product code and mutable user data through hierarchical vault discovery logic, filesystem safety checks in paths.py, and explicit documentation that prevents the repository checkout from ever being selected as a writable vault.
The claude-obsidian project maintains a rigorous architectural boundary between its own installation files and the knowledge vaults it manages. Understanding how the system separates the product repository from the user vault is essential for safe deployment and daily operation. This design ensures that updates to the tool never risk corrupting your personal knowledge base, while preventing accidental writes into the code repository.
Hierarchical Vault Discovery
The resolve_vault_root() function in claude_obsidian/paths.py (lines 61-78) implements a priority-based discovery system that never implicitly returns the product directory as a valid vault. The resolution order follows this strict hierarchy:
- Explicit
--vaultargument passed via CLI CLAUDE_OBSIDIAN_VAULTenvironment variable- Nearest
.claude-obsidian.jsonworkspace config file - Nearest initialized vault directory containing sentinel files
This structured fallback mechanism ensures that even when running commands from within the product checkout directory, the system searches outward for a legitimate user vault rather defaulting to the current working directory.
Filesystem Safety Guards
To prevent catastrophic data corruption, the assert_not_plugin_tree() function (lines 29-58 in claude_obsidian/paths.py) implements a hard boundary check. The function canonicalizes both the candidate vault path and the repository root, then raises a VaultSelectionError if the candidate matches or descends from the plugin directory.
This guard guarantees that mutable operations cannot be written into product files. If you attempt to use the installation directory as a vault, the system immediately blocks the operation with a descriptive error code.
The validate_vault_root() function (lines 103-124) adds an additional legacy-compatible layer by checking for vault sentinel files. Valid vaults must contain at least one of the following directories:
wiki/.obsidian/.raw/
If none exist, the path is rejected as "not a claude-obsidian vault," preventing accidental selection of arbitrary directories.
Documented Architectural Boundaries
The separation is reinforced through explicit documentation rather than code alone. According to docs/compound-vault-guide.md (lines 12-20), the architecture defines four distinct roles:
- Product package (immutable code and templates)
- User vault (mutable knowledge content)
- Derived runtime (temporary/generated assets)
- Public artifact (exportable outputs)
The documentation explicitly states that "an installed plugin cache never becomes the user vault." Similarly, README.md (lines 89-96) emphasizes this boundary with clear prose: "the checkout contains the product. It is not your knowledge vault."
Practical Implementation Examples
When resolving a vault from a CLI command, the system safely navigates the hierarchy:
from claude_obsidian.paths import resolve_vault_root
# Example: user runs `claude-obsidian.py wiki --vault /home/me/my-vault`
vault = resolve_vault_root(explicit="/home/me/my-vault")
print(vault.root) # → Path('/home/me/my-vault')
print(vault.source) # → 'explicit'
print(vault.legacy) # → False (modern workspace config present)
Attempting to use the product repository as a vault triggers an immediate error:
from claude_obsidian.paths import resolve_vault_root, VaultSelectionError
try:
# Suppose the current working directory is the product checkout
vault = resolve_vault_root()
except VaultSelectionError as e:
print(e.code, e)
# → PLUGIN_ROOT_IS_NOT_VAULT Refusing to write mutable vault state into the plugin installation
For path traversal safety, the assert_within() helper validates that all operations remain inside the vault boundary:
from claude_obsidian.paths import assert_within, VaultSelectionError
from pathlib import Path
vault_root = Path("/home/me/my-vault")
candidate = "/home/me/my-vault/wiki/notes/Example.md"
try:
inside = assert_within(vault_root, candidate)
print("OK:", inside)
except VaultSelectionError:
print("Path outside vault!")
Summary
- Hierarchical discovery in
resolve_vault_root()prioritizes explicit user configuration over implicit directory selection, ensuring the product checkout is never accidentally chosen. - Filesystem guards via
assert_not_plugin_tree()raiseVaultSelectionErrorwhen detecting attempts to write mutable state into the immutable product directory. - Sentinel validation through
validate_vault_root()requires specific directory markers (wiki/,.obsidian/, or.raw/) to qualify a path as a legitimate vault. - Explicit documentation in the Compound Vault guide and README establishes clear architectural roles that treat the product as read-only code and the vault as mutable data.
Frequently Asked Questions
What happens if I accidentally point claude-obsidian to its own installation directory?
The system raises a VaultSelectionError with the code PLUGIN_ROOT_IS_NOT_VAULT. The assert_not_plugin_tree() function in claude_obsidian/paths.py detects that the candidate path matches or descends from the repository root and immediately refuses the operation, printing a message that it is "Refusing to write mutable vault state into the plugin installation."
How does claude-obsidian detect valid vault directories?
The validate_vault_root() function checks for the presence of sentinel directories that mark a legitimate vault. A valid path must contain at least one of the following: a wiki/ directory, an .obsidian/ directory, or a .raw/ directory. If none are found, the path is rejected as "not a claude-obsidian vault."
Can I override the safety checks to use the product folder as a vault?
No. The separation is architecturally enforced and not intended to be bypassed. The documentation in docs/compound-vault-guide.md explicitly states that the product package "never becomes the user vault." This immutable boundary protects both the integrity of your knowledge base and the stability of the tool itself.
What are the four architectural roles defined in the Compound Vault guide?
According to docs/compound-vault-guide.md, the four roles are: Product package (the immutable code and templates in the repository), User vault (your mutable knowledge content), Derived runtime (temporary or generated working files), and Public artifact (final exported outputs). This taxonomy ensures clear data ownership and prevents cross-contamination between the tool's code and your content.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →