Skip to content

Retract, Rename & Schema Changes

WarmHub preserves data by default. You retract things instead of deleting them, you rename things in place, and you evolve shapes over time — and each of these keeps the full version history. Destroying data is possible, but it is a separate, privileged removal operation that you have to ask for by name. Each of these changes ripples outward to the wrefs, assertions, and collections that point at what you changed.

This page covers exactly what happens to those references in each case. It assumes you already know things, wrefs, and assertions.

ChangeNew version?Effect on references
Retract a thingYes — a retract versionNone — references keep pointing at the preserved version
Remove a thingNo — the thing and every version are deletedExisting references survive, marked removed; a new write that points at it is refused
Rename a thingNo — an in-place identity editIdentity-pinned references follow it; a wref using the old name breaks
Revise a shape (changed)Yes — a new shape versionNone — existing things are unchanged until their next write; things of a composite that composes the shape pick up the change only after the composite is revised
Revise a shape (identical to current)No — a no-op; current version kept. A composite whose member has a newer version is the exception: it gets a new versionNone — existing things are unchanged
Retract a shapeYes — a retract versionExisting things stay readable; new floating write references to the shape fail, while existing pinned versions remain valid

The throughline: assertions, wref data fields, and collection members written with @vN pin the exact version they referenced, and bare collection members follow their Thing by identity, so a retraction or a rename can never orphan them. Only an input wref that addresses an entity by its name is fragile, and only across a rename. Removal is the one exception to all of this — it destroys the target itself. Even then the references are not erased: they keep the removed thing’s durable id and read back marked as removed. What they can no longer do is reach a live thing, and a new write that points at a removed id is refused.

Retracting a thing marks it inactive. Its name, data, and full version history are preserved, and it is hidden from default queries. Retraction is how you withdraw something while keeping its history; to destroy a thing outright, see Removal below. See Operations — Retract for the operation itself and Things — Active/Inactive Lifecycle for the lifecycle.

What retraction does not do is cascade. Retracting a thing leaves everything that points at it in place:

Reference to the retracted thingWhat happens
Its own wrefHidden from default reads and listings — a plain wh thing view cave returns not-found. Its data and full version history are preserved and stay readable with --include-retracted or a pinned @vN version.
An assertion about itUntouched. The assertion still resolves and still points at the exact target version it was pinned to when created.
A collection that includes itUntouched, with no new collection version. How the member points at it depends on how it was written: a member written with @vN is version-pinned and still resolves to that version; a bare member is an identity reference that follows the Thing.
A subscriptionA retract is a write operation, so a subscription whose filter matches retract fires on it. See Subscription Filters.

Because assertions and @vN collection members pin the exact version they referenced, and bare members point at the Thing’s identity, a retraction can never orphan them — the retracted Thing and its versions still exist.

Removing a thing permanently deletes it and every one of its versions. This cannot be undone: unlike retraction, the thing itself is gone and no version of it can be read again. What survives is other people’s references to it, which keep its durable id and read back marked as removed.

Removal is deliberately hard to reach:

  • It needs unrestricted repository admin access. A token narrowed to particular names is refused outright — there is no permission to delete only part of a repository. See Access reference.
  • Write access is not enough. Being able to create and revise things does not let you destroy them.
  • wh thing remove prompts for confirmation unless you pass --yes. Use --dry-run to preview, and --expected-version to remove only if the thing is still at the version you read.
Terminal window
wh thing remove old-cave --dry-run
wh thing remove old-cave --expected-version 3 --yes

A retracted thing must be named by its durable ID rather than a wref, because retracted names are not unique — wh thing resolve <wref> prints it on the durableId: line before you retract. The MCP tool takes the durable ID in every case.

You can preview a removal before running it: the TypeScript SDK validates a remove operation against the server and reports what it would destroy, then client.thing.remove(...) carries it out. Preview is not available from the Python SDK today — there, use the CLI’s --dry-run. See SDK Write Methods.

