Assertions
An assertion is a thing that makes a claim about another thing. It has its own shape, name, and version history — but it also carries an about reference linking it to its subject.
When to Use Assertions
Section titled “When to Use Assertions”Assertions are the right choice when:
- Attribution matters — you need to know who said something about an entity, not just the current state
- Multiple perspectives coexist — different agents or sources have different views on the same thing
- Confidence varies — assertions carry uncertainty, evidence, or scores that evolve over time
- History of assertions matters — you want to trace how understanding of an entity changed
In practice, assertions are the primary way to model agent observations, opinion-bearing assertions, relationships between things (via collections), evaluations and judgments, and any attributed metadata about an existing entity.
Assertions may be unnecessary when:
- You’re storing plain facts with a single source of truth — a regular thing with revisions may be simpler
- The data doesn’t need attribution — if no one will ever ask “who said this?”, a thing is enough
- You’re modeling static reference data that rarely changes — shapes and things handle this well on their own
Assertions with subjective-logic opinions
Section titled “Assertions with subjective-logic opinions”When you want to capture how confident an agent is about an assertion — not just what it asserted — attach a Subjective Logic opinion to the assertion. The opinion is a tuple (b, d, u, α) — belief, disbelief, uncertainty, and a base rate — and requires the assertion’s underlying proposition to be binary (true or false).
Veritas is the WarmHub component that consumes and revises these opinions across sources. Its Certainty shape is the canonical form for opinions Veritas writes about another assertion.
Keep opinion metadata in a separate assertion from the data being asserted — see Opinions as Separate Assertions for the full pattern and the binomial-opinion constraint.
Creating Assertions
Section titled “Creating Assertions”The same add assertion operation works on every surface — the CLI exposes --shape, --about, and --data as flags, while the SDK and MCP nest the same values inside a commit operation. See Write operations for the full contract.
# CLIwh assertion create --shape Observation --name cave-safe --about Location/cave --data '{"safe": true, "confidence": 0.8}'// SDKawait client.commit.apply("myorg", "world", "Assert cave safety", [ { operation: "add", kind: "assertion", name: "Observation/cave-safe", about: "Location/cave", data: { safe: true, confidence: 0.8 }, },])// MCP — warmhub_commit_submit{ "name": "warmhub_commit_submit", "arguments": { "orgName": "myorg", "repoName": "world", "operations": [ { "operation": "add", "kind": "assertion", "name": "Observation/cave-safe", "about": "Location/cave", "data": { "safe": true, "confidence": 0.8 } } ] }}The confidence: 0.8 field in this example is generic payload data, not a Subjective Logic opinion — see Assertions with subjective-logic opinions for that pattern.
The about field specifies which thing this assertion is about. It accepts local wrefs (Location/cave), canonical wrefs (wh:org/repo/Location/cave), or inline collection syntax ({ "pair": ["Location/A", "Location/B"] }). Assertion names follow the same naming conventions as things — hierarchical names work here too.
Immutable About
Section titled “Immutable About”The about target is set at creation and cannot be changed. On revise, you can update the assertion’s data, but never its about reference (use retract to mark an assertion inactive):
# CLI — update the assertion's data; about stays the samewh assertion revise Observation/cave-safe --data '{"safe": false, "confidence": 0.3}' -m "Update observation"// SDKawait client.commit.apply("myorg", "world", "Update observation", [ { operation: "revise", kind: "assertion", name: "Observation/cave-safe", data: { safe: false, confidence: 0.3 } },])// MCP — warmhub_commit_submit{ "name": "warmhub_commit_submit", "arguments": { "orgName": "myorg", "repoName": "world", "operations": [ { "operation": "revise", "kind": "assertion", "name": "Observation/cave-safe", "data": { "safe": false, "confidence": 0.3 } } ] }}This immutability is a core design principle — it guarantees that the relationship between an assertion and its subject is stable and auditable.
If you assert to the wrong target by mistake, the recovery path is:
- Retract the mis-targeted assertion
- Create a new assertion pointing at the correct target
# CLIwh assertion retract Observation/cave-safe --reason "Wrong target — meant Location/dungeon"wh assertion create --shape Observation --name dungeon-safe --about Location/dungeon --data '{"safe": true, "confidence": 0.8}'// SDK — both steps in one commitawait client.commit.apply("myorg", "world", "Re-target observation", [ { operation: "retract", name: "Observation/cave-safe", reason: "Wrong target — meant Location/dungeon" }, { operation: "add", kind: "assertion", name: "Observation/dungeon-safe", about: "Location/dungeon", data: { safe: true, confidence: 0.8 } },])// MCP — warmhub_commit_submit{ "name": "warmhub_commit_submit", "arguments": { "orgName": "myorg", "repoName": "world", "operations": [ { "operation": "retract", "name": "Observation/cave-safe", "reason": "Wrong target — meant Location/dungeon" }, { "operation": "add", "kind": "assertion", "name": "Observation/dungeon-safe", "about": "Location/dungeon", "data": { "safe": true, "confidence": 0.8 } } ] }}The retracted assertion remains in the version history for auditability, but is hidden from default queries.
Version Pinning
Section titled “Version Pinning”When you create an assertion, the about target is version-pinned to the exact version of the subject at commit time:
about: "Location/cave"— bare wref, auto-pinned to current HEAD versionabout: "Location/cave@v3"— explicit pin to version 3about: "Location/cave@HEAD"— resolved to current HEAD version number
This is the write-path behavior — bare wrefs in commit operations always resolve to @HEAD. Read operations may resolve bare wrefs differently depending on the endpoint (see Version Modifiers for full defaults).
The pinned version is recorded alongside the assertion as the precise version the assertion was made about. This means you can always answer “which version of cave was this assertion about?”
Because the target is version-pinned, retracting or renaming it never orphans the assertion — see Retract, Rename & Schema Changes.
Querying Assertions
Section titled “Querying Assertions”List all assertions about a specific thing:
wh thing about Location/caveFrom the SDK, client.thing.about returns { target, assertions, nextCursor } — the array is named assertions, not items. (HeadResult, FilterResult, SearchResult, RefsResult, and LogResult all use items; AboutResult is the outlier.)
const { target, assertions } = await client.thing.about("acme", "world", "Location/cave");for (const a of assertions) { console.log(a.wref, a.shapeName);}Filter by shape:
wh thing about Location/cave --shape ObservationInclude child assertions about the returned assertions:
wh thing about Location/cave --depth 2wh assertion list --about Location/cave is the equivalent assertion-domain form when you are already browsing assertions.
Browse all assertions in HEAD:
wh assertion listwh assertion list --shape ObservationTo inspect one assertion’s full details, use wh assertion view
(or equivalently wh thing view, since assertions are things):
wh thing about Location/cave --shape Observationwh assertion view Observation/cave-safewh thing view Observation/cave-safe # equivalentInline Syntax
Section titled “Inline Syntax”The about field supports structured collection objects for making assertions about groups of things:
{ "operation": "add", "kind": "assertion", "name": "Distance/A-B", "about": { "pair": ["Location/A", "Location/B"] }, "data": { "value": 5 }}This automatically creates a Pair collection thing and pins the assertion to it. See Collections for the full syntax.
Designing About References
Section titled “Designing About References”The about reference is more than a foreign key — it’s a modeling decision that determines how assertions cluster around subjects. Choose your about targets thoughtfully.
The about ref defines your navigation axis
Section titled “The about ref defines your navigation axis”The about target determines what you’ll browse by. If you assert about Company/acme, you can later query “everything we’ve asserted about Acme.” If you instead assert about Filing/acme/10-k/2024, your assertions cluster around individual filings — a different navigation axis.
Choose based on how agents and humans will explore the data: what will you most often want to ask “what do we know about X?” for?
About targets must exist
Section titled “About targets must exist”The write pipeline resolves the about wref and verifies that the target thing exists. If the target doesn’t exist, the assertion operation fails with a NOT_FOUND error. This means you cannot assert about an entity before it has been added.
If you need to create a thing and immediately assert about it, put both operations in one write request — the thing is created before the assertion is resolved:
wh commit submit --ops '[ {"operation": "add", "kind": "thing", "name": "Company/acme", "data": {"industry": "fintech"}}, {"operation": "add", "kind": "assertion", "name": "Thesis/acme-bull", "about": "Company/acme", "data": {"outlook": "bullish"}}]' -m "Add company with initial thesis"Put identifying data in the payload
Section titled “Put identifying data in the payload”Don’t rely solely on the about wref to carry key identifiers. If an assertion is about Company/acme, include the company name or ticker in the assertion’s data too — this makes the assertion self-describing when read in isolation, without requiring a follow-up query to resolve the about target.
Hit a problem or have a question? Get in touch.