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 the source of truth for when and how a routine runs. Change a routine through these endpoints, the Routines page, or by asking an agent; those are the only durable ways to change one.
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 for routines imported from an earlier setup |
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.