free vs restricted with an allowed-domain list), an autonomy policy, an optional shared persona, and cross-crew connections that gate agent-to-agent messaging.
All crew endpoints require authentication and workspace context. The workspace
may be supplied as workspace_id (query), {workspaceId} (path), or the
X-Workspace-ID header; query/path values take precedence and may be a
workspace ID or slug.
Endpoints
Crew CRUD
Create, read, update, and soft-delete crews and their container/network configuration.List Crews
created_at DESC, id DESC.
Use limit (maximum 500) and offset for pagination.
Auth: Session or CLI token + workspace membership
Request: No path parameters or request body. Workspace context is required;
provide it using the workspace_id query parameter, {workspaceId} path
context where supported, or X-Workspace-ID as described above.
Response: 200 OK
Response Fields
Create Crew
OWNER, ADMIN, or MANAGER role
Request Body:
Two floors.
container_memory_mb and container_cpus are rejected with
a 400 only below Docker’s own minimums (6 MB, 0.01 CPU) — the daemon
refuses to create a container there, so the request could never have worked.Between that and the usable floor (2048 MB, 0.5 CPU by default) the
crew is created, and the response carries a warnings array explaining
what will break: a warmed agent CLI holds 1.5–2 GiB, so a smaller crew is
created successfully and then OOM-killed (exit 137) on start. A small crew
can be deliberate, and refusing it would not make it bigger — so this is
advice, not a veto. Memory is a cgroup ceiling rather than a reservation, so
sizing at the floor costs an idle host nothing.The usable floor is settable per instance via the runtime.agent_min_memory_mb
and runtime.agent_min_cpus instance settings.
runtime.agent_min_memory_mb is also the divisor behind a crew’s
concurrent-run budget.0 on either field means “use the server default”, and it resolves to the
same size on POST and on PATCH — the stored row never holds 0.warnings (array of strings, POST and PATCH responses only) is
present only when there is something to say and is otherwise omitted. It is
additive — a client that ignores it sees an unchanged crew object.
201 Created — returns the created crew object (same shape as List response item).
Error Responses:
Get Crew
crewId is a required path parameter and workspace_id selects the workspace. No request body.
Response:
200 OK — full crew object including _count, issue_prefix, mcp_config_json, and escalation_config.
Update Crew
PATCH and PUT are supported and behave identically (partial update — only provided fields are changed).
Auth: Session or CLI token + OWNER or ADMIN role
Request Body: All fields are optional.
Response:
200 OK — updated crew object.
Changing
network_mode, allowed_domains, or services_json triggers a container restart so the docker provider picks up the new policy / sidecar set on the next agent run. Changing runtime_image, devcontainer_config, or mise_config invalidates cached_image + config_hash to force a rebuild.container_memory_mb / container_cpus do not restart the container, and
do not reach a running one. They are cgroup limits, fixed when the container
is created — a running crew keeps the limits it was created with while this
response, and every later GET, reports the new ones. The container is
deliberately not stopped for them: unlike a stale network policy, a stale
memory limit is not a live exposure, and killing whatever the crew is
executing costs more than the delay does.When the crew’s container is running, the response carries a warnings entry
saying so. A stopped one is rebuilt with the new limits on its next wake and
gets no warning, because nothing is pending on the operator.
GET /container-status reports the configured and
effective figures side by side.Delete Crew
The crew’s agents are soft-deleted with it, which releases their slugs
too: re-applying the manifest that created them succeeds without a manual
DELETE /api/v1/agents/{agentId} first. Each agent’s slug is rewritten to
{slug}_deleted_{id} when a new agent claims it, exactly as the crew’s is.OWNER or ADMIN role
Request: crewId is a required path parameter and workspace_id selects the workspace. No request body.
Response: 200 OK
WebSocket event:
crew.deleted broadcast to workspace:{workspaceId}
Members
Manage the per-crew membership roster and optional per-crew role overrides that win over the workspace role for crew-scoped permissions.List Members
crewId is a required path parameter and workspace_id is the workspace query parameter. No request body.
Response: 200 OK — array of member objects.
Add Member
OWNER, ADMIN, or MANAGER role
Request Body:
201 Created — member object with nested user (id/email/full_name/avatar_url). The role override is not echoed on the Add response (it is only included by List Members).
Update Member Role
role column that, when set, wins over the
workspace-level role for permissions scoped to this crew. Clearing it
(empty or omitted role) drops the member back to inheriting their
workspace role.
Auth: OWNER or ADMIN role on the workspace. A per-crew ADMIN
is not allowed to reshape membership — that could ladder a MEMBER
straight to OWNER and bypass the workspace gate.
Request Body:
200 OK — a status envelope echoing the applied role (an empty role means the override was cleared):
Remove Member
OWNER or ADMIN role
Request: crewId and memberId are required path parameters; workspace_id is the workspace query parameter. No request body.
Response: 200 OK
Persona
The crew layer of the persona stack —PERSONA.md markdown that the
orchestrator injects into every agent in the crew, used as the default
when an agent has no agent-layer file. Resolution is layered: the
agent layer wins if present; otherwise crew default; otherwise the
synthesised “You are the …” stub. See the Agent Persona
section in the agents reference
for the cross-layer model and cap_bytes (1500).
All three endpoints are operator-only; there is no crew-flavoured
suggest analog (agents propose into their own layer, not the crew
default).
Get Crew Persona
crewId is a required path parameter. No request body.
Response: 200 OK
GET /agents/{id}/persona, this endpoint does not report a from_default flag — the crew layer either has a file or it doesn’t. When empty, content is "" and clients fall through to the per-agent synthesised default.
Set Crew Persona
memory_versions keyed
to the crew-layer path so the history endpoint can replay the chain.
Request:
200 OK — { "layer": "crew", "bytes": N, "updated": "<rfc3339>" }
Reset Crew Persona
crewId is a required path parameter. No request body.
Removes the crew layer file. Subsequent reads return empty content
and agents fall back to their per-role synthesised default.
Response: 204 No Content
Policy
Each crew carries an autonomy posture that gates every HITL-relevant decision the orchestrator makes — memory writes, skill creation, behavior-monitor escalations, persona suggestions, ephemeral spawns. The dial is read by every PR-B / PR-C subsystem via the sharedpolicy.Resolver. The CLI counterpart is crewship policy get/set.
Get Crew Policy
200 OK
set_by_user_id / set_at / reason are omitted on crews whose
policy still matches the seed defaults (no operator has ever flipped
it). On crews that have been touched at least once, the audit triple
records who, when, why.
Set Crew Policy
set_by_user_id, set_at,
reason) atomically with the value change and invalidates the resolver cache
so the next decision sees the new state.
Auth: Session or CLI token + workspace membership (no additional role gate)
Request:
Response:
200 OK — same shape as GET, reflecting the new
state and the freshly-recorded audit triple.
Avatar
Bulk-apply an avatar style across a crew’s agents, or clear per-agent overrides.Apply Avatar Style
avatar_style to all non-deleted agents in the crew, or clears per-agent overrides.
This also clears any stored avatar renders on those agents, because a stored render depicts the previous style — leaving it would make this call a no-op for every agent that has one. Affected agents revert to avatar_url: null and are re-stored on next view.
PATCH /api/v1/crews/{crewId} with a new avatar_style does the same for the narrower set of agents that inherit the crew default (their own avatar_style is null). Agents with an explicit style of their own are unaffected by the crew default, so they keep their stored render.
Auth: OWNER or ADMIN role
Request Body:
Response:
200 OK
reset_overrides is true, the response is { "updated": N, "reset": true }.
Container
Container Status
crewshipd over the
internal IPC socket. Useful for confirming a crew’s container came back up after
a network-policy change (which stops the container so it is
recreated with the new policy on the next agent run).
Auth: any workspace member
Request: crewId is a required path parameter and workspace_id selects the workspace. No request body.
Response: 200 OK
Why
config_drift exists. runtime_contract asks whether this container is
older than the BUILD; config_drift asks whether it is older than this CREW’s
own settings. container_memory_mb and container_cpus are cgroup limits,
fixed at container-create and unchangeable on a running container, so
updating a crew moves the row and this endpoint’s configured_*
fields while effective_* stays where it was.Same response as for a stale runtime contract, for the same reasons: a
stopped container whose limits no longer match its crew is rebuilt on the
next wake, and a running one is reported rather than killed. PATCH /api/v1/crews/{crewId} warns on the spot when it resizes a crew that is
currently running.Why
runtime_contract exists. A crew container is created once and reused
for as long as it keeps running, and the settings that harden it — the init
process that reaps orphans, the core: 0 limit that stops a crashing agent
writing its credential environment to disk, supplementary groups, swap, the
/dev/shm size — are applied at container-create time and nowhere else. Upgrade
the server and a crew that was already running keeps the OLD configuration
indefinitely.stale means exactly that: this container predates the current configuration
and does not carry what has been added since. Nothing is broken and no run
fails; the container picks the new settings up the next time it is recreated —
an idle-TTL stop, or
crewship crew restart-agents <slug>. A container found stopped with a
stale contract is rebuilt automatically on the next wake, because at that
moment the rebuild costs nothing. A running one is never torn down for it:
that would kill whatever the crew is executing.200 even when
the runtime is unavailable, so a polling UI/CLI can treat them as transient
states rather than errors:
CLI:
Credential Readiness
git, curl and jq. Tools like gh, aws,
az, gcloud, kubectl, docker, terraform, npm and ansible exist in
the container only when the crew’s devcontainer_config declares the
matching feature (or mise installs the tool). A valid credential and a working
agent are therefore two different things: a healthy GitHub PAT plus a crew with
no github-cli feature still gets gh: command not found.
The endpoint is read-only and advisory. It never edits devcontainer_config
and never triggers a rebuild — adding a feature changes what runs inside the
container, so it stays a separate, user-confirmed action
(Update Crew or crewship crew config).
Request: crewId is a required path parameter and workspace_id selects the workspace. No request body.
Credentials are matched using the same three-way grant rule as the rest of the
credentials surface: workspace-scoped, crew-scoped via credential_crews, or
assigned to one of this crew’s agents (with any lease still live). Revoked and
soft-deleted credentials are excluded. A provider with no known CLI (Notion,
Stripe, an unrecognised string) reports nothing rather than guessing.
Matching is on the tool name, not the feature ref, so an equivalent feature
counts: docker-outside-of-docker satisfies a DOCKER credential, and a mise
nodejs satisfies an NPM one.
Auth: any workspace member
Response: 200 OK
CLI:
Crew Capabilities
crewId is a required path parameter. Workspace context is
required and may be supplied with X-Workspace-ID (or the equivalent
workspace context described at the top of this page). No request body.
Response: 200 OK
container.datastores and container.tools are arrays and may be empty.
Only enabled crew integrations are included; integrations[].tools contains
only explicitly enabled crew-scoped tool bindings. schema is the nested
routine DSL schema object, not a JSON-encoded string.
Connections
Crew connections (“crew links” in the UI) define which crews can reach each other. A link is what allows cross-crew task assignment, messages and shared files; without one every attempt is refused server-side.direction is read from from_crew_id’s side: unidirectional means from may hand work to to and
not the reverse; bidirectional means either may.
Links to a soft-deleted crew are never listed and are removed when the crew is deleted.
List Connections
workspace_id is the required workspace query parameter. No request body.
Response: 200 OK — array of connection objects:
Create Connection
OWNER, ADMIN, or MANAGER role
Request Body:
201 Created for a new link, 200 OK when one already existed.
- Same pair, same orientation → the stored link keeps its id and takes the new
direction. - Same pair, reverse orientation → the stored link becomes
bidirectional(you asked for the way back as well). To make a link one-way in the other direction, delete it and create it again.
Delete Connection
OWNER, ADMIN, or MANAGER role
Request: connectionId is a required path parameter and workspace_id is the workspace query parameter. No request body.
Response: 204 No Content
Crew Files (Proxy)
File operations are proxied through the crewshipd sidecar to the crew’s container filesystem.Delete a Crew File
DELETE /api/v1/crews/{crewId}/files/delete?path={path}
Auth: Authenticated workspace member with the create capability. The
crew must belong to the selected workspace.
Request: No body. The required path query parameter is a relative file
path under the crew’s shared/output tree. Absolute paths and traversal are
rejected.
Response: 200 OK with the sidecar response:
400 missing or invalid path; 401 unauthenticated; 403
insufficient role/capability; 404 crew not found in the workspace; 500
storage/delete failure; 502 sidecar unavailable. A missing storage provider
may return 503 from the sidecar.
Crew Git Diff
Crew Git Diff
GET /api/v1/crews/{crewId}/git-diff?agent_slug={agentSlug}
Returns the crew container’s base-branch diff, the same change set used by the
dashboard’s Changes tab. agent_slug is optional and selects the agent
workspace when the crew has multiple agent workspaces.
Auth: Authenticated workspace member with the read capability. The crew
must belong to the selected workspace.
Request: No body. Optional agent_slug query parameter.
Response: 200 OK with the decoded git-diff object from crewshipd. If the
workspace is not a repository, the response is { "is_repo": false }.
Statuses: 401 unauthenticated; 403 insufficient role/capability; 404
crew not found in the workspace; 500 crew lookup failure; 502 crewshipd
unavailable or diff computation failure.
Live Service Inventory
Live Service Inventory
GET /api/v1/crews/{crewId}/services
Returns the live sidecar containers, not the stored services_json configuration
snapshot.
Auth: Authenticated workspace member with the read capability. The crew
must belong to the selected workspace.
Request: No body or query parameters.
Response: 200 OK:
type is one of postgres, redis, mysql, mongodb, or other. A
provider without live service-list capability returns 200 with an empty
services array.
Statuses: 401 unauthenticated; 403 insufficient role/capability; 404
crew not found in the workspace; 500 crew lookup or service-list failure.
Crew Assignments
crewId is a required path parameter and workspace_id is the workspace query parameter. No request body.
List task assignments for a crew.
Response: 200 OK — array of assignment objects.
Crew Peer Conversations
crewId is a required path parameter and workspace_id is the workspace query parameter. No request body.
List peer-to-peer conversations between agents in a crew.
Response: 200 OK with an object containing conversations (array) and count (integer).
Crew Standup
crewId is a required path parameter; optional query parameters are crew_id and since. No request body.
Get standup summary for a crew.
Response: 200 OK with crew_id, date, summary, and items fields.
Crew Escalations
List Escalations
workspace_id must identify the
caller’s workspace.
Path / query parameters: crewId is the crew ID; workspace_id is the
required workspace ID. Returns the crew’s escalation records.
Response: 200 OK with an array of escalation objects.
Resolve Escalation
escalationId is a required path parameter, workspace_id selects the workspace, and the JSON body is the escalation decision (action and optional resolution details).
Response: 200 OK with the resolved escalation id, status, and action.
Pending Escalation Count
workspace_id is the workspace context. No request body.
Returns count of pending escalations across the workspace.
Response: 200 OK with { "count": integer }.
Purge Crew Escalations
OWNER or ADMIN (manage role).
Path / query parameters: crewId is the crew ID; workspace_id is the
required workspace ID. The request has no body. The operation permanently
deletes all escalation rows for that crew in that workspace.
Response: 200 OK
Activity Feed (removed)
The dedicatedGET /api/v1/activity aggregator has been removed. It merged three
tables (assignments, peer conversations, escalations) in memory and would silently drop a
whole source on any query error while still returning 200 OK.
The activity feed is now sourced from the journal, which is the canonical event stream:
crew_id / agent_id, bound the window with since=, and page with cursor /
limit (see Journal). Display names and crew colors are not part of
the journal row (it stores ids + payload slugs); resolve them via GET /api/v1/journal/lookup.
The crewship activity CLI command wraps this same query — see CLI · Activity.