Skip to content
thefoxbytePublic

About

FoxByte — PostgreSQL with instant branches and a tamper-evident record of every schema change

Resources

Code of conduct

Contributing

Security policy

Stars

7 stars

Watchers

0 watching

Forks

FoxByte — every schema change on record, every row change live

Postgres for AI agents — instant branches, and a tamper-evident record of every schema change.

FoxByte is PostgreSQL with instant branching, for a situation that did not use to exist: code writing to your database without a person having read it first.

Branching is how an agent gets a database of its own — a full copy in seconds, thrown away when it is done. The Blackbox is why you can let it near one. Every CREATE, ALTER, DROP and GRANT is recorded as it happens, attributed to the login that made it, in an append-only hash chain you can verify. A change an agent made at 3am is distinguishable from one you made, and a policy gate can refuse the destructive ones before they run.

Underneath it is stock PostgreSQL 18 on local NVMe, so commits keep native latency. Branching and time-travel move off the commit path — ZFS copy-on-write clones, and asynchronous WAL archival (wal-g) for point-in-time recovery. It speaks the native Postgres wire protocol, so your driver, ORM and SQL are unchanged.

The command-line tool is fox. Everything below is a fox … command.

New here? Jump to Install · Quickstart · Blackbox


Screenshots

The web console is served by the engine itself at https://localhost:8080 — no separate dev server to run.

The FoxByte landing page

Ops dashboard Blackbox
Dashboard Blackbox
SQL console Realtime
Console Realtime

What you get

  • Blackbox — every CREATE/ALTER/DROP/GRANT recorded with the actor (human or agent), tool, and branch; tamper-evident (hash-chained and append-only, checked by fox blackbox verify, with signed anchors for what a database superuser could rewrite). The actor is the login the session authenticated as, which nothing the session runs can change: people and agents each log in through the gateway as a role of their own. Where an application acts for one of its users, it can say which with a signed token, and the record shows the change was made for that user, asserted by the application.
  • Instant branching — fox branch create qa clones the whole database in seconds (copy-on-write), fully isolated; main is untouched. Plus fox branch reset (start over) and fox branch diff (what changed, from Blackbox).
  • Time travel / PITR — continuous WAL archival; restore to any point.
  • One endpoint — connect to :6432; the database name is the branch. Idle branches scale to zero and wake on connect. TLS on by default, so sslmode=require clients connect out of the box.
  • A database per AI agent — the Agent Branch API over HTTP, or the Model Context Protocol (fox mcp): an agent gets a database, runs SQL, sees what it changed (from Blackbox), and throws it away — one standard interface.
  • Migrate from anything — import from PostgreSQL, MySQL/MariaDB, MongoDB, and .sql/.csv/.json/.ndjson files, each landing in a fresh branch.
  • ETL pipelines (experimental) — dbt-style SQL models with data-quality tests, each run against a throwaway branch.
  • High availability — a hot standby with transparent ha failover (single-VM demonstration).
  • Accounts, API keys, RLS — email/password or GitHub/Google OAuth; keys are the gateway password; Postgres row-level security and GRANTs apply to clients.
  • Web console — a React UI served by the engine: dashboard, SQL console, Blackbox viewer, import, pipelines, API keys.
  • Client SDKs — an OpenAPI spec (served at /api/openapi.yaml) plus dependency-free Python and TypeScript clients.

Per-install credentials are generated on first run — nothing is hardcoded.


Blackbox

