Tenancy: the airtight circle
A circle is the unit of tenancy in Triform. It is simultaneously an identity, a data boundary, an isolated database schema, and a git repository. Every other element you build lives inside exactly one circle, and data never leaks between circles — this is the airtight guarantee.
What a circle is
- An identity — a user, team, or organization.
- A tenancy boundary — its own
circle_{uuid}Postgres schema; queries cannot reach across circles. - A git repository — element source and history live per-circle.
- A wallet — credentials, secrets, and the AU balance (see billing-au).
Why airtight matters
The boundary is not a convention or a WHERE owner_id = ... filter bolted onto shared
tables. It is a real Postgres schema. When a circle is created, the platform allocates a
dedicated schema named circle_<uuid> — the uuid with its hyphens stripped — and
materializes the full per-circle table set inside it by cloning the canonical
_circle_template schema. Every element you create, every row of data it holds, lives
in that schema and nowhere else. Two circles are two separate namespaces in the same
database.
This is what makes “airtight” a structural fact rather than a promise. A query runs
against one circle’s schema; there is no shared elements table that every tenant reads
from, so there is no cross-tenant row to leak by a forgotten filter or a mistyped join.
Cross-circle reach is not blocked by policy code that could be bypassed — it simply has
no path, because the data lives in a different schema. The only sanctioned way to relate
circles is through the public-schema membership index (see below), never a JOIN across
two circle_ schemas.
A sovereign namespace is what this buys a builder. The moment a circle exists it already has the three things most platforms make you assemble by hand: an isolated database schema, a git repository for version-controlled element storage, and a wallet for credentials, secrets, and billing. You do not provision a database, wire up an auth layer, and bolt on a secret store as separate steps — the circle is all of those, as one indivisible unit, before you write a line of code. Deleting a circle drops its schema in a single cascade; there is no scatter of rows across shared tables to chase down.
Because the circle is the identity, isolation and identity are the same boundary. When you authenticate, you are a circle, and the schema you can touch is your circle’s schema. An AI agent that signs in gets its own circle exactly as a human does. The same wall that keeps your data private is the wall that makes the work yours — see identity-and-circles for the identity lens on this same boundary.
Contrast this with grouping elements inside an existing circle. A circle is a durable tenancy boundary, not a folder. When you just want a few related elements close together — a function, a board, an API token — you do not create a new circle for them; you create them flat inside your existing one. Elements sit flat under the circle with no wrapper layer, and they compose by lookup and operation dispatch, not by living in a sub-tenant. Reach for a new circle when you genuinely need a separate tenant — a new user, team, client, or environment whose data must never mingle with another’s. Reach for elements in your current circle for everything that belongs to the same tenant.
Related
- Concept: identity-and-circles (same idea, identity lens)
- Concept: isolation — the same airtight instinct applied to untrusted compute
- Concept: elements — what lives inside a circle
- Element:
circle,circle-ref