Skip to main content

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:
  1. POST /api/v1/agents — create the agent, returns the new id.
  2. POST /api/v1/agents/{id}/skills — one call per spec.skills entry.
  3. POST /api/v1/agents/{id}/credentials — one call per spec.env_refs entry.
Binding POSTs are idempotent on the server (a re-bind returns “already assigned”), so re-applying is safe. A skill/env-ref typo fails loud at apply with the offending slug named.

YAML schema

Field reference

Exactly one of prompt / prompt_file must be set. prompt_file is resolved relative to the manifest file and folded into prompt before Validate runs, so a hand-built document that never went through the loader must set prompt directly.
COORDINATOR is asymmetric — and effectively unsupported. The standalone kind: Agent validator (validAgentRoles, internal/manifest/kinds/agent.go) still admits COORDINATOR, but:
  • The nested form — an agent inside a kind: Crew or kind: Workspace bundle — rejects it outright. Its validator (validAgentRole, internal/manifest/validate.go) accepts only AGENT and LEAD.
  • Even via the standalone kind, the server’s agent-role enum was trimmed to AGENT/LEAD in v0.1, so apply can still fail with a 400 at the POST /api/v1/agents call.
In practice use AGENT or LEAD. COORDINATOR survives 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 dedicated crewship 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 — ANTHROPICanthropic/claude-sonnet-4-6, OPENAIopenai/…, GOOGLEgoogle/…. 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, equal crewship/v1 / Agent.
  • metadata.name and metadata.slug are non-empty.
  • spec.crew_slug is non-empty (and required when agent_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_seconds is non-negative.
  • Exactly one of prompt / prompt_file is set.
  • skills[] and env_refs[] have no empty entries.
  • When WorkspaceContext carries crew data, crew_slug must 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 omitting role_title won’t blank out a title set via the UI. Declared bindings are re-asserted (idempotent).
  • Remote present, no field drift, no declared bindings → ActionUnchanged.
The diff is intentionally narrow: 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 different crew_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.

See also

  • Crew — the parent crew; can also declare agents inline under spec.agents.
  • Skill — bound via spec.skills (slug list).
  • Workspace — the top-level bundle that nests crews + agents.
  • Issue — references an agent via spec.assignee_slug.
  • This kind’s Go implementation: internal/manifest/kinds/agent.go.