The differentiator: Blackbox, the database's own flight recorder for schema changes (formerly called the Schema Ledger — fox ledger …, the /ledger API routes and the original MCP tool names all still work). Three Postgres event triggers, installed into main and inherited by every branch, capture every schema change and attribute it:

  • who — the actor (a human email, or agent-alice) and whether it was a human or an agent;
  • for whom — where an application said so, the user it acted for: asserted by shop when the application vouched with a token signed by its key, or claimed when a client only said so;
  • what — the command, the object, and the full statement;
  • context — the tool (application_name, e.g. cursor/opus), the branch, and the session;
  • a guardrail — destructive commands (DROP TABLE, DROP SCHEMA, TRUNCATE) are blocked by policy unless an admin overrides them, and blocked attempts are recorded too;
  • data changes by agents — every UPDATE and DELETE an agent runs is recorded with its table and statement (people's are not, to keep ordinary writes fast), and every TRUNCATE from anyone;
  • limits on agents' changes — an agent's UPDATE or DELETE is refused once it has changed more rows of a table than that table's limit (100 by default, whatever its WHERE says), and refused outright with no WHERE at all, and over time each agent may change at most 1,000 rows of a table per hour across all its statements. fox guardrail limit and fox guardrail budget change them, per table if needed; an admin can let one statement through.
fox blackbox            # every schema change on this branch, most recent first
fox blackbox verify     # check the hash chain: an edited or deleted entry breaks it

It cannot be quietly rewritten. The table is append-only, and each row is hash-chained to the one before it, so a deleted or edited entry breaks the chain and fox blackbox verify catches it. A database superuser could rewrite rows and recompute every hash after them; that is what anchors are for. Every few minutes the engine writes a checkpoint of the chain to a file outside the database, signed with a key the database cannot read, and fox blackbox integrity (or the standalone fox-verify --pubkey) checks the rows against them. Writing those anchors for a branch's Blackbox is an Enterprise feature; checking them is not, in any edition — an independent verifier you have to buy is not much of an independent verifier, and an install that anchored before upgrading keeps every anchor it has and can still prove it. The security log's own anchors are free as well: that is the accountability trail, and safety stays free. Keep anchors off the machine and give the public key (fox blackbox anchor-key) to whoever audits; someone with root on the machine itself holds the key too, so for them anchors held elsewhere are the proof. fox blackbox anchor-target set s3://bucket … copies every anchor to a bucket of its own, ideally one the database administrators do not control, locked in Object Lock's COMPLIANCE mode for a year so nobody can remove or rewrite it; fox check warns while there is none. And because the gateway logs each client in as a per-user Postgres role, the recorded actor is the login the session authenticated as, and no SET in the session changes it: a person's own role, an agent key's agent role (agent:<email>), an agent branch's role (agent-<id>), and for MCP the key's account's agent role. A database superuser is outside that, as for any record a database keeps about itself: they can attribute anything to anyone, which is what anchors held where they cannot reach are for. There is a Blackbox page in the web console too.

Who a change was for. An application that serves many people through one account can say, per transaction, which of its users a change is for. Register it once (fox app register shop --account shop-svc@example.com --key shop.pub), sign a short-lived token per user with its private key, and pass it with the change (SELECT bb.act_for($1), or withActor in the clients). The record then shows alice, asserted by shop. That means the application vouched for alice, with a key only it holds and from its own login, not that alice was present: the application, or whoever holds both its key and its credentials, can assert anyone, which is why a key can be revoked and reported compromised from a given moment. A value a client sets by hand is never taken for an assertion.

And what the event triggers miss. The record is written by event triggers, and a database superuser can stop them (SET event_triggers = off, SET session_replication_role = replica, ALTER EVENT TRIGGER … DISABLE); roles, role memberships, databases and settings never reach them at all. So every five minutes the engine compares the catalogue with what it saw last time, and writes what no entry accounts for into the Blackbox: UNRECORDED for a change made with the triggers stopped, OBSERVED for a role, a membership or a setting, and risk kill-switch for one that switches the record off. Who made such a change is unknown, but it is on the record. fox blackbox scan runs it now, and docs/blackbox-coverage.md lists exactly what the Blackbox records and what it does not.

Undo a change you should not have made. Because every entry carries the transaction that made it, and main archives its write-ahead log, the record is not only evidence — it is a way back. Point at an entry and get a new branch holding main exactly as it was just before that change, with main left alone:

fox blackbox entries            # the newest entries with their ids
fox blackbox branch-before 42   # a branch of main as it was just before entry 42
fox blackbox branch-before 42 --as before-the-drop   # …under a name you choose

It restores a base backup and replays WAL, so it takes a few minutes and needs a base backup taken before the change. Inspect the new branch, copy what you need back, and throw it away — or point your application at it. The same action is on every row of the Blackbox page in the console, and at POST /api/branches/main/ledger/{id}/branch. main is the only branch this works from: it is the only one that archives WAL.

Bring a branch's changes back. Branching was half a workflow until this: you could copy the database, change it, and prove what changed — and then there was no way to apply it to main. A change request offers a branch's recorded statements for review, and someone who can manage the target applies them:

fox branch request dev --to main   # what dev has that main does not; nothing is applied
fox request show 3                 # the statements, in the order they ran on dev
fox request approve 3              # applied to main in one transaction

What is applied is the Blackbox's own record of what ran on dev, so main ends up holding the same statements, each attributed to whoever wrote it, with the approver beside it. It is refused if both branches changed the same object since they split, if main's policy gate would block a statement, or if there is nothing to promote. Schema only — no data is moved. An agent can ask (MCP request_changes) and cannot approve its own: approving needs the right to manage the target. There is a Requests page in the console.

Beside it, a security log records what happens at the doors — sign-ins and failed ones, sign-ups, API keys made and revoked, password changes, deleted accounts, admin grants and every refused request — chained and anchored the same way: fox audit, fox audit verify, and GET /api/audit for admins.


Install

One command installs the fox CLI; a second brings everything up. On macOS and Windows the Linux engine (ZFS/btrfs + Docker + Postgres) runs transparently inside a managed VM, so day-to-day you only ever type fox ….

Every install pulls the latest engine build and (re)installs it, so re-running setup always updates you to the newest version rather than reusing an old one.

macOS

Needs Lima for the local Linux VM.

brew install lima
curl -fsSL https://get.thefoxbyte.com/install.sh | sh
fox setup

fox setup creates a dedicated Lima VM, installs Docker + ZFS in it, and brings the stack up. Your first fox setup downloads Ubuntu (a few minutes); after that it's fast.

Linux

The engine runs directly (no VM). ZFS + Docker are provisioned on first start.

curl -fsSL https://get.thefoxbyte.com/install.sh | sh
sudo fox start

The services listen on 127.0.0.1 only. To reach them from other machines, set FOX_LISTEN=0.0.0.0 — TLS is then required, so give it a real certificate with FOX_TLS_CERT/FOX_TLS_KEY — and put a firewall in front (see Security defaults).

Windows

Run in PowerShell (not Command Prompt — irm/iex are PowerShell commands). Needs Windows 10 21H2+/11 with virtualization enabled; everything else is handled for you. The engine runs in a dedicated WSL2 distro that stores branches on btrfs, so it works on any WSL kernel — nothing kernel-specific to build.

irm https://get.thefoxbyte.com/install.ps1 | iex

That installs WSL if absent (no Linux distribution of your own needed — FoxByte brings its own dedicated distro), downloads FoxByte, puts it on your PATH, and runs fox setup. If Windows needs a reboot to finish enabling WSL, it says so and resumes automatically afterwards. Your other WSL distros and Docker Desktop are untouched. Full prerequisites and troubleshooting: docs/windows-setup.md.

From source (contributors)

make build       # host binary -> ./bin/fox
make vm-build    # build the Linux engine into the Lima VM (macOS)

Set FOX_NO_REFRESH=1 when running fox setup from a source build, so it keeps your locally-built engine instead of downloading a release.

Verifying a release

Every release's SHA256SUMS is signed with the FoxByte release key (SHA256SUMS.sig, Ed25519). install.sh checks the signature against the key it carries — which comes from this repository, not from the release — wherever openssl can do Ed25519 (OpenSSL 3; macOS's LibreSSL cannot, and the installer says so; FOX_REQUIRE_SIGNATURE=1 refuses instead). fox update checks it on every update and never installs a release that fails. Each file also has a GitHub build attestation and the release an SBOM (foxbyte-sbom.spdx.json):

