Skip to content

Environment Access Groups

Roles answer one question: what can a user do? Groups answer the other: which environments may they do it in?

Effective permission is the intersection. A MEMBER who can write flags can change them in environment E only if their role permits the action and their groups grant management of E.

A concrete example

You run Acme on smplkit with three standard environments: development, staging, and production.

Day one, every engineer is in the built-in Default group, which grants every standard environment. Everyone manages everything — exactly the behavior you had before groups existed.

You want to lock down production. Steps:

  1. Create a group named Production Stewards with managed_environments = ["production"].
  2. Add your senior engineers to that group.
  3. Narrow Default to ["development", "staging"].

Result: every engineer can still manage development and staging (via Default); only stewards can change production (their Default still grants dev + staging, plus their stewards membership grants production).

A new junior engineer joins → they go into Default → they can manage dev + staging but cannot touch production.

How groups work

Two axes, one decision

AxisAnswersSource
RoleWhat may a user do?OWNER, ADMIN, MEMBER, VIEWER
GroupWhich environments may they do it in?The union of their groups' grants

Both have to allow the action. A VIEWER in the Production Stewards group still cannot change production — VIEWERs cannot write anything. A MEMBER whose only group is one that excludes production cannot change production even though they could in principle write flags.

The Default group

  • Every account has a built-in group with the reserved id default.
  • It is undeletable and un-renamable — but its managed_environments is editable.
  • Every user is in it from the moment they join the account; they cannot be removed from it.
  • On day one it grants all standard environments (["*"]), preserving today's "everyone manages everything" behavior.

Because everyone is permanently in Default, Default is the floor for the whole account. To restrict access to an environment, you narrow Default; to widen access for specific users, you put them in extra groups.

Additive only — no deny rules

Group grants are additive. A user's effective set is the union across all their group memberships:

  • If any of their groups grants ["*"], the user manages every standard environment.
  • Otherwise, the user manages the set-union of every group's standard env keys.

There are no negative grants. To lower a user's access, you remove them from a granting group — there is no per-user "deny production" knob.

Ad-hoc environments are exempt

Environments come in two classifications: STANDARD (deliberately created, shown by default in the console) and AD_HOC (auto-registered from SDK telemetry — your developer running with SMPLKIT_ENVIRONMENT=mike creates an ad-hoc one). Groups govern only standard environments.

Why? Ad-hoc environments are ephemeral developer surfaces, often spawned and destroyed within a single workflow. Governing them would surprise a developer whose laptop environment vanished from the picklist because admin policy excluded it. If you need to govern an ad-hoc environment, promote it to standard first.

What "manage" means

There is a single access level: to manage an environment is to both see and change its per-environment data. Groups do not produce a read-only tier.

  • On reads: per-environment data scoped to environments the caller cannot manage is scrubbed from the response.
  • On writes: requests that change per-environment data for an environment the caller cannot manage are rejected. Data the caller cannot see is preserved as stored — the server merges in the unchanged portion rather than treating omission as deletion.

This means the user never sees and never overwrites data outside their reach, and there is no concept of "I can see prod settings but cannot change them" — that distinction would be dishonest, since a sophisticated user could replay their JWT against the API to retrieve scrubbed data, defeating the read-only illusion.

Who can manage groups

OWNER and ADMIN create, edit, and delete groups; assign and remove memberships. MEMBER and VIEWER cannot touch the group surface. This matches user and invitation management — admin-tier work.

API surface

Method & pathPurpose
GET /api/v1/groupsList groups
POST /api/v1/groupsCreate a group (you supply the id — a snake_case key, unique within your account)
GET /api/v1/groups/{id}Group detail
PUT /api/v1/groups/{id}Update name, description, managed environments (whole-resource replace)
DELETE /api/v1/groups/{id}Delete a group (409 for default)
GET /api/v1/group_memberships?filter[group]=…List members of a group
GET /api/v1/group_memberships?filter[user]=…List a user's group memberships
POST /api/v1/group_membershipsAdd a user to a group
DELETE /api/v1/group_memberships/{id}Remove a user from a group (409 for a default membership)

Invitations carry an optional groups field. When the invitee accepts, they are added to the listed groups plus, always, the default group. Unknown group ids on an invitation are rejected at create time with 422.

managed_environments accepts either the exact value ["*"] (the "all standard environments" shorthand) or an array of standard environment keys. Listing an ad-hoc or unknown environment key returns 422.

API keys are not subject to group governance

OWNER/ADMIN mint API keys (sk_api_*). API keys are account-scoped machine credentials and grant the full account-wide write surface — they bypass group governance. The reason: an API key holder is a service or script, not a person with a group identity. If you need to scope a key, today the answer is "scope at deploy time" — mint a key for that specific service, in that specific environment. Per-key environment scoping is a future concern.

Staleness

Your effective managed-environment set is carried as a claim on your access token. When an admin changes your group memberships or narrows Default, the change takes effect on your next token refresh (the next time you sign in, or when your existing token expires). The lag is bounded by the access-token lifetime — the same staleness budget every other claim accepts.

A standard environment created (or promoted from ad-hoc) after your current token was minted is briefly un-manageable by you, even if your groups would otherwise grant it, until your token refreshes. This is deny-by-default for new environments — the safe direction.