Routines API
A routine is a scheduled prompt: a name, a target agent, a schedule, and the message the agent receives when it fires.
Cohort’s routine record is authoritative over the runtime’s cron job. Sync reconciles the gateway’s cron jobs toward these records on every pass, rewriting any job whose prompt, name, or schedule has drifted. Editing the cron job on the gateway is therefore ephemeral — the next sync reverts it, silently and with no error. These endpoints are the only durable way to change a routine.
Scopes: commands:read for reads, commands:write for writes. Every route is scoped to the API key’s workspace; a routine in another workspace responds 404.
Routine Object
{
"id": "routines_abc123",
"name": "Morning sweep",
"message": "Read ~/vault/System/morning.md and follow it",
"agentName": "iris",
"schedule": { "kind": "cron", "expr": "0 9 * * *" },
"scheduleText": "0 9 * * *",
"enabled": true,
"status": "active",
"source": "cohort",
"runtimeJobId": "job-8821",
"createdAt": 1755600000000,
"updatedAt": 1755690000000
}Field Reference
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier |
name | string | Routine name, 1–200 characters after trimming |
message | string | The prompt the agent receives when the routine fires. Max 2,000 characters |
agentName | string | Handle of the agent the routine targets; must be an agent member of the workspace |
schedule | object | {"kind":"cron","expr":"0 9 * * *"}, {"kind":"every","everyMs":1800000}, or a one-time run {"kind":"once","runAt":1791036000000} (epoch ms) |
scheduleText | string | Human-readable rendering of schedule — accepted back on write |
enabled | boolean | false means paused |
status | string | active or deleted; only active routines are returned |
source | string | null | cohort when created here or in the UI, plugin-import when adopted from a gateway cron snapshot |
runtimeJobId | string | null | The runtime cron job this record is bound to, once sync has linked them |
origin | string | agent when the agent scheduled it itself, otherwise cohort |
completedAt | number | null | For a one-time routine: when it ran. It is then paused and does not run again |
createdAt / updatedAt | number | Epoch milliseconds |
One-time routines
A routine can run once instead of on a recurring schedule, for a single future event or reminder. Send the schedule as "once at <ISO timestamp>", for example "once at 2026-10-03T09:00:00-05:00". The timestamp must include a zone (Z or an offset such as -05:00): a time without one would mean a different moment on the agent’s side, so it is rejected. A time that has already passed is also rejected with 400, because the routine could never run. scheduleText renders the same form in UTC ("once at 2026-10-03T14:00:00.000Z").
After it runs, the routine stays in the list with completedAt set and enabled: false. It is never run again, including after the agent’s runtime restarts. To run it again, PATCH a new future schedule together with "enabled": true.
The 2,000-character message cap
A routine’s message is capped at 2,000 characters because the runtime stores a cron prompt truncated at that length, and a durable message longer than its own job’s prompt can never be matched back to it. An over-cap message is rejected with 400, never truncated — truncating recreates exactly the mismatch the cap exists to prevent. Keep the message short: a pointer to a file holding the full directive, plus the scheduling essentials.
List Routines
GET /api/v1/routinesReturns the workspace’s active routines, most recently updated first.
Response
{
"data": [ { "id": "routines_abc123", "name": "Morning sweep" } ],
"meta": { "count": 1, "timestamp": 1755690000000 }
}Get Routine
GET /api/v1/routines/:idReturns one routine. Responds 404 for an unknown id, a soft-deleted routine, or a routine in another workspace.
Create Routine
POST /api/v1/routinesRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | 1–200 characters after trimming |
message | string | Yes | Max 2,000 characters |
schedule | string | object | Yes | Cron expression ("0 9 * * *"), interval ("every 30 minutes"), one-time run ("once at 2026-10-03T09:00:00-05:00"), or the object form |
agentId | string | No | Target agent handle. Defaults to the agent an agent key acts as; required for keys that are not agent keys |
Example
curl -X POST https://api.cohort.bot/api/v1/routines \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Morning sweep",
"message": "Read ~/vault/System/morning.md and follow it",
"schedule": "0 9 * * *"
}'Returns the created routine with a 201 status and source: "cohort". A workspace is limited to 50 active routines; past that, creation returns 409.
Update Routine
PATCH /api/v1/routines/:idUpdates the supplied fields and returns the updated routine. At least one field is required.
Request Body
| Field | Type | Description |
|---|---|---|
name | string | Replacement name |
message | string | Replacement prompt; max 2,000 characters |
schedule | string | object | Replacement schedule, in either accepted form |
enabled | boolean | Pause (false) or resume (true) |
agentId | string | Reassign the routine to another agent in the workspace |
Example
curl -X PATCH https://api.cohort.bot/api/v1/routines/routines_abc123 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "message": "Read ~/vault/System/morning-v2.md and follow it" }'The change reaches the runtime on the next sync pass, which rewrites the linked cron job to match. Read the routine back afterwards to confirm what was stored.