Sinks & projections

A signed Grid is the canonical model. Everything else — a profile page, a REST API response, a SQL table, or a knowledge graph — is a projection (a sink). Projections make Grids easy to query, render, and integrate. They are never authoritative: verification always goes back to the signed attestation on each cell.

Source of truth vs output

Signed Grid (gridz/1.0.0)
  subject + theme + cells[] + root_attestation
  └── each cell.attestation  ◄── source of truth
           │
           │  publish / sync (projection only)
           ▼
    ┌──────┴──────┬──────────────┬─────────────┬──────────────┐
    ▼             ▼              ▼             ▼              ▼
 gridz.bio    GET /api/     Postgres /     Neo4j         S3 / Redis
 (HTML UI)    profile       SQLite         (graph)       (object/KV)
              (JSON)        (relational)

gridz.bio is one consumer of the spec — not the only output. The same verified Grid can simultaneously exist as:

  • Rendered UI — HTML/React page (e.g. kevin.gridz.bio)
  • HTTP JSONGET /api/profile/kevin.gridz.eth
  • On-chain index — EAS attestations + GridzResolver on Base (see on-chain)
  • Relational database — Postgres, MySQL, SQLite for SQL analytics and joins
  • Knowledge graph — Neo4j for traversals, agent discovery, linked data
  • Object / document stores — S3, MongoDB, Redis for caching and bulk export

Any projection can be rebuilt from the signed Grid. If a database row disagrees with an attestation, the attestation wins.

Sink interface

@gridz/sinks (TypeScript) and gridz_sinks (Python) implement a common adapter pattern. Each sink exposes:

OperationPurpose
write(cells, ctx)Project signed cells into the sink. Returns a WriteResult per cell with a sink_native_uri (where the copy landed).
read(query)Fetch cells by subject DID (and optional key filter). Used to assemble a Grid for rendering or re-verification.
delete(cellIds)Remove projected cells from the sink (does not revoke on-chain attestations).
project?(grid)Optional whole-Grid projection into an alternate shape (e.g. a graph view). Sinks with capabilities.project: true may implement this.

A sink write is never authoritative. It only records where a copy was stored. The signed attestation on each cell remains the proof; consumers call verifyGrid against the assembled Grid, not against the sink alone.

Database projections

Relational and document sinks store one row (or document) per cell, keyed by (subject.did, cell.key). The full cell JSON — including the attestation envelope — is persisted so the Grid can be reconstructed and verified offline.

Tabular pattern (SQLite, Postgres, MySQL)

CREATE TABLE gridz_cells (
  subject     TEXT NOT NULL,   -- subject DID
  key         TEXT NOT NULL,   -- cell key, e.g. com.github
  id          TEXT NOT NULL,   -- stable cell id
  value_hash  TEXT NOT NULL,   -- attestation.value_hash (indexed)
  cell_json   TEXT NOT NULL,   -- full signed cell
  written_at  TIMESTAMPTZ,
  PRIMARY KEY (subject, key)
);

Typical uses:

  • AnalyticsSELECT key, COUNT(*) FROM gridz_cells GROUP BY key across all subjects
  • Search — find every profile with a com.github cell or a specific agent-endpoint[mcp]
  • ETL — sync on-chain or API-fetched Grids into a warehouse for BI tools
  • Local dev — SQLite (:memory: or file) with no chain dependency

CLI: gridz publish --sink sqlite --grid grid.json. See CLI.

Document & object stores

SinkLayoutUse case
MongoDBOne document per cell, indexed by subject + keyFlexible schema, nested widget values, agent context blobs
S3s3://bucket/{subject}/{key}.jsonStatic export, CDN-backed profile archives, backup
RedisKey-value per cellLow-latency cache in front of chain or Postgres

Knowledge graph projection

A Grid is already a small graph in structure: a subject node connected to many cells by key. The Neo4j sink in @gridz/sinks materializes that shape for traversal queries across many Grids.

Graph model

(:Subject { did: "did:pkh:eip155:8453:0x…" })
    -[:HAS_CELL]->
(:Cell { key: "com.github", id: "…", value_hash: "0x…", cell: <full JSON> })

On write, the sink runs:

MERGE (s:Subject {did: $subject})
MERGE (s)-[:HAS_CELL]->(c:Cell {key: $key})
SET c.id = $id, c.value_hash = $vh, c.cell = $cell

Why a knowledge graph?

  • Agent discovery — traverse (Subject)-[:HAS_CELL]->(Cell {key: "agent-endpoint[mcp]"}) to find MCP endpoints across agents
  • Linked identities — connect subjects that share service keys, registry entries, or operator DIDs
  • Org graphs — organizations with gridz.tokens cells linked to token contract metadata in an external graph
  • RAG / semantic layers — attach embeddings to Cell nodes while keeping value_hash for cryptographic grounding

Graph nodes store the full signed cell JSON. Before trusting a value in a graph query, run verifyGrid on the reconstructed Grid (or verify the individual cell's attestation). The graph indexes and connects; signatures prove authenticity.

ENS as primary sink

For gridz.bio, the primary on-chain projection is ENS + EAS on Base. Each cell maps to resolver storage and an EAS gridz.cell.v1 attestation. The ENS sink in @gridz/sinks can also project to standalone *.eth names via text records (gridz.keys, gridz.layout, per-key values, and gridz.att[key] attestations).

ENS is a sink like any other — convenient for name resolution and wildcard reads, but verification still checks the attestation bytes, not "whatever ENS returned."

End-to-end flow

  1. Author — build a Grid (YAML, editor, or API). Cells may be draft / unattested during editing.
  2. Sign — wallet (or 1Claw HSM) signs each cell via EIP-712 GridzCell. See Attestations.
  3. Publish — push to one or more sinks:
    • gridz.bio → Base EAS + resolver (browser flow)
    • CLI → gridz publish --sink postgres|sqlite|neo4j|ens|…
    • MCP → sink_publish tool for agent-driven sync
  4. Consume — read from any sink, assemble Grid JSON, render or query.
  5. VerifyverifyGrid(grid) checks hashes and signatures independently of which sink supplied the data.

Choosing an output

GoalOutput
Public profile page + ENS identitygridz.bio (on-chain sink)
App integration, bots, agentsGET /api/profile/{subject} or @gridz/core directly
SQL reporting, dashboards, searchPostgres / MySQL / SQLite sink
Relationship traversal, agent registries, semantic searchNeo4j knowledge graph sink
Static backup, IPFS/CDN archiveS3 or file export
Offline verification onlyGrid JSON file — no sink required

Related