Claude Routines
Integration layer to trigger your Anthropic Claude Routines directly from a Spedy ticket — with ticket-context variables, optional board/repo scope, pre- and post-actions, and results posted back into the ticket.
Claude Routines are an Anthropic product: reusable work instructions you define in your Anthropic account and Claude executes for you. Spedy doesn't host or run the routines — Spedy provides the integration layer so you can trigger one of your routines directly from a ticket.
Concretely, this integration:
- resolves ticket context (title, description, status, board, URL) into your prompt template,
- POSTs the resolved prompt to your Anthropic routine webhook with your secret,
- runs optional pre- and post-steps on the ticket (status change, self-assign, PR-link comment),
- tracks each execution and surfaces its status on the ticket.
The routines themselves, the model usage, and the cost remain in your Anthropic account.
The Spedy integration is part of the Pro plan and must be enabled at the organization level via the CLAUDE_ROUTINES feature flag.
Concepts
In Spedy, a routine entry has four layers:
- Metadata — name, slug, description
- Scope — optional board and repository scope
- Instructions — the prompt template (supports variables like
{{ticket.title}}) - Pre- and post-actions — server-side ticket steps that run before/after the hand-off to Claude
Every trigger creates a RoutineExecution that tracks the status of the hand-off, the resolved prompt, and completion metadata. The actual AI work happens on Anthropic — RoutineExecution is only Spedy's view of it.
Permissions and Feature Flag
Routines are gated by:
| Gate | Value | Scope |
|---|---|---|
| Organization feature flag | CLAUDE_ROUTINES | All /routines/* endpoints and UI require this to be enabled |
Permission routines:manage | Default for Admin + Team Member | Create/read/update/delete your own routines |
Permission routines:trigger | Default for Admin + Team Member | Trigger and cancel executions on tickets you can access |
Customers (organization role CUSTOMER) are explicitly excluded from both permissions.
Board-level access is also enforced: triggering a routine on a ticket whose board you cannot access returns 403 Forbidden.
Prompt Variables
Inside instructions, the following {{variable}} placeholders are resolved at trigger time:
| Variable | Source |
|---|---|
{{ticket.id}} | Ticket ID |
{{ticket.displayId}} | Human-readable ticket key (e.g. WEB-42) |
{{ticket.title}} | Ticket title |
{{ticket.description}} | Ticket description |
{{ticket.status}} | Status name |
{{ticket.statusKey}} | Status key (BACKLOG … DONE) |
{{ticket.boardId}} | Board ID |
{{ticket.boardName}} | Board name |
{{ticket.boardSlug}} | Board prefix |
{{ticket.url}} | Relative URL to the ticket |
If the trigger request includes an optional text field, it is appended to the resolved prompt under a --- separator as Additional instructions for this run:.
Pre- and Post-Actions
Three server-side action types are supported in preActions and postActions:
| Type | Params | When it runs | Effect |
|---|---|---|---|
move_status | statusKey: BACKLOG | TODO | IN_PROGRESS | BLOCKED | DONE | pre / post | Transitions the ticket to the matching board status |
assign_self | — | pre / post | Assigns the triggering user as the ticket assignee |
post_pr_comment | — | post | Posts the returned PR link as an internal comment on the ticket |
Actions execute in order. Pre-actions run synchronously before Claude is notified; post-actions run when Claude reports completion.
Scoping
Two fields narrow where a routine may run:
boardIds— if non-empty, the routine is only offered on tickets whose board is in this list. A trigger against a board outside the list returns400.allowedRepos— a list ofowner/repostrings. Only repositories that are linked to the ticket's board and appear in this list are passed to Claude as repo context. An empty list means "no repo constraint".
Use the GET /routines/available-repos helper to discover valid allowedRepos values for your organization.
Outgoing Webhook
To hand off the work to Anthropic's Claude Code Routines endpoint, each routine can set:
| Field | Description |
|---|---|
webhookTargetUrl | HTTPS URL on api.anthropic.com. On trigger, Spedy POSTs { "text": resolvedPrompt } to this URL. |
webhookTargetSecret | Sent as Authorization: Bearer <secret>. Never returned in list/read responses (only the boolean flag webhookTargetSecretSet). |
webhookTargetHeaders | Additional non-secret headers merged into the outgoing request (e.g. {"anthropic-version": "2023-06-01"}). Spedy supplies sensible defaults for api.anthropic.com if you don't. |
On a successful hand-off the execution flips from PENDING to CLAIMED (with claimedAt set), and the ticket card shows Handed off to Claude.
API Reference
All endpoints are mounted under /api/v1/routines, protected by JwtAuthGuard, and support Personal Access Tokens.
GET /routines/me
List the current user's routines.
Permission: routines:manage
Query params
| Name | Type | Description |
|---|---|---|
boardId | string | Optional. Returns routines that are either unscoped or explicitly include this board |
Response 200 — an array of routines. Secret fields (webhookTargetSecret) are stripped; webhookTargetSecretSet indicates whether one is stored.
POST /routines/me
Create a routine for the current user.
Permission: routines:manage
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | 2–120 chars |
slug | string | yes | 2–120 chars, lowercase kebab-case, unique per user |
description | string | no | ≤ 500 chars |
boardIds | string[] | no | Up to 100 board IDs. Empty = all boards |
instructions | string | yes | 10–20000 chars. Supports {{ticket.*}} variables |
preActions | RoutineAction[] | no | See pre/post-actions above |
postActions | RoutineAction[] | no | Same shape as pre-actions |
expectPrLink | boolean | no | Default true. Whether post-actions expect a PR link to post |
isActive | boolean | no | Default true |
allowedRepos | string[] | no | Up to 50 owner/repo strings |
webhookTargetUrl | string | null | no | Must be an https://api.anthropic.com/… URL |
webhookTargetSecret | string | null | no | Stored; never returned |
webhookTargetHeaders | object | no | Map of string → string |
Response 201 — the created routine (secret stripped).
GET /routines/me/:id
Read a single routine owned by the current user.
Permission: routines:manage
PATCH /routines/me/:id
Update a routine. Only the fields present in the body are changed. Passing webhookTargetSecret: "" clears the secret; omitting it leaves it untouched.
Permission: routines:manage
DELETE /routines/me/:id
Soft-delete a routine (marks deletedAt, sets isActive=false).
Permission: routines:manage
Response: 204 No Content
GET /routines/available-repos
Return distinct repoFullName values across all boards in the current organization — the allowed inputs for allowedRepos.
Permission: routines:manage
POST /routines/executions
Trigger a routine on a specific ticket.
Permission: routines:trigger
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
routineId | string | yes | A routine owned by the caller, isActive = true |
ticketId | string | yes | A ticket on a board the caller can access |
text | string | no | ≤ 4000 chars. Appended to the resolved prompt for this single run |
Behavior
- Asserts
CLAUDE_ROUTINESis enabled and the caller can access the ticket's board. - If the routine has
boardIdsset, rejects tickets from other boards with400. - Interpolates
{{ticket.*}}variables and appends the repo context + optionaltext. - Runs any
preActionsserver-side. - Creates a
RoutineExecutionwith statusPENDING. - If
webhookTargetUrlis set, fires the outgoing webhook (fire-and-forget) and flips the execution toCLAIMEDon success.
Response 201 — the RoutineExecution row.
GET /routines/executions?ticketId=…
List the last 20 executions for a given ticket (any user in the org who has board access).
Permission: routines:trigger
Response 200 — executions sorted by enqueuedAt descending, each including routine and triggeredBy summaries.
POST /routines/executions/:id/cancel
Cancel one of your own PENDING or CLAIMED executions. Sets status to CANCELLED and completedAt.
Permission: routines:trigger
Errors
| Code | Reason |
|---|---|
| 403 | Caller is not the user who triggered the execution |
| 400 | Execution is not in PENDING or CLAIMED status |
Using Routines from the UI
- Manage routines:
Account → Claude Routines. Create, edit, delete, and walk through the 4-step setup wizard. - Run a routine: open any ticket on a board you belong to. The Claude Routines card offers every routine that is either unscoped or scoped to this board. Pick one, optionally add extra instructions, and click Trigger.
- See history: the card lists the most recent executions for this ticket, with status and a Cancel button for your own runs.