Skip to main content
One person, device or account usually sits in several vendors under different keys, different formats, and different redaction salts. A link declares how two worlds line up, and a cross-world query asks both at once. 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.
The pin resolves once, at commit, to an exact version of the dependency. The ref after @ 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