ClouisleClouisle

Teams & Members

Create teams, manage member roles, authorize models, and transfer ownership

A team is Clouisle's resource isolation boundary: agents, workflows, knowledge bases, tools, and skills all belong to a team. Every in-team operation must pass two layers — a global permission code and a team membership role gate.

This page covers creating teams, adding/changing/removing members, leaving, transferring ownership, and deleting a team, plus the exact failure reason for each step. For the full role model see Roles & Permissions and the Permissions & Roles Reference.

Create a Team

Creating a team requires the global admin:team:create permission and happens on the dashboard Teams page (/teams). Members and Viewers cannot see that entry (/teams requires admin:team:read).

  1. Go to Admin → Teams.
  2. Click Create Team and fill in:
    • Team Name (required, globally unique; a duplicate returns team_name_exists)
    • Description (optional)
    • Team Avatar (optional, uploaded from your machine; JPEG/PNG/GIF/WebP/SVG/ICO, recommended 200×200, max 10 MB; the upload result is stored in avatar_url)
  3. Save; this calls POST /api/v1/admin/teams.
  4. The creator automatically becomes the team's owner (a TeamMember row with role=owner is written too).

Not implemented / Roadmap: assigning another owner at creation, adding initial members, invite/join settings, and resource quotas are not part of the creation flow. Members join afterwards via Add Member; ownership moves via Transfer Ownership.

After creating it, select it in the team switcher. Confirm the current team when creating new agents, workflows, and knowledge bases — otherwise the resource lands in the wrong team and can only be fixed by cross-team sharing (tools only) or by recreating it.

Team management page
Team management page

The Two Team Surfaces

The team switcher exposes two entries with completely different permissions and capabilities:

EntryRouteRequiresPurpose
Manage All Teams (Admin)/teamsglobal admin:team:readList every team (paginated, searchable by name/description, page_size=50 by default), create, edit, delete, bulk delete; backend is GET/POST/DELETE /api/v1/admin/teams
Manage Current Team/app/teamthe page itself only requires membership (team:read); the entry link appears only for a superuser or a team owner/admin holding team:manageMember management, basic team info editing, leaving, transferring ownership, viewing authorized models (read-only)

The model authorization tab on /app/team is read-only: it shows the team's authorized models, enabled state, and today's usage/limit, and states that authorization is assigned by a system administrator. Every model-authorization write requires a superuser (see below).

Team Details and Members

Team Overview

The /app/team header shows the team avatar, name, a Default Team badge (is_default), and a badge with your role inside this team. The members tab lists username, email, role, and join date, with local filtering by username/email.

Not implemented / Roadmap: team details do not show resource quotas (agent/workflow/storage limits) or usage activity (conversations, runs, API calls), and there is no per-team notification setting or separate resources tab.

Model Authorization

Model authorization is a superuser-only capability; every write endpoint requires get_current_active_superuser:

OperationEndpointPermission
List the team's authorized modelsGET /api/v1/teams/{team_id}/modelsteam membership (or superuser)
Authorize a modelPOST /api/v1/teams/{team_id}/modelssuperuser
Bulk authorizePOST /api/v1/teams/{team_id}/models/batchsuperuser
Change quota / enabled state / priorityPUT /api/v1/teams/{team_id}/models/{model_id}superuser
Revoke an authorizationDELETE /api/v1/teams/{team_id}/models/{model_id}superuser
Bulk revokeDELETE /api/v1/teams/{team_id}/models/batchsuperuser
List models available to authorizeGET /api/v1/teams/{team_id}/available-modelssuperuser

The dashboard team detail's Model Authorization tab offers the same operations, with buttons gated on is_superuser || admin:model:update. Configurable fields include daily/monthly token limits, daily/monthly request limits, is_enabled, and priority. Granting or revoking sends a team.model_granted / team.model_revoked notification to the team. See Manage team models for details.

Add Members

Requires the global team:manage permission and owner/admin inside that team (require_team_admin=True). Members and Viewers get 403 team_admin_required.

  1. Open the Members tab of /app/team and click Add Member (shown only when you can manage the team).
  2. In the "username or email" field, enter the target user's complete username or email.
  3. Pick a role: Admin, Member, or Viewer (Owner is not offered).
  4. Confirm; this calls POST /api/v1/teams/{team_id}/members.

Matching rules and backend validation:

