Self-driving Postgres on the edge
The phrase is not ours. In July 2025 Nikolay Samokhvalov, founder of Postgres AI ↗, announced an open-source project called Self-Driving Postgres ↗. His aim fits in one sentence:
“Our goal is to reduce manual interventions as much as possible.”
Nikolay Samokhvalov, Postgres AI, July 2025
He borrowed the levels of driving automation, from 0 (manual) to 5 (full automation), and applied them to each area of database operations separately: index care, vacuum, upgrades and so on. And he put the emphasis on health rather than cleverness: what matters, he wrote, is “not automated index creation, but rather automated index health management”. Postgres AI has since sharpened this to fixes that come with evidence, are tested on a copy of the data, and need the owner’s approval before they touch production. We find that last step as important as the first.
Next to a machine tool there is no database administrator. There is an operator who sees a screen, and in the control cabinet a small computer that a controls engineer needs a ticket to restart. A database that only stays healthy if someone opens a shell will, in practice, not stay healthy. Background builds fall behind, the disk fills, and the first sign is a search that quietly finds less than it should. So we want to take Nikolay’s idea to the shop floor: MorletDB should look after itself, area by area, and know exactly where it must stop and ask.
Why MorletDB is a good candidate
- Its upkeep is already explicit. Building search envelopes, chunk summaries and roll-ups, and verifying stored data, are SQL calls that do a bounded batch and return how much they did. A supervisor calls them until they return 0. A killed job resumes without duplicates.
- What can be rebuilt is separate from what cannot. Raw samples are the only thing that cannot be recomputed. Everything that makes them fast to search is derived. Under pressure the system can give up speed before it gives up data.
- Forgetting is already a recorded act. Removing data goes through memory levels with a dry run and a ledger entry with the bytes freed and a checksum of what was removed, never through a silent age-based delete.
- It can prove it is consistent. Chunks carry CRC-32C checksums, and a verify pass decodes every chunk and checks its summary against the samples, so a health check is a proof, not a guess.
- It is PostgreSQL underneath. Crash recovery, transactions, roles and backups are inherited rather than reinvented.
The line it must not cross
In Nikolay’s levels, MorletDB should run at a high level for everything above the bottom row of the picture, and at a low one for the bottom row itself. Most self-tuning systems risk a slow query that gets rolled back. MorletDB stores recordings that cannot be measured again. So the rule is narrow on purpose: automate every job whose output can be rebuilt, ration the disk on its own, and never delete raw data unless a person approved that exact plan and a verified copy exists elsewhere. It will also never update itself; in a plant, updates go through change control.
When the disk runs short, the order is fixed. Warn early, in time remaining rather than percent. Pause background work. Drop rebuildable search data if a policy allows it. Then refuse new recordings, with a clear reason. Refusing new data is a visible failure someone can fix. Losing old data unnoticed is not.
What the operator sees
One state: Normal, Attention or Action required, as industrial screens already do it. Each item says what is happening, what happens if nobody acts, one action and who should take it: “Disk full in about 6 days at the current recording rate; then new recordings are refused. Maintenance: add storage or confirm export.” Things the system fixes by itself are logged, not alarmed. The same status should reach the plant’s screens, monitoring and, read-only, AI agents over MCP.
Update, 8 November: the first tests
A day later, part of the design runs. morlet-steward ↗ is a small program next to the database, as a container or a systemd service. It runs the rebuildable jobs (envelopes, summaries, roll-ups, a weekly morlet_verify pass) in one loop with a time budget, only when the machine is not busy, and writes a row for every action and one plain status. Its database role can build derived data and cannot remove stored samples: its test checks that DELETE, UPDATE of samples, TRUNCATE and DROP are refused.
Then we filled a disk on purpose. On a Raspberry Pi 3B+, the database lived on a 1.2 GB filesystem, and a writer appended incompressible noise until it was refused. The result ↗:
- Refused before full. With a 300 MB reserve, the steward set the ingest hold at 295 MB free, after 54 million samples. New appends then failed with a clear reason (SQLSTATE 53100), never with a PostgreSQL write error, and the database log shows no PANIC.
- Recovered alone. When 200 MB was freed, the steward released the hold and the next append succeeded 14.5 seconds later, with no person involved.
- Nothing lost. All 208 acknowledged batches read back bit for bit (SHA-256).
The edge also had a say. The first run was stopped by hand because the power strip feeding the Pi started clicking. The Pi kept power, but the soak will run on a better outlet. Power is part of the problem, not just the disk.
Half of the line not to cross is now enforced in SQL, not just written down. Anything that removes or changes stored samples, or updates the extension, is a plan. The steward or a person proposes it, a second person approves that exact plan (tied to its hash, valid for 24 hours, applied once, no self-approval), and a person applies it. The steward notices when a newer pg_morlet is installed and proposes the update. It never applies one. The other half, a verified copy elsewhere before raw data goes, is not checked yet; it waits for the backup drills (#192 ↗). These rules bind the steward and the plan path; the database owner can still act directly, as in any PostgreSQL.
Search on the Pi also got faster. Exact search used to build query matrices larger than the Pi’s cache; now it scores windows directly when they do not fit. A query over 1,341 windows of 16,384 samples went from 15.1 s to 1.5 s, with bit-identical distances (results ↗). All of this is in release 0.3.8-alpha.1 ↗.
Still open
Of the four steps in the picture, step 4 (refuse new recordings) has now been tested on a real disk. Steps 1 and 2, warning in time remaining and pausing background work, are built and unit-tested, but need days of real growth to show they act in time. Step 3, dropping rebuildable search data by policy, is not built yet. The status is a view that an HMI can poll and a status / check command; the read-only MCP tool and the metrics endpoint (#197 ↗) are not built yet. MorletDB has also not yet passed a power-cut test (#190 ↗) or a multi-week soak (#191 ↗), which will run on the Pi with live data from a smart plug. The plan and its progress are in issue #287 ↗ Comments and objections are welcome there.