# What Information Is Stored in the Source Ledger in claude-obsidian

> Discover what the source ledger in claude-obsidian stores: SHA-256 hashes, page references, and metadata. Build immutable audit trails and enable selective re-ingestion for compound vaults.

- Repository: [Agrici.Daniel/claude-obsidian](https://github.com/AgriciDaniel/claude-obsidian)
- Tags: internals
- Published: 2026-08-28

---

**The source ledger in claude-obsidian stores SHA-256 content hashes, generated page references, and provenance metadata for every raw input source, enabling immutable audit trails and selective re-ingestion in compound vaults.**

The **source ledger** is the immutable provenance backbone of the claude-obsidian vault system. Located in [`.raw/.manifest.json`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/.raw/.manifest.json), it maintains a complete record of **content identity** and **downstream dependencies** for every raw file ingested into the repository. According to the AgriciDaniel/claude-obsidian source code, this separation between raw evidence and generated wiki prose enables atomic rollbacks and incremental updates without losing provenance history.

## Core Data Structure of the Source Ledger

Each entry in the source ledger maps a raw file path to a metadata object containing four critical information categories.

### Content Identity via SHA-256 Hashes

The `hash` field stores a 64-character **SHA-256 hash** of the source file's content. As implemented in [`claude_obsidian/ledgers.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/claude_obsidian/ledgers.py), this guarantees that any modification to the underlying data can be cryptographically detected, triggering selective re-ingestion only for changed sources.

Example from the test suite:

```json
"hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"

```

### Generated Page References

The `pages_created` field contains an array of wiki page paths generated from the source. This creates a bidirectional dependency graph that the transaction engine uses to invalidate stale outputs. For example:

```json
"pages_created": ["wiki/A.md", "wiki/sources/First.md"]

```

### Provenance Metadata

The source ledger documents high-level **authority**, **independence**, and **freshness** attributes for each source. These fields describe who created the evidence, whether it stands independent of other claims, and its temporal validity. The compound vault architecture in [`docs/compound-vault-guide.md`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/docs/compound-vault-guide.md) treats these as first-class provenance signals.

### Optional Address Mapping

The `address_map` field provides an optional mapping between absolute file paths and logical identifiers used by downstream processes. While present in the overall manifest structure, this field is not required for every source entry.

## Storage Location and Schema Enforcement

The source ledger persists as a JSON object under the `sources` key in [`.raw/.manifest.json`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/.raw/.manifest.json). The **SOURCE_SCHEMA** constant in [`claude_obsidian/ledgers.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/claude_obsidian/ledgers.py) enforces strict validation rules:

- The top-level ledger must be an object
- Each source record must contain a valid `hash` string of exactly 64 characters
- The `pages_created` array, when present, must contain only strings

## Dependencies and Validation Constraints

When a **claim ledger** exists in the vault, the system mandates a corresponding source ledger. Both [`claude_obsidian/transaction.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/claude_obsidian/transaction.py) and [`claude_obsidian/lint_engine.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/claude_obsidian/lint_engine.py) raise `"source ledger is required when a claim ledger exists"` errors if this invariant is violated. This ensures that every asserted claim remains traceable to verifiable raw evidence.

## Working with the Source Ledger Programmatically

The claude-obsidian SDK provides atomic operations for reading and writing source entries.

Adding a source entry via Python:

```python
from claude_obsidian import ledgers, transaction

# Load current manifest from .raw/.manifest.json

manifest = transaction.read_manifest()

# Create a new source record

source_id = ".raw/example.md"
source_record = {
    "hash": "3d2e1f... (64-char SHA-256)",
    "pages_created": ["wiki/Example.md"]
}

# Insert into the source ledger

manifest.setdefault("sources", {})[source_id] = source_record

# Write back (the SDK handles validation)

transaction.write_manifest(manifest)

```

Capturing sources via CLI:

```bash
claude-obsidian capture \
  --source ".raw/new-data.md" \
  --pages "wiki/NewData.md"

```

## Summary

- The **source ledger** in [`.raw/.manifest.json`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/.raw/.manifest.json) maintains immutable records of every ingested raw file in claude-obsidian.
- Each entry stores a **64-character SHA-256 hash**, a list of generated **pages_created**, and provenance metadata (**authority**, **independence**, **freshness**).
- The `SOURCE_SCHEMA` in [`claude_obsidian/ledgers.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/claude_obsidian/ledgers.py) enforces data integrity and type safety.
- The ledger is **required** whenever a claim ledger exists, ensuring complete audit trails from claims back to raw evidence.
- Functional implementations appear in [`claude_obsidian/ledgers.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/claude_obsidian/ledgers.py), [`transaction.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/transaction.py), and [`lint_engine.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/lint_engine.py), with test coverage in [`tests/test_ledgers.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/tests/test_ledgers.py).

## Frequently Asked Questions

### What is the exact hash format required for source entries?

The source ledger requires **SHA-256 hashes** represented as 64-character hexadecimal strings. The validation logic in [`claude_obsidian/ledgers.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/claude_obsidian/ledgers.py) explicitly checks the string length to ensure cryptographic integrity.

### Is the source ledger mandatory in all claude-obsidian vaults?

No. The source ledger becomes **mandatory only when a claim ledger is present**. Both [`transaction.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/transaction.py) and [`lint_engine.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/lint_engine.py) enforce this dependency, raising validation errors if claims exist without corresponding source provenance.

### Where is the source ledger physically stored?

The source ledger resides in **[`.raw/.manifest.json`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/.raw/.manifest.json)** under the `sources` key. This file contains the complete manifest including the address map and optional claim ledger, serving as the single source of truth for vault provenance.

### Can I store additional custom fields in source ledger entries?

While the **SOURCE_SCHEMA** enforces strict typing for `hash` and `pages_created`, the documented provenance fields (**authority**, **independence**, **freshness**) and optional `address_map` provide extensible metadata hooks without breaking validation.