CaseResult
Exact username match, or case-insensitive exact email matchuser found
Nothing matchesuser_not_found, HTTP 404
Only a fragment (e.g. the prefix john)no match, 404 — there is no fuzzy search or user picker
The user is already a memberalready_team_member
Role set to ownercannot_add_as_owner
Role set to admin but the target lacks global team:manageoperation_not_permitted, HTTP 403 (permission: team:manage)

Grant the global role before making someone a team admin

Adding a user who lacks global team:manage as a team admin is rejected outright. The order must be: first grant them the Team Admin role (or any role with team:manage) in Admin → Users, then set them as team admin.

On success the new member receives a team.member_added notification and the team gets a summary notification; membership is effective immediately — there is no invitation/accept flow.

Change Member Roles

Only the team owner (or a superuser) can change roles. A team admin gets 403 team_owner_required.

  1. Find the target member in the list and open the ... menu.
  2. Choose Change Role and pick Admin / Member / Viewer.
  3. Save; this calls PUT /api/v1/teams/{team_id}/members/{user_id}.

Backend validation order:

CaseResult
Caller is not the owner (and not a superuser)team_owner_required, HTTP 403
Target is currently ownercannot_change_owner_role — the owner's role cannot be modified; use Transfer Ownership
New role is ownercannot_promote_to_owner — promoting to owner only happens via Transfer Ownership
New role is admin but the target lacks global team:manageoperation_not_permitted, HTTP 403
Target is not a member of the teamteam_member_not_found, HTTP 404

On success the target receives a team.role_changed notification.

Member role changes are not audited: team audit coverage is limited to create_team / update_team / delete_team / add_team_member / remove_team_member plus the team model authorization actions.

The frontend hides the menu as well: canActOnMember requires "you are not the target" and "you are the owner, or the target is not an admin". So a team admin never sees the action menu for other admins or the owner, and nobody sees it on their own row.

Remove Members

DELETE /api/v1/teams/{team_id}/members/{user_id} has two paths:

ScenarioRequired permissionNotes
Remove someone elseglobal team:manage + team owner/adminthe frontend menu is likewise limited by canActOnMember
Remove yourselfteam:read onlyself-removal needs no management permission (equivalent to leaving)

Shared limits: an owner can never be removed (cannot_remove_owner, including by themselves); if the target is not a member you get team_member_not_found (404).

After removal the user immediately loses access to all of that team's resources; only the membership row is deleted, so their conversations, API keys, and personal resources are not deleted (conversations simply become inaccessible without team access). The team receives a team.member_removed notification and so does the removed user. They can be added again later.

Leaving Teams

  1. /app/team → Settings tab → danger zone, click Leave Team.
  2. Confirm in the dialog; this calls POST /api/v1/teams/{team_id}/leave (requires only team:read).

An owner cannot leave: the endpoint returns owner_cannot_leave, and the frontend shows "As the team owner, you cannot directly leave the team. Please transfer ownership first." You must transfer ownership to leave. Also, the default team (is_default=true) hides the leave button in the UI — but that is frontend behaviour; the endpoint itself does not reject on is_default.

After leaving you lose access to that team's resources; existing conversations are preserved. The team list refreshes and the page returns to /app.

Transfer Ownership

Requires global team:manage and owner/admin inside the team, and you must be the owner (or a superuser). A team admin gets 403 team_owner_required.

  1. Open the member list on /app/team, find the target member, ... → Transfer Ownership (only owners see this item).
  2. Confirm in the dialog; this calls POST /api/v1/teams/{team_id}/transfer-ownership?new_owner_id={user_id}.

Backend rules (in order):

  1. The target must be a member of the team, otherwise team_member_not_found (404).
  2. The target must already hold global team:manage, otherwise operation_not_permitted (403). Again: grant the global role first.
  3. If the target is the current owner → cannot_promote_to_owner (400).
  4. The previous owner's membership role is demoted to admin, the target becomes owner, and Team.owner is updated accordingly.
  5. Both owners receive a team.ownership_transferred notification.

Transferring is instant and irreversible from your side: the former owner keeps only admin rights and cannot revert it themselves (changing roles requires being the owner). Confirm the target before proceeding.

Edit Team Info

Requires the global team:update permission and owner/admin inside the team (PUT /api/v1/teams/{team_id}).

  • /app/team → Settings tab: change team name, description, and avatar (inputs are disabled when you lack the permission).
  • The dashboard /teams edit dialog: the same fields, requiring admin:team:update.

