Your database is already most of an API.

Every table as REST and MCP tools, permissioned and audited.

The data layer, already written. Bring the idea. Let Claude draw the screens. Ship a product in four weeks, not a year.

One binary registers a Postgres, MySQL, MariaDB or ClickHouse database — or any of 11 more that speak their protocols, 15 in all. Every table, served as REST and MCP. Every role, decided on the table. Every call, on the record. The year of backend a product needs before it exists — finished before you begin. API Bay and Chat Studio were built this way. Now it is yours to build on.

Licences are set up with you in a session for now. Your database stays where it is; nothing is copied out of it. Meanwhile, read the Book of Minimal.

database → tables → rest + mcp → roles → audit

One table, three calls

Acme’s employee table, read, refused, and read by an agent.

The organization acme, the project people, a Postgres database registered as acme. Every request below is lifted from the Book of Minimal and runs as printed against a deployment.

The table is the last segment of the path. fc picks columns, oy orders, ps and pg page. No route was written for this; none is written for the other ten relations either.

http
GET /minimal/api/rest/auto/v1/acme/people/pg/acme/employee?fc=id,full_name,department_id&oy=id.as&ps=5&pg=0 HTTP/1.1
Host: api.acme.example
LB-Access-Token: <your-access-token>
json · 200
[
  { "id": 1, "full_name": "Rafael Delacroix", "department_id": 11 },
  { "id": 2, "full_name": "Rafael Müller", "department_id": 7 },
  { "id": 3, "full_name": "Rafael Novak", "department_id": 8 },
  { "id": 4, "full_name": "Kwame Haddad", "department_id": 6 },
  { "id": 5, "full_name": "Rafael Haddad", "department_id": 6 }
]

Filters are column=operator.value — department_id=gt.6, full_name=like.Raf*. Page size and page number are mandatory, so no call ever reads a table whole by accident. Vol. I, Chapter 5 is the full query language.

The same path, a DELETE, sent with a token minted for hr-analyst. The table’s permission template lists hr-admin alone on delete. The refusal names the roles the caller held, not the rows it would have touched.

http
DELETE /minimal/api/rest/auto/v1/acme/people/pg/acme/employee?id=eq.5 HTTP/1.1
Host: api.acme.example
LB-Access-Token: <token · roles hr-analyst · key_type -r-->
json · 403
{
  "code": 403,
  "status": "Forbidden",
  "message": "insufficient permissions for this operation on this table, got [hr-analyst]"
}

Three gates, checked in order: a lock mask says whether anyone may delete here at all; the template says which roles may; a row scope, if set, says which rows. The token itself could not have helped — -r-- is read-only, and a token never carries more than its minter held. Vol. I, Chapter 6.

An agent that has the skill file knows the session rule, the order to discover a project in, and which headers to send. It opens a session, lists the databases and tables its token can see, then reads the same five rows. Every call on the right is from Vol. I, Chapter 7.

shell · once per project
mkdir -p .claude/skills/minimal-core
curl -o .claude/skills/minimal-core/SKILL.md \
  https://littlebitlabs.com/skills/minimal-core/SKILL.md
tool calls · one session
start_ai_session    {name, context}
  → session_id 01M20681V68Y5421QC5N23F9DB
meta_list_databases
  → [{"type":"pg","schema":"acme"}]
meta_list_tables    {type: pg, schema: acme}
  → employee, department, salary, … 11 tables
auto_read_rows      {type: pg, schema: acme, table: employee,
                     page_size: 5, page_number: 0, query: {oy: "id.as"}}
  → 5 rows, recorded to the session

MCP invents no capability of its own: everything an agent can reach this way, a backend can reach over REST, refused for the same reasons. What MCP adds is the session — a persistent record of what the agent actually did. The skill file is one page, written from the same chapters. Vol. I, Chapter 7.

Agent skill

Teach your agent Minimal Core in one page.