gh attestation verify fox-darwin-arm64 --repo thefoxbyte/foxbyte
gh attestation verify oci://ghcr.io/thefoxbyte/postgres-walg:18 --repo thefoxbyte/foxbyte

For maintainers: the release key's private half is the FOX_RELEASE_SIGNING_KEY Actions secret (and a password manager); make release-key made it once, and replacing it would stop released builds from updating. The Actions are pinned by commit and the images by digest; Dependabot proposes Action and module updates, and scripts/check-image-digests.sh reports image pins that have fallen behind their tags.


Quickstart

After fox setup (macOS/Windows) or fox start (Linux), the console opens by itself at https://localhost:8080, with the one-time setup token already in the link — choose an email and a password and you are in. (fox setup-token prints the token if you need it; fox user create <email> works too, and FOX_NO_BROWSER=1 leaves the browser alone.) The first account on an install can override the destructive-change guardrail, which is why it needs the token.

main already has three small sample tables — users, projects and events, with five rows each — so there is something to query, alter and branch straight away. FOX_NO_DEMO=1 starts empty; fox demo drop removes them later.

Then make an API key on the API keys page (or fox apikey create <email> <name>; it is shown once) and use it as the password in the connection string below:

fox check                        # is this install healthy? each failure says what to run
fox status                       # servers, primary readiness, branches
fox branch create qa             # copy-on-write branch of main; prints its connection string
fox connect qa                   # that string again, then a psql shell on the branch
fox sql --branch qa "SELECT 1"   # run SQL and print the result
fox sql --format csv "SELECT …" > out.csv   # or tsv, markdown, json, insert --table <t>
fox sql --format xlsx "SELECT …" > out.xlsx # an Excel workbook
fox export "SELECT …" > all.csv             # every row, streamed (csv, tsv, json, xlsx); read only
fox history                                 # the SQL you ran (never results), kept 90 days
fox history --search orders                 # find one; then: fox history run <id>, show <id>, save <name> --from <id>
fox schema                                  # what a branch holds; fox schema orders [--ddl] for one, with its CREATE script
fox track orders                            # keep created_at, updated_at and last_modified_by on every row
fox pii scan                                # where personal data is (Aadhaar, PAN, mobile, card…); never the values (Enterprise)

