Skip to content
Hoody.com

List, trigger, reload, and inspect history of scheduled script executions on a container.

The schedule subsystem runs on top of the @schedule JSDoc directive. Schedules are auto-discovered by scanning the scripts directory at /hoody/storage/hoody-exec/scripts on a container. The four endpoints on this page let operators:

  • list every currently registered schedule with its computed next fire
  • reload schedules after scripts are added, removed, or edited
  • trigger a specific schedule on demand, bypassing the cron timer
  • read the recent fire history (with optional rotated log scanning)

All endpoints live on the exec service on a container hostname of the form {projectId}-{containerId}-exec-1.{server}.containers.hoody.com.

Returns every currently registered @schedule directive with its computed next fire and last fire metadata.

This endpoint takes no parameters.

Terminal window
curl https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/schedules/list \
-H "Authorization: Bearer <token>"
{
"total": 2,
"schedules": [
{
"scriptPath": "/hoody/storage/hoody-exec/scripts/default/1/cron/nightly-report.ts",
"scriptRel": "default/1/cron/nightly-report.ts",
"subdomain": "default",
"execId": "1",
"vmCacheKey": "default/1",
"expression": "0 2 * * *",
"timeoutMs": 60000,
"registeredAt": "2026-01-01T00:00:00.000Z",
"nextFire": "2026-01-02T02:00:00.000Z",
"lastFireAt": "2026-01-01T02:00:00.000Z",
"lastFireStatus": "ok",
"lastFireRunId": "f4e3d2c1-b5a6-9780-1234-567890abcdef"
},
{
"scriptPath": "/hoody/storage/hoody-exec/scripts/default/1/cron/hourly-cleanup.ts",
"scriptRel": "default/1/cron/hourly-cleanup.ts",
"subdomain": "default",
"execId": "1",
"vmCacheKey": "default/1",
"expression": "@hourly",
"timeoutMs": 0,
"registeredAt": "2026-01-01T00:00:00.000Z",
"nextFire": "2026-01-01T01:00:00.000Z",
"lastFireAt": null,
"lastFireStatus": null,
"lastFireRunId": null
}
]
}

Returns the newest-first NDJSON entries from fires.log for every scheduled fire, with optional filtering by script and timestamp and support for paginating through rotated log files.

NameInTypeRequiredDescription
scriptPathquerystringNoFilter entries to one script. An absolute path must be inside scripts-dir. A relative path is scoped like scripts/read: on a host that names an execId (-exec-<id>) or a subdomain, it is read as <subdomain|default>/<execId>/<path> (<subdomain>/<path> when there is no execId) unless it already starts with that prefix; a default. subdomain counts as none. On any other host it is relative to scripts-dir. A path outside scripts-dir is 400. Optional.
sincequerystringNoISO 8601 lower bound on ts. Optional.
limitqueryintegerNoMax entries to return. Default 100, hard max 1000.
includeRotatedquerybooleanNoWhen true, also scan rotated fires.log.* files (slower).
cursorquerystringNoContinuation token from a previous truncated response; resumes the backward scan where it stopped. Optional.
Terminal window
curl "https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/schedules/history?limit=50&includeRotated=true" \
-H "Authorization: Bearer <token>"
{
"total": 2,
"limit": 100,
"includeRotated": false,
"truncated": false,
"entries": [
{
"ts": "2026-01-01T02:00:00.000Z",
"scriptPath": "default/1/cron/nightly-report.ts",
"expression": "0 2 * * *",
"runId": "f4e3d2c1-b5a6-9780-1234-567890abcdef",
"status": "ok",
"durationMs": 1842,
"returnPreview": "{\"rows\": 4218}"
},
{
"ts": "2026-01-01T01:00:00.000Z",
"scriptPath": "default/1/cron/hourly-cleanup.ts",
"expression": "@hourly",
"runId": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
"status": "error",
"durationMs": 312,
"error": "connection refused (db)"
}
]
}

Scans the scripts directory and reconciles the registered schedule set with the current filesystem state. Use this after adding, removing, or editing scripts to pick up @schedule directive changes without restarting the container.

FieldTypeRequiredDefaultDescription
dry_runbooleanNofalseWhen true, compute the diff against the filesystem but do not apply. Returns the same shape with {added, kept, removed} lists.
Terminal window
curl -X POST https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/schedules/reload \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"dry_run": true}'
{
"dry_run": true,
"added": [
"default/1/cron/nightly-report.ts"
],
"kept": [
"default/1/cron/hourly-cleanup.ts"
],
"removed": [
"default/1/cron/legacy-job.ts"
],
"failed": [
{
"path": "default/1/cron/broken-cron.ts",
"reason": "invalid cron expression: \"* * *\""
}
]
}

Fires a specific registered schedule immediately, bypassing the cron timer. The endpoint runs the script in its registered context and returns the fire outcome.

FieldTypeRequiredDefaultDescription
scriptPathstringYesPath of a script with a valid @schedule directive. An absolute path must be inside scripts-dir. A relative path is scoped like scripts/read: on a host that names an execId (-exec-<id>) or a subdomain, it is read as <subdomain|default>/<execId>/<path> (<subdomain>/<path> when there is no execId) unless it already starts with that prefix; a default. subdomain counts as none. On any other host it is relative to scripts-dir. A path outside scripts-dir is 400.
forcebooleanNofalseWhen true, bypass the @token refusal. Use with care: this fires the script as cron (no token auth).
Terminal window
curl -X POST https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/schedules/trigger \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"scriptPath": "default/1/cron/nightly-report.ts"}'
{
"triggered": true,
"scriptPath": "default/1/cron/nightly-report.ts",
"runId": "f4e3d2c1-b5a6-9780-1234-567890abcdef",
"status": "ok",
"durationMs": 1842
}