Assertions
An assertion is a thing that makes a claim about another entity. 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, --name, 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 entity this assertion is about. It accepts the wref of any entity — a thing, a shape, a collection, another assertion, or the canonical cross-repo form of any of these (e.g. wh:org/repo/Location/cave). The only requirement is that the target exists at commit time. Assertion names follow the same naming conventions as things — hierarchical names work here too.
Pinning affirmed target versions at creation
Section titled “Pinning affirmed target versions at creation”When you create an assertion, you can supply an affirmedTargets field alongside about to record a snapshot of the specific wref versions the assertion is grounded in. This is the affirmation snapshot — a list of versioned wrefs that captures exactly which versions of which entities were considered when the assertion was made.
The affirmation snapshot concept surfaces under three different names depending on where you encounter it:
affirmedTargets— the field name you supply in write operations (CLI--affirmflag, SDKaffirmedTargetsproperty, MCPaffirmedTargetsarray)affirms:— the label printed bywh assertion viewin normal human-readable outputaffirmedWrefs— the structured field name returned in JSON/SDK responses
These are three surface-specific names for the same affirmation snapshot.
# CLI — use --affirm (repeatable) to supply each versioned wrefwh assertion create --shape Observation --name cave-safe --about Location/cave \ --affirm Location/cave@v3 --affirm Survey/cave-2024@v1 \ --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", affirmedTargets: ["Location/cave@v3", "Survey/cave-2024@v1"], 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", "affirmedTargets": ["Location/cave@v3", "Survey/cave-2024@v1"], "data": { "safe": true, "confidence": 0.8 } } ] }}The stored snapshot is readable back as affirmedWrefs in JSON/SDK responses. Use wh assertion view to inspect it in the terminal — the human-readable output labels the snapshot affirms::
wh assertion view Observation/cave-safe# affirms: ["Location/cave@v3", "Survey/cave-2024@v1"]You can also query assertions by the entities they affirmed. See Querying Assertions for examples.
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 same# Include --affirm flags to preserve the affirmation snapshotwh assertion revise Observation/cave-safe \ --affirm Location/cave@v3 --affirm Survey/cave-2024@v1 \ --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", affirmedTargets: ["Location/cave@v3", "Survey/cave-2024@v1"], 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", "affirmedTargets": ["Location/cave@v3", "Survey/cave-2024@v1"], "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.
Updating the Affirmation Snapshot
Section titled “Updating the Affirmation Snapshot”The affirmation snapshot set at creation can be updated independently of the assertion’s data using wh assertion reaffirm. This is useful when the underlying entities have been revised and you want to advance the snapshot to reflect the versions the assertion is now grounded in — without issuing a full data revise.
The reaffirm surface is delta-based: you supply --add and --remove flags (CLI), or add / remove arrays (SDK and MCP), to modify the existing snapshot incrementally.
# CLI — add and/or remove individual versioned wrefs from the snapshotwh assertion reaffirm Observation/cave-safe \ --add Location/cave@v5 --add Survey/cave-2024@v2 \ --remove Location/cave@v3 --remove Survey/cave-2024@v1 \ -m "Reaffirm against updated survey"// SDK — ReaffirmOperation accepts add and remove arraysawait client.commit.apply("myorg", "world", "Reaffirm against updated survey", [ { operation: "reaffirm", kind: "assertion", name: "Observation/cave-safe", add: ["Location/cave@v5", "Survey/cave-2024@v2"], remove: ["Location/cave@v3", "Survey/cave-2024@v1"], },])// MCP — warmhub_commit_submit{ "name": "warmhub_commit_submit", "arguments": { "orgName": "myorg", "repoName": "world", "operations": [ { "operation": "reaffirm", "kind": "assertion", "name": "Observation/cave-safe", "add": ["Location/cave@v5", "Survey/cave-2024@v2"], "remove": ["Location/cave@v3", "Survey/cave-2024@v1"] } ] }}After a reaffirm, wh assertion view Observation/cave-safe returns the updated snapshot under the affirms: label in human-readable output, or as affirmedWrefs in JSON/SDK responses. The previous snapshot is preserved in the assertion’s version history.
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.
Query by affirmed target version — find every assertion whose affirmation snapshot includes a specific versioned entity:
wh thing query --affirmed-about Location/cave@v3Browse 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 # equivalentAssertions About Collections
Section titled “Assertions About Collections”Collections are ordinary things, so assertions about groups use the same about model as assertions about single things. Create the named collection first, then assert about its wref:
[ { "operation": "add", "kind": "collection", "type": "arc", "name": "A-B", "members": ["Location/A", "Location/B"] }, { "operation": "add", "kind": "assertion", "name": "Distance/A-B", "about": "Arc/A-B", "data": { "value": 5 } }]The second operation references the collection by its named wref. In later commits, use the same collection wref directly:
{ "operation": "add", "kind": "assertion", "name": "Distance/A-B", "about": "Arc/A-B", "data": { "value": 5 }}Structured inline collection objects such as { "arc": ["Location/A", "Location/B"] } are not accepted in about.
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”WarmHub checks that the about target exists before creating the assertion. If the target does not exist, the write is rejected. 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.