Skip to main content
The Teams API covers everything scoped to a team: creating and updating teams, assigning agents to teams, managing the per-team onboarding gate, storing durable team rules, and reading or triggering the mixed-runtime peer-chat room. Teams are stored in SQLite; agent membership is the nullable 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

MethodPathSummary
GET/api/teamsList teams with agent counts and assignments
POST/api/teamsCreate a team
PATCH/api/teams/:idPartial update of a team
DELETE/api/teams/:idDelete a team and orphan its agents
POST/api/teams/:id/agentsAssign (upsert) an agent into the team
DELETE/api/teams/:id/agents/:agentIdRemove an agent from a team
GET/api/teams/:id/onboardingRead the Know Your Team onboarding state
PATCH/api/teams/:id/onboardingUpdate the onboarding state
GET/api/team-rules/:teamIdRead the durable team-rules text
PUT/api/team-rules/:teamIdReplace the team-rules text
GET/api/team-chatCursor-read the team peer-chat room
POST/api/team-chat/exchangeKick 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.
includeArchived
string
Pass "true" to include archived teams (isArchived = 1).

Response 200 OK

teams
array
All teams with their fields and computed agent counts.
assignments
array
All agents that have a non-null teamId, as { agentId, teamId } pairs.
curl http://localhost:18790/api/teams
curl 'http://localhost:18790/api/teams?includeArchived=true'

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

name
string
required
Team display name.
icon
string
required
Emoji icon for the team.
color
string
required
Hex color string (e.g. "#34d399").
leaderAgentId
string
Agent id to designate as team leader.
id
string
Optional client-supplied UUID. Honored only if it matches the UUID pattern; otherwise the server mints one.

Response 200 OK

{ "team": { "id": "...", "name": "Research Squad", "icon": "🔬", "color": "#34d399", "agentCount": 0 } }
This route returns 200, not 201, even on a successful create.
curl -X POST http://localhost:18790/api/teams \
  -H 'Content-Type: application/json' \
  -d '{"name":"Research Squad","icon":"🔬","color":"#34d399"}'

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)

name
string
Updated team name.
icon
string
Updated emoji icon.
color
string
Updated hex color.
isArchived
number
Truthy → 1, falsy → 0.
leaderAgentId
string | null
Updated leader agent id.
curl -X PATCH http://localhost:18790/api/teams/<team-id> \
  -H 'Content-Type: application/json' \
  -d '{"name":"Renamed Squad","leaderAgentId":"<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

{ "ok": true }
The handler does not 404 a non-existent team id. An unknown id still returns { "ok": true }.
curl -X DELETE http://localhost:18790/api/teams/<team-id>

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

agentId
string
required
The id of the agent to assign.
agentName
string
Display name used when creating a new placeholder row. Defaults to agentId.
curl -X POST http://localhost:18790/api/teams/<team-id>/agents \
  -H 'Content-Type: application/json' \
  -d '{"agentId":"<agent-id>"}'

DELETE /api/teams/:id/agents/:agentId

Removes an agent from the team by setting its teamId to null. The agent row is not deleted.
curl -X DELETE http://localhost:18790/api/teams/<team-id>/agents/<agent-id>

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

agentsIntroduced
boolean
true after agents have done their self-introductions. Defaults to false.
userIntroduced
boolean
true after the user has introduced themselves. Defaults to false.
userIntroText
string
The user’s self-introduction text. Injected into team context on every group-chat message. Defaults to "".
curl http://localhost:18790/api/teams/<team-id>/onboarding

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)

agentsIntroduced
boolean
Mark agent introductions complete.
userIntroduced
boolean
Mark user introduction complete.
userIntroText
string
The user’s self-introduction. Sliced to 4,000 chars server-side.
curl -X PATCH http://localhost:18790/api/teams/<team-id>/onboarding \
  -H 'Content-Type: application/json' \
  -d '{"agentsIntroduced":true,"userIntroduced":true,"userIntroText":"I run a small SaaS."}'

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.
curl http://localhost:18790/api/team-rules/<team-id>

PUT /api/team-rules/:teamId

Replaces the team-rules text. Content exceeding 4,000 characters is rejected (not truncated).

Request body

content
string
required
The full team rules text. Maximum 4,000 characters.
curl -X PUT http://localhost:18790/api/team-rules/<team-id> \
  -H 'Content-Type: application/json' \
  -d '{"content":"Always delegate via <delegate>; never do the work yourself."}'

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.
teamId
string
Resolves the room id to team:<teamId>. Required unless roomId is supplied.
roomId
string
An explicit room id. Overrides teamId.
sinceSeq
number
Returns posts with seq > sinceSeq. Defaults to 0.
limit
number
Cap the batch size.

Response 200 OK

posts
array
Chat posts in ascending seq order.
nextSeq
number
The last post’s seq. Use as sinceSeq on the next poll.
curl 'http://localhost:18790/api/team-chat?teamId=<team-id>&sinceSeq=0'

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

teamId
string
required
The team to run the exchange for.
stimulus
string
The initiating message for the first speaker’s turn.
firstSpeakers
string[]
Agent ids seeded to speak first. Defaults to the team leader.
maxExchangeTurns
number
Clamped server-side to DEFAULT_MAX_EXCHANGE_TURNS (5) × participants.

Responses

200 OK — the exchange ran to completion:
{
  ok: true
  roomId: string
  result: {
    turnsTaken: number
    endedReason: 'max_turns' | 'no_pending_obligation' | 'budget_paused' | 'aborted'
    speakers: string[]   // ordered agent ids who spoke
  }
}
409 Conflict — an exchange is already running for this room:
{ "ok": false, "error": "an exchange is already running for this room" }
curl -X POST http://localhost:18790/api/team-chat/exchange \
  -H 'Content-Type: application/json' \
  -d '{"teamId":"<team-id>","stimulus":"Plan the launch checklist."}'

See also