Skip to content

Filtering and Lookup

Beyond HEAD snapshots, WarmHub provides targeted query functions for specific lookups, filtered searches, history, and batch operations.

Fetch a single thing by its exact wref. Use this when you know the reference and want its current state or a pinned version.

Terminal window
wh thing view Location/cave
wh thing view Location/cave --version 3
{
"name": "warmhub_thing_get",
"arguments": { "wref": "Location/cave", "version": 3 }
}

The HTTP API does not currently mount a single-wref thing lookup route. Use the CLI, SDK, or MCP surfaces for direct wref lookups.

Each result includes the thing’s core identity fields (name, wref, shapeName, kind, version, active), its data payload, and a metadata envelope containing durableId, createdOn, and revisedOn. Assertions also include an aboutWref field. The committerWref field is present when the originating write recorded a committer identity. The createdBy field, when present, carries the immutable creator attribution recorded at the time the thing was first written. The revisedBy field, when present, identifies the author of the version that was actually returned — which is the current HEAD version on an unversioned read, or the pinned version when a specific version was requested (e.g. --version 3).

Within data, fields typed as wref rehydrate on read: same-repo refs return their local form (e.g. Loc/cave@v1), and a cross-repo ref returns a canonical label (e.g. wh:org/repo/Loc/cave@v1).

Query a repo by combinable filters such as shape, kind, about target, and wref glob. Use this when you don’t have an exact wref. Filters are optional and they stack.

Terminal window
# By shape
wh thing query --shape Location
# By kind
wh thing query --kind assertion
# By about target (assertions about a specific thing)
wh thing query --about Location/cave
# Combined filters
wh thing query --shape Observation --about Location/cave --limit 20
# Resolve through collections — include assertions about collections containing the target
wh thing query --about Location/cave --resolve-collections
wh thing query --shape Observation --about Location/cave --resolve-collections
# With glob pattern (match applies to full wrefs: Shape/name)
wh thing query --shape Location --match "Location/dungeon/*"
# By affirmed-about target (assertions pinned to a specific version of a thing)
wh thing query --affirmed-about Location/cave@v3
# Count matching items (no pagination, returns { count: N })
wh thing query --shape Location --count
wh thing query --kind assertion --about Location/cave --count
wh thing query --affirmed-about Location/cave@v3 --count

MCP note: Pass orgName and repoName in the arguments object alongside the fields shown below.

{
"name": "warmhub_thing_query",
"arguments": {
"shape": "Observation",
"about": "Location/cave",
"kind": "assertion",
"match": "Observation/dungeon/*",
"includeRetracted": false,
"limit": 50
}
}

Count via MCP:

{
"name": "warmhub_thing_query",
"arguments": {
"shape": "Observation",
"about": "Location/cave",
"count": true
}
}

The HTTP example below uses the public warmhub-data/us.congress.trades repo so you can copy-paste it directly; the CLI and MCP blocks above use generic Location/Observation names that you’d swap for your repo’s own shapes.

GET /api/repos/warmhub-data/us.congress.trades/query?shape=CongressTrade&kind=thing&match=CongressTrade%2F20034954%2F*&limit=25

Anonymous callers reading public repos are capped at limit=25 per page; authenticated callers can request up to limit=500. See Anonymous Pagination Caps.

All filter parameters are optional. Combine them to narrow results. The HTTP API does not currently mount a count-only route; use CLI/MCP count surfaces for count-only reads.

The affirmedAbout filter narrows results to assertions that were explicitly pinned to a specific version of a target thing at the time they were written. It is available across CLI (--affirmed-about), MCP (warmhub_thing_query.arguments.affirmedAbout), and the TypeScript SDK (FilterOptions.affirmedAbout).

Terminal window
# Assertions pinned to version 3 of Location/cave
wh thing query --affirmed-about Location/cave@v3
# Combined with a shape filter
wh thing query --shape Observation --affirmed-about Location/cave@v3
# Combined with --match
wh thing query --affirmed-about Location/cave@v3 --match "Observation/*"
# Count only
wh thing query --affirmed-about Location/cave@v3 --count
{
"name": "warmhub_thing_query",
"arguments": {
"affirmedAbout": "Location/cave@v3"
}
}
// SDK
const result = await client.thing.query('acme', 'world', {
affirmedAbout: 'Location/cave@v3',
})

Pinned-only contract: the value passed to affirmedAbout must include an explicit version pin (e.g. Location/cave@v3). Passing an unpinned wref is rejected.