A coding agent that has this file knows the MCP session rule, the order to discover a project in, which headers to send, and what to do when it is refused. Four kilobytes, written from Vol. I, Chapter 7.

  • Before any call
  • REST addressing
  • Reading rows
  • Writing rows
  • MCP
  • Refusals
  • Rules for the agent
mkdir -p .claude/skills/minimal-core
curl -o .claude/skills/minimal-core/SKILL.md \
  https://littlebitlabs.com/skills/minimal-core/SKILL.md

Saves into the project; Claude Code loads skills from .claude/skills/.Saves into the project as a Cursor rule.Appends to AGENTS.md in the project root.

.claude/skills/minimal-core/SKILL.md68 lines · 4.2 KB
---
name: minimal-core
description: Read and change data through Minimal Core, the data access layer over a database you already run. Use when a task names a Minimal deployment, an LB-Access-Token, the Auto API path /minimal/api/rest/auto/v1, or the MCP endpoint /minimal/mcp/rpc/v1.
---

# Minimal Core

Minimal Core serves every table of a registered database two ways: REST (Auto API) and MCP tools. Both pass the same permission checks, so a call refused on one is refused on the other.
Full reference: the Book of Minimal, https://littlebitlabs.com/docs (three volumes). Minimal Core is in beta.

## Before any call

- Send an access token in the `LB-Access-Token` header. It carries organization, project, space, user and roles. Never pass those as arguments.
- A token never holds more than the identity that minted it. `key_type` reads in create-read-update-delete order: `crud` is everything, `-r--` is read-only.
- MCP needs a token owned by an MCP identity, with MCP switched on for its space.

53 more lines · the REST and MCP rules, refusals, and what the agent must never do

Where it fits

The layer over a database. Three neighbours look similar.

Every team that puts a database behind an API writes the same routing, auth middleware and tenant checks, then the same list, get, insert, update and delete handler for the eleventh table. Minimal Core removes that work. What is left to write is the one endpoint that computes a payroll total, not the fifty that move rows. Vol. I, Chapter 1 makes the argument in full.

A database — Supabase, Neon, PlanetScale

These hold your data. Minimal Core goes over the database you already run and leaves the rows where they are, so there is no migration and no second copy.

An API generator — PostgREST, Hasura

These give you an API. Minimal Core also serves every table as MCP tools and permissions each caller by identity, so an agent receives what its role allows.

An MCP gateway

A gateway sits in front of existing endpoints and allows or denies each call. Minimal Core decides on the table: one role list answers REST and MCP alike, so an agent is refused for the same reasons a backend is.

Two doors into every table.

Both open at once. Choosing between them is the first design decision you make for any piece of data.

Auto API — the routes that are just routes.

List, filter, insert, update, delete, on every table a project has indexed, with no authoring step. GET, POST, PUT, DELETE; column selection, ordering, grouping and paging as query parameters; JSON, CSV or YAML back. This is the door for the admin screen, the mobile backend, the fifty handlers that only move rows.

Custom API — the logic that is actually yours.

One YAML definition: a method, a path, a version, the roles allowed to call it, and an ordered waterfall of steps. A sql step is one statement with ?:name placeholders; a lua or lark step reshapes what the step before fetched. Mark a step omit and its raw rows never leave the server. Written in dev, copied to prod once staging has proven it.

The payroll total is a definition. The payroll table is not. Vol. II, Chapter 1 writes the first one end to end.

Who is asking

Identity arrives on five headers. Permission lives on the table.

Every request names an organization, a project, a space, a user and a comma-separated list of roles — as five headers, or as one access token that stands in for them. Minimal never defines what a role means. A role is a string; a table says which strings may do what.

Permission template

A named policy, assigned to as many tables as you like. Twelve role lists: four verbs across the REST, MCP and machine-to-machine channels. Change the template and every table on it changes. An empty list means nobody, not everybody.

Lock mask and visibility

