Declare a link
A link is a[dependencies] entry plus an entities table mapping a local field onto the
dependency’s field. [dependencies] lives in gateway-env.toml, the world’s manifest, not in
connector.toml.
@ is a
branch or tag name (main is every world’s default branch, so @main is its tip at that
moment and never moves afterwards), a content-hash prefix, or a semantic version. Every mapping is
checked then too: both entities and both fields must exist in their worlds’ contracts, or the
commit is refused naming what is missing. A link crosses projects inside your organization and
stops at its edge.
gateway worlds describe <slug> and GET /api/public/worlds/{slug} list a world’s links with
their mappings.
Transforms, for values that are not stored the same way
Two worlds seldom hold one value identically: one keeps a phone as bare digits, a client sends+1 (559) 779-1433. A transform normalizes the plaintext on both sides before each world’s
redaction is applied. Transforms are a closed, named set, applied left to right:
Any client can reproduce a transform from the manifest alone. An unknown transform is refused at commit. The same set exists in the
TypeScript SDK, with shared test vectors.
Ask across worlds
--across runs the query in the world you name and in every linked world that maps the fields
you passed. For each linked world it takes your plaintext, applies the mapping’s transforms,
turns the result into the form that world stores under its own [redact] policy, and queries
it. One header line per world on stdout, then its rows; each group also reports the chain it
applied as transformed. Use --json to pipe the output, since the headers share stdout with
the rows. The world you name is queried as given, without transforms: a transform belongs to
the mapping into a dependency.
--compare adds the parity table: per field and per world, whether anything matched, and the
transform that was applied. A field with no mapping to some world is reported as unmapped,
never an error.
The same question is GET /api/public/worlds/{slug}/data?entity=&where=&resolve=true&across=true&compare=true,
queryRows(slug, entity, { where, resolve: true, across: true, compare: true }) in the
TypeScript SDK, and query_world_data({ ..., across: true, compare: true }) for an agent.
Resolution happens at query time, from the plaintext you supply. Nothing is joined on disk.
Each world salts its digests with its own slug, so the same email is a different digest in
two worlds. Recomputing both forms from the plaintext is what makes the link work without a
shared salt, a re-ingest, or digests anyone holding a snapshot could join.
Where to go next
- Put data in a world for
data query,--whereand--resolveon one world. - Describe a world for how each field is stored and what resolves.