How the Claim Ledger Connects Source Evidence to Knowledge Assertions in Claude-Obsidian
The claim ledger connects knowledge assertions to source evidence through stable identifiers and structured JSON evidence arrays that enforce provenance, freshness, and independence constraints.
In the claude-obsidian repository, provenance is managed through a dual-ledger system that separates raw evidence from derived knowledge. The claim ledger serves as the bridge that ties every assertion back to auditable source material using cryptographically stable identifiers and rigorous validation rules.
The Dual-Ledger Architecture
Claude-obsidian maintains provenance in two complementary JSON files stored in the vault's wiki/meta/ledgers/ directory:
- Source ledger (
wiki/meta/ledgers/source-ledger.json): Catalogs every piece of raw evidence with its origin, content hash, authority, and review status. - Claim ledger (
wiki/meta/ledgers/claim-ledger.json): Stores knowledge assertions alongside risk assessments and an evidence array that references entries in the source ledger.
This separation ensures that source material exists independently of the claims that reference it, enabling multiple assertions to draw from the same evidence without duplication.
Creating Stable Source Identifiers
The connection begins with deterministic ID generation in claude_obsidian/ledgers.py. The stable_source_id() function (lines 7-14) produces immutable identifiers by hashing a canonical representation of the source:
from claude_obsidian.ledgers import stable_source_id
# Generate a deterministic source ID
origin_kind = "url"
canonical_locator = "https://example.com/article.pdf"
content_sha256 = "d2d2d2..." # 64-character hex string
src_id = stable_source_id(origin_kind, canonical_locator, content_sha256)
# Returns: "src-a1b2c3d4e5f6..."
The function constructs a hash input using the pattern "{origin_kind}\0{canonical_locator}\0{content_sha256}", ensuring that identical source content always produces the same identifier regardless of when or where it is registered.
Recording and Validating Sources
Once generated, the source ID serves as the key in the source ledger. The validate_source_ledger function (lines 1018-1025) enforces that the ID matches the canonical identity derived from the stored origin and content hash. A complete source entry includes:
origin: Kind and locator (file path or URL)content_sha256: SHA-256 hash of the contentauthority: Trust level (e.g.,official,community)review_status: Current state (active,stale,rejected)pages: Array of wiki pages citing this source
from claude_obsidian.ledgers import empty_source_ledger
source_ledger = empty_source_ledger()
source_ledger["sources"][src_id] = {
"origin": {"kind": "url", "locator": "https://example.com/article.pdf"},
"content_kind": "document",
"title": "Example Article",
"authority": "official",
"content_sha256": content_sha256,
"review_status": "active",
"pages": ["wiki/articles/example.md"],
}
Linking Claims to Evidence
The claim ledger establishes connections through an evidence array within each claim object. Every element in this array is a structured object containing:
{
"source_id": "src-a1b2c3d4e5f6...",
"relation": "supports",
"locator": "optional section reference"
}
Valid relations are defined in the EVIDENCE_RELATIONS constant: supports, contradicts, or context. When validating the claim ledger, validate_claim_ledger (lines 1054-1064) verifies that every source_id resolves to an existing entry in the source ledger and that the relation type is valid.
from claude_obsidian.ledgers import empty_claim_ledger
claim_ledger = empty_claim_ledger()
claim_ledger["claims"]["clm-001"] = {
"text": "The article confirms that X is true.",
"risk": "normal",
"assessment": "accepted",
"confidence": "high",
"location": {"path": "wiki/knowledge/x_is_true.md"},
"reviewed_at": "2024-09-01",
"evidence": [
{"source_id": src_id, "relation": "supports"}
],
}
Enforcing Evidence Quality and Independence
The validation layer applies sophisticated rules to ensure claims rest on verifiable foundations. For a claim to receive an accepted assessment, the validator (lines 987-1000) requires at least one fresh active support—a source with review_status == "active" that has not exceeded its freshness threshold.
High-risk accepted claims face stricter requirements: they must demonstrate two independent sources. The _independent_group_count function groups sources by identical origin, content hash, or declared independence key to prevent circular reasoning from duplicate or derivative sources.
Each claim also records a location object specifying the wiki page path and optional anchor (^block-id or #heading). The validator cross-references these against _markdown_anchor_sets to confirm that the claimed location actually exists in the vault's Markdown files.
Running Complete Validation
To verify the integrity of the entire provenance chain:
from claude_obsidian.ledgers import validate_source_ledger, validate_claim_ledger
src_errors = validate_source_ledger(source_ledger)
clm_errors = validate_claim_ledger(claim_ledger, source_ledger)
assert not src_errors, "Source ledger validation failed"
assert not clm_errors, "Claim ledger validation failed"
The claim ledger validation specifically checks that all source references resolve correctly, that evidence relations are valid, and that freshness and independence constraints meet the thresholds defined by the claim's risk level.
Summary
- Dual-ledger design: The claim ledger references the source ledger via stable IDs, maintaining separation between evidence and assertions.
- Cryptographic stability: Source IDs are deterministically generated from content hashes, ensuring immutable provenance links.
- Structured evidence: Claims link to sources through typed relations (
supports,contradicts,context) with optional locators. - Quality enforcement: Validation requires fresh active supports and independent sourcing for high-risk claims.
- Location verification: Every claim tracks its wiki page location and anchor, validated against actual Markdown content.
Frequently Asked Questions
What is the difference between the source ledger and claim ledger in claude-obsidian?
The source ledger (wiki/meta/ledgers/source-ledger.json) catalogs raw evidence files, URLs, and manual entries with their content hashes and review status. The claim ledger (wiki/meta/ledgers/claim-ledger.json) contains knowledge assertions and metadata (risk, confidence, assessment) along with evidence arrays that point to specific entries in the source ledger. This separation allows multiple claims to reference the same source without duplication.
How does the system ensure source identifiers remain stable over time?
The stable_source_id() function in claude_obsidian/ledgers.py generates deterministic identifiers by hashing a canonical string composed of the origin kind, locator, and content SHA-256. This ensures that identical source material always produces the same src-... identifier, preventing broken links when sources are re-imported or synchronized across different vault instances.
What validation rules ensure claims rest on verifiable evidence?
The validate_claim_ledger function enforces that every source_id in a claim's evidence array exists in the source ledger and that the relation value belongs to EVIDENCE_RELATIONS. Additionally, accepted claims must have at least one fresh active support (not stale, status active), and high-risk claims require two independent sources as calculated by _independent_group_count.
How does the claim ledger handle conflicting evidence for a single assertion?
The evidence array supports multiple entries with different relations, allowing a claim to simultaneously reference sources that support, contradict, or provide context for the assertion. The validation logic evaluates the net evidence state based on source authority and freshness, though the current implementation leaves final assessment decisions to human reviewers who weigh the conflicting sources recorded in the ledger.
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 →