Governance

Per-project keys, model allowlists, spend caps, audit log, RBAC. The reason Synapse Garden exists.

FIG.
FIG. 00 · GOVERNANCEPOLICY GATES

This is what you're paying for. Governance-on-tap. Every call from your app — including the AI SDK's streamText — flows through the same project-scoped gates: allowlist, rate limit, spend cap.

FIG. 01POLICY PIPELINE
SCHEMATIC
Each request is checked against the project's model allowlist, RPM/TPM rate limit, and spend cap before it ever touches an upstream provider. A failure on any gate returns a stable error code (`MODEL_NOT_ALLOWED`, `RATE_LIMITED`, `BUDGET_EXCEEDED`) instead of charging tokens.

Projects

A project is the unit of governance. Each project has its own:

API keys

Issue, rotate, revoke without touching production.

Rate limits

RPM and TPM caps independently per project.

Spend cap

Hard ceiling on monthly cost. Exceeded = HTTP 402.

Model allowlist

Toggle which models this project can call.

Audit trail

Every dashboard action — 90-day retention (Pro+), unlimited (Scale).

Routing defaults

Default provider order, sort, and fallback strategy.

Common project layouts:

acme-co/
├── production            ← live customer traffic, strict allowlist, tight cap
├── staging               ← QA + integration tests, looser cap
├── eval                  ← model comparison runs, all models enabled
└── per-developer/
    ├── ayush             ← dev sandbox
    └── jane              ← dev sandbox

Spend caps

Set a hard ceiling per project in Dashboard → Project → Settings → Spend cap.

When consumed_cents >= included + cap:

01

Requests start returning 402

New requests immediately return HTTP 402 Payment Required with code BUDGET_EXCEEDED.

02

Project owner gets emailed

Email goes out to all project owners. Includes the rolling consumption chart and a one-click link to raise the cap.

03

Cap resets at the period boundary

Or you can manually reset from the dashboard. Resetting mid-period bills you for the additional usage at the standard rate.

You can also set soft caps at 80% / 90% / 100% of the included tokens to email you ahead of the hard limit.

Spend caps are atomic

We deduct from the credit balance with a single SQL UPDATE — no race condition. Bursts can't overshoot the cap by more than one in-flight request.

Model allowlists

In Dashboard → Project → Models, toggle which models this project can call.

Production project              Eval project
[x] openai/gpt-5.4              [x] openai/gpt-5.5
[x] openai/gpt-5.4-mini         [x] openai/gpt-5.4
[x] anthropic/claude-sonnet-4.6 [x] anthropic/*
[ ] anthropic/claude-opus-4.6   [x] google/*
[ ] google/*                    [x] meta/*
[ ] meta/*                      [x] bfl/*
                                [x] (everything)

A blocked model returns HTTP 403 Forbidden with code MODEL_NOT_ALLOWED.

Allowlist resolution

The allowlist resolves in this order (per lib/rules/model-access.rule.ts):

  1. If a row exists for (orgId, projectId, modelId) → use its enabled value
  2. Else if a row exists for (orgId, NULL, modelId) (org default) → use that
  3. Else → fall back to the plan's default allowlist

In English: project-specific rules win, then org-wide rules, then plan defaults.

Audit log

Every dashboard action lands here:

ActionActorTargetWhen
api_key.createdayush@…mg_live_a1b2… (prefix)2026-05-10 15:42
project.archivedjane@…staging2026-05-09 10:11
member.role_changedowner@…bob@… (developer → admin)2026-05-08 09:30
allowlist.updatedayush@…production2026-05-07 14:00
plan.changedowner@…Hobby → Pro2026-05-01 08:00

Visible at Dashboard → Audit log. Filter by actor, action, target, date range. Export as CSV from any view.

RBAC

Workspace roles, in order of access:

RoleCan do
OwnerEverything, including delete workspace, transfer ownership, manage billing.
AdminEverything except delete workspace and transfer ownership.
DeveloperCreate / manage projects + keys; see usage. Cannot manage billing or members.
ViewerRead-only on usage and projects. No mutation.

Roles are workspace-wide for v1. Per-project roles ship in v2.

Rate limits

Set per project in Dashboard → Project → Settings → Rate limits.

LimitDefaultConfigurable up to
RPM (requests / minute)60Plan ceiling
TPM (tokens / minute)100,000Plan ceiling

Exceeded = HTTP 429 Too Many Requests with X-RateLimit-* headers and a Retry-After value (seconds).

Plan ceilings:

PlanMax RPM / projectMax TPM / project
Free60100,000
Hobby6001,000,000
Pro6,00010,000,000
Agency60,000100,000,000
ScaleCustomCustom

Per-environment patterns

The pattern most teams settle on:

production    cap: $1,000/mo   allowlist: known-good models    rpm: 6,000
staging       cap: $50/mo      allowlist: ~production           rpm: 600
eval          cap: $20/mo      allowlist: everything            rpm: 60
local-dev     cap: $5/mo       allowlist: cheap models only     rpm: 60

All four projects share the workspace's billing and audit log. One "rogue test loop" can never blow your production cap.