nexus/skills/paperclip-routines/SKILL.md
Aron Prins e5b2e8b29b fix(skills): address greptile review on paperclip-routines skill
- Add missing `description` field to the Creating a Routine field table
- Document optional `label` field available on all trigger kinds
2026-04-01 13:56:10 +02:00

5.9 KiB
Raw Blame History

name description
paperclip-routines Create, manage, and trigger Paperclip routines — recurring tasks that fire on a schedule (cron), webhook, or API call and create an execution issue for the assigned agent. Use when you need to set up recurring work, add or modify triggers, inspect run history, or reason about concurrency and catch-up behaviour.

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, or API)
  • A concurrency policy (what to do when a previous run is still active)
  • A catch-up policy (what to do with missed scheduled runs)

Authorization: Agents can read all routines in their company but can only create/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"
}
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

Concurrency Policies

Controls what happens when a trigger fires while the previous run issue is still open/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 (e.g. server downtime).

Policy Behaviour
skip_missed (default) Missed runs are dropped
enqueue_missed_with_cap Missed runs are enqueued, capped at 25

Adding Triggers

A routine can have multiple triggers of different kinds.

All trigger kinds accept an optional label field (max 120 chars) — 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 syntax
  • timezone: IANA timezone string (e.g. UTC, America/New_York)
  • The server computes nextRunAt automatically

Webhook

{
  "kind": "webhook",
  "signingMode": "hmac_sha256",
  "replayWindowSec": 300
}
  • signingMode: bearer (default) or hmac_sha256
  • replayWindowSec: 3086400 (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-Timestamp headers

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 (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          // list all
GET /api/routines/{routineId}                    // detail with triggers
GET /api/routines/{routineId}/runs?limit=50      // run history (default 50)

Key Endpoints

Action Endpoint
List routines GET /api/companies/{companyId}/routines
Get routine GET /api/routines/{routineId}
Create routine POST /api/companies/{companyId}/routines
Update routine PATCH /api/routines/{routineId}
Add trigger POST /api/routines/{routineId}/triggers
Update trigger PATCH /api/routine-triggers/{triggerId}
Delete trigger DELETE /api/routine-triggers/{triggerId}
Rotate webhook secret POST /api/routine-triggers/{triggerId}/rotate-secret
Manual run POST /api/routines/{routineId}/run
Fire webhook (external) POST /api/routine-triggers/public/{publicId}/fire
List runs GET /api/routines/{routineId}/runs