Access and API keys
Principals (worker, manager, admin), how console roles map to them, and named API keys per project.
Principals
Every request to the loop routes carries a principal of one kind, ordered worker < manager < admin. The kind decides which writes are allowed; reads are open to every kind.
| Kind | May |
|---|---|
worker | Send events, read context, read status, policy, kill state, lessons, transitions, proposals, snapshots and skills; claim, heartbeat, complete and fail jobs |
manager | Everything above, plus edit and reset the project policy layer, read the audit log, list jobs, resolve proposals, take snapshots |
admin | Everything above, plus set the kill switch, restore snapshots, promote between environments |
How the kind is resolved for a request:
- The API key's role: an
Adminkey givesadmin, aUserkey givesworker. - The
x-mubit-principalheader (MUBIT_PRINCIPALin the SDK) can only lower the key's kind, never raise it;systemis never accepted from a request. - A write that needs a higher kind is refused with
403 principal <kind> cannot <action>; needs <kind>(for exampleprincipal manager cannot set the kill switch; needs admin).
Every write records who did it: the actor (key:<key_id>, or key:<key_id>/<name> when the SDK sends MUBIT_ACTOR) and the principal. Both appear on transitions, audit records, jobs, proposals, snapshots and the kill state, and both are columns in the console.
One rule depends on the actor rather than the kind: a proposal cannot be accepted by the actor who proposed it unless the principal is admin (409 proposer cannot approve own proposal).
Console roles
The console sends the principal for you, from your organisation role:
| Console role | Principal sent |
|---|---|
| owner, admin | admin |
| member | manager |
Controls you cannot use are shown disabled with a tooltip naming the needed kind ("needs admin"), so a manager sees what an admin could do. A 403 from the instance is shown with its text. One control is stricter in the console than on the server: the server accepts DELETE /v2/loop/policy from a manager, but the console offers Reset all overrides only to owners and admins.
SDK and CLI
The SDK sends the key as is; set MUBIT_PRINCIPAL=worker on a production agent so a leaked key cannot change policy, and MUBIT_ACTOR=<service name> so the audit log names the service. The control namespaces (client.policy, client.kill, client.snapshots, client.proposals, client.jobs) always raise on a 403; the CLI prints the message and exits 1.
MUBIT_API_KEY="mbt_<instance>_<key_id>_<secret>"
MUBIT_ENDPOINT="https://api.mubit.ai"
MUBIT_PROJECT="billing"
MUBIT_ENV="prod"
MUBIT_PRINCIPAL="worker"
MUBIT_ACTOR="invoice-helper"API keys
Keys are created per project under Project โ Settings โ API keys (also reachable from Settings โ API keys, which lists every project). A key looks like mbt_<instance>_<key_id>_<secret>: the instance segment routes the call, the key id is safe to log and appears as the actor in the audit log, the secret is shown once.
| Item | Behaviour |
|---|---|
| First key | Created with the project and shown once on the first-run screen |
| Create key | Mints a named key (name, role User or Admin) that does not rotate; the secret is shown once |
| Key list | name, prefix, role, created, last used |
| Revoke | Removes the key after you type its name back; running processes get 401 on their next call and the SDK prints one warning |
| Rotate admin key | Separate action in the Admin key card on the same page; invalidates the current admin key, behind a confirmation |
Give each service its own named key, User role by default, so that revoking one key stops one service and the audit log tells them apart. Use an Admin key only where an operator or a CI job needs to change policy, restore a snapshot or set the kill switch.
The four .env lines
The key reveal shows four lines; copy them together. The SDK, the CLI and the console read the same values, so the run you start from a shell lands in the project and environment the console is showing.
MUBIT_API_KEY="mbt_<instance>_<key_id>_<secret>"
MUBIT_ENDPOINT="https://api.mubit.ai"
MUBIT_PROJECT="first-project"
MUBIT_ENV="dev"MUBIT_ENDPOINT is included even though mubit.init() and Client() default to it, because the CLI and the learn path still default to a local address in 0.14. A key's project and environment are not bound to the key itself: they come from these two variables or from mubit.init(project=..., env=...). mubit doctor prints the resolved scope: line so you can confirm the binding before the first run.
Environments
Every project starts with two environments, dev (open) and prod (protected). Protected environments render with a warning tint in the environment switcher; writes on them ask for the environment name typed back and a reason, and promote and restore ask for the target environment name typed back on every environment. There is no environment registry to fill in: the SDK creates an environment implicitly the first time a run names it in MUBIT_ENV, and the switcher lists it as soon as it has lessons, snapshots or transitions.