Protocol Compatibility
Relata speaks ten external wire protocols from one binary and one governed store. Any off-the-shelf client library that speaks one of them can use Relata as a drop-in backend — no Relata SDK required. Backed by ADR-163–ADR-170.
This is the fastest adoption path if you already have tooling that talks to S3, Postgres/pgvector, ClickHouse, Neo4j, Redis, or MongoDB: point it at Relata and the same governed, bi-temporal, ACL-enforced, audited store is underneath.
All doors are off by default unless their port env var is set, bind to 127.0.0.1, and share one credential: RELATA_BEARER_TOKEN. pgwire refuses to start without a token; the others default to open dev mode when unset.
At a glance
| Door | ADR | Port env (default) | Persisted in governed store? |
|---|---|---|---|
| S3 | 164 / 170 | RELATA_S3_PORT (9191) | Yes — S3Object / S3Bucket |
| Postgres + pgvector | 165 | RELATA_PG_PORT (5433) | Yes — typed rows + _emb_text vectors |
| ClickHouse HTTP | 166 | RELATA_CLICKHOUSE_PORT (8123) | Reads only (governed /query) |
| ClickHouse native TCP | — | RELATA_CH_NATIVE_PORT (9000) | Reads only |
| Neo4j HTTP Cypher | 167 | RELATA_NEO4J_PORT (7474) | Reads only (Cypher→SQL) |
| Neo4j Bolt | — | RELATA_BOLT_PORT (7687) | Reads only (Cypher→SQL) |
| Redis RESP | 168 / 170 | RELATA_REDIS_PORT (6379) | Yes — KvEntry |
| MongoDB wire | 169 / 170 | RELATA_MONGO_PORT (27017) | Yes — MongoDocument |
The native Relata protocols are also always available:
| Door | Default port | Notes |
|---|---|---|
| HTTP REST | 9090 | /query, /memory/*, /mcp, /health, /status, /audit/count, /cluster/nodes, /watch/stream, /sparql |
| gRPC | 50051 | Used by the Rust SDK (ADR-073) |
| Arrow Flight | 8815 | Zero-copy columnar streaming; enable with RELATA_FLIGHT_ENABLE=true (#958) |
| MCP | /mcp | Model Context Protocol on the HTTP door |
| SPARQL | /sparql | Single Basic Graph Pattern over KnowledgeTriple + optional LIMIT |
Cross-protocol: write via S3/Redis/Mongo and read the same data back through any other surface, e.g.
SELECT key, size FROM S3ObjectorSELECT value FROM KvEntryover SQL/psql. SmartIngest also runs on governed writes, so identities detected in an S3 object body link to identities in a Mongo doc viaLOOKUP_IDENTITY.
Start the doors
export RELATA_BEARER_TOKEN=change-me
RELATA_S3_PORT=9191 \
RELATA_PG_PORT=5433 \
RELATA_CLICKHOUSE_PORT=8123 \
RELATA_NEO4J_PORT=7474 \
RELATA_REDIS_PORT=6379 \
RELATA_MONGO_PORT=27017 \
relata serveA single end-to-end smoke test for all six ecosystems lives at scripts/protocol_smoke_test.py.
S3 — boto3 / aws CLI / rclone / MinIO client
Nine core ops: ListBuckets, Create/Head/Delete Bucket, ListObjectsV2 + GetBucketLocation, Put/Get/Delete/Head Object, plus multipart upload.
import boto3
from botocore.config import Config
s3 = boto3.client(
"s3",
endpoint_url="http://127.0.0.1:9191",
aws_access_key_id="change-me",
aws_secret_access_key="unused",
config=Config(signature_version="s3v4", s3={"addressing_style": "path"}),
)
s3.create_bucket(Bucket="cases")
s3.put_object(Bucket="cases", Key="exhibit-1.txt", Body=b"hello")
print(s3.get_object(Bucket="cases", Key="exhibit-1.txt")["Body"].read())When RELATA_S3_SECRET_KEY is set, the door requires verified SigV4 and rejects plaintext bearer / unsigned access-key auth.
Read S3 objects back over SQL
SELECT key, size, content_hash FROM S3Object WHERE bucket = 'cases';Postgres + pgvector — psql / psycopg2 / LangChain & LlamaIndex PGVector
psql -h 127.0.0.1 -p 5433 -U relata relata # password = RELATA_BEARER_TOKENCREATE EXTENSION vector;
CREATE TABLE docs (id text PRIMARY KEY, embedding vector(3));
INSERT INTO docs (id, embedding) VALUES ('a','[1,0,0]'), ('b','[0.9,0.1,0]');
-- cosine KNN (auto-routed to Relata's HNSW index):
SELECT id FROM docs ORDER BY embedding <=> '[0.9,0.1,0]' LIMIT 2;INSERT/UPDATE/DELETE and ordinary SELECT work. TablePlus / DBeaver / pgAdmin / DataGrip connect and browse schema via the catalog intercept.
| Operator | Metric | Note |
|---|---|---|
<=> | cosine distance | preferred — ANN index is cosine-only |
<-> | L2 distance | metric-correct via over-fetch + re-rank |
<#> | negative inner product | metric-correct via over-fetch + re-rank |
ClickHouse — HTTP or native
# HTTP
curl -X POST "http://127.0.0.1:8123/?query=SELECT+1" \
-H "X-ClickHouse-Key: change-me"
curl -X POST http://127.0.0.1:8123/ --data-binary \
"SELECT name FROM Person FORMAT JSONEachRow" \
-H "X-ClickHouse-Key: change-me"from clickhouse_driver import Client
ch = Client(host="127.0.0.1", port=9000, password="change-me")
print(ch.execute("SELECT name FROM Person LIMIT 5"))Reads only — the door routes governed SELECTs through the planner.
Neo4j — HTTP or Bolt
# HTTP
curl -X POST http://neo4j:change-me@127.0.0.1:7474/db/neo4j/tx/commit \
-H "Content-Type: application/json" \
-d '{"statements":[{"statement":"MATCH (n) RETURN n LIMIT 5"}]}'from neo4j import GraphDatabase
driver = GraphDatabase.driver("bolt://127.0.0.1:7687",
auth=("neo4j", "change-me"))
with driver.session() as s:
print(s.run("MATCH (n) RETURN n LIMIT 5").data())Cypher subset: relationship path patterns incl. bounded -[r*1..5]->, single-identifier RETURN [AS alias], whitelisted property predicates. Typed labels (n:Person) and typed edges [:KNOWS] are parsed but ignored. Read Cypher only.
Redis — any RESP client
redis-cli -h 127.0.0.1 -p 6379 -a change-me SET foo bar
redis-cli -h 127.0.0.1 -p 6379 -a change-me GET fooGoverned keys persist as KvEntry rows; read back over SQL with SELECT key, value FROM KvEntry.
No MULTI/EXEC, BLPOP, scripting, or cluster commands. Pub/Sub is in-memory (zero persistence).
MongoDB — any Mongo wire client
// pymongo / mongoose / mongosh — all work
const { MongoClient } = require("mongodb");
const c = new MongoClient("mongodb://localhost:27017", {
auth: { username: "relata", password: "change-me" },
});
const db = c.db("cases");
await db.collection("exhibits").insertOne({ _id: "ex1", body: "hello" });
console.log(await db.collection("exhibits").findOne({ _id: "ex1" }));Governed docs persist as MongoDocument rows; read back over SQL with SELECT * FROM MongoDocument.
| Limit | Detail |
|---|---|
| Auth | SCRAM-SHA-256 only |
maxWireVersion | 17 |
| Transactions / change streams | not supported |
$push / $pull / $unset | not supported |
| Nested equality | via flattened columns only |
Per-protocol security notes
- All doors bind to
127.0.0.1and shareRELATA_BEARER_TOKEN. - pgwire is fail-closed — refuses to start without a token.
- The other doors default to open dev mode when the token is unset.
- Egress filtering (ADR-057) applies uniformly across every door.
/sparqlGET+POST verify bearer auth (issue #563 fixed).
See also
- SQL Reference — the underlying query plane
- MCP Tools Reference — agent-native surface
- Limits & Caveats — known partial behaviours per protocol
- Protocol compatibility guide — the full ADR-backed reference