Connect any Postgres client through the gateway — the database name is the branch, and the password is your API key:

psql "postgresql://dbadmin:<API_KEY>@localhost:6432/qa?sslmode=require"
CREATE TABLE notes (id serial PRIMARY KEY, body text, created_at timestamptz DEFAULT now());
INSERT INTO notes(body) VALUES ('hello');
fox blackbox qa                  # see that CREATE TABLE, attributed to you
fox branch delete qa             # throw it away; main is untouched

Mint more keys with fox apikey create <email> (or on the web API keys page).


The web console

fox start serves the console at https://localhost:8080 (a self-signed cert, so your browser shows a one-time "not private" warning to accept; point FOX_TLS_CERT/_KEY at a real pair to avoid it). It has:

  • a dashboard (live status + branch create/suspend/resume/delete),
  • a SQL console (run queries against any branch, expand rows as JSON),
  • a Blackbox viewer (filter by actor, table, risk, kind),
  • import and pipelines pages, and API keys.

The web app is embedded in the engine binary and served same-origin — there is no separate dev server to run.


Usage

fox start        # bring EVERYTHING up in the background: stack + gateway + APIs
fox status       # servers, main readiness, backups, HA, branches
fox logs gateway # tail a background server's log
fox stop         # stop servers and containers (data preserved)

Branching

fox branch create qa            # instant copy-on-write branch of main
fox branch list                 # branches and their containers
fox branch reset qa             # re-clone from parent, discarding changes
fox branch diff main qa         # schema changes distinguishing two branches (from Blackbox)
fox branch suspend qa           # stop a branch (data preserved); wakes on connect
fox branch resume qa
fox branch delete qa
fox branch owner qa you@example.com  # hand a CLI-made branch to an account (shows the owner without an email)

