# Where Is the Claude-Obsidian Source Ledger Stored? Schema and Fields Explained

> Discover where the Claude-Obsidian source ledger is stored and explore its schema fields including uri, type, and retrieved. Learn about its structure within your vault.

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

---

**The Claude-Obsidian source ledger is stored at [`wiki/meta/ledgers/source-ledger.json`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/wiki/meta/ledgers/source-ledger.json) inside each vault and contains fields including `uri`, `type`, `retrieved`, `refresh_due`, `sha256`, `pages_created`, and optional `metadata`.**

Claude-Obsidian tracks provenance for every ingested source in a structured **source ledger** that lives within your vault's file system. According to the AgriciDaniel/claude-obsidian source code, this JSON file follows a strict schema to ensure data integrity across remote URLs and local files. Understanding its location and field structure is essential for developing plugins, debugging ingestion pipelines, or manually auditing source provenance.

## File Location and Schema Version

The source ledger persists as a JSON file at a canonical path relative to your vault root. As referenced in the test suite at [`tests/test_lint_engine.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/tests/test_lint_engine.py) (lines 460–465), the expected location is:

```text
wiki/meta/ledgers/source-ledger.json

```

This file conforms to the schema identifier **`claude-obsidian.source-ledger.v1`**, with validation logic implemented in [`claude_obsidian/ledgers.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/claude_obsidian/ledgers.py) (lines 421–514). The top-level structure contains a single key, **`"sources"`**, which maps stable source identifiers to their respective provenance records.

## Field Definitions and Data Types

Each entry under the `sources` object is a dictionary containing the following fields. According to the validation routine in [`claude_obsidian/ledgers.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/claude_obsidian/ledgers.py), the schema distinguishes between remote URLs, local files, and raw manifest entries through the `type` field.

**`uri`** (string): The absolute HTTPS URL for remote resources or the file path for ingested local files. Remote sources must use absolute HTTPS URIs (validated at line 542).

**`type`** (string): Specifies the source origin. Valid values include `"url"` for remote HTTP(S) resources, `"file"` for local ingested files, and `"raw"` for raw manifest entries.

**`retrieved`** (string, ISO-8601 datetime): The timestamp when the content was fetched or ingested. Required for active remote sources and file sources (enforced at line 646).

**`refresh_due`** (string, ISO-8601 datetime): The scheduled refresh timestamp for active remote sources. Required alongside `retrieved` for any source marked as active (lines 646–652).

**`sha256`** (string): The SHA-256 hash of the retrieved content. Mandatory for ingested file sources and active remote sources (required at line 633).

**`pages_created`** (array of strings): Paths to wiki pages generated from this source during ingestion. Tracks which vault files depend on the source record.

**`metadata`** (object, optional): Container for additional provenance data such as HTTP headers, ETags, or custom skill attachments.

## Validation Logic and Constraints

The **`validate_source_ledger`** function in [`claude_obsidian/ledgers.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/claude_obsidian/ledgers.py) enforces structural integrity through type-specific rules. At line 421, it first verifies that `sources` is an object. Then, for each record, it applies conditional requirements based on the `type` field (lines 542–652).

Remote sources undergo strict URI validation to ensure they use absolute HTTPS paths. File sources must provide both a SHA-256 hash and a retrieval timestamp. Active sources require both `retrieved` and `refresh_due` fields to prevent stale data from persisting indefinitely.

When validation fails, the system emits structured error objects containing a JSON Pointer path (e.g., `"sources.<source_id>.uri"`) and a human-readable message. This error-building logic resides at line 914 in [`claude_obsidian/ledgers.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/claude_obsidian/ledgers.py).

## Working with the Source Ledger in Python

The `claude_obsidian.ledgers` module provides functions to load, modify, and validate the ledger programmatically. The **`stable_source_id`** helper generates deterministic identifiers by hashing the URI, ensuring consistent source tracking across sessions.

```python
import json
from pathlib import Path
from claude_obsidian.ledgers import (
    load_source_ledger,
    validate_source_ledger,
    stable_source_id,
)

# Load the ledger from the current vault

vault_root = Path.cwd()
ledger_path = vault_root / "wiki" / "meta" / "ledgers" / "source-ledger.json"
ledger = load_source_ledger(ledger_path)

# Add a new remote source with a stable ID

new_source = {
    "uri": "https://example.com/article.html",
    "type": "url",
    "retrieved": "2026-08-26T12:34:56Z",
    "refresh_due": "2026-09-26T12:34:56Z",
}
source_id = stable_source_id(new_source["uri"])
ledger["sources"][source_id] = new_source

# Validate before saving

errors = validate_source_ledger(ledger)
if errors:
    for error in errors:
        print(f"Validation error at {error['path']}: {error['message']}")
else:
    ledger_path.write_text(json.dumps(ledger, indent=2))
    print("Source ledger updated successfully")

```

## Summary

- The Claude-Obsidian source ledger resides at **[`wiki/meta/ledgers/source-ledger.json`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/wiki/meta/ledgers/source-ledger.json)** within each vault.
- It follows the **`claude-obsidian.source-ledger.v1`** schema defined in [`claude_obsidian/ledgers.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/claude_obsidian/ledgers.py).
- The top-level **`sources`** key maps stable IDs to provenance records containing fields like `uri`, `type`, `sha256`, and timestamps.
- **`validate_source_ledger`** enforces type-specific requirements (HTTPS for URLs, hashes for files) and reports errors with JSON Pointer paths.
- Use helper functions like **`stable_source_id`** and **`load_source_ledger`** to interact with the ledger programmatically.

## Frequently Asked Questions

### What is the exact file path for the Claude-Obsidian source ledger?

The source ledger is stored at [`wiki/meta/ledgers/source-ledger.json`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/wiki/meta/ledgers/source-ledger.json) relative to your vault root directory. This path is hardcoded in the validation tests at [`tests/test_lint_engine.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/tests/test_lint_engine.py) (lines 460–465) and is the canonical location the ingestion pipeline reads from and writes to.

### What schema version does the source ledger use?

The ledger conforms to the **`claude-obsidian.source-ledger.v1`** schema. This version identifier is referenced in the validation logic within [`claude_obsidian/ledgers.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/claude_obsidian/ledgers.py) (lines 421–514) and governs the structure of the JSON document.

### Which fields are required for remote URL sources versus local files?

Remote URL sources require an absolute HTTPS `uri`, `type: "url"`, `retrieved` timestamp, `refresh_due` timestamp, and `sha256` hash. Local file sources require `type: "file"`, `sha256`, and `retrieved`, but do not require `refresh_due`. These constraints are enforced in [`claude_obsidian/ledgers.py`](https://github.com/AgriciDaniel/claude-obsidian/blob/main/claude_obsidian/ledgers.py) between lines 542 and 652.

### How does the validation system report schema errors?

The **`validate_source_ledger`** function returns a list of error objects, each containing a `path` field with a JSON Pointer (e.g., `"sources.abc123.uri"`) and a `message` field describing the constraint violation. This structured format, built by the helper at line 914, enables precise debugging of malformed ledger entries.