Technical docs
Staff
Overview
Support reference for the Staff area:
- `/staff`
- `/staff/ai/[employee_id]`
- `/staff/user/[user_id]`
What users see
- Main tabs: `Staff` and `Invites`.
- Trash view is reached from `View Deleted` and is labeled `Pending Deletion`.
- The invite dialog also opens from `?invite=true`.
- Primary actions on the active Staff view:
- `Invite Member`
- `Add AI Teammate`
- Empty state buttons:
- `Invite Member`
- `Add AI`
Staff tab
- Header title: `Staff Directory`.
- Description: `Manage your team members and AI Teammates in one place`.
- Current table filters:
- `Type`: `Team Member`, `AI Teammate`
- `Status`: `Active`, `Pending`, `Inactive`
- `Added`
- `Updated` or `Deleted` in trash view
- `Role`
- `AI Skill`
- Current table columns can include:
- `LLM` for AI teammates
- The `LLM` cell shows the resolved model display name when Alloy has one, otherwise the raw model id.
- Current behavior:
- The staff API currently returns the full list without server pagination, server filtering, or server search.
- Search, pagination, date filters, role filters, and skill filters are handled in the frontend.
- Human rows come from accepted organization memberships, not from pending invites.
- Trash view is AI-teammates only.
- Per-user Ally rows show a `Personal` badge in the name cell.
- Row actions:
- AI teammates: `Chat`
- All rows: click-through to the detail page
- Human teammates: no inline action button in the list
- Bulk actions:
- Active view: `Delete`
- Trash view: `Restore`
- Selection rules:
- active-view human owners cannot be bulk-selected
- active-view system AI teammates cannot be bulk-selected
- trash-view selection is AI-only
Invites tab
- Header title: `Pending Invites`.
- Description: `Track and manage pending organization invitations`.
- The invite dialog supports two delivery methods:
- send by email
- generate a shareable invite link
- Both delivery methods create the same backend invite record through `POST /api/organizations/{orgId}/invites/`.
- The dialog's `Administrator` option maps to backend invite role `admin`.
- The free-text `Position` field is currently UI-only and is not persisted by the backend invite model.
- Current filters:
- `Status`: `Pending`, `Accepted`, `Cancelled`, `Expired`
- `Role`: `Admin`, `Member`
- `Added`
- `Updated`
- Row actions:
- pending email invites: `Resend`, `Cancel`, `Copy invite link`
- pending link invites: `Cancel`, `Copy invite link`
- accepted, cancelled, and expired rows are read-only
- Invites use server pagination, but filtering and status presentation are handled in the frontend.
- The frontend treats a pending invite whose `expires_at` is in the past as `Expired` for display.
AI teammate detail
- Create route: `/staff/ai/new`.
- Create mode initially exposes only the `Rules` tab; the full tab set appears after the teammate is created.
- Tabs:
- `Rules`
- `Skills`
- `Storage`
- `Connectors`
- `PATs`
- `Telegram`
- `MS Teams`
- `Slack`
- `Logs`
- `Reports`
- `Jobs`
- `Schedulers`
- `API` only when channel is `API`
- When the tab strip is too narrow, hidden tabs move into the `Tabs` overflow menu. The overflow menu can select hidden tabs, change which tabs stay visible, and reorder tabs through `Reorder {name}` drag handles. Tab tooltips use the current tab descriptions, including `Review activity and execution history` for Logs, `Review performance and usage reports` for Reports, and `Schedule recurring and one-off runs` for Schedulers.
- Ally is a special case:
- their detail page hides `Storage`
- their detail page hides `API`
- a personal Ally is auto-created for each user the first time the employee list or staff list is accessed, so every user always has an Ally without manual setup
- the current user's personal Ally is available in shared internal-chat target strips and history
- personal Ally employees remain excluded from Cowork teammate selection, `@` mention catalogs, skills builder selectors, Staff table teammate choices, and system settings dropdowns for global Ally and Onboarding teammate selection
- Channel choices in the header:
- `Not selected`
- `Web Chat`
- `API`
- `Web Chat` shows a copy action for the chat widget snippet in the header.
- `API` uses a dedicated tab with:
- `API Endpoint`
- request examples and built-in request tester
- API request log filtered from workflow runs
- Jobs and schedulers are documented in jobs-and-schedulers.md. The Schedulers tab uses a mixed recurring/one-off list, dashboard metrics, and create cards for `Schedule recurring` and `One-off run`.
- Connectors tab lets users enable or disable org MCP servers for that teammate. The tab description is `Connected systems and services`.
- The same Connectors tab also manages OAuth service connections for that specific teammate.
- For connected OAuth services, the tab can show:
- status badge `Valid`, `Invalid`, or `Unknown`
- `Connected by {user}`
- connected account identifier when available
- OAuth connector checkboxes stay disabled until the matching service is connected for that teammate.
- PATs tab lets users create tokens that let external AI agents act as that teammate.
- Telegram tab lets users:
- connect a Telegram bot by pasting a BotFather token
- disconnect the linked bot
- reconnect the webhook when the bot is linked but webhook delivery is not active
- Telegram tab states:
- unlinked: `No Telegram bot is linked to this AI Teammate yet. Connect a bot to receive messages from Telegram.`
- linked + active webhook: `Connected` badge plus webhook success notice
- linked + missing webhook: warning notice plus `Reconnect webhook`
- MS Teams tab lets users:
- connect a Microsoft Teams bot by entering Azure Bot app credentials
- disconnect the linked Teams bot
- copy the current `Messaging endpoint (set this in your Azure Bot)` value
- download the sideloadable Teams app package as `.zip`
- Full setup procedure: `tech docs/references/microsoft-teams-ai-teammate.md`.
- MS Teams tab always shows the current messaging endpoint when the backend provides one, even before the bot is connected.
- MS Teams tab currently has two nested views:
- `Contacts`
- `Channels`
- `Contacts` shows the per-contact approval list for personal Teams chats.
- Personal Teams bot replies are gated by contact approval state:
- `Approved`
- `Not approved`
- The contact approval switch lets users allow or block AI replies for each listed Teams contact.
- `Channels` shows Teams channels and group chats the bot has already seen.
- Channel rows currently show:
- display name from `channel_name`, or fallback to raw `ms_teams_channel_id`
- status badge `Enabled` or `Disabled`
- a toggle for enabling or disabling AI replies in that channel or group
- Newly discovered Teams channels are created disabled by default and only appear after the bot has seen a message there.
- Slack tab lets users:
- connect a Slack bot by entering Bot User OAuth Token and Signing Secret
- disconnect the linked bot
- copy a generated Slack app manifest JSON for quick app setup
- copy the `Events Request URL` from the `Troubleshooting` accordion when Slack URL verification needs checking
- Full setup procedure: `tech docs/references/slack-ai-teammate.md`.
- Slack tab states:
- unlinked: `No Slack bot is linked to this AI Teammate yet. Connect a dedicated Slack app to receive messages from Slack.`
- linked: `Connected` badge with bot app name and bot user ID
- Slack tab shows a `Quick setup with a Slack app manifest` card before connection. The manifest is generated by the backend and pre-fills the Slack app name, scopes, events, App Home direct-message settings, and Events Request URL.
- Slack tab shows a `ChannelChatsList` for managing per-channel enable/disable state, same pattern as Telegram and MS Teams tabs.
- Slack app setup details live in the Slack reference instead of this Staff-area overview.
- Storage tab shows only the folders explicitly shared with that teammate; it no longer expands every file inside those folders into the table.
- The Storage table is centered on access-management metadata: shared folder name, location, current teammate access, grantor, and grant date.
- Storage table filters include created, modified, granted, team, and grantor.
- Folder row actions are `Open`, `Share`, and `Delete`.
- The empty state for AI teammate Storage still links back to `/storage`.
- Employee-backed search/list endpoints filter per-user Ally records so a signed-in user only sees their own Ally.
- Updating a per-user Ally keeps the name fixed as `Ally`; editable fields are the assistant settings such as description, role, instructions, model, tools, and voice configuration.
- In the AI teammate model picker, Codex models are disabled when `GET /api/init/models` returns `is_connected: false` for them. Disabled Codex models show a lock icon with accessibility label `Codex is not connected`.
- When a provider group contains unavailable Codex models, org admins see a `Connect` link to `/org-settings/api-keys`; non-admin users see `Admin required`.
- System AI teammates cannot be deleted from the active Staff list, bulk delete, or the AI teammate detail page.
- AI teammate create and update paths now snapshot teammate state into the shared backend `entity_versions` store.
- The stored entity type for AI teammate versions is `ai_employee`.
- Restore support is confirmed in backend code through the shared entity-version restore route.
- This doc does not claim a dedicated AI teammate version-history UI because that was not confirmed in the current frontend source.
Human teammate detail
- Back action: `Back`.
- The route reads accepted organization users via `GET /api/organizations/{orgId}/users/{user_id}`.
- Pending invitations stay in the `Invites` tab and do not become human Staff rows.
- Overflow menu includes:
- `Open in new tab`
- `Remove` for non-owner rows only
- The page shows email, phone, location, joined date, and invited date when available.
API and realtime
- Staff list:
- `GET /api/organizations/{orgId}/staff`
- `GET /api/organizations/{orgId}/staff/deleted`
- Humans:
- `GET /api/organizations/{orgId}/users`
- `GET /api/organizations/{orgId}/users/{user_id}`
- `PUT /api/organizations/{orgId}/users/{user_id}/role`
- `DELETE /api/organizations/{orgId}/users/{user_id}`
- `POST /api/organizations/{orgId}/users/bulk-delete`
- `POST /api/organizations/{orgId}/users/bulk-restore`
- Invites:
- `POST /api/organizations/{orgId}/invites/`
- `GET /api/organizations/{orgId}/invites/`
- `DELETE /api/organizations/{orgId}/invites/{invite_id}/`
- `POST /api/organizations/{orgId}/invites/{invite_id}/resend`
- public acceptance flow: `/api/invites/{code}` and `/api/invites/{code}/accept`
- AI teammates:
- `GET /api/organizations/{orgId}/employees/`
- `POST /api/organizations/{orgId}/employees/`
- `GET /api/organizations/{orgId}/employees/{employee_id}`
- `PUT /api/organizations/{orgId}/employees/{employee_id}`
- `DELETE /api/organizations/{orgId}/employees/{employee_id}`
- `POST /api/organizations/{orgId}/employees/bulk-delete`
- `POST /api/organizations/{orgId}/employees/bulk-restore`
- `GET /api/organizations/{orgId}/employees/{employee_id}/external-urls`
- `GET /api/organizations/{orgId}/employees/{employee_id}/telegram`
- `POST /api/organizations/{orgId}/employees/{employee_id}/telegram`
- `DELETE /api/organizations/{orgId}/employees/{employee_id}/telegram`
- `PUT /api/organizations/{orgId}/employees/{employee_id}/telegram/webhook`
- `GET /api/organizations/{orgId}/employees/{employee_id}/msteams`
- `POST /api/organizations/{orgId}/employees/{employee_id}/msteams`
- `DELETE /api/organizations/{orgId}/employees/{employee_id}/msteams`
- `GET /api/organizations/{orgId}/employees/{employee_id}/msteams/contacts`
- `POST /api/organizations/{orgId}/employees/{employee_id}/msteams/contacts/{contact_id}`
- `DELETE /api/organizations/{orgId}/employees/{employee_id}/msteams/contacts/{contact_id}`
- `GET /api/organizations/{orgId}/employees/{employee_id}/msteams/channels`
- `PUT /api/organizations/{orgId}/employees/{employee_id}/msteams/channels/{channel_id}/status`
- `GET /api/organizations/{orgId}/employees/{employee_id}/msteams/package`
- `GET /api/organizations/{orgId}/employees/{employee_id}/slack/manifest`
- `GET /api/organizations/{orgId}/entity-versions/ai_employee/{employee_id}?limit=<n>&before_version=<n>`
- `POST /api/organizations/{orgId}/entity-versions/{entity_version_id}/restore`
- Logs and MCPs:
- `GET /api/organizations/{orgId}/workflows/runs/`
- `GET /api/organizations/{orgId}/mcps`
- `GET /api/organizations/{orgId}/mcps?employee_id={employee_id}`
- `POST /api/organizations/{orgId}/mcps/{mcp_id}/employee/{employee_id}`
- `DELETE /api/organizations/{orgId}/mcps/{mcp_id}/employee/{employee_id}`
- Jobs and schedulers APIs are documented in jobs-and-schedulers.md.
- WebSocket events used by Staff/Invites:
- `organization.staff_user_added`
- `organization.staff_user_removed`
- `ai_employee.created`
- `ai_employee.updated`
- `ai_employee.deleted`
- `staff_employee.created`
- `staff_employee.updated`
- `staff_employee.deleted`
- `organization_invite.created`
- `organization_invite.updated`
- `ai_employee_ms_teams_channel.created`
- `ai_employee_ms_teams_channel.updated`
Permission notes
- Staff and invite actions are organization-scoped and authorized by backend checks.
- Human removal and human bulk delete/restore are admin-or-owner only on the backend.
- Human role changes are owner-only on the backend.
- The current trash UI only surfaces deleted AI teammates even though backend user restore endpoints exist.