Blackbox (fox ledger … works too)

fox blackbox [branch] [--limit N] # captured DDL — attributed and policy-checked
fox blackbox verify [branch]    # verify the tamper-evident hash chain
fox blackbox revert --to <ts>   # point-in-time restore of main on :5433 (like fox restore)

Durability / time travel

Send the backups off the machine before you rely on them. By default the write-ahead-log archive and every base backup go to the object store beside main, on the same disk — so one disk or host failure takes the database and every backup of it at the same moment, and there is nothing left to restore from. fox check says so until a remote target is set. One command fixes it, and a bucket with Object Lock means nothing written there can be deleted before its retention ends.

fox backup create               # base backup -> object storage
fox backup list
fox backup target               # where backups go (the local store, or a bucket)
fox backup target set s3://my-bucket/fox --endpoint https://s3.eu-west-1.amazonaws.com \
    --access-key AKIA… --region eu-west-1   # asks for the secret key
fox backup prune --keep 7       # delete all but the newest 7 full backups
fox restore --to latest         # PITR into a disposable container on port 5433
fox restore --to '2026-08-24 15:07:00+00'
fox backup export               # portable copy of every branch, on this machine
fox backup restore <file> --as <new-branch>

The object store's images come from FoxByte's own registry. MinIO's images left Docker Hub, and then quay.io stopped serving them without credentials, so they are mirrored to ghcr.io/thefoxbyte and pinned there. If you run your own copy, point the engine at it with FOX_MINIO_IMAGE and FOX_MC_IMAGE.

Backups are taken for you. fox start takes a first base backup on an install that has none, so point-in-time restore works from the first minutes; the control plane takes another whenever the newest is older than FOX_BACKUP_INTERVAL (24h) and keeps the newest FOX_BACKUP_RETAIN (7), with the WAL they need. fox status shows how old the newest one is, and warns.

Keep them off this machine. By default the WAL archive and base backups are in the object store beside main — on the same disk, so a disk failure takes both. fox backup target set sends them to any S3-compatible bucket instead (the secret key is asked for, or read from FOX_BACKUP_S3_SECRET_KEY, and kept in a 0600 file). Create the bucket with Object Lock and a default retention, and nothing written there — backups, WAL, and the copies of the Blackbox's and security log's anchors that go there too — can be changed or deleted before it expires, not even by whoever controls this machine. Tested against MinIO with Object Lock; AWS S3 and other providers are expected to work the same way. Moving the target restarts main and takes a first backup there; backups left on the old target stay there, and are restorable after moving back.

Branches are disposable. Only main archives WAL; a branch is a copy-on-write clone for experiments and agents. If a branch holds work that matters, fox backup export --branch <name> keeps a copy.

A base backup belongs to one PostgreSQL major; an export (pg_dump, roles and the Blackbox, verified against its own checksums) restores into the same or any newer one.

High availability

A standby streams from main, authenticating as db_replica — a role that can copy the database and read none of it — admitted by a single pg_hba rule naming it and this install's own network. fox check carries a replication line saying so.

fox ha enable                   # hot standby streaming from main
fox ha status
fox ha failover [--force]       # promote the standby; 'main' reroutes to it
fox ha disable
fox ha failback                 # after a failover: back to main's own container, keeping every write
fox ha sync on | off            # zero data loss: a commit waits for the standby
fox ha drill --yes              # kill the primary for real, and report what it cost
fox node expose --address A --peer B --yes   # let a standby on another machine copy this one
fox node join <token>           # on the other machine: become its standby
fox node unexpose | leave | status | token

fox node expose is the only thing that puts Postgres on a network, and it is off until you ask. It publishes on the one address you name, over TLS with a certificate that standby verifies, admitting only db_replica — which can copy the database and read none of it — and only from the one peer address. The join token it prints carries that CA and that role's password, and deliberately not the install secret. fox check reports the exposure on every run.

