references/routines.md
references/routines.mdBrowse 9 files
7,419 bytes
Token encoding: o200k_base
Snapshot 5b913e7
Paperclip Routines
Routines are recurring tasks. Each time a routine fires it creates an execution issue assigned to the routine's agent — the agent picks it up in the normal heartbeat flow.
A routine has:
- One assigned agent and one project
- One or more triggers (
schedule,webhook, orapi) - A concurrency policy (what to do when a previous run is still active)
- A catch-up policy (what to do with missed scheduled runs)
- An activity gate policy (whether quiet scheduled ticks should be skipped)
Authorization: Agents can read all routines in their company but can only create or manage routines assigned to themselves. Board operators have full access, including reassignment.
Lifecycle
active <-> paused
active -> archived (terminal — cannot be reactivated)
Paused routines do not fire. Archived routines do not fire and cannot be unarchived.
Creating a Routine
POST /api/companies/{companyId}/routines
{
"title": "Weekly CEO briefing",
"description": "Compile status report and post to Slack",
"assigneeAgentId": "{agentId}",
"projectId": "{projectId}",
"goalId": "{goalId}", // optional
"parentIssueId": "{issueId}", // optional — parent for run issues
"priority": "medium",
"status": "active",
"concurrencyPolicy": "coalesce_if_active",
"catchUpPolicy": "skip_missed",
"activityGatePolicy": "always",
"activityGateScope": "company"
}
| Field | Required | Notes |
|---|---|---|
title | yes | Max 200 chars |
description | no | Human-readable description of the routine |
assigneeAgentId | yes | Agents: must be themselves |
projectId | yes | |
goalId | no | Inherited by run issues |
parentIssueId | no | Run issues become children of this issue |
priority | no | critical high medium (default) low |
status | no | active (default) paused archived |
concurrencyPolicy | no | See below |
catchUpPolicy | no | See below |
activityGatePolicy | no | always (default) or require_external_activity; see below |
activityGateScope | no | company (default) or project; see below |
Concurrency Policies
Controls what happens when a trigger fires while the previous run issue is still open or active.
| Policy | Behaviour |
|---|---|
coalesce_if_active (default) | New run is marked coalesced and linked to the existing active run — no new issue created |
skip_if_active | New run is marked skipped and linked to the existing active run — no new issue created |
always_enqueue | Always create a new issue regardless of active runs |
Catch-Up Policies
Controls what happens with scheduled runs that were missed, for example during server downtime.
| Policy | Behaviour |
|---|---|
skip_missed (default) | Missed runs are dropped |
enqueue_missed_with_cap | Missed runs are enqueued, capped at 25 |
Activity-Gated Scheduled Runs
activityGatePolicy controls whether a schedule trigger runs when the system has been quiet. It does not gate manual, API, or webhook runs.
| Policy | Behaviour |
|---|---|
always (default) | Run on every scheduled tick |
require_external_activity | Run only when qualifying activity occurred after this routine's last dispatched, non-skipped run |
activityGateScope selects where qualifying activity is checked:
| Scope | Behaviour |
|---|---|
company (default) | Activity anywhere in the routine's company can wake it |
project | Only activity attributed to the routine's project can wake it |
The activity window starts at the triggeredAt time of the last dispatched run. A routine that has never dispatched always runs once. Runs skipped for quiet activity do not advance the window, so one later qualifying event still wakes the next scheduled tick.
The gate excludes activity generated by the routine's own dispatched run issues, scheduler bookkeeping for that routine, and pure-read actions such as issue read/unread changes and inbox archive/unarchive actions. Work performed by other agents on tasks the routine delegated is external activity and wakes the routine on its next tick.
Example: skip quiet nights
This hourly watcher runs after company activity, follows up while delegated work continues, and stops consuming runs once the company settles overnight:
{
"title": "Hourly work watcher",
"description": "Review recent work and follow up on delegated tasks",
"assigneeAgentId": "{agentId}",
"projectId": "{projectId}",
"activityGatePolicy": "require_external_activity",
"activityGateScope": "company"
}
Add a schedule trigger with cronExpression: "0 * * * *". The first tick runs. Later ticks run only after qualifying company activity since the last dispatched run; quiet skipped ticks keep the original activity window open.
Adding Triggers
A routine can have multiple triggers of different kinds.
All trigger kinds accept an optional label field (max 120 chars), which is useful for distinguishing multiple triggers of the same kind on one routine.
POST /api/routines/{routineId}/triggers
Schedule (cron)
{
"kind": "schedule",
"cronExpression": "0 9 * * 1",
"timezone": "Europe/Amsterdam"
}
cronExpression: standard 5-field cron syntaxtimezone: IANA timezone string (for exampleUTCorAmerica/New_York)- The server computes
nextRunAtautomatically
Webhook
{
"kind": "webhook",
"signingMode": "hmac_sha256",
"replayWindowSec": 300
}
signingMode:bearer(default) orhmac_sha256replayWindowSec: 30-86400 (default 300)- Response includes the webhook URL (
publicId-based) and the signing secret - Fire externally:
POST /api/routine-triggers/public/{publicId}/fire- Bearer:
Authorization: Bearer <secret> - HMAC:
X-Paperclip-Signature+X-Paperclip-Timestampheaders
- Bearer:
API (manual only)
{
"kind": "api"
}
No configuration. Fire via the manual run endpoint.
Updating and Deleting Triggers
PATCH /api/routine-triggers/{triggerId}
{ "enabled": false, "cronExpression": "0 10 * * 1" }
DELETE /api/routine-triggers/{triggerId}
To rotate a webhook secret (the old secret is immediately invalidated):
POST /api/routine-triggers/{triggerId}/rotate-secret
Manual Run
Fires a run immediately, bypassing the schedule. Concurrency policy still applies.
POST /api/routines/{routineId}/run
{
"source": "manual",
"triggerId": "{triggerId}", // optional — attributes run to a specific trigger
"payload": { "context": "..." }, // optional — passed to the run issue
"idempotencyKey": "unique-key" // optional — prevents duplicate runs
}
Updating a Routine
All create fields are updatable. Agents cannot reassign a routine to another agent.
PATCH /api/routines/{routineId}
{ "status": "paused", "title": "New title" }
Reading Routines and Runs
GET /api/companies/{companyId}/routines
GET /api/routines/{routineId}
GET /api/routines/{routineId}/runs?limit=50
Use the generic API endpoint tables in skills/paperclip/references/api-reference.md when you need a full cross-domain reference. Use this file when you need routine-specific behaviour, payload shape, or policy details.