Lesson 34 — Plans & tiers: what the cloud grants each account
Goal: by the end of this lesson you can tell which tier an org is on, predict what its graphs may and may not do, read the quota display in the editor, and — as an operator — change an org's tier (including freezing an abuser) and hand a visitor an anonymous demo.
Concepts introduced: the :plan slug, the access tiers
(anonymous / free / network / dedicated) and the suspended
kill-switch, per-tier effects, the egress rate cap, ephemeral demo
orgs.
The model in one paragraph
On the cloud, every org carries a :plan slug. A plan resolves to
two things: the side effects its submitted graphs may use (from
Lesson 13) and its quota ceilings (fns, list items, outbound
calls/min). That's the whole tier system — a tier is just a named
bundle of "what effects" + "how much". The single source of truth is
graphden.tenancy.plan; the human-readable table lives in
PLANS.md.
The tiers
| Tier | Network? | Own DB? | Fns | Calls/min | Notes |
|---|---|---|---|---|---|
anonymous |
✗ | ✗ | 200 | 0 | locked demo, ephemeral, the fail-safe default |
free (registered) |
✓ metered | ✓ | 500 | 120 | a signed-up account |
network (paid) |
✓ | ✓ | 5,000 | 6,000 | higher ceilings |
dedicated (paid) |
✓ | ✓ | 5,000 | ∞ | its own pod + always-on services (lesson 32) |
suspended |
✗ | ✗ | 0 | 0 | operator freeze — no effects, no writes |
The key line is anonymous → free. Anonymous is what a landing
visitor gets: no outbound network, small ceilings, and the org is
reaped after a TTL — you can try graphs with nothing to lose. It is
also the fail-safe default: an org with no slug resolves here, so
a mis-provisioned account is locked, never accidentally opened.
Free (registered) is what signing up gives you (lesson 24),
and it is genuinely useful: base effects PLUS metered :network. It
is kept as long as it is used: after 60 days with no sign-in, no API
call, no run and no edit, the org is scheduled for deletion two weeks out and everyone in
it gets an email saying so, plus a last reminder two days before —
one sign-in, one call, one run or one edit keeps it. In
practice that means you can build a personal Telegram bot, keep a few
hundred records, and connect to your own external database — the
external :sql-query / :sql-exec base-fns count as network, not
raw-sql (arbitrary SQL on the platform DB stays forbidden for
everyone; see lesson 13 + SECURITY_MODEL.md).
Outbound is bounded, not blocked: every external call goes through the SSRF egress guard (no internal / platform targets) and a per-tier calls-per-minute cap, so a free bot works but can't be turned into a DDoS.
Seeing your quota
The editor shows the current org's usage against its ceilings
(fetched from GET /api/orgs/quota) — plan, N / max fns,
N / max list items. When you approach a ceiling it's a nudge to
upgrade; if you ever see plan anonymous on an account you thought
was registered, that's the fail-safe default telling you the org's
:plan was never set.
Changing a tier (operator)
:org is a tenant-forbidden entity (lesson 24), so tiers are an
operator activity. One platform-only route sets any org's plan:
POST /api/orgs/plan (form: name=<org>&plan=<tier>)
plan must be one of free / network / dedicated / suspended
(a typo is rejected, not silently applied). Use it to upgrade a
paying customer — or to freeze an abuser: setting suspended
gives the org no effects and zero ceilings, so it can neither run nor
create anything, effective on its next request. Restore by setting
its real tier back. (Delete still works, so a frozen tenant can clean
up its own data.)
Operators also get a fourth surface, Platform (its account-menu entry appears
only for platform-tier principals): the cross-org registry of
organizations and the platform-access delegation panel — the
UI counterpart to the operator routes above, and the place where
platform capabilities (like :view-all-stats) are handed to
delegates.
Run your own executor (BYO)
Paid tiers (network / dedicated) can also opt out of executing on
the cloud entirely: the org's graph stays on the hub (editing,
branches, review — everything you've learned), while a bring-your-own
executor on the customer's hardware runs the org's app. The flip is
per-ORG and operator-side; the customer's half is one container with a
minted API token. If you want one app self-run and the rest hosted,
that app gets its own org (you can belong to several — lesson 30) and
only that org flips. As the org's owner you can watch it from
Organization → Executor: the current mode, whether your executor is
connected to the hub right now, and a ready-to-run snippet with your org
prefilled. The full recipe — both halves, verification, troubleshooting —
is BYO_RUNBOOK.md.
Handing out a demo
A landing page mints an anonymous org for a visitor through the
unauthenticated POST /api/demo/start, which returns a bearer token
for a throwaway anonymous org. It is off by default (a public
row-creating endpoint is an abuse surface) — a deploy opts in, and it
is per-IP rate-limited. See PLANS.md § Starting an anonymous
demo.
Try it
(Operator account on a tenancy-addon instance.)
- Sign up a new account (lesson 24) — its org lands on
free. Confirm the quota display readsfree. POST /api/orgs/plan name=<that-org> plan=suspended. As that account, try to run any fn — the effect gate now refuses even:db; a create is rejected by the zero row-cap.- Set it back to
free; the account works again on its next request (the resolver isn't memoised). - Try
plan=premium— rejected (:plan/unknown), the org's tier is unchanged.
What we glossed over
- The two-layer effect gate — how a tier's effect set actually gates a submitted graph vs a trusted request (TENANCY_SEAM.md § Effect gate).
- The egress guard internals — SSRF classification + the per-org rate/size caps (SECURITY_MODEL.md).
- Fleet placement — how an org is sharded to a pod, which is why the per-pod rate cap behaves per-org (SCALING.md).
Next
That's the end of the current tutorial. New lessons are added as features ship — see tutorial/README.md.