Skip to content
In this postPostgreSQLValkeyQdrantClickHouse

I Gave Claude Code One API Key. It Provisioned a Four-Database Stack in 38 Seconds.

9 min readAI AgentsCLILayerbase

Ask a coding agent to build a feature that needs a cache, and watch what it does about storage. It writes a docker-compose you did not ask for, or stuffs state into a SQLite file next to your source, or stubs the whole layer with an in-memory map and a TODO. The code is usually fine. The storage is improvised, because the agent had nowhere real to put it.

That is the actual problem: an agent halfway through a task needs a database it creates mid-task, writes to, reads back, and walks away from. The walking away is the hard part, because every agent that provisions infrastructure eventually crashes between the create and the delete, and the leftovers are your problem.

So I gave Claude Code one Layerbase API key and a terminal. It provisioned four databases across four engines in 38.3 seconds, verified every connection, gave each one an hour to live, and never wrote a teardown step. A later session went back and actually used them, writing state and reading it back, which is further down.

The brief

Paraphrased, but this is the whole of it. Build the four-layer stack from the small-stack post: durable Postgres for state, a cache for working memory, a vector store for retrieval, something columnar for run traces. Transient, with TTLs. Verify each connection instead of trusting a create response. Stay inside the account's quota.

No engine versions, no region, no naming scheme, nothing about credentials, no teardown plan. What I left out is what I wanted to watch it handle.

The transcript

It counted before it created, which is the behavior I care about most. One declared redaction: names are renamed and the email masked, because the real ones are my projects. Counts, engines, statuses, timings, errors, and commands are verbatim.

text
$ layerbase whoami
Authenticated as [redacted] (pro plan).
Programmatic creates this month: 0/500 (resets 2026-09-01T00:00:00.000Z).

$ layerbase cloud ls
NAME                    ENGINE        STATUS        EXPIRES
billing                 postgresql    running       -
app_prod                postgresql    running       -
... 8 more, every EXPIRES cell a dash

Ten databases, none transient: in --json every one carries expiresAt: null, the field the agent keyed on.

Name the objection before you have to. That is my own account, and the key the agent held could create and delete on it. Layerbase keys can be scoped to a single database, and the scope is enforced in the cloud API's auth layer rather than stored as decoration: a scoped key reaching outside its own database gets a 403. This run used an account-scoped key, the unrestricted default, on my own account, deliberately. If you would not hand an agent your production credentials, scope its key to one database, or give it an account of its own.

It also did arithmetic it should not have had to. Ten is the published Pro cap, it counted ten, and it fired four creates anyway. The limit is real and enforced server side: the create endpoint refuses with database_limit_reached and your count against your max. My account carries a raised max, so accepting those four was correct enforcement of my limit, not a hole in it. The gap that is ours is narrower: nothing in the CLI tells the agent its own limit or headroom, so it compared a list to a number on a pricing page.

bash
layerbase cloud create agent-pg      --engine postgresql --ttl 1h --json
layerbase cloud create agent-cache   --engine valkey     --ttl 1h --json
layerbase cloud create agent-vectors --engine qdrant     --ttl 1h --json
layerbase cloud create agent-traces  --engine clickhouse --ttl 1h --json

The --ttl was its own choice: the skill says transient is the default shape for agent work, and 1h is the CLI floor.

DatabaseEngineCreate to ready
agent-pgPostgreSQL 186.9s
agent-cacheValkey 9.06.2s
agent-vectorsQdrant 1.1610.3s
agent-tracesClickHouse 25.1210.5s

34.1 seconds of wall clock, back to back from a laptop. Three came back "status": "running"; ClickHouse returned in 0.5 seconds saying "provisioning", unusable until a poll flipped it. One engine in four hands you a handle to something that is not up yet.

Verifying before writing code

cloud url handed back a connection string per database, and the agent used every one of them rather than trusting a create response. Postgres answered select version() with PostgreSQL 18.4, Valkey answered PONG, Qdrant returned its 1.16.3 root document over HTTPS, and ClickHouse got a socket connect rather than a query, because layerbase cloud connect shells out to a clickhouse-client I did not have installed.

Valkey took a detour worth a sentence. The naive redis-cli -u ... fails because the endpoint routes by TLS servername, and the error says exactly that and names the option on both ioredis and node-redis. An error that names its own fix is the difference between an agent recovering in one turn and burning ten.

First cloud create to last verified connection: 38.3 seconds. One credential, one binary, no console, no four signup flows, no verification email mid-session.

Writing state, reading it back

Standing a stack up is the easy half. So a second session got the same key and the same brief with one addition, use the layers rather than just create them, against four fresh databases on the same one hour TTL. Every number above is from the provisioning run and unchanged by this one.

Postgres took the durable checkpoint table and handed a row back:

sql
create table agent_checkpoint (
  id         bigserial primary key,
  step       text not null,
  status     text not null,
  payload    jsonb not null,
  updated_at timestamptz not null default now()
);

insert into agent_checkpoint (step, status, payload) values
  ('fetch_sources', 'done',    '{"docs": 12, "tokens": 8431}'),
  ('rank_chunks',   'done',    '{"kept": 5, "dropped": 7}'),
  ('draft_answer',  'running', '{"attempt": 2}');

select id, step, status, payload from agent_checkpoint where status = 'running';
text
 id |     step     | status  |    payload
----+--------------+---------+----------------
  3 | draft_answer | running | {"attempt": 2}
(1 row)

