Concepts
Tenants, keys and scopes, namespaces, documents, durability, and what each query reports about its cost.
The handful of ideas everything else in SkimmerDB builds on.
Tenants and users
A tenant owns namespaces, API keys, usage and a bill. Signing up makes a person and their
first tenant. A person can own or belong to several tenants (POST /v1/tenants makes another);
a login acts for the person's default tenant, or the one named by the X-Tenant: <id> header.
One tenant never sees another's namespaces. A name another tenant uses answers exactly like a name nobody uses, over REST and MCP alike, and each tenant's objects live under a prefix of its own in object storage.
API keys and scopes
Every request carries a key: Authorization: Bearer tb_... (or X-API-Key: tb_...). A key
belongs to one tenant and has a scope:
| Scope | May |
|---|---|
read | list namespaces, search, count, get documents, warm, SQL, usage |
write | also create and delete namespaces, and write, update, delete and import documents |
admin | also make, list, change and revoke keys, and billing |
A key can also be limited to some namespaces (names or prefixes such as agent-7-*) and capped
(requests a second, queries and writes a billing period). Namespaces outside a key's list
answer like names nobody has. The key from signup is admin with no limits: give apps and
agents narrower ones. See Keys, scopes and tenants.
Namespaces
A namespace is a named set of documents: 1 to 64 characters of a-z, 0-9, -, _ and
.. Writing to a name that doesn't exist makes it (the answer says "created": true, so a
typo shows); POST /v1/namespaces makes one explicitly, for example to choose the euclidean
metric for vectors.
Namespaces cost nothing while idle: nothing runs for one while nobody uses it. Make one per user, per agent run, per customer or per dataset; the free plan allows 1,000 a tenant and pro has no limit. A search, count or SQL query reads one namespace, which is the main thing to keep in mind when you choose them: see Data model.
Documents
A document is:
| Field | What | Limit |
|---|---|---|
id | any string, one line; writing an id again replaces the document | 512 bytes |
text | what search (q) matches, exactly or by regex | 2 MB |
meta | a JSON object of strings, numbers and booleans: what filters and SQL read | 16 KB |
vector | an embedding, in namespaces with vectors | 1 to 2,048 numbers |
A write request puts (inserts or replaces) up to 10,000 documents and deletes ids, 64 MB at
most. PATCH updates documents in place: text replaced if given, meta merged key by key
(null removes a key). The newest write of an id is the one every read sees; replaced and
deleted documents are never counted or returned.
Durable on write
A write is answered once it is stored in object storage. Writes from every tenant on a server
are committed together about every 250 ms, so a write takes about that long. It is searchable
on the server that took it at once, and on every server within about a second. Send
"wait": true to answer only once it is searchable. A write request is atomic: its documents
and deletes become visible together, or not at all. More in Durability.
Temperature and what a query cost
Every search, count, read and SQL answer reports:
| Field | Meaning |
|---|---|
temperature | warm: the namespace was open; local: opened from the server's disk; cold: opened from object storage |
store_gets, store_bytes | what the query read from object storage (0 when warm) |
took_ms | time on the server |
cpu_ms | CPU the query used |
partial | some hits may be missing (an object-storage read failed, or the time limit passed) |
The first query after a long idle period is cold: it opens the namespace in a round trip or
two. POST .../warm opens a namespace ahead of an agent's session. See
Performance and cost.
Next
- Data model: choosing namespaces, ids and metadata.
- Writing documents and Search and filters.
- Limits and plans.