agents.teamId foreign key — one agent belongs to at most one team at a time.
Deleting a team orphans its agents (sets their
teamId to null) rather than deleting them. The agents themselves are managed through the Agents API.Routes
| Method | Path | Summary |
|---|---|---|
GET | /api/teams | List teams with agent counts and assignments |
POST | /api/teams | Create a team |
PATCH | /api/teams/:id | Partial update of a team |
DELETE | /api/teams/:id | Delete a team and orphan its agents |
POST | /api/teams/:id/agents | Assign (upsert) an agent into the team |
DELETE | /api/teams/:id/agents/:agentId | Remove an agent from a team |
GET | /api/teams/:id/onboarding | Read the Know Your Team onboarding state |
PATCH | /api/teams/:id/onboarding | Update the onboarding state |
GET | /api/team-rules/:teamId | Read the durable team-rules text |
PUT | /api/team-rules/:teamId | Replace the team-rules text |
GET | /api/team-chat | Cursor-read the team peer-chat room |
POST | /api/team-chat/exchange | Kick off one bounded peer-chat exchange |
GET /api/teams
Lists every team with a computed agentCount and the full agent-to-team assignment list. Archived teams are excluded unless you pass includeArchived=true.
Pass
"true" to include archived teams (isArchived = 1).Response 200 OK
All teams with their fields and computed agent counts.
All agents that have a non-null
teamId, as { agentId, teamId } pairs.POST /api/teams
Creates a team. The server mints a UUID unless you supply a valid UUID id — the create-team UI seeds a client-side id so the color-palette preview matches the deployed team.
Request body
Team display name.
Emoji icon for the team.
Hex color string (e.g.
"#34d399").Agent id to designate as team leader.
Optional client-supplied UUID. Honored only if it matches the UUID pattern; otherwise the server mints one.
Response 200 OK
This route returns
200, not 201, even on a successful create.PATCH /api/teams/:id
Partially updates a team. Only the fields present in the body are written; updatedAt is always refreshed. Returns the full updated row with a recomputed agentCount.
Request body (all optional)
Updated team name.
Updated emoji icon.
Updated hex color.
Truthy →
1, falsy → 0.Updated leader agent id.
DELETE /api/teams/:id
Deletes the team in one operation: clears teamId on all member agents, deletes the team-scoped settings rows (team-rules:<teamId>, team-onboarding:<teamId>), and deletes the team row.
Response 200 OK
The handler does not
404 a non-existent team id. An unknown id still returns { "ok": true }.POST /api/teams/:id/agents
Assigns an agent to the team. This is an upsert: if the agent row exists, only its teamId is updated; if the row does not exist, a placeholder is created.
Request body
The id of the agent to assign.
Display name used when creating a new placeholder row. Defaults to
agentId.DELETE /api/teams/:id/agents/:agentId
Removes an agent from the team by setting its teamId to null. The agent row is not deleted.
GET /api/teams/:id/onboarding
Reads the per-team Know Your Team onboarding state. Both agentsIntroduced and userIntroduced must be true before the group-chat composer unlocks. Returns defaults when no state is stored.
Response 200 OK
true after agents have done their self-introductions. Defaults to false.true after the user has introduced themselves. Defaults to false.The user’s self-introduction text. Injected into team context on every group-chat message. Defaults to
"".PATCH /api/teams/:id/onboarding
Merge-updates the onboarding state. Only fields with the correct type are applied. userIntroText is truncated server-side to 4,000 characters.
Request body (all optional)
Mark agent introductions complete.
Mark user introduction complete.
The user’s self-introduction. Sliced to 4,000 chars server-side.
GET /api/team-rules/:teamId
Reads the durable per-team rules text. These rules are injected into the message preamble for every team agent so user corrections survive across sessions. Returns { content: "" } when no rules are stored.
This route uses the path parameter
:teamId, not :id like the team CRUD routes above. The value is still the team’s UUID.PUT /api/team-rules/:teamId
Replaces the team-rules text. Content exceeding 4,000 characters is rejected (not truncated).
Request body
The full team rules text. Maximum 4,000 characters.
GET /api/team-chat
Cursor-reads the team’s mixed-runtime peer-chat room. The model-facing write half is the TeamChat MCP server; this REST route is the UI-facing read. Posts are returned in ascending seq order.
Resolves the room id to
team:<teamId>. Required unless roomId is supplied.An explicit room id. Overrides
teamId.Returns posts with
seq > sinceSeq. Defaults to 0.Cap the batch size.
Response 200 OK
Chat posts in ascending
seq order.The last post’s
seq. Use as sinceSeq on the next poll.POST /api/team-chat/exchange
Kicks off one bounded peer-chat exchange for a team. Assembles active members into chat participants, drives a bounded round of turns through the real runtime adapters, and projects the lifecycle into the observability event log. This is a deliberate, invokable trigger — not an autonomous loop.
The board stays canonical. A peer-chat post never mutates the board. Decisions that land as board mutations are narrated into the room as
kind: "system" lines.Request body
The team to run the exchange for.
The initiating message for the first speaker’s turn.
Agent ids seeded to speak first. Defaults to the team leader.
Clamped server-side to
DEFAULT_MAX_EXCHANGE_TURNS (5) × participants.Responses
200 OK — the exchange ran to completion:
409 Conflict — an exchange is already running for this room:
See also
- Mixed-runtime peer chat — rooms, speaker selection,
isUser=false - Agents API — the agent registry these membership routes reference
- Tools & MCP API — the TeamChat MCP server write half
- REST API overview