kind: Agent
What it is
kind: Agent is the per-record CRUD entry point for a single agent —
the standalone counterpart to the agents: list nested under a
kind: Crew or kind: Workspace document. Operators reach for the
standalone form when they want to author or patch one agent in
isolation (e.g. add a skill, repoint the model) without re-shipping
the whole crew bundle.
Every agent belongs to exactly one crew. The manifest references its
parent crew by slug (spec.crew_slug); Plan resolves that slug to
the crew’s id at apply time — the Create handler only accepts a
crew_id, never a slug.
The kind is implemented in internal/manifest/kinds/agent.go.
Bindings are separate POSTs
The Create handler does not accept inline skills or credential references in its body. Each binding is its own POST. So the Create Exec runs three phases in order:POST /api/v1/agents— create the agent, returns the new id.POST /api/v1/agents/{id}/skills— one call perspec.skillsentry.POST /api/v1/agents/{id}/credentials— one call perspec.env_refsentry.
YAML schema
Field reference
Exactly one ofprompt/prompt_filemust be set.prompt_fileis resolved relative to the manifest file and folded intopromptbefore Validate runs, so a hand-built document that never went through the loader must setpromptdirectly.
COORDINATORis asymmetric — and effectively unsupported. The standalonekind: Agentvalidator (validAgentRoles,internal/manifest/kinds/agent.go) still admitsCOORDINATOR, but:In practice use
- The nested form — an agent inside a
kind: Creworkind: Workspacebundle — rejects it outright. Its validator (validAgentRole,internal/manifest/validate.go) accepts onlyAGENTandLEAD.- Even via the standalone kind, the server’s agent-role enum was trimmed to
AGENT/LEADin v0.1, so apply can still fail with a400at thePOST /api/v1/agentscall.AGENTorLEAD.COORDINATORsurvives in the standalone front-end validator only so a future server rollback stays a one-line change; treat it as unsupported today.
Examples
Minimal
Lead with model, tools, and bindings
Prompt from a sibling file
CLI reference
There is no dedicatedcrewship agent per-kind admin command — agents
are authored through the manifest pipeline (or the UI). The relevant
CLI surface is the global apply/export flow:
REST endpoint mapping
How each manifest field maps onto the create/update request body and binding calls:OpenCode model routing
OpenCode is BYOK across providers, so its--model value must be in
provider/model form. Crewship qualifies it for you: when an OPENCODE
agent’s llm_model has no provider/ segment (e.g. claude-sonnet-4-6),
the agent’s llm_provider is prepended automatically — ANTHROPIC →
anthropic/claude-sonnet-4-6, OPENAI → openai/…, GOOGLE → google/….
You can still pin the fully-qualified form yourself (anthropic/claude-sonnet-4-6),
which is passed through untouched, as are local-model ids (ollama/…). If the
provider is unset or unrecognized, the bare model is passed through unchanged
and OpenCode surfaces its own routing error in the run journal.
Endpoints used:
Validation rules
AgentDocument.Validate enforces:
apiVersion/kind, when set, equalcrewship/v1/Agent.metadata.nameandmetadata.slugare non-empty.spec.crew_slugis non-empty (and required whenagent_role: LEAD).agent_role,cli_adapter,llm.provider,tool_profile, when set, are members of their allow-lists (errors spell out the legal values).timeout_secondsis non-negative.- Exactly one of
prompt/prompt_fileis set. skills[]andenv_refs[]have no empty entries.- When
WorkspaceContextcarries crew data,crew_slugmust reference a declared or remote crew. Skill/credential FK checks run at Plan time (the live client is available there).
Apply behavior
ApplyUpsert (default)
- Remote missing →
ActionCreate: POST the agent, then bind each skill + env-ref in sequence. A partial binding failure leaves the agent created; re-applying converges (the bindings are idempotent). - Remote present, fields drift →
ActionUpdate: a sparse PATCH carrying only the fields whose declared value differs from the remote. Empty declared fields are skipped — so omittingrole_titlewon’t blank out a title set via the UI. Declared bindings are re-asserted (idempotent). - Remote present, no field drift, no declared bindings →
ActionUnchanged.
system_prompt, description, and
memory_enabled are not touched unless explicitly declared, so the
manifest never silently clobbers a prompt grown via the UI.
Crew reassignment
Declaring a differentcrew_slug on an existing agent emits a
crew_id patch — supported but rare.
Round-trip via export
crewship export workspace calls ExportAgents, which renders one
kind: Agent document per agent (sorted by slug), folding crew_id
back to crew_slug and pulling each agent’s bound skill slugs +
credential env-names back into spec.skills / spec.env_refs.
memory_enabled is emitted explicitly so the round-trip diff doesn’t
fall into the “use server default” branch. Fields the manifest doesn’t
model (runtime status, run counts, timestamps) are dropped.