# Forge Accounts, Teams, and Service Tiers

Status: public beta contract

Contract version: `forge-accounts/v1`

Entitlement resolver: `forge-entitlements/v1`

Forge Accounts provide one ownership, authorization, quota, suspension, and
future billing boundary for Forge repositories, Deploy projects, hosted
applications, and other products. Payment is deliberately not part of this
contract. A future payment provider will be one audited writer of service-tier
assignments; it will not become Forge's source of truth.

## Product vocabulary

- A **user** is one human identity.
- An **account** owns resources, quotas, usage, and lifecycle state. It is
  either personal or organizational.
- A **team** is an access-control group inside an organization account. Teams
  do not own service tiers or billing.
- A **service tier** is one of `free`, `pro`, `team`, or `enterprise`.
- **Entitlements** are resolved machine-readable capabilities and limits.
- **Usage** is observed consumption and is stored independently from
  entitlements.
- **Forge Identity** is the optional, app-scoped identity and team-disclosure
  service for Forge-hosted applications.

The account that owns a resource determines its limits. A Pro user working in a
Free organization does not lend Pro capabilities to that organization.

Personal accounts never turn into organization accounts. A Pro user who needs
shared ownership creates a Team organization and transfers resources.

## Initial beta tiers

These are versioned product defaults, not Cloudflare or Forge platform safety
ceilings. Enterprise assignments can raise reviewed product limits, but never
bypass safety ceilings automatically.

| Capability | Free | Pro | Team | Enterprise |
| --- | ---: | ---: | ---: | ---: |
| Account shape | Personal or public organization | Personal | Organization | Organization |
| Members | 3 | 1 | 25 beta cap; 5 included | Contracted |
| Teams | 1 | — | 25 | Contracted |
| Active Deploy projects | 1 | 10 | 50 | Contracted |
| Builds per month | 100 | 1,000 | 10,000 | Contracted |
| Build minutes per month | 500 | 3,000 | 20,000 | Contracted |
| Concurrent builds | 1 | 2 | 5 | Reviewed |
| Retained assets | 1 GiB | 25 GiB | 250 GiB | Contracted |
| Preview retention | 7 days | 30 days | 90 days | Contracted |
| Forge Identity | Basic | Higher MAU, branding | Organization collaboration | SSO, SCIM, policy |
| Gist file size vocabulary | 256 KiB | 10 MiB | 25 MiB | Up to 100 MiB after review |
| Binary Gist vocabulary | No | Yes | Yes | Yes |

Private source, custom domains, and Deploy secrets are represented in the tier
catalog now, but remain unavailable until their individual platform features
are shipped and security-reviewed. An entitlement never creates a provider
capability that does not exist.

## Resolution and precedence

Forge resolves one immutable entitlement document in this order:

1. the effective versioned service-tier assignment;
2. active, time-bounded account overrides;
3. optional project requests that can only disable features or lower limits;
4. platform safety ceilings;
5. account suspension or closure.

The result is canonicalized, hashed, and stored as an immutable snapshot.
Deploy eligibility records and deployment plans carry the snapshot ID, digest,
resolver version, tier version, override IDs, and authorization generation.
Eligibility evidence is an audit receipt, not the source of truth.

Repository configuration can ask for less:

```ts
export default defineForge({
  version: 1,
  name: "small-realtime-app",
  app: {
    entrypoint: "src/server.ts",
    limits: {
      realtime: {
        maxProjectConnections: 20,
        maxEventBytes: "4KiB",
      },
    },
  },
  routes: [{ pattern: "/*", to: "app.http" }],
});
```

It cannot raise the owning account's trusted ceilings.

## Usage and admission

Forge keeps three distinct forms of usage state:

- **gauges** for retained bytes, active projects, seats, and object counts;
- **period counters** for builds, build time, requests, bandwidth, and app
  users;
- **temporary reservations** for race-sensitive work such as concurrent
  builds and uploads.

Reservations are idempotent and expire if work never starts. Committing a
reservation writes an append-only usage event and changes the relevant balance
in one transaction. Analytics telemetry can inform reporting, but it is not
authoritative admission state.

If an account exceeds a new lower limit after a downgrade, Forge blocks new
usage-increasing operations. Existing content remains readable, downloadable,
exportable, and deletable. Forge does not truncate or silently delete data on
downgrade.

## Organization and team invariants

- Organization creation, its owner membership, the organization account, and
  the default Members team are one transaction.
- Every organization member is synchronized into the default Members team.
- Removing an organization member removes all of that user's team membership.
- A user cannot be inserted into an organization team without being an
  organization member.
- The final organization owner cannot be removed or demoted.
- Organization and team rosters require organization membership.
- Owners and administrators can administer organization repositories.
- Ordinary members see private organization repositories only through an
  explicit team grant.
- Database constraints reject unknown roles and permission values.

These rules apply at the database boundary as well as in API handlers.

## API

All endpoints require authentication. Responses use
`Cache-Control: private, no-store`.

```http
GET /api/accounts
GET /api/accounts/:accountId
GET /api/accounts/:accountId/capabilities
```

The capabilities response includes the caller's role, account lifecycle state,
resolved tier and version, full feature/limit document, digest, generation,
effective expiry, and current strong usage gauges.

Clients may use capabilities for preflight and interface hints. The server is
always authoritative.

### Operator account ledger