affirmedAbout is also accepted by thing.search and thing.count.

The CLI and SDK support an additional --role filter for wh thing query. Use it to narrow results to assertions that play a specific role within a collection — for example, only the from end of an Arc or the to end of a Bond. For a full explanation of collection shapes (Arc, Bond, and their roles), see Collections.

Terminal window
# Filter by role
wh thing query --kind assertion --about Location/cave --resolve-collections --role from
wh thing query --kind assertion --about Location/cave --resolve-collections --role to
wh thing query --kind assertion --about Location/cave --resolve-collections --role ends

Valid role values are from, to, and ends. The --role filter requires both --about and --resolve-collections to be set — the CLI validates this combination and returns an error if either is missing.

The SDK exposes the same filter as role in FilterOptions:

const result = await client.thing.query('acme', 'world', {
kind: 'assertion',
about: 'Location/cave',
resolveCollections: true,
role: 'from',
})

MCP surface: warmhub_thing_query does not accept a role argument. To filter by role on MCP, use warmhub_thing_about with resolveCollections: true and the role argument — it accepts from, to, and ends alongside the standard warmhub_thing_about parameters.

The kind filter has a semantic split worth noting:

  • kind=thing returns non-collection things only — collection instances (Arc, Bond, Pair, Set, List, and retired Triple) are excluded from these results.
  • kind=collection returns collection instances only — Arc, Bond, Pair, Set, List, and retired Triple rows.
  • kind=assertion returns assertions.

Unfiltered thing.query and thing.head calls include collection rows and project them as kind: 'collection'. If you query with --kind thing (or kind: "thing" in the SDK/MCP) and expect collection-shaped rows to appear, they will not — collection instances are projected to kind: "collection" and are excluded when you explicitly request kind=thing.

Both wh thing query and wh thing about are paginated reads. The initial call returns only the first page. When more results exist, the response carries a nextCursor token: the SDK returns it as nextCursor on the Page result, while the CLI --json output nests it under page.nextCursor — it is not a top-level field (see below).

Page-size caps depend on authentication:

  • Anonymous callers (unauthenticated requests to public repos) are capped at limit=25 per page. Requesting a limit above 25 returns Sign in for larger pages. Anonymous callers are additionally limited to at most two pages. How crossing that boundary surfaces depends on which surface you call: the SDK and the CLI read layer raise UNAUTHENTICATED with Sign in to keep paging, while the public HTTP query endpoints (/head, /query, /about) rewrite that deny path to an opaque 404 with Vary: Authorization to keep repository existence private (see Anonymous Pagination Caps). Reducing limit will not resolve that boundary; you need to authenticate to continue paginating.
  • Authenticated callers can request up to limit=500 per page.

To retrieve subsequent pages manually, pass both --limit and --cursor <token> together — --cursor is rejected unless --limit is also supplied. To fetch all pages in a single command, use --all. To control page size, use --limit=<n>:

Terminal window
# Fetch the first page (authenticated callers: up to 500 items; anonymous: up to 25)
wh thing query --shape Observation --limit 100
# Fetch the next page — both --limit and --cursor are required together
wh thing query --shape Observation --limit 100 --cursor <token>
# Fetch all pages automatically
wh thing query --shape Observation --all
# Same pagination contract applies to thing about
wh thing about Location/cave --limit 100
wh thing about Location/cave --limit 100 --cursor <token>
wh thing about Location/cave --all

The cursor token is only available in structured output, and on the CLI it is nested inside the page envelope rather than at the top level. --json returns the full { items, page: { limit, count, hasMore, nextCursor } } shape, so read the cursor from page.nextCursor (and page.hasMore tells you whether another page exists). --format jsonl emits only the item rows with no page metadata, so use --json when you need the cursor. Pretty (human-readable) output does not print the token — it emits a hint that more results exist and suggests --all. To capture the cursor for a follow-up CLI call, use --json:

Terminal window
# Capture page.nextCursor from the --json envelope
wh thing query --shape Observation --limit 100 --json
# Then pass it to the next page
wh thing query --shape Observation --limit 100 --cursor <token from page.nextCursor above>

Keep paginating until page.nextCursor is null to collect all results.

Incremental reads with --since-repo-seq (wh thing query and wh thing list): use this flag to re-read only the items whose current state changed since a known checkpoint, instead of re-fetching the whole result set on every poll. --since-repo-seq is not available on wh thing about. (For wh thing list incremental reads, see also HEAD queries.)

