Skip to content

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.

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

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.

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.

Terminal window
# CLI
wh assertion create --shape Observation --name cave-safe --about Location/cave --data '{"safe": true, "confidence": 0.8}'
// SDK
await 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 --affirm flag, SDK affirmedTargets property, MCP affirmedTargets array)
  • affirms: — the label printed by wh assertion view in normal human-readable output
  • affirmedWrefs — the structured field name returned in JSON/SDK responses

These are three surface-specific names for the same affirmation snapshot.

Terminal window
# CLI — use --affirm (repeatable) to supply each versioned wref
wh 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}'
// SDK
await 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::

Terminal window
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.

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).

Terminal window
# CLI — update the assertion's data; about stays the same
# Include --affirm flags to preserve the affirmation snapshot
wh assertion revise Observation/cave-safe \
--affirm Location/cave@v3 --affirm Survey/cave-2024@v1 \
--data '{"safe": false, "confidence": 0.3}' -m "Update observation"
// SDK
await 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:

  1. Retract the mis-targeted assertion
  2. Create a new assertion pointing at the correct target
Terminal window
# CLI
wh 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 commit
await 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.

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 version
  • about: "Location/cave@v3" — explicit pin to version 3
  • about: "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.

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.

Terminal window
# CLI — add and/or remove individual versioned wrefs from the snapshot
wh 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 arrays
await 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.

List all assertions about a specific thing:

Terminal window
wh thing about Location/cave

From 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:

Terminal window
wh thing about Location/cave --shape Observation

Include child assertions about the returned assertions:

Terminal window
wh thing about Location/cave --depth 2

wh 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:

Terminal window
wh thing query --affirmed-about Location/cave@v3

Browse all assertions in HEAD:

Terminal window
wh assertion list
wh assertion list --shape Observation

To inspect one assertion’s full details, use wh assertion view (or equivalently wh thing view, since assertions are things):

Terminal window
wh thing about Location/cave --shape Observation
wh assertion view Observation/cave-safe
wh thing view Observation/cave-safe # equivalent

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.

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?

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:

Terminal window
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"

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.