How Claims Are Tracked and Assessed in Claude-Obsidian's Claim Ledger

The claim ledger stores falsifiable statements with structured metadata including risk levels, evidence links, and assessment states, enforcing strict validation rules for location integrity, source freshness, and evidentiary independence.

The AgriciDaniel/claude-obsidian repository implements a rigorous provenance system through its claim ledger functionality. Every falsifiable statement is tracked in a JSON file located at wiki/meta/ledgers/claim-ledger.json, following the schema "claude-obsidian.claim-ledger.v1". This system ensures that factual assertions within your Obsidian vault remain traceable to verifiable evidence through automated validation and assessment logic.

Claim Data Model and Core Fields

Each entry in the claim ledger is a dictionary keyed by a safe claim identifier (e.g., clm-001) and must conform to strict validation rules defined in claude_obsidian/ledgers.py.

The claim data model requires the following fields:

Field Purpose Validation Source
text The falsifiable statement as a non-empty Unicode scalar string. Checked at lines 949-953
risk Either "normal" or "high", determining independence requirements. Validated at lines 955-958
assessment One of "accepted", "provisional", "contested", "unsupported", or "deprecated". Validated at lines 959-961
confidence "high", "medium", "low", or "unknown". Validated at lines 962-964
location Object with path (vault-relative) and optional anchor (heading or block ID). Path sanity at lines 965-981; anchor existence at lines 918-924
reviewed_at ISO date when formally reviewed; required for accepted claims. Parsed at lines 930-934; future-date guard at lines 940-945
notes Optional free-form commentary; must be scalar text if present. Checked at lines 946-950
supersedes Optional reference to a previous claim ID (clm-…). Validated at lines 951-953
evidence Array of objects linking to source IDs (src-…) with relations supports, contradicts, or context. Structure at lines 954-966; relation checks at lines 970-974

Claim Identification and Location Integrity

Safe Claim ID Format

Every claim identifier must match the regex ^clm-[A-Za-z0-9][A-Za-z0-9._-]* as enforced by the _safe_ledger_id function (lines 659-664). The validator checks this pattern at the start of each record (line 944).

Location Anchoring

