Schema for Transactions in Claude-Obsidian: The Complete Developer Guide
Claude-Obsidian defines three JSON schemas—BUNDLE_SCHEMA, RESULT_SCHEMA, and JOURNAL_SCHEMA—that govern how atomic, recoverable vault modifications are structured, validated, and persisted.
The open-source AgriciDaniel/claude-obsidian repository implements a strict transaction system to ensure safe, auditable changes to Obsidian vaults. Understanding the schema for transactions in Claude-Obsidian is essential for developers building automation tools, CLI integrations, or custom vault workflows that require deterministic rollback capabilities.
The Three Core Transaction Schemas
The transaction system relies on three distinct schema constants defined at the top of claude_obsidian/transaction.py (lines 41–43). Each serves a specific purpose in the transaction lifecycle:
BUNDLE_SCHEMA("claude-obsidian.transaction.v1"): The top-level JSON structure submitted to the system containing operation metadata, file writes, and optional backups.RESULT_SCHEMA("claude-obsidian.transaction-result.v1"): The JSON object returned after transaction completion, recording final state, bundle hashes, and diagnostics.JOURNAL_SCHEMA("claude-obsidian.transaction-journal.v1"): The persistent audit log stored under.vault-meta/transactions/<operation_id>/journal.json, enabling deterministic recovery.
Anatomy of a Transaction Bundle
A transaction bundle is a Python dict that must include the schema field set to BUNDLE_SCHEMA. The structure enforces atomic, recoverable updates through carefully validated fields.
Operation Metadata and Validation
Every bundle requires two critical identifier fields validated by specific helper functions:
operation_id: A filesystem-safe string validated bysafe_operation_id()(lines 35–51 inclaude_obsidian/transaction.py).operation_type: Must be one of the values inOPERATION_TYPES(e.g.,"save","ingest","autoresearch") defined at lines 44–58.
Write Specifications
The writes array contains dictionaries specifying each file modification. Each entry includes:
{
"path": "wiki/notes/example.md",
"mode": 0o644,
"content_sha256": "<hash of new content>",
"original_sha256": null
}
Path validation occurs through _normalize_vault_path and _assert_portable_write_path (lines 54–86 and 88–104), ensuring writes remain confined to the vault directory and follow portable naming conventions.
Optional Backups
The backups field accepts an optional list of backup descriptors, allowing the system to preserve existing state before applying changes.
Transaction Results and Journal Persistence
After applying a bundle, the system returns a result JSON conforming to RESULT_SCHEMA:
{
"schema": "claude-obsidian.transaction-result.v1",
"operation_id": "my-update-001",
"status": "applied",
"bundle_sha256": "<hash of the applied bundle>",
"runtime": { "duration_ms": 123 }
}
Simultaneously, the system writes a journal entry following JOURNAL_SCHEMA to .vault-meta/transactions/<operation_id>/journal.json. This persistent log records pre-condition hashes, write outcomes, and timestamps, enabling the rollback logic implemented in _confined_vault_unlink and _confined_vault_write.
Security and Validation: The Approval Hash
Before execution, the system computes an approval hash using plan_approval_sha256 (lines 287–309). This cryptographic binding incorporates:
- The bundle's canonical JSON representation
- The vault identity
- A projection of prepared writes
This hash ensures that any later inspection can verify the exact content that was approved, preventing tampering between review and execution.
Working with the Schema in Python
The following example demonstrates constructing a valid transaction bundle and computing its approval hash:
from pathlib import Path
from claude_obsidian.transaction import (
safe_operation_id,
plan_approval_sha256,
BUNDLE_SCHEMA,
)
# 1️⃣ Build a write description
write = {
"path": "wiki/notes/example.md",
"mode": 0o644,
"content_sha256": "c1e5b9…", # pre‑computed SHA‑256 of new file bytes
"original_sha256": None, # file does not exist yet
}
# 2️⃣ Assemble the bundle
bundle = {
"schema": BUNDLE_SCHEMA,
"operation_id": safe_operation_id("my-update-001"),
"operation_type": "save",
"writes": [write],
"backups": [], # optional
}
# 3️⃣ Compute the approval hash (what a reviewer would sign)
vault_root = Path("/path/to/vault")
approval_hash = plan_approval_sha256(
vault_root=vault_root,
expanded_bundle=bundle,
prepared_writes=[], # normally filled after a planning step
)
print("Approve this transaction with hash:", approval_hash)
Apply the bundle via the CLI:
claude-obsidian transaction apply --vault /path/to/vault bundle.json
Summary
- Three distinct schemas govern Claude-Obsidian transactions:
BUNDLE_SCHEMAfor input,RESULT_SCHEMAfor output, andJOURNAL_SCHEMAfor persistence. - Strict validation occurs through
safe_operation_id,_normalize_vault_path, and_assert_portable_write_pathinclaude_obsidian/transaction.py. - Approval hashing via
plan_approval_sha256cryptographically binds the bundle to vault identity and write projections. - Journal files live under
.vault-meta/transactions/<operation_id>/journal.json, enabling deterministic recovery and audit trails.
Frequently Asked Questions
What is the exact schema version string for a transaction bundle?
The BUNDLE_SCHEMA constant resolves to "claude-obsidian.transaction.v1". This string must appear in the schema field of any bundle submitted to the system, as defined at line 41 of claude_obsidian/transaction.py.
Where does Claude-Obsidian store transaction journals?
Journal entries persist under .vault-meta/transactions/<operation_id>/journal.json within the vault root. These files follow JOURNAL_SCHEMA and record write operations, pre-condition hashes, and timestamps to support rollback and recovery operations.
How does the system validate file paths in a transaction bundle?
Path validation occurs through the helper functions _normalize_vault_path and _assert_portable_write_path (lines 54–104 in claude_obsidian/transaction.py). These ensure paths remain within the vault directory and adhere to cross-platform portability constraints.
What operation types are valid for the operation_type field?
The operation_type must be one of the values defined in OPERATION_TYPES, which includes "save", "ingest", and "autoresearch". The safe_operation_id function validates the operation ID format at lines 35–51, while the operation type itself is checked against the permitted enumeration at lines 44–58.
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 →