Skip to main content

Schedule recurring work

A cron sends a saved prompt to one or more of a workspace's projects on a schedule. Each time it fires, Kosuke hands the prompt, word for word, to the Cron Agent in the main sandbox of each of its projects, one run each. A run opens no chat session of its own. Every run spends the workspace's Credentials, never a member's Subscription. To manage crons in the web app, see Crons.

Create a cron​

curl -s -X POST "https://app.kosuke.ai/api/organizations/$WORKSPACE_ID/crons" \
-H "Authorization: Bearer $KOSUKE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Weekly dependency check",
"projectIds": ["'"$PROJECT_ID"'"],
"prompt": "Check for outdated dependencies and update the patch versions.",
"cronExpression": "0 6 * * 1"
}' > cron.json

CRON_ID=$(jq -r '.data.id' cron.json)
FieldRequiredValue
nameYesUp to 100 characters.
projectIdsYesThe projects it fires in, at least one, all of this workspace. A project created later joins only when you edit the cron to add it.
promptYesWhat the Cron Agent is asked to do, handed to it word for word. It can run a skill from the project's checkout.
cronExpressionYesFive fields, in order minute, hour, day of month, month and day of week, read in the Workspace Timezone. The schedule may fire at most once every 15 minutes.
modelNoA model id such as anthropic:opus__xhigh. Leave it out, or send null, for the workspace default.

The response answers 201 with the cron, enabled:

{
"data": {
"id": "0e6b2d91-…",
"name": "Weekly dependency check",
"projects": [{ "id": "9b1d4e27-…", "name": "storefront", "pausedAt": null, "lastRunStatus": null }],
"cronExpression": "0 6 * * 1",
"timezone": "UTC",
"model": null,
"enabled": true,
"nextRunAt": "2026-10-05T06:00:00.000Z",
"createdByName": "Ada Lovelace"
}
}

With the CLI:

kosuke crons create "$WORKSPACE_ID" --project "$PROJECT_ID" --name "Weekly dependency check" \
--prompt "Check for outdated dependencies and update the patch versions." \
--cron-expression "0 6 * * 1"

Repeat --project to add more projects. kosuke workspaces list gives the workspace id.

A cron has no timezone of its own. Every cron of a workspace is read in the Workspace Timezone, UTC until an owner or admin sets another. The cron's timezone field tells you which zone that is, and you cannot send it. To change it for every cron at once:

kosuke workspaces timezone-set "$WORKSPACE_ID" --timezone Europe/Zurich

Creating a cron answers 400 for a body that sends timezone, a schedule that fires more often than every 15 minutes, no project, or a project of another workspace. It also answers 400 when the workspace has no usable AI provider Credentials.

Read its runs​

Every fire leaves one run in each project it fires in, even one that started nothing. A project that five failed runs paused gets no run:

curl -s "https://app.kosuke.ai/api/organizations/$WORKSPACE_ID/crons/$CRON_ID/runs" \
-H "Authorization: Bearer $KOSUKE_API_KEY" \
| jq '.data.runs[] | {projectName, status, summary, error, startedAt}'

The response holds runs, newest first, with total and failed counts. It takes page and pageSize, and projectId and status filters that repeat for several values, such as ?status=failed&status=skipped.

Run statusMeaning
runningThe Cron Agent is working.
succeededThe Cron Agent finished. summary holds the first line of its reply.
failedThe fire was refused, or the Cron Agent failed. error says why.
cancelledThe cron's creator or a workspace admin stopped the run.
skippedThe previous run in that project was still working, so this fire started nothing there.

kosuke crons runs get reads one run with its reply and the sessions it filed. kosuke crons runs messages reads its transcript, and kosuke crons runs cancel stops a run that is still going. With the CLI, list the runs with kosuke crons runs list <workspaceId> <cronId>, adding --project or --status to filter them.

Run it now​

Fire the cron once, whether it is paused or not, in every project that is not paused:

curl -s -X POST "https://app.kosuke.ai/api/organizations/$WORKSPACE_ID/crons/$CRON_ID/run" \
-H "Authorization: Bearer $KOSUKE_API_KEY"

The request answers { "data": { "runs": [{ "projectId": "…", "runId": "…", "status": "running" }] } }, one entry per project. status is the run's status when the request answers, so it can be any status in the table above. A run that ended quickly is already succeeded, failed or cancelled. It is queued when the fire had not opened the run within about ten seconds. The run fires exactly as a scheduled one does, on the workspace's Credentials, and the sessions the Cron Agent files are Kosuke's, not yours. Read a run with kosuke crons runs get <workspaceId> <cronId> <runId> to see how it went. Send { "projectIds": [...] } to run it in only some of its projects; a paused project named there runs once and stays paused. With the CLI, run kosuke crons run <workspaceId> <cronId>, with --project for each project to pick.

Pause and resume​

Send enabled: false to pause the cron, and enabled: true to resume it:

curl -s -X PATCH "https://app.kosuke.ai/api/organizations/$WORKSPACE_ID/crons/$CRON_ID" \
-H "Authorization: Bearer $KOSUKE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"enabled": false}'

With the CLI, run kosuke crons update <workspaceId> <cronId> --no-enabled to pause and --enabled to resume.

The same request changes any other field, and only the fields you send change. projectIds replaces the cron's projects. "model": null goes back to the workspace default. The CLI sends it with --body '{"model": null}'.

Five failed runs in a row pause that one project inside the cron, and the cron's other projects keep firing. A run that failed because a Deploy replaced the main sandbox does not count, and only a run that succeeds sets the count back to zero. kosuke crons projects resume <workspaceId> <cronId> <projectId> resumes it. When every project is paused, the cron disables itself: it reads enabled: false, and disabledReason says why. Pausing or resuming clears the reason, and resuming or saving any edit resumes every project.

Who can do what​

ActionWho
Create a cronAny member of the workspace
Read crons and their runsAny member of the workspace
Change, pause, resume, resume a project, run now, stop a run or deleteThe cron's creator, or a workspace owner or admin. Anyone else gets 403.

The agent inside a chat session acts as the session's Assignee, when the Assignee sent the turn. It can create, change, run and stop crons as they could, but never delete one.

Delete a cron​

curl -s -X DELETE "https://app.kosuke.ai/api/organizations/$WORKSPACE_ID/crons/$CRON_ID" \
-H "Authorization: Bearer $KOSUKE_API_KEY"

Deleting a cron also deletes its runs, their transcripts and their Artifacts. The sessions its runs filed stay. Pause the cron instead if you want to keep them. With the CLI, run kosuke crons delete <workspaceId> <cronId>.

Next steps​