Skip to main content

kind: Skill

What it is

kind: Skill declares a standalone entry in the workspace’s skill registry — a SKILL.md body (markdown + front-matter) that any agent in any crew can later bind to. It is the inverse of the nested Skill reference under Crew.spec.agents[].skills: the nested form says “this agent uses skill X (by slug)” and assumes the row already exists; the standalone kind: Skill document says “ensure THIS SKILL.md exists in the registry.” The common pattern pairs the two: declare the Skill once at the top level (or as a top-level document in a workspace bundle), then reference its slug from as many agents as you like. The kind is implemented in internal/manifest/kinds/skill.go. The backing endpoint is the import handler, which is a genuine upsert keyed on slug — so Create and Update both POST the same body; the manifest only distinguishes the two for readable dry-run output.

One body source — pick exactly one

A Skill carries its SKILL.md body via exactly one of three mutually-exclusive sources. Zero is a validation error (there is nothing to import); two or more is rejected with the offending list.

YAML schema

Field reference

display_name, category, and icon are forward-compatibility metadata today: the importer reads front-matter from the body verbatim and does not yet merge these spec fields into it. They still round-trip via export, so set them now if you want them populated when the merge lands.

Examples

Inline body

Sibling file (large body)

Remote source

Cross-kind reference

Once a Skill is declared, agents reference it by slug:

CLI reference

The manifest pipeline drives the same import endpoint the UI uses; no new per-kind subcommands ship with this kind.

REST endpoint mapping

Endpoints used:

Validation rules

SkillDocument.Validate (offline — no HTTP, no filesystem) enforces:
  • apiVersion, when set, equals crewship/v1.
  • kind, when set, equals Skill.
  • metadata.name is non-empty.
  • metadata.slug is non-empty and matches ^[a-z0-9][a-z0-9_-]*$.
  • spec.description is non-empty.
  • Exactly one of inline / path / source is set (zero or more than one is an error, with the offending list named).
  • inline body length ≤ 8 KiB.
  • source, when set, parses as a URL, uses the https scheme, and has a host.
  • path, when set, must have been resolved by the bundle loader (a hand-constructed document that never went through Load is flagged).
Validate does not consult WorkspaceContext — Skill is a leaf kind with no FK references; the argument exists only for dispatcher uniformity.

Apply behavior

ApplyUpsert (default)

For each declared Skill, Plan compares against the matched-by-slug remote row:
  • Remote missing → ActionCreate (POST import).
  • Remote present and a body source is declaredActionUpdate (POST import). Because the list endpoint exposes no body hash, the manifest cannot tell whether the body actually changed, so any apply that declares a body re-posts it. This is deliberate: it is preferable to silently losing an edit.
  • Remote present, no body source, decoration matches → ActionUnchanged (no REST call).
  • Remote row is source: BUNDLEDerror. Bundled skills are server-seeded on every startup; the manifest refuses to touch them (mirrors the server-side guard). Pick a different slug.

ApplyReplace

Replace mode can DELETE the registry row then re-POST it. Be aware bundled rows are still off-limits.

Round-trip via export

crewship export workspace calls ExportSkills, which emits one kind: Skill document per non-BUNDLED row, sorted by slug. Body lossiness: the list endpoint does NOT return the SKILL.md content, so exported documents carry metadata + decoration but no body source (no inline, path, or source). The export is suitable for cataloguing what a workspace has, but re-applying it as-is fails Validate (“exactly one of inline / path / source must be set”). To get a round-trip-safe export you must re-attach a body (materialise the SKILL.md files and rewrite the docs with path: entries).

See also

  • Agent — binds skills via spec.skills (slug list).
  • Workspace — declares skills inline under spec.skills.
  • Backend: internal/api/skills.go, internal/skills/importer.go.
  • This kind’s Go implementation: internal/manifest/kinds/skill.go.