Skip to content

Naming as Navigation

Names in WarmHub — for things and assertions alike — can contain / to create hierarchical paths, like directories in a filesystem. This isn’t a cosmetic feature. Naming is navigation. A well-designed namespace turns a flat bag of records into a structure that agents can explore, predict, scope, and react to.

This hierarchy doesn’t start at the thing name — it extends all the way up through WarmHub’s URL structure:

app.warmhub.ai/orgs/acme/repos/catalog/Product/electronics/phones/pixel-9
───┬─ ──┬─── ──┬─── ─────────┬──────────────
org repo shape thing name

Organization, repository, shape, and thing name compose into one continuous path. The slashes in your thing names are a natural extension of the hierarchy that already exists — from org to repo to shape to the deepest leaf of your data.

One important difference from a filesystem: intermediate path segments don’t need to exist as their own entities. If you have Product/electronics/phones/pixel-9, there is no requirement for a thing called Product/electronics or Product/electronics/phones to exist. The hierarchy lives in the naming convention, not in a tree of parent objects. Glob queries like Product/electronics/** still work — they match against the name string, not against a chain of parent entities. This means you can design deep, descriptive paths without needing to populate every level.

A WarmHub repo gives you two navigation axes:

Vertical — the hierarchy. Slash-separated names create parent-child relationships. If you’re looking at Product/electronics/phones/pixel-9, you can move up to see all phones, all electronics, or every product in the catalog. This is tree navigation — the same mental model as a filesystem.

Lateral — assertions. Assertions link things to other things across the hierarchy. A Review assertion might connect Product/electronics/phones/pixel-9 to Brand/google. That link cuts across the tree, connecting two branches that hierarchy alone can’t reach.

Together, these form a web — not a flat list, not a rigid tree, but a navigable structure with both predictable paths (hierarchy) and cross-cutting connections (assertions).

Product/ Brand/
├── electronics/ ├── google ◄─────────────────┐
│ ├── phones/ ├── apple │
│ │ ├── pixel-9 ─────────────────│── Review assertion ─────────┘
│ │ └── iphone-16 └── samsung
│ └── laptops/
│ ├── macbook-air Supplier/
│ └── thinkpad-x1 ├── asia/
├── home/ │ ├── foxconn
│ ├── kitchen/ │ └── tsmc
│ └── lighting/ └── na/
└── outdoor/ └── intel

An agent exploring this structure can navigate the product tree to find a specific item, then follow assertions laterally to discover its brand — and from that brand, follow their assertions to find other products, ratings, or supplier relationships. The hierarchy gets you to the right neighborhood; assertions let you traverse the graph.

If you’re an AI agent working with a WarmHub repo, hierarchical naming changes what’s possible within your context window.

You can’t load an entire repo. But you can narrow to a subtree:

Terminal window
# Everything in electronics
wh thing list --match "Product/electronics/**"
# Just phones
wh thing list --match "Product/electronics/phones/*"
# All categories, just 2024 models
wh thing list --match "Product/**/2024/*"

This is the difference between searching and navigating. Searching requires you to know what you’re looking for. Navigation lets you explore a structure and find things you didn’t know existed.

If you see Sensor/building-a/floor-3/temp, you can predict that Sensor/building-a/floor-2/temp probably exists. If you see Report/2024-q1/summary, you can guess at Report/2024-q2/summary. Hierarchy makes the unknown discoverable by analogy — you can infer the namespace conventions from a few examples and then navigate confidently to things you haven’t seen yet.

Flat naming (sensor-building-a-floor-3-temp) carries the same information for humans, but gives agents no structure to parse, no segments to substitute, no tree to traverse.

The wref Article/tech/2024/transformer-scaling tells you what it is before you read any data. The hierarchy is metadata — category, year, topic — encoded in the address itself. An agent can reason about what a thing represents purely from its name, without fetching its data.

Subscriptions can filter on match with the same glob syntax used by wh thing list --match, so you can set up Actions that watch entire branches of the hierarchy — or any subset expressible as a glob:

{
"all": [
{ "operation": "add" },
{ "kind": "thing" },
{ "match": "Sensor/building-a/**" }
]
}

Any new thing added under Sensor/building-a/ — any floor, any sensor type — triggers the action. The hierarchy becomes an event routing structure, not just an address scheme. You can build pipelines that react to categories of data without enumerating every possible thing name, and you can use globstars (Sensor/**/temp), single-segment wildcards (Product/*/phones/*), or brace expansion (Sensor/hq/floor-{3,4}/*) to express exactly the subset you care about.

The best hierarchies follow how the data is actually organized, queried, and explored. Ask: “What are the most common ways someone will want to narrow into this data?”

Product catalog — the natural grain is category, then subcategory, then item:

Product/electronics/phones/pixel-9
Product/electronics/laptops/macbook-air
Product/home/kitchen/instant-pot-duo
Product/outdoor/camping/rei-half-dome

This lets you query by top-level category (Product/electronics/**), by subcategory (Product/electronics/phones/*), or across categories for a specific type (Product/**/camping/*).

IoT sensor network — the natural grain is physical location, then sensor type:

Sensor/hq/floor-3/conference-a/temp
Sensor/hq/floor-3/conference-a/humidity
Sensor/hq/floor-3/hallway/motion
Sensor/warehouse/zone-b/temp

An agent monitoring building conditions can glob Sensor/hq/floor-3/** to get everything on that floor, or Sensor/**/temp to compare temperatures across all locations.

Research corpus — the natural grain is source, then year, then topic:

Paper/arxiv/2024/attention-mechanisms-survey
Paper/arxiv/2023/transformer-efficiency
Paper/acl/2024/multilingual-rag

The first segments after the shape should be the dimensions you’ll filter on most often. If you almost always query by region, put region first. If you almost always query by date, lead with date.

# Category-first — good when most queries browse by type
Product/electronics/phones/pixel-9
# Region-first — good when most queries are geography-scoped
Product/us/electronics/phones/pixel-9

Neither is universally right. Pick the order that matches how agents will actually explore the data.

Each segment should carry information. Avoid segments that are just structural padding:

# Every segment tells you something
Company/acme/filing/10-k/2024
# "data" and "records" are noise
Company/acme/data/records/filing/10-k/2024

Use stable identifiers — not timestamps, not UUIDs (unless you have a reason). Names can be changed, but stable names make wrefs readable and wrefs are how agents refer to things in conversation.

Stay flat when hierarchy doesn’t earn its keep

Section titled “Stay flat when hierarchy doesn’t earn its keep”

Not everything needs deep nesting. If a shape has a few dozen things with no natural grouping, flat names are fine:

# No need for hierarchy here
Currency/usd
Currency/eur
Currency/jpy

Hierarchy should emerge from the domain, not from a desire for tidiness. Two levels is often enough. Five levels should make you pause and ask whether the extra depth is actually helping agents navigate.

Use hierarchy for things, assertions for relationships

Section titled “Use hierarchy for things, assertions for relationships”

Hierarchy models containment — a product belongs to a category and subcategory. Assertions model connections — a product is reviewed by an agent, or a paper cites another paper.

Don’t try to encode relationships in the name:

# Don't do this — the relationship belongs in an assertion
Product/electronics/made-by-samsung/phones/galaxy-s24
# Do this — clean hierarchy, with assertions for relationships
Product/electronics/phones/galaxy-s24
└── SuppliedBy assertion → about: Supplier/asia/samsung
└── Review assertion → about: Product/electronics/phones/galaxy-s24

Hierarchy answers “where does this live?” Assertions answer “what is this connected to?”

The --match flag on query commands supports full glob syntax:

PatternMeaning
Product/electronics/*Direct children of Product/electronics/ (one segment)
Product/electronics/**All descendants of Product/electronics/ (any depth)
Product/*/phones/*All phones across all top-level categories
Sensor/**/tempAll temperature sensors at any location depth
Product/{electronics,home}/**Electronics and home products (brace expansion)
Company/acme/filing/10-*Partial segment match (10-K, 10-Q)
Terminal window
# Explore a subtree
wh thing list --match "Sensor/hq/floor-3/**"
# Cross-cut: all temperature readings everywhere
wh thing list --match "Sensor/**/temp"
# Multiple categories
wh thing list --match "Product/{electronics,home,outdoor}/**"

Glob patterns also work in MCP queries and the SDK’s query methods — not just the CLI.

The real power shows when you combine hierarchical queries with assertion traversal:

Terminal window
# Step 1: Find all phones in the catalog
wh thing list --match "Product/electronics/phones/*"
# Step 2: For a specific product, find what's been said about it
wh thing about Product/electronics/phones/pixel-9
# Step 3: Follow a link to the brand
wh thing view Brand/google
# Step 4: What else do we know about this brand?
wh thing about Brand/google

This is tree-then-graph navigation: use hierarchy to get to the right neighborhood, then follow assertions to traverse the web.

For reactive pipelines, match on subscription filters uses the same glob vocabulary as query --match, so the patterns you learn for navigation translate directly to what you subscribe to:

{
"all": [
{ "operation": "add" },
{ "kind": "thing" },
{ "match": "Product/electronics/**" }
]
}

This fires whenever any new thing is added under Product/electronics/ — phones, laptops, tablets, anything. And unlike a plain prefix, the glob lets you slice by shape patterns too: Sensor/**/temp to react to temperature sensors wherever they live in the tree, or Product/{electronics,home}/phones/* to watch phones across multiple top-level categories.

Array form OR-combines patterns ({"match": ["A/**", "B/**"]} matches either branch); wrap two predicates in all to require both.

A scraper pulls product listings from multiple sources, organized by category:

Product/electronics/phones/pixel-9
Product/electronics/phones/iphone-16
Product/electronics/laptops/macbook-air
Product/home/kitchen/instant-pot-duo

A subscription watches Product/electronics/ and triggers a classification action for each new item. That action creates assertions — Review assessments, PriceTrack observations, SimilarTo comparisons linking to other products. Now agents can navigate the product tree to find items, then follow assertions to discover relationships, ratings, and alternatives.

Three agents investigate companies from different angles:

# Things — the entities
Company/acme
Company/globex
Filing/acme/10-k/2024
Filing/globex/10-k/2024
# Assertions — each agent's perspective
Thesis/acme-growth (about: Company/acme) — agent-1's growth thesis
RiskFlag/acme-debt (about: Company/acme) — agent-2's risk assessment
Comparison/acme-v-globex (about: {pair: [Company/acme, Company/globex]}) — agent-3

An agent reviewing Acme can:

  1. Glob Filing/acme/** to see all filings
  2. Query assertions about Company/acme to see every agent’s perspective
  3. Follow the Comparison assertion to discover Globex as a peer, then explore Filing/globex/**

The hierarchy organized the filings. The assertions connected the perspectives. The agent navigated both.

Sensor/hq/floor-3/conference-a/temp
Sensor/hq/floor-3/conference-a/co2
Alert/hq/floor-3/conference-a/co2-high-2024-03-15

A subscription with match: "Sensor/hq/**" triggers a threshold-check action for any sensor data committed under HQ. When CO2 exceeds limits, the action commits an Alert thing — named in the same hierarchy so it’s discoverable alongside the sensor it relates to. A separate subscription with match: "Alert/**" triggers notifications.

The naming hierarchy is doing double duty: organizing the data and routing the events.

Encoding relationships in names. If you find yourself putting one thing’s identity inside another thing’s name (Product/reviewed-by-agent-1/phones/pixel-9), use an assertion instead. Names should reflect containment and categorization, not cross-references.

UUID-heavy names. Product/f47ac10b-58cc-4372-a567-0e02b2c3d479 is valid but opaque. Agents can’t infer anything from it. If you need generated names, use batch tokens ($N/#N), but prefer human-readable names when the domain has natural identifiers.

Inconsistent depth. If most products are Product/category/subcategory/name but some are Product/name, agents can’t predict the structure. Keep the same shape’s things at consistent depth, or at least document the convention. Note that consistent depth doesn’t mean every level needs things at it — Product/electronics/phones/pixel-9 works fine even if nothing exists at Product/electronics/phones. The point is that things of the same kind should live at the same depth so glob patterns work predictably.

Too deep. Every segment should earn its place. Data/raw/ingested/pipeline-v2/batch-003/electronics/phones/pixel-9 has structural noise that doesn’t help navigation. Flatten to what agents will actually filter on.

Overloading hierarchy when a shape would work. If you’re using hierarchy to separate fundamentally different kinds of data (Entity/person/jones vs Entity/company/acme), consider whether those should be separate shapes (Person/jones, Company/acme). Shapes give you schema-level structure; hierarchy gives you instance-level organization. Use both.