Tenants and Administration

A tenant is an isolated workspace: it owns its own states, transactions, members, and settings. Every state belongs to exactly one tenant. A self-hosted install starts with a single tenant (named Default unless you change STATEGRAPH_DEFAULT_TENANT_NAME), and the first user to complete setup administers the whole installation.

Most self-hosted teams run everything in the one Default tenant — all users share it, which keeps collaboration simple. You only need more than one tenant when you want hard isolation between groups of infrastructure.

Instance admin vs tenant admin

Administration comes in two scopes, both expressed through the user's admin capability:

  • Instance admin — an unrestricted admin grant ({"admin": {}}). Administers the whole installation: every tenant, the global user list, and installation settings. The first user created at setup is an instance admin.
  • Tenant admin — an admin grant scoped to one or more tenants ({"admin": {"tenants": ["<tenant-id>"]}}). Administers only those tenants — their membership, invitations, and settings — and cannot see the installation-wide user list or other tenants.

A separate, narrower right, users-manage scoped to a tenant, lets someone manage that tenant's membership (add, remove, and change members' roles) without being a full tenant admin.

The older documentation described admin as a simple on/off flag and referenced an is_admin column. Admin is now a structured capability (installation-wide when it names no tenants, scoped when it does). The boolean that used to be called is_admin is now is_instance_admin, on POST /api/v1/users, PUT /api/v1/users/update and the dedicated POST /api/v1/users/set-instance-admin. It grants or revokes the installation-wide admin object — and revoking it removes any tenant-scoped admin grant the user also held. User responses report the two scopes separately, in an admin_rights object carrying is_instance_admin and is_tenant_admin.

Membership

A user only sees and can act on a tenant they are a member of — there is a membership row joining the user to the tenant. Holding an admin capability that covers a tenant is not the same as being a member of it: an instance admin who is not a member of some tenant will get a 403 TENANT_MEMBERSHIP_REQUIRED when trying to manage it, distinct from the 401 you get with no session. Add yourself (or be added) as a member first.

New users are placed into the Default tenant automatically at sign-in. To give an existing user access to another tenant, add them to it (below).

Adding an existing user to a tenant

From Settings → Members, an administrator of the tenant (or a users-manage holder for it) can add an existing user directly by their user id. This is the fast path for someone who already has an account. It grants membership only — no tenant-scoped capabilities — so the added user starts as a plain member; promote them with the role controls if needed.

Under the hood this is POST /api/v1/tenants/{tenant_id}/members with {"user_id": "..."}. It is idempotent, and returns 404 if no such active user exists — use an invitation (below) for someone who does not yet have an account.

Creating a tenant

An instance admin can create a new tenant from Settings → Preferences → Create a tenant, or with POST /api/v1/tenants and {"name": "..."}. The name is trimmed and must not be blank, may be at most 255 characters, and must not already be in use by another tenant (400 INVALID_TENANT_NAME and 409 TENANT_NAME_CONFLICT respectively). The creator is added as a member and can then switch to the new tenant and appoint a tenant admin with the member role controls.

There is no way to delete a tenant from the UI.

Invitations

To bring in someone who does not yet have an account, send an invitation from Settings → Members → Invite. An invitation is a single-use, time-limited link (default 7 days, STATEGRAPH_INVITATION_TTL_HOURS). The invitee opens the link, signs in (creating their account), and is added to the tenant — as a member, or as a tenant admin if you invited them as one.

Email delivery is optional. Stategraph delivers invitation emails through Aegis, the hosted control plane. A self-hosted install without Aegis configured does not send email — this is a supported mode, not an error. The invitation is still created and the accept link is returned to you to copy and hand over yourself. The Members screen shows "email not delivered" on such invitations and always gives you the copyable link.

For a purely local, password-only install (no OAuth), a brand-new invitee cannot self-register from the login page. In that case create the user first (Settings → Users → Create User, instance admin) and then add them to the tenant.

Sessions and capability changes

Changing a user's capabilities — promoting, demoting, or toggling admin — revokes that user's active browser (login) sessions, so their next request forces a fresh sign-in with the new rights. This is deliberate: a session carries a snapshot of the capabilities it was minted with. Acting on your own membership does not sign you out; only the affected user's other sessions are ended.

See the environment variables reference for STATEGRAPH_DEFAULT_TENANT_NAME, STATEGRAPH_INVITATION_TTL_HOURS, STATEGRAPH_MODE, and the licensing and Aegis settings.