This returns changed records, not a list of writes. You get the current state of each item that changed since your checkpoint — one row per item, however many times it was written. Two writes to the same thing between polls give you one row with its latest state, not two rows. If you would rather be notified when writes happen than poll for them, set up a subscription that fires on matching writes instead.

By default an incremental read returns only active items, so a retraction shows up as the row simply no longer appearing. Pass --include-retracted and retracted items are returned too, so you can see which ones went away. One exception: --include-retracted cannot be combined with a --where field predicate — that composition is rejected on any read, incremental or not.

Running the read

  • Starting fresh: pass --since-repo-seq -1 on your first call. -1 is a bootstrap sentinel rather than a real repository sequence — it requests the complete current-state snapshot, not a walk of the repo’s write history. The server never returns -1.
  • Resuming from a checkpoint: on subsequent calls, pass the repoSeq value you stored from the previous exhausted page as --since-repo-seq <seq>.
  • Use the same --limit on every page of a single incremental read. Changing --limit mid-stream — between pages of the same poll — causes the incremental cursor to be rejected.

Storing the checkpoint

  • Where to find it: when you have read the last page — page.hasMore is false and there are no further items — the --json envelope carries a top-level repoSeq alongside the page object. Count-only reads (--count --since-repo-seq <n>) carry it too, so you can checkpoint from a count call — but pass --json there as well, because the default human-readable output prints just the number and drops the checkpoint.
  • What it means: repoSeq marks where your scan started, not the end of the repo. It is fixed when the scan begins, so anything written while you were paging is not missed — your next poll picks it up.
  • When there is none: an abandoned or failed scan earns no new checkpoint. Keep the previous one and retry.
  • Next poll: pass the stored repoSeq as --since-repo-seq instead of a cursor. This works for both manual page-by-page reads and --all drains.

When an incremental read is refused

  • Four query forms cannot be read incrementally. These you can fix yourself by changing the query:

    • a glob --match filter
    • --resolve-collections
    • a cross-repo --about target, such as --about wh:other-org/other-repo/Shape/name
    • an --affirmed-about filter (affirmedAbout is not supported for incremental reads; use a full query call when you need that filter)
  • Availability is the other cause, and no query change will help. Incremental reads are not available on every repo yet. If your query avoids all four forms above and the call is still refused, the feature is not available to you there — fall back to a full read for now and retry incrementally later.

    Both causes return INCREMENTAL_READ_UNAVAILABLE, and the error deliberately does not say which applied — so rule out the four query forms first.

  • You need read access to the whole repo. If your token is restricted to a subset of wrefs, incremental reads return FORBIDDEN — even if the restriction is broad enough to cover everything you are querying. Use a token with unrestricted read access.

Here is a minimal two-step polling flow. The first call seeds the initial snapshot; the second call resumes from the stored checkpoint:

Terminal window
# Step 1 — bootstrap: read the complete current-state snapshot
wh thing query --shape Observation --since-repo-seq -1 --limit 100 --json
# Paginate (keeping --limit 100) until page.hasMore is false, then store the
# top-level repoSeq from the final page's JSON envelope as your checkpoint.
# Step 2 — subsequent poll: fetch only the items that changed after the checkpoint
wh thing query --shape Observation --since-repo-seq <stored repoSeq> --limit 100 --json
# Again paginate until page.hasMore is false, then update your stored repoSeq.

From the SDK you do not have to run this loop yourself. client.thing.queryChanges(...) takes the same filters plus a required sinceRepoSeq and hands you back the changed items — retracted ones included — along with the checkpoint to store. Note that affirmedAbout is not supported for incremental reads; use a full query call when you need that filter. client.thing.headChanges(...) is the equivalent for list-style reads. Reach for the manual cursor recipe above only when you want to process each page as it arrives.

Key a local cache by item.metadata.durableId, since a rename carries its checkpoint wref and a retraction arrives as active: false.

One limit to plan around: neither helper captures every writer’s changes. Treat what they return as a best-effort delta, and when you need a complete copy of the data, periodically reconcile it against a full read rather than relying on the deltas alone.

For SDK pagination details, see the SDK read semantics reference. For HTTP pagination details, see the HTTP Queries reference.

Shape, kind, about target, and wref glob narrow by a record’s identity. To filter on the values of fields inside a thing’s datastate, severity, a nested address.county — add where predicates.

where is supported across the typed read surfaces: the CLI (wh thing query, wh thing list), the SDK (client.thing.query, thing.head, thing.about, thing.count), and MCP (warmhub_thing_query, warmhub_thing_head, warmhub_thing_about). No HTTP read route parses where, and thing.search does not accept it — use thing.query for structured field filtering.