Platform administrators use
[`/admin/accounts`](https://forge.smol.ai/admin/accounts) to inspect the
resource-owning account, current service-tier version, resolved entitlement
digest, usage gauges and period counters, active reservations, recent usage
events, prior assignments, and prior overrides.

Tier changes and entitlement exceptions are never in-place edits. The console
first resolves a side-effect-free proposed document, shows the exact
current-to-proposed feature and limit diff, requires an audit reason, then
records a new append-only assignment or time-bounded override. Account-bound
idempotency keys make browser and network retries safe.

```http
GET  /api/admin/accounts?q=<query>
GET  /api/admin/accounts/catalog
GET  /api/admin/accounts/:accountId
POST /api/admin/accounts/:accountId/preview
POST /api/admin/accounts/:accountId/tier-assignments
POST /api/admin/accounts/:accountId/overrides
```

Preview calls do not write. Assignments and overrides record the acting
administrator, reason, effective window, and immutable evidence. Existing
generation triggers invalidate stale deployment and Identity contexts when an
effective entitlement source changes.

### Growth and abuse operations

Platform administrators use
[`/admin/operations`](https://forge.smol.ai/admin/operations) to compare
7-day, 30-day, and 90-day user/account growth; inspect separately labeled
storage, project, deployment, and request-pressure evidence; and open an
account-specific enforcement workbench.

Threshold crossings are review signals, not automatic punishment. An operator
may append a user-visible account warning or a temporary personal-account
request cap. Caps retain the platform's fixed window, can only lower the
existing allowance, and expire within 30 days. Warnings, resolutions, caps,
and clears retain the actor, reason, time window, and idempotency evidence.
Organization request caps are rejected until Forge can attribute each request
to its resource-owning account.

```http
GET  /api/admin/accounts/operations?window=30d
GET  /api/admin/accounts/:accountId/enforcement
POST /api/admin/accounts/:accountId/warnings
POST /api/admin/accounts/:accountId/warnings/:warningId/resolve
POST /api/admin/accounts/:accountId/rate-limit-overrides
POST /api/admin/accounts/:accountId/rate-limit-overrides/:overrideId/clear
```

The full measurement and safety contract is documented in
[Account operations](account-operations.md).

## Deploy authority

`deploy_projects.account_id` is the canonical ownership foreign key and every
generalized deployment receives an immutable entitlement receipt. The Sites
product surface and edge read that same generalized authority; they do not
maintain a second entitlement projection or deployment record.

The database rejects a project whose canonical account does not match its
recorded tenant. The edge requires complete effective limits and a current
entitlement receipt for every deployment. Missing evidence fails closed and
never falls back to the platform maximum simply because a repository omitted a
limit.

## Suspension and authorization generations

Tier assignments, entitlement overrides, membership changes, and account state
changes advance an account authorization generation. Reductions fan out to
affected Sites and environments:

- new builds, tickets, sessions, and mutations are rejected;
- short-lived signed contexts expire;
- bounded runtime shards are awakened to close affected sockets;
- generalized desired generations advance;
- project access and realtime generations advance.

This preserves immediate suspension while allowing old immutable deployments
and audit records to remain inspectable.

User credentials have a separate lifecycle: `active`, `suspended`, or
`tombstoned`. Suspending a user advances that user's authorization generation
and immediately blocks password login, signed session JWTs, personal access
tokens, and Git authentication. Forge Identity sessions and unused
authorization codes are revoked by the lifecycle operation. The user's
personal account is suspended as well, which advances the account generation
and uses the existing authorization outbox to fan containment out to hosted
applications.

Tombstoning is an identity-redaction state, not an unsafe row deletion. Forge
keeps foreign-key-safe audit evidence, replaces public identity fields, and
closes the personal account. Repository history is removed only through the
normal repository deletion coordinator, which inventories and deletes the
repository's R2 object prefix before removing D1 metadata. Reads, audit
evidence, and immutable operation receipts therefore remain explainable.

## Forge Identity boundary

Forge Identity is app-scoped. It is not access to the Site owner's Forge
session or organization directory.

The controlled-preview protocol uses authorization code with S256 PKCE, exact
registered origins, short-lived single-use codes, app-scoped user IDs, explicit
disclosure scopes, and host-only secure application cookies. The trusted Sites
edge owns those cookies and strips them before repository code runs.

Hosted applications never receive:

- Forge control-plane cookies or bearer tokens;
- the Forge JWT signing secret;
- a D1 binding or Cloudflare credentials;
- unrestricted account or team directories.

The first public scopes are `user:basic`, `accounts:read`, and `teams:read`.
Membership and account authorization generations revoke stale disclosure. The
live protocol and SDK contract are documented at
[`/spec/identity/v1`](https://forge.smol.ai/spec/identity/v1).

## Self-hosting and recovery

There are two separate milestones:

1. **Forge deploys Forge:** exact-SHA build, immutable preview, promotion,
   rollback, and provider evidence.
2. **Forge uses Forge Accounts and Identity:** the console consumes the same
   reusable account/tier/usage APIs offered to hosted applications.

Forge itself is represented as an ordinary Enterprise organization account,
`forge-platform`, with explicit maintainers, deployers, operations, and
security teams. Internal exceptions are audited, expiring overrides—not a
hidden fifth tier.

The Accounts service, Deploy control plane, artifact authority, direct
`forge.smol.ai` recovery route, and Cloudflare break-glass access remain
independently recoverable. Hosted-app identity is not a bootstrap dependency
for control-plane login.

## Current limitations

- Tier changes are operator-managed; payment integration is not implemented.
- Forge Identity's broker and browser SDK support the controlled
  `sites.smol.ai` hosting surface and Forge-verified active custom domains for
  connected production Workers. Connected previews, Workers.dev hostnames, and
  path-only routes intentionally remain outside the callback trust boundary.
- Gists expose tier vocabulary but do not yet use the shared R2-backed binary
  storage design.