Valkey held the working copy of that same checkpoint with an expiry of its own, plus a counter, through the CLI's own shell:

text
$ layerbase redis-cli usage-cache
SETEX agent:run42:checkpoint 900 "step=draft_answer tokens=8431"
OK
GET agent:run42:checkpoint
step=draft_answer tokens=8431
TTL agent:run42:checkpoint
900
INCR agent:run42:tool_calls
1
INCR agent:run42:tool_calls
2

Qdrant got a four dimensional toy collection, three notes, and a query for the nearest one:

bash
curl -s -X PUT "$QDRANT_URL/collections/agent_memory" \
  -H "api-key: [redacted]" -H 'Content-Type: application/json' \
  -d '{"vectors":{"size":4,"distance":"Cosine"}}'

curl -s -X POST "$QDRANT_URL/collections/agent_memory/points/search" \
  -H "api-key: [redacted]" -H 'Content-Type: application/json' \
  -d '{"vector":[0.85,0.15,0.0,0.0],"limit":1,"with_payload":true}'
json
{"result":[{"id":1,"version":1,"score":0.99795175,"payload":{"note":"user prefers pnpm over npm"}}],"status":"ok","time":0.002072201}

ClickHouse is the layer with no output to show, for the same reason as the first session: layerbase cloud connect shells out to a clickhouse-client that is not installed here, so it got a socket level connection check rather than a query, and the native protocol port does not answer plain HTTP either. Three layers written to and read back, one connected but unqueried. That is a real rough edge in our tooling, and I would rather print it than a query I did not run.

The teardown

The account the moment the last check passed:

text
NAME                    ENGINE        STATUS        EXPIRES
agent-traces            clickhouse    running       ttl 2026-08-02 17:33
agent-vectors           qdrant        running       ttl 2026-08-02 17:33
agent-cache             valkey        running       ttl 2026-08-02 17:33
agent-pg                postgresql    running       ttl 2026-08-02 17:33
... the same 10 as before, every EXPIRES cell a dash

Four rows carrying a hard expiresAt, stamped one hour after each create, to the second. The TTL is a property of the record from the instant it exists, not a reminder I honor later.

That is the entire point. The agent will eventually crash between create and delete, whether it hits a rate limit, loses its session, or is simply killed mid-run. Cleanup has to be absorbed by the platform, not by a shell trap in a process that may never reach it.

Any coding agent, not just Claude Code

Nothing above is Claude-specific. The CLI is plain commands, so Codex, Cursor, Gemini CLI, or a cron job runs the identical flow, and the skill npx layerbase agent init drops in is plain markdown that mostly tells the agent to fetch layerbase.com/agents.md before stating any price, limit, or engine, so it reads today's answer instead of its training data. There is no Layerbase MCP server yet because a tool schema is fixed at connect time and carries call signatures rather than current facts, so we went at the facts first.

One key, or four vendors

Buy these four layers the usual way and it is Neon, Upstash, Qdrant Cloud, and ClickHouse Cloud: four keys, four dashboards, four invoices, four incompatible meters. Every price is defensible on its own page, and the cost shows up at the seams, which I worked through in the multi-database tax. A human forgets one dashboard. An agent holds all four credentials and SDKs in context at once.

Why this isn't Neon

Neon is very good at this. They publish about 350 millisecond database creation, faster than anything above, they have a real Agent Plan, they ship claimable Postgres at pg.new with no account at all, and in May 2025 they reported that "over 80% of databases were being created by AI agents rather than humans". They saw this coming first.

What their answer does not cover is the shape of the stack. Every agent-database vendor sells one engine: Neon and Supabase are Postgres, PlanetScale is MySQL and Postgres, Turso is SQLite. Fine if the agent only needs a relational database, and four vendors the moment it has working memory to checkpoint and traces to grade. Not faster than Neon. Broader, on one credential.

What it costs

Pro is $15/month, flat: up to 10 databases across all 18 cloud engines, no compute-hour meter, no per-command charge, no read units. The four above held four slots for an hour and then zero, and the bill afterward was $15, the same as before.

The CI version of this loop, a database per test run, is in databases for CI and AI agents. To hand your own agent a key: create a database, mint a key in settings, and run npx layerbase agent init in your repo.

Appendix: what an agent can reach for

Layerbase Cloud hosts 18 engines on one credential. Each tier includes everything to the left of it:

CategoryFreeSoloPro
RelationalPostgreSQL, MariaDB, SQLite, libSQLMySQL-
Key-valueRedis, Valkey--
Document-FerretDBCouchDB
Columnar analyticsDuckDB-ClickHouse
Search--Meilisearch
Vector--Qdrant, Weaviate
Time series--QuestDB, InfluxDB
Graph and knowledgeTypeDB--
Ledger--TigerBeetle

FerretDB is the document answer on Cloud: it speaks the MongoDB wire protocol, so Mongo drivers connect unchanged. MongoDB itself is licensed in a way we cannot host, which I would rather name than leave unexplained.

The run above needed Pro because Qdrant and ClickHouse draw on the always-on pool. The two layers most agent loops need sit in the free column, on the same flag and reaper:

bash
layerbase cloud create agent-pg    --engine postgresql --ttl 1h --json
layerbase cloud create agent-cache --engine valkey     --ttl 1h --json

Free is eight engines, 2 database slots, and 5 GB, and the ceiling you hit there first is the monthly meter on programmatic creates rather than the slot count: 5 a month from an API key against 500 on Pro. Enough to wire an agent up and watch it work, not enough to run a CI loop on.