tidepool is a live analytics server. You push rows to it over HTTP. You keep the tables, the model and the dashboards in YAML files in git. The dashboards update while data arrives, and a click filters every number on the page.
$ tidepool init shop $ tidepool serve --config shop # http://127.0.0.1:7070 $ tidepool feed # sample orders, live
one rust binary · rows over HTTP · the model in git · pre-1.0
epoch 4 812€252 300
4 135 orders · 20 rows/s
filter_direction: both. The data is invented. The rules are the product's.associative
A click on a value, a bar or a table row selects it. Every visual on the dashboard then shows only the data that the selection allows. Each filter shows its values in three states:


live
Each table gets an ingest endpoint when you declare it. Send JSON, NDJSON or Arrow. tidepool checks every value and writes all of a batch or none of it. At each epoch, every open dashboard gets only what changed.
Idempotency-Key makes a retry safe, also across a restart.503 with Retry-After.$ curl -X POST 'localhost:7070/v1/tables/orders/rows?wait=visible' \ -H 'content-type: application/x-ndjson' \ -H 'idempotency-key: batch-42' \ --data-binary @orders.ndjson {"written":5000,"replaced":0,"missing":0,"epoch":4813}
50 live sessions, 100,000 rows/s, 200 ms epochs, 10 million orders
0.6 to 0.9 ms, at 100 million orders
the project is code
Tables, the semantic model and dashboards are YAML files. The model is Apache Ossie, with SQL for fields and metrics. tidepool plans every change and gives it a class. It applies the change while it serves, and writes it back to the files.
The same steps apply to the files, the config page, the API and agents. tidepool validate points at the wrong token, and says what you meant.
shop/
├── tidepool.yaml
├── model.ossie.yaml
├── tables/
│ ├── orders.yaml
│ └── customers.yaml
└── dashboards/
└── sales.yaml# model.ossie.yaml metrics: - name: paid_revenue expression: { dialects: [{ dialect: ANSI_SQL, expression: "SUM(orders.amount) FILTER (WHERE orders.status = 'paid')" }] }
$ tidepool plan --config shop --base main 1 change (0 safe, 1 rebuild, 0 destructive) + relationship product_supplier (products → suppliers) rebuild (joins existing data: the key dictionaries are merged)
fast, and checked
The numbers are from an Apple M1 Max (10 cores), release build, with the benchmarks in the repository. The reference is a retail star schema.
8 clients, batches of 10,000, until visible. NDJSON: 2.2M.
100 million orders, region × category, three metrics
for each stored order. 100 million orders: about 2.8 GB.
100 million orders, from a checkpoint and the log
Random schemas, data and queries from a seed. Each query runs on three paths of the engine, and each answer must be the same as DuckDB's. Live answers are compared after every epoch.
1,000 simulated crashes, some during a checkpoint, and 25 kill -9 cycles of the binary. No acknowledged write is lost.
Each check of the model has a golden test of its exact message. Every YAML sample on this site compiles in the test suite.
with kayak
tidepool reads HTTP only. Its sister project, kayak, reads MQTT, Kafka, NATS, OPC UA and databases. kayak's tidepool output checks its mapping against the table at startup, and sends each batch with an idempotency key.
just demo starts a simulated plant: MQTT → kayak → tidepool, with a live dashboard of the plant floor.
# fragment: kayak's config.yaml outputs: - type: tidepool connection: tidepool table: readings
agents
An agent can read the model, calculate metrics, and plan changes over MCP. Each tool calls the HTTP endpoint that it wraps, with the token of the agent. The agent applies only the change classes that you allow. A person approves the rest.
$ claude mcp add --transport http tidepool http://127.0.0.1:7070/mcp# tidepool.yaml agents: auto_apply: [safe] # the default
limits
No cluster and no shards. The target is up to about 500 million fact rows on one machine.
One model for each server. No tenants and no row-level security.
tidepool has no connectors. Use kayak for brokers and databases.
A query is metrics by fields, under a selection. There is no SQL console.
Dashboards are YAML files. The config page edits the files.
The config format and the data directory can change between minor versions.