Removals do not trigger subscriptions. A subscription filtering on remove never fires, and nothing else announces the removal either — it leaves no subscription-visible trail at all. Do not build a workflow that expects to be told when something is destroyed: if you need a record of removals, write one yourself at the point you perform them.

Renaming changes a thing’s name in place — wh thing rename cave cavern, or client.thing.rename in the SDK. Both arguments are plain thing names, and the shapes the thing declares are unaffected by the rename. It does not create a new version, so a rename does not appear in wh thing history and the old name is not readable back through the history commands today. Plan as though the old name is not recoverable: if you need to know a thing’s former names, record them yourself.

That makes the rule simple: references that point by identity follow the rename; references that use the old name break.

Reference to the renamed thingWhat happens
An assertion about itFollows the rename. Assertions link to their target by identity, so reading the assertion — or querying what it is about — resolves to the thing under its new name automatically.
A collection that includes itFollows the rename. Collection members are pinned by identity, so the member resolves to the new name automatically. Nothing dangles.
Its durable idUnaffected. A durable id names a thing by identity, so it survives every rename.
A wref that uses the old nameBreaks. Every old spelling, including @HEAD and @vN, returns not-found. There is no redirect; use the new name to address both current and historical versions.
A subscriptionNot re-evaluated. A rename is not a write operation, so it never triggers subscription matching (see below).

Shapes rename the same way: wh shape rename (or client.shape.rename) patches the shape’s name in place, preserves its history, and creates no new version. Things keep validating against it, because they reference their shape by identity. If Player becomes Participant, old spellings such as Player and Player@v2 stop resolving; Participant and Participant@v2 resolve the current and historical definitions.

Subscriptions match write operations as they happen — an add, a revise, or a retract carrying a name, shape, and kind. A rename is not a write operation, so it produces nothing for a subscription to match.

The practical consequence: renaming a thing into or out of a subscription’s name pattern — a glob match like Product/electronics/** — does not notify that subscription. The renamed thing matches it again only the next time it is written (its next revise or retract, under the new name).

Renames are not invisible everywhere, though. A repository can subscribe to the thing.renamed and shape.renamed metadata events, which do fire on a rename and carry the old and new names. Use those if you need to react to renames; a name-pattern subscription on write operations will not do it. Removal has no equivalent — see Removal and subscriptions.

Revising a shape replaces its field definitions — it is a full replacement, like any revise. You can add fields (optional or required), remove fields, or rename them.

If the revised shape is identical to the current version, the operation succeeds as a no-op and no new version is created. Only a changed revise produces a new shape version.

Existing things are not re-validated when the shape changes. They keep their data and stay valid against the shape version they were written under. The new shape is enforced the next time each thing is written.

A shape that a composite shape composes is the exception: things written under the composite validate against the member version the composite captured. They pick up the revised member only after the composite itself is revised, because every composite revise re-captures its members at their current versions. That composite revise is refused if the revised member now conflicts with the composite.

Adding a required field is therefore backwards-incompatible in a specific way: existing things stay valid until you next revise one, and that next revise must satisfy the new shape. Shapes — Back-Filling Required Fields covers the two migration strategies: back-fill on next revise, or mass-revise every thing immediately. To avoid the incompatibility entirely, add the field as optional.

Shapes can be retracted, with two restrictions: the built-in shapes (Arc, Bond, Pair, Set, List, Content, View, LicenseSubject, LicenseDeclaration) cannot be — View, LicenseSubject, and LicenseDeclaration are materialized lazily on first write, so the name is reserved whether or not the shape exists yet — and the retired Triple shape namespace is read-only and also cannot be retracted. Retracting a shape you defined marks the shape inactive. The things validated against it are not deleted or changed, and they still resolve. On write paths, a floating wref to the retracted shape (Player or Player@HEAD) fails; an existing pinned version (Player@vN) remains valid. As with any name, you can add a new shape at the same name afterward — a fresh identity.

One change deliberately does nothing: revising a thing with data identical to its current version. WarmHub returns a no-op and creates no new version, so re-submitting an unchanged revise is always safe. See Operations — Idempotent revise for details.