A lock switches a verb off for everyone on a channel, whoever they are — a table nobody should delete from stays that way even for the role that could. A hidden table is not offered to a caller at all.

Row-level security

One column bound to one request header. Every read is filtered to rows where they match; an insert has the column set from the header whatever the body said. department ← X-Department turns one view into a different table per caller.

Access tokens

Minted with a name, a role subset, a key_type in create-read-update-delete order (crud, -r--) and an expiry. A token is an alias for an identity, never a bigger grant than its minter held.

Spaces

dev, staging, prod, or whatever split you want, under one project. Definitions and modules live in exactly one space until you copy them. The tables are shared; the logic is promoted.

The DDL surface

Register a database, read the live catalog, run a schema change as an ordered list of statements under an exclusive run lock, drop a database — each gated by its own role list on the organization or project.

What Minimal Core does not do. It does not authenticate anyone. The five headers are trusted as given, by design, because Minimal runs behind a boundary that has already verified a real person or service and sets those headers itself — a private network, or a gateway. Expose it to a network you do not fully trust and that boundary has to exist and be the only path in.

What stays yours. The identity provider, the gateway, third-party integrations, and any logic unrelated to your database. Vol. III builds the boundary once, concretely — Zitadel for identity, APISIX as the only public listener, Minimal on loopback behind it, one Postgres for all three — so you can copy it rather than design it.

What you run

One binary, one YAML file, one definition store.

Minimal reads a single configuration file at startup. Its own state — organizations, projects, templates, definitions — lives in a definition store you point it at: a Postgres or MariaDB database, with connection secrets sealed under an encryption key you hold. Your tenant databases are registered, read and written in place. Nothing is copied out of them.

Listeners

REST on one port; the MCP listener on its own, opened only if the mcp: block exists. TLS with a minimum version and cipher preferences; optional mutual TLS that can require and verify a client certificate. Bound to loopback in the reference deployment, reached only through the gateway.

Budgets

A 4 MiB cap on every request body, REST and MCP alike — a real memory bound, not a formality. Script steps get their own accounting: execution time, value size, nesting depth, pattern length, and a concurrency ceiling no single organization can take more than half of while another is running.

The record

Every call leaves an audit row: who, which route, which status, how long, from which address, under which token and session. Readable at three scopes — your own trail, your organization’s, the deployment’s. Traces export to any OpenTelemetry collector; a caller’s request is never blocked on telemetry.

The whole file, setting by setting, including the one default that deliberately is not safe: Vol. II, Chapter 9.

Per-engine notes: Postgres · MySQL and MariaDB · ClickHouse.

The ask

Three ways in. Two of them cost nothing.

Try it · $0

The hosted deployment at selectstar.wtf. Free tier, no card, no expiry. Volume I runs against it as printed; Chapter 2 has you reading rows before the end of the page.

Start free

Run it · $100 a year

The full licence on hardware you control, air-gapped if you need it. Every feature unlocked, plus $1 per 1,000 requests, prepaid and never expiring, topped up on the licensing site (opening soon) rather than from an API Bay wallet. Support is free; an on-call engineer is $150 an hour. Beta; indicative until final numbers publish on 1 Nov 2026.

See pricing

Be granted it · $0 for twelve months

Ostrich: companies, a Minimal Core licence of $100K to $300K a year, roughly 100M to 300M requests. Pelican: qualifying non-profits, renewed on review, no cap. Both open on 1 Nov 2026.

Read the grant terms

Put it in front of a database.

Book a session and we stand Minimal Core up against your own database with you, with Volume I open in another tab.

Nothing is copied out of your database. Prefer email? Write to us.

Next on the shelf

Where to go from here.

API Bayß

A dataset in, a priced API out.

Drop a file; we code, host, back up and serve the endpoints. You set the price and keep all of it.

Chat Studioß

A specialist for every part of your site.

Hand it your pages and documents, publish, and one line of code puts it on your site.

Free to try

Free tier, no card, no expiry.

The hosted tier costs nothing to start.