Skip to main content

kind: Issue

What it is

kind: Issue is the per-row CRUD entry point for a single issue (a tracker ticket) declared in source control. Its cousin RecurringIssue mints the same shape on a cron; kind: Issue is for human-authored, one-shot tickets that should be tracked declaratively rather than clicked into the UI. Issues are crew-scoped — the create endpoint embeds the crew id in the URL — so every Issue references its parent crew by spec.crew_slug, resolved to a crew id at Plan time. Optional references to a project, an assignee agent, and labels are likewise resolved slug → id before the POST. The kind is implemented in internal/manifest/kinds/issue.go.

The slug is manifest-side only

The missions table that backs issues has no slug column and no predictable identifier (the server-generated ENG-7-style identifier is assigned by an atomic counter on POST). So metadata.slug is a manifest-side idempotency key: it makes plan output and the apply journal grep-able and lets cross-document references resolve, but it is not persisted server-side. Because there’s no server slug, drift detection matches a declared issue to a remote row by the pair (crew, title). The consequence: renaming an issue’s title in the manifest creates a new row instead of updating the old one. This mirrors how Milestone behaves (also no slug column). Keep titles stable if you want updates to land on the same row.

YAML schema

Field reference

Create-status quirk. The create handler hard-codes the new row to BACKLOG and ignores spec.status on POST. If you declare status: done on a brand-new Issue, the row first lands in BACKLOG; the next apply detects the drift and PATCHes it to DONE. Reaching a non-default starting status is therefore a two-apply operation today.

Examples

Minimal

Full

Cross-kind references

The Issue’s FK targets (crew, project, agent, labels) must be declared earlier in the same bundle or already exist on the server. The apply phase order guarantees those kinds are created before the Issue:

CLI reference

There is no dedicated crewship issue per-kind admin command for declarative authoring — issues are managed through the manifest pipeline (or the UI / runtime mission flow). The relevant CLI surface is the global apply/export flow:

REST endpoint mapping

Endpoints used:

Validation rules

IssueDocument.Validate enforces:
  • apiVersion / kind, when set, equal crewship/v1 / Issue.
  • metadata.slug is non-empty.
  • spec.crew_slug is non-empty.
  • A non-empty resolved title (spec.title OR metadata.name).
  • priority / status, when set, are members of their allow-lists.
  • spec.labels has no empty entries and no duplicates.
  • When WorkspaceContext carries the relevant data, crew_slug, project_slug, assignee_slug, and each label must reference a declared or remote entity (degrades gracefully when the context is empty — Plan catches dangling FKs at resolution).

Apply behavior

ApplyUpsert (default)

  • No remote row with the same (crew, title) → ActionCreate: resolve every FK, then POST to the crew-scoped endpoint.
  • Matching remote, fields/labels drift → ActionUpdate: a sparse PATCH of only the drifted fields. Labels ride in the same PATCH — a non-nil labels key is a full replacement; an empty list clears all labels.
  • Matching remote, no drift → ActionUnchanged.
Clearing an assignee via manifest is not supported today (an empty assignee_slug is treated as “leave alone”, not “clear”) — clearing is a UI operation.

Round-trip via export

crewship export workspace calls ExportIssues, which walks every crew, lists its issues (paginated), and renders each as a kind: Issue document. To avoid duplicate metadata.slug values across crews, the export namespaces the slug as <crew-slug>--<title-slug> (falling back to the server identifier when the title yields no slug-safe characters). Project, assignee, and label references are folded back to slugs. Fields the manifest doesn’t model (identifier, timestamps, comment counts) are dropped.

See also

  • RecurringIssue — the cron-driven sibling that mints the same shape.
  • TriageRule — auto-routes incoming issues.
  • Crew — the parent crew (spec.crew_slug).
  • Project / Label / Agent — FK targets.
  • This kind’s Go implementation: internal/manifest/kinds/issue.go.