Terminal window
# Equality
wh thing query --shape Observation --where "status=active"
# Numeric comparison (also >, <, <=, !=)
wh thing query --shape Observation --where "severity>=3"
# Prefix match on a string field (trailing * is optional)
wh thing query --shape Location --where "region~north"
# Set membership — value is one of the list
wh thing query --shape Location --where "biome in:[forest,desert,tundra]"
# Field existence
wh thing query --shape Observation --where "resolvedAt?"
# Multiple predicates are ANDed (up to 8 per query)
wh thing query --shape Observation --where "status=active" --where "severity>=3"

Each --where flag is one predicate, written as a field path, an operator, and (except for exists) a value:

CLI formOperatorMatches
field=valueeqequal
field!=valuenenot equal
field>value / field>=valuegt / gtegreater than (or equal to)
field<value / field<=valuelt / lteless than (or equal to)
field~prefixprefixstring or wref field starts with prefix
field in:[a,b,c]invalue is one of the list (1–1000 values)
field?existsfield is present

The SDK and MCP take the same predicates as structured objects — { fieldPath, op, rhs }, where rhs is a scalar for the scalar operators, an array for in, and omitted for exists:

// SDK
const result = await client.thing.query('acme', 'world', {
shape: 'Observation',
where: [
{ fieldPath: 'status', op: 'eq', rhs: 'active' },
{ fieldPath: 'severity', op: 'gte', rhs: 3 },
],
})
// MCP equivalent
{
"name": "warmhub_thing_query",
"arguments": {
"shape": "Observation",
"where": [
{ "fieldPath": "status", "op": "eq", "rhs": "active" },
{ "fieldPath": "severity", "op": "gte", "rhs": 3 }
]
}
}

Notes:

  • where requires a shape and can’t be combined with a glob match or includeRetracted. Each predicate resolves against a shape’s typed fields, so the query must set a shape (--shape / shape). Combining where with a --match/match glob pattern or with --include-retracted/includeRetracted returns a field-index error rather than running.
  • Predicates combine as AND, up to 8 per call. Field paths are dotted for nested fields (address.county).
  • You can filter on scalar fields a shape declaresstring, number, boolean, and reference (wref) fields. Fields that hold objects or arrays aren’t filterable, and a predicate on a field that isn’t available for filtering fails with an error naming the field, rather than silently returning no matches.
  • Value typing follows the field’s declared type. The CLI keeps numeric-looking strings ("42") and ISO date strings as strings and lets the field’s type classify them, but parses bare true/false as booleans — quote them (field="true") to match literal text. In the SDK and MCP, pass the scalar as the type you want (3 versus "3").
  • Execution budget: typed where reads are execution-bounded. If a broad predicate or a deep page exhausts the query budget, the call fails with QUERY_TOO_EXPENSIVE. When you see that error, narrow the predicate (add more filters or tighten the value range) or request a shallower page. The same budget applies to count-only reads (--count / count: true).

wh assertion list also accepts an equality shorthand for field filtering: --field data.path=value. This uses the same indexed field filtering path as wh thing query, and works for unscoped lists, target-scoped lists (--about), and --count. Only equality (=) is supported — for other operators, use wh thing query --shape <YourAssertionShape> --kind assertion --where.

Terminal window
# Equality filter on an assertion data field
wh assertion list --field data.status=active
# Combined with a target scope
wh assertion list --about Location/cave --field data.severity=3
# Count only
wh assertion list --field data.status=active --count

Field paths must use the data. prefix. The filter is equality-only on this surface.

List the assertions that target a specific thing. Use this when you have a thing’s wref and want the assertions made about it:

Terminal window
wh thing about Location/cave
wh thing about Location/cave --shape Observation
wh thing about Location/cave --match "Observation/*"
# Include assertions about collections containing the target
wh thing about Location/cave --resolve-collections

wh assertion list --about Location/cave remains available when you are already working in the assertion domain.

By default, --about only returns assertions that directly target the specified thing. To also include assertions about collections (Arc, Bond, Set, List) that contain the thing, add --resolve-collections:

Terminal window
wh thing about Location/cave --resolve-collections
wh assertion list --about Location/cave --resolve-collections
wh thing query --about Location/cave --resolve-collections
wh thing history --about Location/cave --resolve-collections
wh thing search "safe" --about Location/cave --resolve-collections

Collection resolution looks up current (HEAD) collection memberships. It is not supported with --mode vector or --mode hybrid search.