Fields and constraints: name is required and globally unique (duplicate → team_name_exists); description is optional; avatar_url is written by the upload component. There is no team slug, alias, or domain field.

Delete a Team

Deleting a team is irreversible and only possible from the dashboard /teams, requiring admin:team:delete. A team owner has no delete entry on /app/team.

  1. In the /teams list open the target team's ... menu → Delete Team (the default team does not show the item).
  2. Confirm in the dialog; this calls DELETE /api/v1/admin/teams/{team_id}. The dialog only asks for confirmation — you do not type the team name.
  3. The default team (is_default=true) is rejected: cannot_delete_default_team.

Deletion impact (model FK cascades, verified in models/*.py):

DeletedPreserved
The team record and all TeamMember rowsMembers' user accounts
The team's agents, workflows, knowledge bases, tools, skills, assetsAudit logs (for compliance)
Team model authorizations (TeamModel), tool configs, notifications, import sessionsMembers' account data (API keys belong to the user, not the team)
Agent conversations and their messages (cascading with the agents)—

Team Roles and Permissions

A team role is one of four fixed values — owner / admin / member / viewer — and carries no permission codes; it only acts as the team gate. Actual capability = global role permissions ∩ team gate.

Gate Rules

  • TEAM_MANAGEMENT_PERMISSIONS = team:update, team:manage, team:delete, tool:delete: these actions require both the global permission code and owner/admin in that team.
  • A team viewer may only use team:read, agent:read/agent:chat, workflow:read/workflow:run/workflow:execute, kb:read/kb:test, tool:read/tool:execute, skill:read/skill:execute, conversation:read; every other write returns 403 operation_not_permitted.
  • A superuser (is_superuser) bypasses membership and the team gate entirely.

Team Management Permissions

ActionOwnerTeam AdminMemberViewer
View team and members✓✓✓✓
Edit team info (name/description/avatar)✓✓✗✗
Add members✓✓✗✗
Change member roles✓✗✗✗
Remove members✓✓ (not other admins/owner)✗✗
Leave the team✗ (transfer first)✓✓✓
Transfer ownership✓✗✗✗
Delete the team✗ (needs dashboard admin:team:delete)✗✗✗

In-Team Resource Permissions

ActionOwnerTeam AdminMemberViewer
Create agents / workflows / knowledge bases✓✓✓✗
Edit others' agents / workflows / knowledge bases✓✓✗✗
Delete agents, publish agents and workflows✓✓✗✗
Chat with agents, run workflows✓✓✓✓
Create/edit your own tools and skills✓✓✓✗
Edit others' tools / skills✓✓✗✗
Delete tools✓✓✗ (team gate rejects, even though Member holds tool:delete)✗
Search/test knowledge bases, upload/rename/delete documents✓✓✓read-only search
Execute tools and skills✓✓✓✓

API keys are not part of a team

An API key belongs to a person via user_id: for non-superusers the list endpoint only returns their own keys, and ensure_api_key_owner() requires "owner or superuser". Team roles have no effect on API keys — a team owner/admin cannot see or revoke anyone else's key.

Default Team Role

The site setting default_team_id names the default team and default_team_role names the membership role new users get there. It accepts only viewer / member / admin (any other value falls back to member, which is also the default value). Assignment runs on registration and on SSO auto-provisioning, and never overwrites an existing membership. owner is never assigned automatically.

Custom Team Roles

Not implemented. Teams have exactly four fixed roles — owner, admin, member, viewer — each mapping to a fixed set of gate rules; you cannot add or remove permissions for a single team. For finer-grained permissions, use global custom roles instead (see Roles & Permissions).

Collaboration and Notifications

Collaboration happens through shared resources: agents, workflows, knowledge bases, tools, and skills are shared inside the team, and members access them subject to the role gate. Workflow run history is visible to team members (permissions permitting), so you can see who ran what and when.

Team-related automatic notifications (delivery channels are configured by administrators in site settings — see Notifications & External Channels):

TypeWhenRecipients
team.member_addedA member is addedthe new member + the team
team.member_removedA member is removedthe removed user + the team
team.role_changedA member's role changesthe affected member
team.ownership_transferredOwnership is transferredone each to the old and new owner
team.model_granted / team.model_revokedA model is authorized / revokedthe team

Not implemented / Roadmap: there is no per-team notification configuration, and no @mentions, shared conversations, team activity feed, document comments, or in-app team messaging.

Troubleshooting

Cannot Access Team Resources

  1. Confirm the correct team is selected in the team switcher.
  2. Confirm you are a member of that team (if /app/team opens you are; otherwise not_team_member).
  3. Confirm your global roles carry the needed code; a team viewer can only read and execute.
  4. Confirm resource visibility: a private resource returns agent_access_denied / tool_access_denied to non-creators.

Cannot Change Role / No "Change Role" in the Menu

  • Only the owner (or a superuser) can change roles; a team admin gets team_owner_required.
  • The frontend also hides it: you cannot act on yourself, and a team admin cannot see the menu for other admins or the owner.
  • An owner's role cannot be changed (cannot_change_owner_role); to change who owns the team, use Transfer Ownership.
  • To promote someone to team admin, they must already hold global team:manage.

Adding a Member Returns 404 user_not_found

The input must be the complete username or complete email (email is case-insensitive). Fragments, nicknames, and display names do not match — there is no fuzzy search.

Adding a Member Returns 403 operation_not_permitted

The role was admin but the target lacks global team:manage. Grant the Team Admin global role first, then set them as team admin.

Ownership Transfer Rejected

  • team_owner_required: you are not the owner (or a superuser).
  • team_member_not_found: the target is not a team member; add them first.
  • operation_not_permitted: the target lacks global team:manage.
  • cannot_promote_to_owner: the target is already the owner.

Cannot Leave / No Leave Button

An owner cannot leave (owner_cannot_leave), and the default team hides the button in the UI. Transfer ownership first; for the default team an administrator must change the default team in site settings.

Cannot Delete a Team

  • Requires admin:team:delete; the entry exists only on the dashboard /teams.
  • The default team is rejected: cannot_delete_default_team.

Permissions Unchanged After a Role Change

The frontend's cached permission snapshot may be stale: refresh the page or sign in again. The backend reads permissions from the database per request, so no cache expiry wait is needed.

API Endpoints

Team endpoints use JWT user-session authentication (API keys are not accepted).

Platform side (/api/v1/teams):

MethodPathPurposePermission / gate
GET/api/v1/teams/myList the current user's teams and rolesany signed-in user
GET/api/v1/teams/{team_id}Team details (includes the member list)team:read + membership
PUT/api/v1/teams/{team_id}Change name/description/avatarteam:update + owner/admin
POST/api/v1/teams/{team_id}/membersAdd a member (identifier or user_id + role)team:manage + owner/admin
PUT/api/v1/teams/{team_id}/members/{user_id}Change a member's roleteam:manage + owner/admin, and the caller must be owner/superuser
DELETE/api/v1/teams/{team_id}/members/{user_id}Remove a member (self = leave)others: team:manage + owner/admin; self: team:read
POST/api/v1/teams/{team_id}/leaveLeave the teamteam:read; owners are rejected
POST/api/v1/teams/{team_id}/transfer-ownership?new_owner_id=…Transfer ownershipteam:manage + owner/superuser; the target must hold global team:manage

Admin side (/api/v1/admin/teams):

MethodPathPurposePermission
GET/api/v1/admin/teamsList all teams (page/page_size, default 50; search matches name or description)admin:team:read
POST/api/v1/admin/teamsCreate a team (creator becomes owner)admin:team:create
DELETE/api/v1/admin/teams/{team_id}Delete a teamadmin:team:delete; the default team is rejected

There is no GET /api/v1/teams (list all teams) endpoint. To walk every team in the system, use the admin-side GET /api/v1/admin/teams.

Common Error Codes

msg_keyHTTPMeaning and fix
team_not_found404The team does not exist
not_team_member403The caller is not a member of that team
team_admin_required403Team owner/admin required
team_owner_required403Only the team owner (or a superuser) may do this
operation_not_permitted403Missing global permission code (the response carries a permission field)
team_name_exists400Duplicate team name
user_not_found404The member identifier matched no user
already_team_member400The user is already a team member
cannot_add_as_owner400Cannot set owner through Add Member
cannot_change_owner_role400The owner's membership role cannot be changed
cannot_promote_to_owner400Cannot promote to owner via a role change or by transferring to yourself
cannot_remove_owner400The owner cannot be removed (including self-removal)
owner_cannot_leave400The owner must transfer ownership before leaving
team_member_not_found404The target user is not a member of that team
cannot_delete_default_team400The default team cannot be deleted
team_model_already_authorized400That model is already authorized for this team
team_model_not_found404The team model authorization does not exist

For complete request/response formats and code examples, see Teams API.

See also:

How is this guide?

On this page