Docs/Packages

predicates

A curated registry of 133 verbs — 25 enshrined, 108 proposed — each defined once with machine-readable semantics and a precomputed deterministic ID.

@0xintuition/predicates answers the third question in the data model — what triples do we support? It ships a curated registry of verbs — 25 enshrined, 108 proposed, 133 in all across 14 categories — for connecting atoms: createdBy, sameAs, hasTag, listedIn, endorse, trust, authoredBy, and the rest. The full registry is browsable at /predicates.html, one page per verb — e.g. createdBy, sameAs, use.

A schema.org property becomes a predicate only once promoted. schema.org can inform which predicates Intuition adds, but it never auto-creates them — promotion means Intuition deliberately adopts the verb and decides its object model. That curation is what keeps the graph's grammar shared instead of sprawling.

Two tiers: proposed and enshrined#

Every predicate in the registry sits in one of two tiers, and the difference is about how settled the verb is — not whether it exists:

Tier Count What's settled What it means for you
Proposed 108 Stable definition + deterministic atom ID, already The verb is in the registry today and its ID won't change; its semantics are still being refined before promotion.
Enshrined 25 Object model decided Safe to build on — the atom ID is what's stored onchain.

The 25 enshrined keys today: hasType, sameAs, hasTag, hasCategory, follow, like, endorse, trust, distrust, recommend, vouchFor, contain, listedIn, curatedBy, alternativeTo, createdBy, linkedAccount, url, imgUrl, hasDescription, agreeWith, disagreeWith, bullishOn, bearishOn, betterThan.

Promotion is a one-way move from proposed to enshrined, and it changes nothing about identity — a proposed predicate's atom ID is already deterministic, so triples written against it survive the promotion untouched. What promotion adds is commitment: the object model is decided, and the verb becomes part of the vocabulary the protocol stands behind.

Machine-readable semantics#

A predicate isn't just a name with an ID. Every predicate — proposed or enshrined — carries a typed semantic record:

  • marketPatternattributive | depositional | comparative. Is this a fact about the subject, a position someone takes, or a ranking between two things?
  • objectKindentity | claim | literal (with a literalType when literal). What belongs in the object slot: another atom, a claim, or a raw value like a string or URL?
  • polarity — whether the verb carries positive, negative, or neutral sentiment.
  • temporalNaturepermanent | state | event. Does the claim hold forever, until revised, or describe a moment?
  • claimTypefactual | evaluative. Is this checkable against the world, or an opinion?
  • Structural flagsisTransitive, isSymmetric, isHierarchical.
  • inversePredicate — optional pointer to the verb that reads the edge the other way.

This is what lets an app handle an edge it has never seen. A renderer that knows nothing about betterThan can still read marketPattern: comparative and claimType: evaluative and present it as a contested ranking rather than a fact. A graph traversal can follow isTransitive verbs safely, flip edges through inversePredicate, and know from objectKind whether the object resolves to an atom or a literal. Generic tooling works across all 133 verbs because the semantics travel with the predicate, not with the app.

One file per predicate, tree-shakeable#

Each predicate has its own standalone import, so only the verbs you use ship in your bundle:

link.ts
import { multiVaultCreateTriples } from "@0xintuition/protocol";
import { useId }                   from "@0xintuition/predicates/use";
import { createdById }             from "@0xintuition/predicates/createdBy";
import { calculateAtomId }         from "@0xintuition/ids";
import { parseEther }              from "viem";

const reactId  = calculateAtomId("https://react.dev");
const vercelId = calculateAtomId("https://vercel.com");

const per    = parseEther("0.1");
const txHash = await multiVaultCreateTriples(cfg, {
  args: [
    [id,      id          ],  // subjects
    [useId,   createdById ],  // predicates — registry atom IDs
    [reactId, vercelId    ],  // objects
    [per,     per         ],  // value per triple
  ],
  value: per * 2n,
});

Here createdBy is enshrined and use is proposed — both resolve to deterministic atom IDs from the same registry. Prefer the aggregate import? import { PREDICATE_IDS } from "@0xintuition/predicates" still works.

The lifecycle of a predicate#

  1. Defined once. One file per predicate, one canonical record. Each export carries its key, spec, semantic metadata, and a precomputed atom ID (derived via @0xintuition/ids from canonical bytes — never hand-copied into source).
  2. Used everywhere. Every triple references the same canonical predicate atom ID. Joins line up; queries return consistent shapes across apps that have never coordinated.
  3. Stable onchain. When a triple is committed, the predicate atom ID is what's stored. No translation between offchain and on.

Same key, same predicate atom ID, everywhere. This is what makes claims portable: a createdBy triple written by one app is the same edge a second app queries for, because both resolved the verb through this package.

Two columns, decided separately#

The same schema.org property can matter to atom data and to triples — but each decision is made on its own:

two-columns.ts
// Atom-data column  →  classifications.fields
//   embedded in the atom at creation time
Book atom data:      name, author, isbn, sameAs

// Triple-metadata column  →  predicates (registry verbs)
//   recommended for claims about the atom later
Book triple metadata: authoredBy, hasCategory, hasDescription, sameAs

// A schema.org property can matter to both columns,
// but each decision is made on its own.

The atom-data column belongs to classifications; this package owns the triple-metadata column. The two are formally connected: every classification ships metadataPredicates — its recommended verbs — plus a typed matrix declaring what kind of object each verb expects for that classification. See the classifications page for the matrix and its accessors.

Where predicates take you#

Predicates are the grammar; Triples & Predicates covers the full claim model, including counter-triples for disagreement. buildTripleByName in @0xintuition/primitives/triple resolves predicates by name when you want ergonomics over explicit imports, and Offchain to Onchain shows the verbs at work in a full lifecycle. Browse the whole registry at /predicates.html.