Search pagination caveat: when combining search with --about or --resolve-collections, pages may be sparse — a page may contain fewer items than limit, or even zero items, while nextCursor is still non-null. Keep paginating until nextCursor is absent to collect all results.

The --depth flag retrieves child assertions about the returned assertions:

Terminal window
wh thing about Location/cave --depth 2
{
"name": "warmhub_thing_about",
"arguments": {
"wref": "Location/cave",
"shape": "Observation",
"match": "Observation/*",
"includeRetracted": false,
"depth": 2
}
}

The response includes a target object (the thing being queried) and an assertions array. Both the target object and each entry in assertions include a metadata envelope with durableId, createdOn, and revisedOn. With depth > 1, each assertion may include a children array.

When the queried target belongs to the addressed repo, thing.about (CLI wh thing about, SDK client.thing.about, and MCP warmhub_thing_about) also aggregates readable foreign assertions: assertions stored in other repos that the caller has repo:read access to and that target the same thing. These foreign assertions appear inline in the assertions array with their canonical wh:org/repo/... wrefs, so you can distinguish them from assertions stored in the addressed repo.

See every version of a thing, or filter history by shape or about target. Use this when you need how an item changed over time, not just its current state:

Terminal window
wh thing history Location/cave
wh thing history Location/cave --limit 10

Query history by shape or about filters (without a specific wref):

Terminal window
wh thing history --shape Observation --limit 20
wh thing history --about Location/cave --limit 5
# Include collection assertions in history filtering
wh thing history --about Location/cave --resolve-collections
{
"name": "warmhub_thing_history",
"arguments": {
"wref": "Location/cave",
"limit": 10
}
}

At least one of wref, shape, or about is required. Each version entry includes fields such as: version, operation (add/revise/retract), active, createdAt, committerWref — the committer’s local or canonical wref when the originating write recorded one, omitted otherwise — revisedBy — the author of that specific version, when recorded — metadata.durableId and metadata.createdOn, and aboutWref on assertion rows. This list is not exhaustive; responses may also include other fields depending on the item.

Cross-repo wref lookups require effective repo:read permission on the target repo. Public repos are readable by anyone. For private repos, callers without that access see an error — except cross-repo search and batch lookup, which fold unreadable results into { items: [] } or missing[] entries to keep search and batch streaming-friendly.

See Getting Access for the precise rules.

Resolve a shape or shaped-thing wref to its canonical identity. Use this when you have a local or version-relative reference and need its stable canonical form — CLI and SDK also return the resolved version’s data:

Terminal window
wh thing resolve Location/cave
{
"name": "warmhub_wref_resolve",
"arguments": { "wref": "Location/cave" }
}
  • CLI wh thing resolve and SDK client.thing.resolve(...) return the same payload as thing.get. The default CLI render shows identity columns only; pass --json for the full payload.
  • MCP warmhub_wref_resolve returns name, kind, active, version, shapeName, and the metadata identity/timestamp envelope. Pair with warmhub_thing_get to fetch data.

Fetch shapes or shaped things by wref in a single call. On the CLI, wh thing view is variadic — pass multiple wrefs or use --file to trigger batch mode. Also available via the TypeScript SDK (client.thing.getMany) and MCP.

The CLI enforces a 500-wref cap per call, applied after deduplication — so repeated wrefs across positional args, --file, and stdin are collapsed before the cap is checked. The MCP enforces a 500-wref cap on the raw wrefs array length as supplied, before any deduplication. The SDK accepts any number of wrefs and automatically chunks requests above the 500-wref backend transport cap, so you do not need to manually split large lists when using the SDK.

The CLI examples below use a couple of wref conventions: Shape/name reads HEAD, Shape/name@v3 pins to version 3, and --file=- is the standard Unix marker for “read newline-delimited input from stdin.”

Terminal window
# CLI — wrefs come from positional args, --file <path>, or piped stdin (any combination)
wh thing view Location/cave Location/forest Player/alice
cat wrefs.txt | wh thing view # one wref per line, piped stdin
wh thing view --file wrefs.txt --version 1 # newline-delimited file, pin all to @v1
wh thing view --file=- < wrefs.txt --format jsonl # one JSON line per *deduped* requested wref
// SDK — accepts any number of wrefs; auto-chunks above 500
const result = await client.thing.getMany(
'acme', 'world',
['Location/cave', 'Location/forest', 'Player/alice'],
1, // optional fallback version for unpinned wrefs
{ includeRetracted: true }, // optional — return retract versions when reading a historical version (otherwise retract versions are excluded)
)
// result: { requested, items, missing }
// MCP equivalent
{
"name": "warmhub_thing_get_many",
"arguments": {
"orgName": "acme",
"repoName": "world",
"wrefs": ["Location/cave", "Location/forest", "Player/alice"],
"version": 1
}
}

