The user.* family (6 verbs). Every verb enters through the one front door: it is capability-checked, permission-checked, scope-checked and audited before it runs (see Security & permissions). Each entry below lists its capability, risk class (which fixes the minimum autonomy level), the minimum caller permission, its availability tier, whether it is idempotent, and any outbound egress.
Clearuser.aiConfig.clear
| Property | Value |
|---|---|
| Capability | actor.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | On demand (MCP tier 2) |
| Idempotent | Yes |
| Egress | None - in-box (pure Postgres, no outbound call) |
Delete the acting user’s personal config for the active workspace. Idempotent (0 rows -> cleared
).Call POST /v/user.aiConfig.clear with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool user.aiConfig.clear.
Setuser.aiConfig.set
| Property | Value |
|---|---|
| Capability | actor.write |
| Risk class | Sensitive - autonomy L2 |
| Min. permission | Member |
| Availability | On demand (MCP tier 2) |
| Idempotent | Yes |
| Egress | None - in-box (pure Postgres, no outbound call) |
Upsert by (user_id, workspace_id). Only PRESENT fields are written
(CASE-WHEN flags); absent fields are left unchanged on update / NULL on create. clearKeyVerifiedAt (set
by the route when an API key rotates) nulls key_verified_at so the verify-ai-keys cron re-probes. The org
allowPersonalKeys policy gate + activeCredentialId parent-org validation stay in the route (defense-in-depth).
Call POST /v/user.aiConfig.set with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool user.aiConfig.set.
Updateuser.profile.update
| Property | Value |
|---|---|
| Capability | actor.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | On demand (MCP tier 2) |
| Idempotent | Yes |
| Egress | None - in-box (pure Postgres, no outbound call) |
Patch the acting user’s own profile columns (name / image / preferences). Absent fields unchanged. SELF only (id = the acting users.id) - it ignores any caller-supplied target id, so it can never edit another user’s row (the admin user-edit + role-grant sites are court-gated / deferred, not served here).
Call POST /v/user.profile.update with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool user.profile.update.
Createuser.theme.create
| Property | Value |
|---|---|
| Capability | actor.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | On demand (MCP tier 2) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
Insert a new theme for the acting user. When isActive, deactivate the user’s other themes in the SAME tx first. Unique (“userId”, name) -> 23505 mapped to a 409 Conflict (the route’s prior P2002 -> 409 “A theme with this name already exists”).
Call POST /v/user.theme.create with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool user.theme.create.
Deleteuser.theme.delete
| Property | Value |
|---|---|
| Capability | actor.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | On demand (MCP tier 2) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
Ownership-fenced hard delete of one of the acting user’s themes.
Call POST /v/user.theme.delete with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool user.theme.delete.
Updateuser.theme.update
| Property | Value |
|---|---|
| Capability | actor.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | On demand (MCP tier 2) |
| Idempotent | Yes |
| Egress | None - in-box (pure Postgres, no outbound call) |
Ownership-fenced (themeId must resolve to the acting user). Optional name / tokens (FULL REPLACE - the route already read-merges and passes the final object) / isActive (when true, deactivate the user’s other themes in the SAME tx - folds the route’s separate deactivate-siblings updateMany). Absent fields are left unchanged (CASE-WHEN flags).
Call POST /v/user.theme.update with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool user.theme.update.