Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.crewship.ai/llms.txt

Use this file to discover all available pages before exploring further.

Recurring Issues

A recurring issue is a template that produces a fresh backlog issue on every cron tick: same title, description, priority, project, milestone, assignee, and labels. The intended workflow is “weekly bug triage”, “daily standup digest”, “monthly cost review” — anything you’d otherwise re-type as an issue on a schedule. Implementation: internal/api/recurring_issue_handler.go. Backed by the recurring_issues table. The cron expression is parsed and validated at write time using the standard 5-field syntax (Minute | Hour | DayOfMonth | Month | DayOfWeek); the parser is github.com/robfig/cron/v3. The next fire time is computed on create and on every cron change and stored in next_run, so the dispatcher can wake by index without re-parsing. All endpoints require an authenticated session and workspace context.

Recurring issue shape

FieldTypeNotes
idstring (CUID)
crew_idstringOwning crew. Verified against workspace_id on create.
crew_namestringPre-joined from crews.name for display — empty string if the crew was deleted.
titlestringTemplate title used verbatim on each fire.
descriptionstring | nullTemplate description (Markdown).
prioritystringOne of low, normal, high, urgent, or none. Defaults to none when omitted on create.
project_idstring | nullOptional project to file the new issue under.
milestone_idstring | nullOptional milestone to attach.
assignee_typestring | nullagent or user.
assignee_idstring | nullThe agent or user id.
labels_jsonstring | nullOpaque JSON array of label ids — applied verbatim to each fire.
cron_expressionstringStandard 5-field cron expression.
enabledboolWhen false, the dispatcher skips the row. Created enabled by default.
next_runRFC3339 | nullComputed from cron_expression at write time.
last_runRFC3339 | nullSet by the dispatcher after a successful fire.
run_countintTotal successful fires.
created_atRFC3339

GET /api/v1/recurring-issues

List recurring issues in the workspace, newest first. Auth: authenticated session + workspace context. Query parameters:
ParamTypeDefaultNotes
crew_idstring(unset)Narrow to a single crew.
Response: 200 OK — JSON array (never null).
[
  {
    "id": "ri_01HVZ...",
    "crew_id": "crw_backend",
    "crew_name": "Backend",
    "title": "Weekly dependency audit",
    "description": "Run `npm audit` and `pnpm outdated`; file follow-ups for critical advisories.",
    "priority": "normal",
    "project_id": "prj_security",
    "milestone_id": null,
    "assignee_type": "agent",
    "assignee_id": "agt_viktor",
    "labels_json": "[\"lbl_security\",\"lbl_chore\"]",
    "cron_expression": "0 9 * * 1",
    "enabled": true,
    "next_run": "2026-05-25T09:00:00Z",
    "last_run": "2026-05-18T09:00:00Z",
    "run_count": 14,
    "created_at": "2026-02-03T12:01:00Z"
  }
]

POST /api/v1/recurring-issues

Create a new recurring issue template. Auth: authenticated session + workspace context + OWNER, ADMIN, or MANAGER role (requireRole("create")). Request body:
FieldTypeRequiredDefaultNotes
crew_idstringYesMust exist in the current workspace (SELECT 1 FROM crews WHERE id = ? AND workspace_id = ?). A missing crew → 400 Crew not found in workspace.
titlestringYesEmpty → 400 title is required.
descriptionstringNonull
prioritystringNo"none"
project_idstringNonull
milestone_idstringNonull
assignee_typestringNonullagent or user.
assignee_idstringNonull
labels_jsonstringNonullOpaque JSON.
cron_expressionstringYesStandard 5-field cron. Invalid → 400 Invalid cron expression: <parser error>. next_run is computed from this immediately.
enabled is forced to true on create; flip it with PATCH. Response: 201 Created with the full recurring issue object. WebSocket event: recurring_issue.created broadcast on the workspace channel.
StatusCondition
400Missing crew_id / title / cron_expression, invalid cron expression, or crew does not belong to the workspace.
401Not authenticated.
403Caller is below the MANAGER role.

PATCH /api/v1/recurring-issues/{recurringId}

Partial update. When cron_expression is changed, the new value is re-parsed and next_run is recomputed in the same write — so the dispatcher’s next wake reflects the new schedule without a second round-trip. Auth: authenticated session + workspace context + OWNER, ADMIN, or MANAGER role. Request body: every field optional.
FieldTypeNotes
crew_idstring
titlestring
descriptionstring
prioritystring
project_idstring"" → NULL.
milestone_idstring"" → NULL.
assignee_typestring
assignee_idstring
labels_jsonstring
cron_expressionstringRe-parsed; invalid → 400. Forces next_run recompute.
enabledbool
Response: 200 OK with the full updated recurring issue object (with crew_name re-joined from crews). WebSocket event: recurring_issue.updated broadcast on the workspace channel.
StatusCondition
400Malformed JSON body, invalid cron expression, or no fields to update.
401Not authenticated.
403Caller is below the MANAGER role.
404Recurring issue id not found in this workspace.

DELETE /api/v1/recurring-issues/{recurringId}

Hard delete. The recurring template is removed; already-fired issues are not touched — they remain in the backlog with whatever state they’ve reached. Auth: authenticated session + workspace context + OWNER or ADMIN role (requireRole("manage")). Response: 204 No Content. WebSocket event: recurring_issue.deleted broadcast on the workspace channel.
StatusCondition
401Not authenticated.
403Caller is below the ADMIN role.
404Recurring issue id not found in this workspace.

Cron syntax cheatsheet

5-field expression: <minute> <hour> <day-of-month> <month> <day-of-week>.
ExpressionMeaning
0 9 * * 1Every Monday at 09:00 UTC.
*/15 * * * *Every 15 minutes.
0 0 1 * *Midnight UTC on the 1st of every month.
0 0 * * 0Midnight UTC every Sunday.
All times are interpreted in UTC. There is currently no per-workspace timezone offset — the dispatcher schedules from next_run directly.

See also

  • Issues — the missions table where each fire lands.
  • Triage Rules — auto-route the newly-created backlog issue to a crew / agent.
  • Crews — the crew_id target.
  • Milestones — optional milestone_id target.