Use this page to put BasaltDB on a Postgres you own and choose the tables your agent may touch. To try it first on a sample database, use the Quickstart.
You need:
- macOS or Linux, with
sudo. - Go 1.26 or newer, and
git. - A Postgres you own: Supabase, RDS, or one you host yourself. You need its admin connection string, the one for the
postgresuser. - A browser on the same machine, with a passkey (Touch ID, a security key, or a password manager that stores passkeys).
- An agent that supports MCP. See Connect an agent.
The admin connection string is used once, by basalt init, typed into its hidden prompt. It is never stored. Do not export it or put it on a command line.
1. Build and install basalt
Section titled “1. Build and install basalt”There is no release download yet. You build basalt from source. You need Go 1.26 or newer and git.
git clone https://github.com/BasaltDBHq/BasaltDB.git
cd BasaltDB
go build -o basalt ./cmd/basalt
sudo install -d -o root -m 0755 /usr/local/libexec
sudo install -o root -m 0755 basalt /usr/local/libexec/basalt
sudo mkdir -p /usr/local/bin
sudo ln -sf /usr/local/libexec/basalt /usr/local/bin/basalt
basalt version
basalt version prints the version.
The engine runs as its own OS user from the real file behind the link, /usr/local/libexec/basalt. Whoever can change that file can run code with the agent’s credential. So basalt init and basalt service install check that the file and every directory above it belong to root and are not writable by group or others. If they do not, they stop before changing anything:
basalt: /usr/local/bin is owned by uid 501, not root: the engine service runs /usr/local/bin/basalt as the engine's OS user, so only root may be able to change it or any directory above it. Install basalt in a root-owned directory and run that copy: ... (or run basalt init with --no-service)
That is why the commands above put the binary in /usr/local/libexec and only link it from /usr/local/bin. Do not install it in your home directory.
2. Get the admin connection string
Section titled “2. Get the admin connection string”Supabase. In the dashboard press Connect and copy the string that matches your network.
| String | Use it |
|---|---|
Session pooler, port 5432 (postgres.<ref>@aws-0-<region>.pooler.supabase.com) |
If unsure. Works on IPv4 and IPv6. |
Direct connection (db.<ref>.supabase.co) |
Only if your network has IPv6. |
Fill in [PASSWORD] with your database password. URL-encode characters such as @, /, : and #. Add ?sslmode=require at the end.
Other Postgres. Use postgresql://postgres:PASSWORD@HOST:5432/DBNAME?sslmode=require. See Hosts for RDS and self-hosted notes.
3. Guard your tables
Section titled “3. Guard your tables”Name the tables the agent may use. --write lists tables it may read and change. --read lists tables it may only read. Both take a comma-separated list of schema.table.
basalt init --agent my_bot \
--write public.leads --read public.lead_notes
my_bot is the agent’s name. Pick any name. Init asks, in order:
Admin connection string (used once, never stored):Paste the string from step 2. Nothing is echoed.- Only if a table has row-level security on and no policy for the agent:
... hides its rows with row-level security. Let my_bot see all <n> rows of this table? [y/N]. Answeryto add a policy for the agent role only. Withnthe agent reads zero rows. Supabase can turn row-level security on for every new table. Init asks before it shows the SQL. - It prints the setup SQL, then
Run this SQL as postgres? [y/N]. Typey. basalt: guard installed; agent role basalt_agent_my_bot- It prints a
http://localhost:8787/passkeys/register#...link. Open it, press the button, confirm with your passkey, copy thebasalt-passkey.1....code the page shows, and paste it atPaste the code the page shows:. Thenbasalt: passkey registered for localhost. Install the engine as a background service? ... [Y/n]Press Enter. Init runs onesudo, installs and starts the service, and checks that the engine answers.
Port 8787 must be free while init waits for the passkey, and afterwards for the engine. lsof -nP -iTCP:8787 -sTCP:LISTEN shows what holds it.
4. Check that it works
Section titled “4. Check that it works”basalt status --agent my_bot
curl -s http://localhost:8787/healthz
basalt status reports the engine, the guard version and the passkey, and lists any problem with what to do about it. curl prints ok.
5. Connect your agent
Section titled “5. Connect your agent”Next: Connect an agent. The agent starts basalt mcp --agent my_bot.
If something is off
Section titled “If something is off”tables ... not found in database: the tables in--writeor--readdo not exist in the database this connection string points at. Init checks first and changes nothing.- The agent reads zero rows from a table that has rows: row-level security is on with no policy for the agent. Run step 3 again and answer
yto the row-level security question, or add--agent-rls=all-rows. /mcpshows the server failed, or the connection closes at once: the engine admits only the OS user that raninit. Start the agent as that user.guard schema vN is older than this build's vM: runbasalt upgrade --agent my_bot. See Upgrade.- No
sudo, or you do not want a service: add--no-servicetobasalt init. It prints the onebasalt engine --config ...command to run in the foreground as you. Writes are still guarded in Postgres, but your user can read the agent’s credential file.
Remove it
Section titled “Remove it”basalt uninstall
sudo basalt service uninstall
basalt uninstall asks for the admin connection string, then drops the basalt_meta schema, the guard’s triggers and policies, and the basalt_* roles. service uninstall stops and removes the engine service. See Remove BasaltDB.
BasaltDB · Apache-2.0