On the second machine, fox node join <token> copies that primary over TLS and runs the copy as a standby, verifying the primary's certificate. Everything else then works as it does on one machine: fox ha status shows how far behind it is, fox ha failover promotes it, and fox ha drill measures what a failover costs. That machine's own main sits idle while it follows another primary.

fox ha failover on a machine that follows a remote primary refuses while that primary still answers — promoting would make a second primary and the two copies would diverge, and this command cannot stop a database on another machine. Stop it first, or pass --force if something else already has. The check cannot tell a dead primary from one it merely cannot reach, so a network partition still needs a failover manager to arbitrate.

Replication is asynchronous by default: commits never wait, and losing the machine costs up to a minute of writes (archive_timeout=60). fox ha sync on trades the first for the second — the primary holds a commit until the standby has it on disk, so nothing is lost, and every write is slower by the round trip to the standby. There is one standby, so if it stops, writes stop; fox ha sync off releases them and works while they are waiting. fox check carries a durability line saying which of the two is in effect.

fox ha drill is how you find out what a failover actually costs here rather than taking anyone's word for it: it kills the primary with writes in flight, recovers through the same path fox ha failover uses, and writes a dated report to ~/.fox/drills/ with the writes lost and the time to service — alongside the configuration that produced them, and what the drill did not test.

Accounts & keys

fox apikey create <email> [name]   # mint an API key (shown once)
fox apikey create <email> [name] --agent   # a key to give an AI agent
fox apikey list <email>
fox apikey revoke <email> <id>
fox user create <email>            # create an account (prompts for a password)
fox user passwd <email>            # forgotten password: set a new one
fox user list | delete <email>     # accounts: list, delete