The location field guarantees that claims appear on specific wiki pages:

  • The path must be a canonical vault-relative wiki path (wiki/...). The validator rejects absolute paths, upward traversal (..), non-scalar characters, or illegal characters (lines 970-977).
  • If an anchor is supplied, the target page is read via read_vault_regular and its headings or block IDs are extracted by _markdown_anchor_sets. The anchor must exist as a heading (# Heading) or a block (^block-id) (lines 918-924).

Evidence-Based Assessment Logic

The validate_claim_ledger function implements sophisticated logic to determine claim validity based on linked evidence in the source ledger.

Fresh Active Support Requirements

Supporting evidence must meet fresh active support criteria:

  1. Valid origin: Passes _source_origin_is_valid (lines 661-686).
  2. Active status: review_status equals "active" and not synthetic (authority ≠ synthetic, content_kind ≠ synthetic).
  3. Not stale: Passes source_is_stale check (lines 752-758).
  4. Temporal validity: The source's retrieval/ingestion date precedes the claim's reviewed_at date.

This collection is built at lines 1102-1111.

Acceptance Rules

  • Accepted claims require at least one fresh supporting source (lines 1121-1127).
  • High-risk claims demand two independent sources. Independence is computed by _independent_group_count, which groups sources sharing the same origin, content hash, or declared independence_key (lines 897-903). Failure triggers an error at lines 1128-1132.

Handling Contradictory Evidence

When fresh contradictory sources exist (relation=="contradicts"):

  • An accepted claim must either be marked "contested" or provide explicit adjudication notes (lines 1136-1150).
  • Conversely, a claim marked "contested" must have at least one contradictory source or non-empty notes (lines 1152-1164).

Review Date Constraints and Migration

Review Date Validation

Accepted claims carry strict temporal requirements:

  • The reviewed_at field is mandatory when assessment == "accepted" (lines 935-939).
  • The review date cannot be later than the audit date (as_of parameter) (lines 940-945).

Legacy Migration

Legacy manifests are migrated to the new claim ledger format by migrate_legacy_manifest, which creates an empty claim ledger via empty_claim_ledger (lines 925-931) and validates the freshly built source ledger before returning both structures.

Practical Implementation Examples

Minimal Claim Ledger Structure

{
  "schema": "claude-obsidian.claim-ledger.v1",
  "generated_at": "2026-07-11T12:00:00Z",
  "claims": {
    "clm-001": {
      "text": "The moon's orbital period is 27.3 days.",
      "risk": "normal",
      "assessment": "accepted",
      "confidence": "high",
      "location": { "path": "wiki/Astronomy.md", "anchor": "Moon-orbit" },
      "reviewed_at": "2026-07-10",
      "notes": "Verified against NASA data.",
      "supersedes": null,
      "evidence": [
        { "source_id": "src-abc123def4567890", "relation": "supports" }
      ]
    }
  }
}

The src-… identifier must match the canonical source ID generated by stable_source_id (lines 707-714).

Validating Claims in Python

from pathlib import Path
from claude_obsidian.ledgers import validate_claim_ledger, empty_claim_ledger

# Load source ledger (normally produced by the source‑ledger validator)

source_ledger = ...  # dict from source‑ledger.json

# Build a claim ledger (could be edited by the user)

claim_ledger = empty_claim_ledger()
claim_ledger["claims"]["clm-001"] = {
    "text": "The moon's orbital period is 27.3 days.",
    "risk": "normal",
    "assessment": "accepted",
    "confidence": "high",
    "location": {"path": "wiki/Astronomy.md", "anchor": "Moon-orbit"},
    "reviewed_at": "2026-07-10",
    "evidence": [{"source_id": "src-abc123def4567890", "relation": "supports"}],
}

# Run validation (raises LedgerValidationError on failure)

errors = validate_claim_ledger(claim_ledger, source_ledger, vault_root=Path("/my/vault"))
if errors:
    for err in errors:
        print(f"{err['path']}: {err['message']}")
else:
    print("All claims are valid!")

Computing Stable Source IDs

from claude_obsidian.ledgers import stable_source_id

source_id = stable_source_id(
    origin_kind="url",
    locator="https://example.com/data.json",
    content_sha256="3a7bd3e2360a7e5c5b9d4a0f4e1c92f6d5a5e8e7b2c6d4a9f2e1c3b4d5f6a7b8"
)
print(source_id)   # e.g., "src-1f2e3d4c5b6a7e8d9c0"

Summary

  • The claim ledger (wiki/meta/ledgers/claim-ledger.json) stores every falsifiable statement using the schema "claude-obsidian.claim-ledger.v1" with mandatory fields for text, risk, assessment, confidence, location, and evidence.
  • Claim IDs must follow the regex ^clm-[A-Za-z0-9][A-Za-z0-9._-]* and locations must reference valid vault paths and existing anchors.
  • Accepted claims require at least one fresh supporting source, while high-risk claims demand two independent sources computed by _independent_group_count.
  • The validator enforces temporal constraints ensuring reviewed_at dates exist for accepted claims and never exceed the audit date.
  • Contradictory evidence triggers contested status requirements, ensuring claims with opposing sources are properly flagged or annotated.

Frequently Asked Questions

What file path does Claude-Obsidian use for the claim ledger?

The claim ledger is stored at wiki/meta/ledgers/claim-ledger.json relative to your vault root. This JSON file follows the schema "claude-obsidian.claim-ledger.v1" and contains all tracked claims keyed by their safe identifiers.

How does the system validate that a claim's location actually exists?

The validator checks the location.path against canonical vault-relative wiki paths (rejecting absolute paths or traversal patterns) at lines 970-977. If an anchor is provided, the system reads the target page via read_vault_regular and extracts headings or block IDs using _markdown_anchor_sets to verify the anchor exists (lines 918-924).

What constitutes a "fresh" supporting source for claim acceptance?

A fresh supporting source must have a valid origin per _source_origin_is_valid, carry review_status == "active", be non-synthetic, not be stale according to source_is_stale, and have a retrieval date preceding the claim's reviewed_at date. These criteria are evaluated at lines 1102-1111.

Why do high-risk claims require independent sources?

High-risk claims (where risk == "high") require two independent sources to prevent circular verification. The _independent_group_count function groups sources sharing the same origin, content hash, or independence_key (lines 897-903), and the validator enforces this requirement at lines 1128-1132 to ensure robust evidentiary support.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →