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
Themissions 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 toBACKLOGand ignoresspec.statuson POST. If you declarestatus: doneon a brand-new Issue, the row first lands inBACKLOG; the next apply detects the drift and PATCHes it toDONE. 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 dedicatedcrewship 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, equalcrewship/v1/Issue.metadata.slugis non-empty.spec.crew_slugis non-empty.- A non-empty resolved title (
spec.titleORmetadata.name). priority/status, when set, are members of their allow-lists.spec.labelshas no empty entries and no duplicates.- When
WorkspaceContextcarries 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-nillabelskey is a full replacement; an empty list clears all labels. - Matching remote, no drift →
ActionUnchanged.
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.