Open sourcePostgreSQL extension
Gnomon: Git for Postgres data, built for agents
Give an agent its own branch of your real database, as nothing more than a connection string. See every field it changed, merge it into main when it’s right, and undo it if it wasn’t.
Gnomon runs inside the Postgres you already have. One extension, no copies, no second database.
A branch of production, in an instant
A branch reads everything from main and keeps only what it changes, so it opens instantly and copies nothing, however big your database is. Give one to every agent run, every pull request and every test.
Your application doesn’t change. A branch is a connection string: point a session at it, and the queries it already runs read and write the branch instead of main.
- select gnomon.create_branch('agent/refunds');
- select gnomon.use('agent/refunds');
- -- Every query from here on runs on the branch
- update orders set status = 'refunded' where id = 4182;
Schema changes come along too. Run a migration on a branch to add a column, rename one or create a table, and main stays as it is until the merge, which brings the new shape and its data across together. Every pull request gets its own branch, with the rows and the schema it changed in a comment.
Review data like code
Every branch comes with a diff: each row and field it changed, before and after. Review it in your browser, comment on a single row and settle conflicts side by side. When an agent is done, Gnomon opens the review and sends you the link.
Add checks written in SQL, and Gnomon runs them on the merged result before the merge is allowed to land. An approval covers what you saw: if the branch changes afterwards, it comes back to you.
- orders4182status
paidrefunded - refundsnew rowamount129.00
- customers77credit
0.00129.00
A refund never exceeds its order totalPassed on the branch
Merges that understand your data
When main and a branch change the same value, Gnomon doesn’t just pick a side. Counts add up, JSON merges key by key and text merges line by line. Anything that truly clashes becomes a conflict, for a person to settle or for a query to resolve.
- Where both started10
- Main sells 37
- The branch sells 28
- Merged5
Branches merge into each other too, not only into main, and a single transaction can be picked from one branch onto another.
Undo works the same way. Take back one transaction, everything an agent did this afternoon, or a whole merge. Gnomon never overwrites a change made since; if one is in the way, it asks. And when you just want a table back the way it was at three o’clock, revert it to that moment.
Any moment, exactly as it was
Gnomon keeps the history of every table you track. Read the whole database as it was at any moment, with the queries you already have, and get the same answer every time. When an agent makes a decision, you can see exactly what it saw.
- -- The open invoices at the end of October
- select gnomon.as_of('2026-10-31 23:59');
- select sum(amount) from invoices where status = 'open';
The same history streams out as it happens, to Kafka, NATS or a webhook, and into dbt as snapshots that keep deleted rows. Older history can move to object storage, and Gnomon brings it back when a query reaches that far.
Find the change that broke it
When a check that used to pass starts failing, Gnomon finds the transaction that broke it. It runs the check on the database as it was halfway between the last good moment and now, then halves what’s left, until one transaction remains: who made it, when and why.
- Passed at 08:00, fails now64
- As of 13:10 · passes32
- As of 15:50 · fails16
- As of 14:30 · fails8
- As of 13:50 · passes4
- As of 14:10 · fails2
- As of 14:00 · passes1
Found in 6 steps: transaction 88137, by support-bot at 14:10, “Refund order 4182”. Undo just that one, and everything after it stays.
- # The first transaction after which the check fails
- gnomon bisect refund_within_total --good '2026-11-12 08:00'
Safe to hand to an agent
One command gives an agent a database role, a branch of its own and a connection string. That’s all it needs, whatever it’s built with. It reads and writes its branch, and the database refuses the rest, main included, even when the agent asks for it by name.
- # A database role, a branch of its own and a connection string
- gnomon agent create support-bot
It merges only what you allow
Merging is for the people you choose. Or let an agent merge on its own within rules you write, such as at most twenty rows, only these tables and every check passing. Postgres enforces them, whatever the agent is told.
Nothing leaves before you approve
Emails, webhooks and payments an agent queues stay on its branch until the merge.
Every change has a name on it
Each change records the agent, the run and the reason it gave. Ask which agent changed a price, and why.
Replay what it saw
Gnomon records the moment of every read an agent makes. Replay a run and get back exactly the rows it read.
Try a few ways at once
Start several attempts from the same moment, compare their changes and checks, and keep the best one.
Stop it, and take it back
One command locks an agent out, closes its branches and undoes what it merged, newest first.
Ready for your agents
The Gnomon MCP server, on the agent’s machine or over HTTP, lets it explore the schema, try a change without keeping it, and rewind its branch to a checkpoint.
Build it into your product
The TypeScript and Python SDKs give each task your agents take on a run: a branch of its own, with limits already set. Merge it, send it for review, or let it go.
- import { Gnomon } from "@bitsinfra/gnomon";
- import { nodePostgres } from "@bitsinfra/gnomon/pg";
- const gnomon = new Gnomon({
- app: nodePostgres(appPool), // your application's own login
- runs: nodePostgres(runsPool), // one login shared by every agent run
- });
- // A branch for this task, discarded unless it's merged or submitted
- await using run = await gnomon.startRun({
- task: "Refund order 4182",
- actor: "support-bot",
- });
- await run.sql("update orders set status = 'refunded' where id = 4182");
- const { checks, changes } = await run.summary();
- if (checks.passed && changes.rows <= 20) await run.merge();
- else await run.submit({ title: "Refund order 4182" });
Runs can’t read each other’s branches, even when they share one database login. The Approve, Reject and Undo buttons in your own product call the same review.
Bring the agent framework you already use: the Anthropic SDK, the Claude Agent SDK, the Vercel AI SDK, the OpenAI Agents SDK, LangChain or any MCP client gets the same few tools, bound to one run. They work through your drivers and ORMs, from node-postgres and Prisma to psycopg and Django. And in your tests, each test gets its own branch of one seeded database and can check exactly what it changed.
Get started
Gnomon is open source under the PostgreSQL License. It runs on PostgreSQL 15 to 18, on your own servers or on managed Postgres such as Amazon RDS and Supabase.
create extension gnomon;Or let gnomon init install it, track your tables and check the setup. There’s also a container image with everything switched on. The tutorial takes you through a branch, a review and an agent with its own connection string.
- # TypeScript
- npm install @bitsinfra/gnomon
- # Python
- python -m pip install gnomon-postgres