# Architecture

The engine runs next to your agent and the guard runs inside your Postgres. Your data never moves.

BasaltDB has two parts. The engine runs next to your agent. The guard runs inside your Postgres. Your data stays where it is.

![Your agent talks MCP to the BasaltDB engine, which connects to your Postgres with the agent role. Inside your Postgres, the guard checks every write and the ledger in basalt_meta keeps the old values.](https://docs.basaltvault.app/diagrams/engine-overview.png)

Your agent talks MCP to basalt mcp, which hands its requests to the BasaltDB engine next to it. The agent never holds a database URL. The engine connects to your Postgres with the agent role. Inside your Postgres the guard checks every write and refuses the risky ones, and the ledger in the basalt_meta schema keeps the old values so a job can be undone.

## The engine

The engine is one Go program. It runs as its own OS user, and the agent reaches it through a small program, `basalt mcp`, which relays MCP requests to it. The agent holds no database URL. Only the engine holds the agent's scoped credential.

The engine reads each statement, refuses what is never allowed, records reads, and passes the rest to Postgres. It also serves the pages where you approve and undo, on `http://localhost:8787` by default.

## The guard

The guard is the `basalt_meta` schema in your Postgres, with its own roles and triggers. Agent roles have no rights to change tables. The triggers act only for agent roles. They require the reason, save old and new rows in the same transaction, and count rows per action against the [rules](/concepts/rules/), cascades included.

Because the rules live in Postgres, they hold on any path. An agent that opens a direct connection with its credential meets the same checks. If the guard cannot record or evaluate an agent's write, the write fails. Writes by people and by your app are never blocked. They pay one role check.

The guard also checks passkey signatures for approvals and undos, inside Postgres. Whatever carries a signature cannot forge one.

## What is where

| Piece                                | Where it runs                       | Holds                         |
| ------------------------------------ | ----------------------------------- | ----------------------------- |
| `basalt mcp`                         | Next to your agent                  | No credential                 |
| Engine                               | Next to your agent, own OS user     | The agent's scoped credential |
| Guard, ledger and passkey public key | Inside your Postgres, `basalt_meta` | Records, old values, rules    |
| Your tables                          | Your Postgres                       | Your data, unchanged          |

The admin credential is used once, by `basalt init`, and is never stored.

## Where it stops

If the agent shares an OS user with the engine, it can reach the engine's credential. In that same-user mode writes are still guarded by the triggers, but reads over a direct connection are not recorded. An agent with your admin credential, or with `sudo` on the engine's machine, is outside what BasaltDB protects against. See [Limits](/limits/).

## Remove it

BasaltDB adds the `basalt_meta` schema, its own `basalt_*` roles, and triggers and policies on the tables you guard. `basalt uninstall` removes all of it. See [Remove BasaltDB](/guides/remove/).

## Next

- [Install](/start/install/): set up the guard on your Postgres.
- [Rules](/concepts/rules/): what the guard enforces.
