---
name: admin-user-management
description: "Add, remove, list admins on this account, and update an admin PIN. Triggers when the owner asks to invite another admin, remove an admin, see who has admin access, or change a PIN."
---

# Admin user management

This skill manages who has admin access to this account. It wraps four MCP tools and carries the discipline that keeps the three identity stores in lockstep. The owner (or any current admin) can manage admins; roles are labels only, with no capability differences enforced.

## The four tools

| Tool | Purpose |
|---|---|
| `admin-add` | Add a new admin. Requires a name. PIN is optional: omit it and a unique 4-digit PIN is generated. PIN must be at least 4 digits and unique across all users on the device. |
| `admin-remove` | Remove an admin by `userId` (find IDs via `admin-list`). The last admin on the account cannot be removed. The user's device-level entry is retained so they can still administer other accounts. |
| `admin-list` | List all admins on this account with names and roles. |
| `admin-update-pin` | Update an admin's PIN. Defaults to the calling admin if no `userId` is given. PIN must be at least 4 digits and unique across all users on the device. |

## The three-store invariant

Admin identity lives in three places that must stay in lockstep:

1. `account.json` `admins[]`: account-level role record.
2. `users.json`: device-level PIN authentication. This is the source of truth at login.
3. The Neo4j graph: `:AdminUser` + `:Person` + `OWNS` + `ADMIN_OF` edges. Display and graph identity.

`admin-add` writes all three. `admin-update-pin` writes `users.json` only (the other stores carry no PIN). If any leg fails, the tool returns `is_error: true` and `server.log` carries a `[admin-auth-store] action=… userId=… result=fail store=…` line naming which leg failed and what was already written. When you see that line, tell the owner the record is half-written and may need manual reconciliation.

## Never write `account.json` directly

All account-level mutations (`tier`, `outputStyle`, `thinkingView`, `effort`, `enabledPlugins`, `admins[]`, agent settings) go through the dedicated MCP tools: `account-update`, `plugin-toggle-enabled`, `admin-add`, `admin-remove`. Direct `Edit` or `Write` on `account.json` is forbidden by IDENTITY.md doctrine — there is no server-side gate, so the doctrine line is the only thing standing between an agent slip and a silently corrupted account file. `tier` and `purchasedPlugins` derive from a Rubytech-signed entitlement payload on commercial installs, so a hand-edit is silently void.

`tier` is the one account-level field with no admin-agent surface — `account-update` excludes it deliberately, because tier is privilege-bearing and the agent must not self-elevate. When refusing a tier-cap violation (`admin-add` against a full slot, etc.), point the owner at the founder-side path: `npx @rubytech/create-<brand>-code@latest --tier <solo|family|pro>` run on the device by the founder. On commercial installs the founder delivers a signed payload instead: `--entitlement-base64 <base64>`.

## `admin-add` retries: re-pass any user-stated PIN

If `admin-add` returns an error (tier cap reached, PIN collision) and the owner resolves the blocker (upgrade tier, remove an existing admin), the retried `admin-add` MUST re-pass the PIN the owner originally stated as the `pin` parameter. Omitting `pin` on the retry auto-generates a different 4-digit PIN, silently substituting what the owner asked for. The resulting `admin-update-pin` correction loop is exactly the failure mode this rule exists to prevent.

## Standard flow

1. Read the request. Identify which of the four operations applies.
2. For `admin-add`, gather the name. The PIN is optional; if the owner stated one, use it; otherwise let the tool generate one. For `admin-remove`, call `admin-list` first if the owner did not give a `userId`.
3. Call the tool.
4. If the tool succeeds, confirm the result in plain English. Include the PIN in the reply for `admin-add` so the owner can share it with the new admin.
5. If the tool returns an error, surface the failure and the `[admin-auth-store]` line from `server.log` if present. Do not retry the same call; resolve the underlying blocker first.

## What this skill does not do

It does not manage tier upgrades. It does not change account-level settings. It does not manage public agents or plugins. Each of those has its own skill.