Giving a key to an AI agent? Mint an agent key (--agent, or "for an AI agent" on the console's Keys page). It opens your branches through the Gateway, but as an agent: its changes are recorded as an agent's and the agent guardrails apply to it. It never holds your admin grant, and the console and the control-plane API refuse it.

Forgotten a password? It cannot be recovered — only a hash of it is stored, so nobody can read it back, not even an admin. Set a new one from the machine FoxByte runs on:

fox user passwd you@example.com

That signs the account out everywhere and is recorded in the security log (fox audit). It needs no sign-in, only access to the machine — which is what owning an install means. On macOS and Windows run it exactly the same way; the launcher passes it into the VM for you.


Connect your app

FoxByte is PostgreSQL, so every driver and ORM connects unchanged — set one env var to the gateway address (database = branch, password = API key):

DATABASE_URL="postgresql://dbadmin:<API_KEY>@localhost:6432/main?sslmode=require"

Point Prisma, Drizzle, SQLAlchemy, Django, GORM, ActiveRecord, etc. at that URL.

For the REST API there is an OpenAPI spec (served at https://localhost:8080/api/openapi.yaml) and thin, dependency-free SDKs under clients/:

from foxbyte import FoxByte
db = FoxByte(api_key="key_…", verify_tls=False)   # local self-signed cert
db.create_branch("qa")
print(db.query("qa", "select 1"))
print(db.verify_blackbox("qa"))

Generate a client for any other language from the spec (see clients/README.md).


A database per AI agent

Give each agent its own instant, disposable database — over HTTP:

fox serve --addr :8088          # the Agent Branch API
curl -k -H "Authorization: Bearer $FOX_KEY" -X POST https://localhost:8088/agents/alice/branch
# -> { "dsn": "postgresql://agent-alice:key_…@localhost:6432/agent-alice?sslmode=require", … }
curl -k -H "Authorization: Bearer $FOX_KEY" -X DELETE https://localhost:8088/agents/alice/branch

The agent connects with that DSN — through the gateway, so it works from your machine as well as inside the VM. Its password is an API key scoped to that one branch: it opens no other branch, and the control plane and this API both refuse it. Deleting the branch revokes the key.

…or over the Model Context Protocol, so an agent framework drives it through one standard interface:

FOX_API_KEY=key_… fox mcp   # MCP server on stdio (needs a key)

Client setup and the full tool reference: docs/mcp.md.

MCP tools: create_branch, run_sql, changes (what did I change, from Blackbox), verify_blackbox, list_branches, delete_branch. DDL an agent runs is attributed to that agent automatically.


Import & migration

Every import lands in a fresh branch, so migration is safe and reversible.

fox import --from postgres://user:pw@host/db  --as prod-copy
fox import --from mysql://user:pw@host/db     --as legacy
fox import --from mongodb://host/db           --as events     # collections -> JSONB
fox import --from ./dump.sql                  --as fromfile    # .sql/.csv/.json/.ndjson

fox import --from postgres://… --continuous --as live          # logical replication
fox import-cutover live                                         # finish the cutover

PostgreSQL versions

A fresh install runs PostgreSQL 18 (stock, plus wal-g). An install created on an older major keeps running that major: FoxByte reads the version from your data directory and runs the matching image, so fox update never moves your data between majors behind your back. That is a migration, and it stays your call.

Fresh install PostgreSQL 18
Still supported for existing installs PostgreSQL 16
Moving an install to a newer major fox pg upgrade — shows every change first, takes an export, keeps the old databases until you say so (how)

A base backup (fox backup create) belongs to one major and cannot be restored into another; an export (fox backup export) can. docs/postgres-versions.md has the details, and the checklist for moving FoxByte itself to the next major.

Security defaults

A fresh install exposes nothing it does not have to:

  • Loopback only. The control plane (:8080), Gateway (:6432) and Agent API (:8088) listen on 127.0.0.1; the backup store's ports and a point-in-time restore's :5433 are published on 127.0.0.1 too. On macOS and Windows the VM forwards them to your machine's loopback. FOX_LISTEN=0.0.0.0 exposes the three services.

  • TLS, and no silent fallback. All three serve TLS (self-signed unless you give a certificate). A service that cannot load its certificate refuses to start rather than serve plain HTTP, unless it listens on loopback, and the Gateway refuses a client on another machine that has not switched to TLS (sslmode=require).

  • The first account needs the setup token, and sign-up is closed after it: an admin adds people with fox user create, or FOX_SIGNUP=open lets them register. Signing in with GitHub or Google needs a verified email, and makes no account while sign-up is closed.

  • Brakes on guessing and flooding. Ten failed sign-ins for one address or one email in 15 minutes hold further attempts; request bodies are capped; the Gateway serves at most FOX_GATEWAY_MAX_CONNS (1000) connections and gives a client 30 seconds to authenticate.

  • Branches belong to whoever made them. Every account may use main; a branch made through the console, the API, the Agent API or MCP is its maker's to use and delete; an admin (the first account, or anyone given fox admin grant) may do anything. Other people's branches are not listed, and answer "not found" — through the Gateway too. A branch made with the CLI is an admin's.

  • A password per database role. Each account, each agent and the client role log in to Postgres with their own password, derived from the install secret; the secret itself is the superuser's alone and never appears on a command line.

  • Imports reach public databases. Importing from this machine, a private network or a container is for admins; cloud metadata addresses are refused.

  • No superuser switches in release builds. FOX_AGENT_SUPERUSER and FOX_MCP_SUPERUSER, like FOX_GATEWAY_NOAUTH, only work in a build made with -tags insecure.

  • Backups can leave the machine. fox backup target set sends the WAL archive, base backups and anchor copies to an S3 bucket (see Durability); the keys never appear on a command line.

What FoxByte is not

  • One machine, for now. Compute and storage are separated logically (stateless containers over persistent storage, scale-to-zero) but still run on one host; there is no multi-host deployment. Networked storage disaggregation is on the roadmap.
  • HA is a single-VM demonstration, not a production multi-host deployment.
  • Not a vector database — it is PostgreSQL (use pgvector on it if you like).
  • One instance, shared — accounts own their branches and share main; there are no separate projects or per-project quotas yet.
  • Not the first to branch Postgres. The copy-on-write-clone-as-a-database idea is postgres.ai / Database Lab's, and Neon, Supabase and PlanetScale all offer branching of some kind. What is ours is what happens after the branch exists: the Blackbox, the attribution, and the policy gate.

Development

make build        # host binary -> ./bin/fox
make vm-build     # Linux engine binary into the Lima VM (macOS)
make vet test     # go vet + unit tests (also run in CI on Linux and Windows)
make integration  # full end-to-end test, in a throwaway test VM
make integration-sdks  # the published Python and TypeScript clients, against a live engine
make integration-ui    # the web console in a real browser (Playwright; first run downloads Chromium)

All of them run nightly in CI as well (Actions → nightly), one runner per suite, and one can be run there on demand.

The integration suites (make integration, integration-v2, integration-update, integration-pg-upgrade, integration-sdks, integration-ui) are destructive — they wipe Blackbox history, restore main to an earlier point and fail HA over — so they run in a VM of their own (fox-test, created on first use by make test-vm), never in the VM that holds your install, and refuse to start anywhere else. make test-vm-stop frees its memory; make test-vm-delete removes it.

The web app lives in web/ (Vite + React + TypeScript) and is embedded into the engine binary via the embedui build tag, then served same-origin by fox start.

Releases are automated: pushing a v* tag builds every binary + the install assets and publishes the multi-arch Postgres image to GHCR.


Editions

FoxByte ships as two binaries built from this one tree. fox is the Standard edition and is what the installer gives you by default. fox-enterprise is the same engine with the code under enterprise/ compiled in, and its features need a licence — without one it behaves exactly like Standard.

Standard Enterprise
Branching, gateway, backups, PITR, time travel yes yes
Blackbox: the hash-chained record of every schema change yes yes
Agent guardrails: TRUNCATE blocked; agents' DELETE/UPDATE limited by rows changed, and refused without a WHERE yes yes
Realtime row-level change feed — yes
Writing signed Blackbox anchors (checkpoints, on a schedule) — yes
Checking anchors: fox blackbox integrity, fox-verify, anchor-key yes yes
The security log's own anchors (fox audit verify) yes yes
Writing Blackbox policy rules; impact analysis; asking for and applying a change request — yes
Reading rules, checking a statement against them, the evaluations log, listing and rejecting requests yes yes
Blackbox export (the compliance bundle) — yes
ETL pipelines (fox import is free: migrating in is onboarding, not ETL) — yes
Scanning for personal data (fox pii scan); reading what earlier scans found — / yes yes
The access review report (fox access review) — yes
curl -fsSL https://get.thefoxbyte.com/install.sh \
  | FOX_EDITION=enterprise sh

The command is fox either way. On macOS and Windows the engine runs in a managed Linux VM, and the installer puts the matching edition on both sides.

Already running Standard? An admin can choose Upgrade → Install Enterprise in the console, or switch from a terminal, at the version you have:

fox upgrade --edition enterprise     # sudo on Linux; --edition standard switches back

It shows the Enterprise licence and asks you to accept it before downloading anything, checks the signed release the way fox update does, and replaces fox on both sides of the VM. Databases, accounts, keys and settings are not touched. The command is part of the free edition, but all it knows about Enterprise is the file to fetch: the paid code only ever arrives in that download.

License

  • Core / server (this repo, except clients/ and enterprise/): AGPL-3.0-or-later — see LICENSE.
  • Clients & SDKs (clients/): Apache-2.0 — see clients/LICENSE.
  • Enterprise edition (enterprise/): a commercial licence — see enterprise/LICENSE. Source-available, not open source. The Standard binary contains none of this code, which is checked against the built binary rather than the source (scripts/test_editions.sh).

Using FoxByte does not make your application AGPL. Connecting over the Postgres wire protocol is not a derivative work, and the client libraries are Apache-2.0. The copyleft applies only if you modify FoxByte itself and offer it to others as a service.

About

FoxByte — PostgreSQL with instant branches and a tamper-evident record of every schema change

Resources

Code of conduct

Contributing

Security policy

Stars

7 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages