For developers

Connect Postgres. Write SQL. Read it anywhere.

eddy follows your Postgres, keeps the SQL models you write current on every commit, and serves them as a Postgres database, an HTTP API and an MCP server. Your coding agent can use the same MCP server to preview and apply models while production keeps running.

Nothing installed in your database but one publication and one replication slot; the role needs REPLICATION and SELECT. We onboard every team by hand. How pricing works.

What it needs →

01 · MCP

Your coding agent, connected.

Add eddy as an MCP server in Claude, Claude Code or any MCP client. The agent reads the catalog and the views, previews SQL against real data, and — if you named it a writer — creates the model and waits for it to be ready.

generated from the OpenAPI · readers and writers · every change attributed

~/acme · your coding agent
$ claude mcp add --transport http eddy https://acme.eddy.example/mcp
  signed in through AuthKit · writer

› add a model for weekly active seats per account
  ▸ eddy.get_catalog              12 models · 6 tables
  ▸ eddy.preview_model            refused
    a correlated scalar subquery DataFusion did not decorrelate is not rendered
  ▸ eddy.preview_model            ok · 3,112 rows · 9 operators
  ▸ eddy.create_model             command 312 · hydrating
  ▸ eddy.get_command 312          ready · built in 3.0 s, still ticking
  ▸ eddy.query                    select * from eddy.weekly_active_seats …

  Added weekly_active_seats. Rewrote the subquery as a join so eddy can keep
  it incremental; it matches Postgres row for row.

02 · The loop

Write, preview, review, apply, read.

The same lifecycle from your agent, the API or the console: nothing reaches production without a preview, and a replace shows its effect on the data first.

  1. 01 · write

    SQL, where it lives

    A dbt project (eddy reads the compiled manifest) or a folder of .sql files. Nothing eddy-specific in the SQL.

  2. 02 · preview

    Ask before you build

    preview_model says what the model returns and what the renderer can’t run yet, as data, with the reason, so you or your agent rewrite it.

  3. 03 · review

    See what changes

    For a replace, model_review runs both definitions in Postgres and shows the rows that move, what rebuilds and how long it takes.

  4. 04 · apply

    Online, logged

    Create, replace or drop appends a command. The model builds beside the running tenant, is judged by Postgres from its first change, and the history names who asked.

  5. 05 · read

    From anywhere

    Your workspace’s Postgres endpoint for psql and your app (views under eddy.), HTTP under /api, MCP at /mcp: one snapshot per read, at most one tick behind the last commit.

  6. 06 · debug

    Follow any number

    Provenance walks a row back to its source rows; the trace follows one transaction through every operator it reached.

03 · Your workspace

Connect once. Get three endpoints.

Connect your Postgres and your dbt project, and the workspace gives you a Postgres endpoint, an HTTP API and an MCP server over the same live views. There is nothing to deploy or scale.

~/acme
$ psql "$EDDY_URL"
acme=> select count(*) from eddy.account_health;
  3208
Time: 0.4 ms
eddy console · workspace acme
source      app@db.internal:5432 · slot eddy · 12 tables
models      dbt project · 12 models · all ready
customers   a tenant per account_id · 1,000

postgres    postgres://acme.eddy.example:5439/acme
http        https://acme.eddy.example/api
mcp         https://acme.eddy.example/mcp

readers     everyone you invite
writers     dev@acme.com, ops-agent@acme.com

04 · SQL

The SQL dbt runs, shown as steps.

Joins (inner and outer), window functions, recursive CTEs, running balances, sessions, rolling windows, funnels, latest-per-key and top-N: fifty-six models, from jaffle-shop marts to TPC-H shapes, diffed against DuckDB after every chunk. What the renderer can’t run yet, preview_model says with the reason, such as a correlated scalar subquery that can be rewritten as a join.

models/account_health.sqlready · built while ticking
select a.id, a.name,
       sum(s.mrr)            as mrr,
       count(u.id)          as events_30d,
       case when count(u.id) < 50
            then 'high' else 'low'
       end                   as risk
from subscriptions s
join accounts a on a.id = s.account_id
left join usage_events u
  on u.account_id = a.id
 and u.at > now() - interval '30 days'
where s.status = 'active'
group by a.id, a.name
  1. fromsubscriptions18,204
  2. joinaccounts18,204
  3. wherestatus = 'active'15,977
  4. left joinusage, last 30 days402,118
  5. group byone row per account3,112

05 · Requirements

What your Postgres needs.

The connection check tests each of these before anything is read, and tells you the fix for any that fail.

  • wal_level = logicalLogical decoding on; on RDS and Aurora through the parameter group.
  • A free replication sloteddy needs one; adding a table online briefly needs a second.
  • A role with REPLICATION and SELECTOn the published tables. A superuser works, but isn’t needed.
  • Primary keysOn every table eddy reads; a table without one is keyed by columns unique today, with a warning.
  • One publication, one sloteddy creates them, or uses a publication you make for it.
  • max_slot_wal_keep_sizeBounds the WAL the slot can hold; the check says how long eddy could be stopped before the slot is invalidated.

06 · In and out

Postgres and Kafka in. A Postgres database out.

eddy follows your system of record and your event streams, and serves what it keeps the way your stack already reads data: as Postgres.

Sources

  • PostgresLogical replication from the database your product runs on. Every commit, inserts, updates and deletes.live
  • KafkaProduct events from a topic (Segment’s message format today), exactly once through a restart, joined with your Postgres tables in one query.live
  • Files on S3Parquet and JSONL that land in a bucket, appended or replaced whole. Built and tested; coming to hosted workspaces next.next
  • More sourcesTell us what your data lives in. We add sources behind the same interface, in the order customers need them.ask

Served as

  • A Postgres databaseYour app, psql, psycopg, SQLAlchemy and Metabase connect as they would to Postgres. Every metric is a table under eddy.live
  • An HTTP APIEvery view and every operation, described by an OpenAPI document, one customer’s rows at a time if you want them.live
  • An MCP serverThe same views and operations as tools for agents, with read or write access per user.live

07 · Limits today

What it doesn’t do yet.

Stated plainly, so you can plan around it.

  • Not self-serveEarly access; we onboard each team by hand.
  • Files on S3Built and tested; not yet in hosted workspaces.
  • KafkaSegment’s message format today.
  • TenancyBy a tenant column in your tables, one store per customer.
  • SQLWhat DataFusion plans, rendered operator by operator; the rest is refused with the reason at preview.
  • PricingUsage-based, by rows processed and state kept; rates not published yet.

Not self-serve yet.

Leave a work email and a founder replies within two business days; we onboard every team by hand, on your own schema, and connect your editor to it.