Shared across CLI, SDK, and MCP:

  • All three surfaces return { requested, items, missing }:
    • requested is a number — the count of input wrefs the call processed. The CLI unions positional + --file + stdin inputs and dedupes them before the round-trip, so a wref supplied more than once counts only once toward both requested and the 500-wref cap. The SDK and MCP forward the wrefs array as-is, so duplicates produce duplicate items/missing entries; on MCP, each entry in the supplied array counts toward the 500-wref cap.
    • items[] carries the resolved entities — same fields as a single-thing read, including the metadata envelope with durableId, createdOn, and revisedOn, and the optional createdBy and revisedBy attribution fields.
    • missing[] is string[] — wrefs that don’t exist or that the caller can’t read, returned instead of throwing.
  • Missing entries are version-qualified when a top-level version / --version was supplied and the wref didn’t already carry a version modifier (@vN or @HEAD). Per-wref pins always survive intact (no double-pinning).
  • The CLI enforces a 500-wref cap after dedupe; MCP enforces a 500-wref cap on the raw supplied array. The SDK auto-chunks above that cap.

CLI-only:

  • --version implies --include-retracted, so retract versions can be retrieved by their pinned id (mirrors wh thing view --version). Pass --include-retracted explicitly when you want retract versions without a fallback --version.

  • --format jsonl emits one row per deduped requested wref, in input order. (Inputs from positionals + --file + stdin are unioned and deduped before the round-trip, so a wref supplied twice produces one row.) Use it for shell pipelines where you want to filter or fan out the result. Use --json instead when you want the full {requested, items, missing} envelope as a single object.

    Each row is {requested, found, wref, ...}. requested is the input wref preserved verbatim (so canonical/cross-repo inputs are still identifiable on the consumer side), wref is the local form for hits or the version-qualified form for misses, and found is the boolean.

  • --live is rejected (batch reads are one-shot — use wh thing view <wref> --live for per-thing polling).

Search things by text content. Three modes are available:

  • text (default) — full-text search against thing names, shape names, and data fields. Supports pagination.
  • vector — semantic similarity search using embeddings. No pagination.
  • hybrid — runs text and vector searches in parallel, merges results with reciprocal rank fusion. No pagination.
Terminal window
# Full-text search (default mode)
wh thing search "safe location" --shape Observation
# Semantic similarity search
wh thing search "places that are dangerous" --mode vector
# Hybrid search — combines text and vector results
wh thing search "policy" --mode hybrid --limit 10
# Filter by about target (not supported with --mode vector)
wh thing search "safe" --about Location/cave
# Filter by affirmed-about target (pinned version)
wh thing search "safe" --affirmed-about Location/cave@v3
# Resolve through collections (text mode only)
wh thing search "safe" --about Location/cave --resolve-collections
# Paginate through text results
# NOTE: when using --about or --resolve-collections, pages may be sparse —
# a page may return fewer items than --limit (or even zero) while nextCursor
# is still present. Paginate until nextCursor is absent to collect all results.
wh thing search "policy" --limit 50 --cursor <token>
# Fetch all pages automatically (text mode only)
wh thing search "policy" --all

MCP note: Pass orgName and repoName in the arguments object alongside the fields shown below.

{
"name": "warmhub_thing_search",
"arguments": {
"query": "safe location",
"shape": "Observation",
"mode": "hybrid",
"limit": 10
}
}

Search is available via the CLI, SDK (client.thing.search()), and MCP (warmhub_thing_search) but is not currently exposed as an HTTP endpoint.

Anonymous search narrowing: anonymous callers (unauthenticated requests to public repos) are subject to narrowed paging on all thing.search calls: limit is capped at 25 and an omitted limit defaults to 25. Text-mode paging additionally stops after two pages — once that boundary is crossed, the backend returns UNAUTHENTICATED (Sign in to keep paging). Reducing limit will not resolve that error; you need to authenticate to continue paginating.

Most CLI queries support --live for real-time updates:

Terminal window
wh thing query --shape Location --live
wh thing history Location/cave --live
wh thing about Location/cave --live

This re-runs the query periodically and re-renders whenever the underlying data changes.