Protocol Compatibility
RelataDB speaks 8 compatibility doors plus 5 native protocols (13 wire surfaces total) from one binary and one governed store. Any existing client library that speaks one of the compat doors works without the Relata SDK. Backed by ADR-163–ADR-170.
All compat doors bind to 127.0.0.1 and share one credential: RELATA_BEARER_TOKEN. Doors auto-enable when RELATA_BEARER_TOKEN is set (any tier); an explicit RELATA_<DOOR>_ENABLE=true|false overrides. With no token and no explicit enable, doors stay off by default (an unauthenticated port is never auto-exposed). pgwire refuses to start without a token. On non-free profiles, an explicit =true without a token fails closed, and RELATA_TENANCY_MODE=multi refuses the tenant-less shared-token doors (use pgwire, which carries per-connection org).
Cross-protocol consistency: write via S3, Redis, or MongoDB and read the same data back over SQL, pgwire, or any other surface. ACL, org isolation, and the audit log apply on every door uniformly (ADR-170).
Protocol matrix
| Door | ADR | Port env var (default) | Writes to governed store? |
|---|---|---|---|
| S3 (AWS / boto3 / rclone) | 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) | Read-only (governed SELECT) |
| ClickHouse native TCP | — | RELATA_CH_NATIVE_PORT (9000) | Read-only |
| Neo4j HTTP Cypher | 167 | RELATA_NEO4J_PORT (7474) | Yes — CREATE/MERGE via governed write door (#1090) |
| Neo4j Bolt | — | RELATA_BOLT_PORT (7687) | Yes — CREATE/MERGE via governed write door (#1090) |
| Redis RESP | 168, 170 | RELATA_REDIS_PORT (6379) | Yes — KvEntry |
| MongoDB wire | 169, 170 | RELATA_MONGO_PORT (27017) | Yes — MongoDocument |
Native Relata protocols (always on):
| Door | Default port | Notes |
|---|---|---|
| HTTP REST | 9090 | /query, /ingest, /search, /memory/*, /mcp, /health, /status, /metrics, /types, /specs, /sparql, /watch/stream |
| gRPC | 50051 | gRPC door (ADR-073) |
| Arrow Flight | 8815 | Zero-copy columnar streaming; enable with RELATA_FLIGHT_ENABLE=true |
| MCP | /mcp on HTTP | Model Context Protocol tools |
| SPARQL | /sparql on HTTP | Single Basic Graph Pattern over KnowledgeTriple + optional LIMIT |
Start the doors
export RELATA_BEARER_TOKEN=<your-strong-token>
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 compat doors: scripts/protocol_smoke_test.py.
S3 — boto3 / aws CLI / rclone / MinIO client
Supported operations: ListBuckets, CreateBucket / HeadBucket / DeleteBucket, ListObjectsV2, GetBucketLocation, PutObject / GetObject / DeleteObject / HeadObject, and 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 world")
body = s3.get_object(Bucket="cases", Key="exhibit-1.txt")["Body"].read()
print(body)When RELATA_S3_SECRET_KEY is set the door requires verified SigV4 and rejects plaintext bearer auth.
Read S3 objects over SQL
SELECT key, size, content_hash FROM S3Object WHERE bucket = 'cases';Limits
- Buckets must be empty to delete.
- Multipart parts are in-memory only (lost on restart).
- ETag is SHA-256.
- Object bodies ≥
RELATA_S3_BLOB_THRESHOLD_MB(default 4 MiB) spill to the content-addressed blob store.
Postgres + pgvector — psql / psycopg2 / LangChain 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 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. GUI clients (TablePlus, DBeaver, pgAdmin, DataGrip) connect and browse schema via the catalog intercept.
| KNN 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 |
pgwire is fail-closed: refuses to start when
RELATA_BEARER_TOKENis unset.
ClickHouse — HTTP or native TCP
# 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/ \
-H "X-ClickHouse-Key: change-me" \
--data-binary "SELECT name FROM Person FORMAT JSONEachRow"from clickhouse_driver import Client
ch = Client(host="127.0.0.1", port=9000, password="change-me")
rows = ch.execute("SELECT name FROM Person LIMIT 5")
print(rows)Read-only. The door routes governed SELECTs through the planner; writes are not supported.
Neo4j — HTTP Cypher or Bolt
# HTTP Cypher
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 supported:
- Relationship path patterns including 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:
SELECT key, value FROM KvEntry WHERE key = 'foo';Not supported: MULTI/EXEC, BLPOP, scripting, cluster commands. Pub/Sub is in-memory only (zero persistence).
MongoDB — any Mongo wire client
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:
SELECT * FROM MongoDocument WHERE collection = 'exhibits';| 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 |
Arrow Flight — zero-copy streaming
# Enable on the server
RELATA_FLIGHT_ENABLE=true relata serveConnect any Arrow Flight client (Python pyarrow.flight, etc.) to grpc://localhost:8815:
import pyarrow.flight as fl
client = fl.connect("grpc://localhost:8815")
reader = client.do_get(fl.FlightDescriptor.for_command(
b"PURPOSE 'analytics' SELECT * FROM Person"))
for batch in reader:
print(batch.data.num_rows, "rows")Arrow IPC format — no JSON intermediate, no string serialisation. Use for high-throughput columnar reads.
SPARQL
# GET
curl "http://localhost:9090/sparql?query=SELECT+%3Fs+%3Fp+%3Fo+WHERE+%7B+%3Fs+%3Fp+%3Fo+%7D+LIMIT+10" \
-H "Authorization: Bearer $RELATA_BEARER_TOKEN"
# POST
curl -X POST http://localhost:9090/sparql \
-H "Content-Type: application/sparql-query" \
-H "Authorization: Bearer $RELATA_BEARER_TOKEN" \
-d "SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 10"Single Basic Graph Pattern over KnowledgeTriple. Optional LIMIT. Both GET and POST verify bearer auth.
Security notes
- All doors bind to
127.0.0.1. - All doors share
RELATA_BEARER_TOKEN. - pgwire is fail-closed (refuses to start without a token).
- All other doors default to open dev mode when the token is unset.
- Egress filtering (ADR-057) applies uniformly on every door.
- Cross-protocol reads and writes go through the same planner with the same ACL, org isolation, and audit chain.
See also
- SQL Reference — the underlying query plane
- MCP Tools Reference — agent-native surface
- Limits — per-protocol status and known caveats