Jobs

Runs

Every time a job is triggered, novem records a run. Each run keeps its own log, output, stats and status, reachable under the job's runs directory.

AI assisted, human approved — novem uses AI to review and keep our documentation up to date.

A run is one execution of a job's chain, whether you triggered it by hand, a schedule fired, or an inbound e-mail kicked it off. Runs live under the job's runs directory:

daily_report
├── data                  => POST here to trigger a run
├── log                   => Latest run's log (shortcut)
├── stats
│   └── runs              => Run history (time, trigger, duration, status)
└── runs
    └── <run>             => One entry per run
        ├── log           => The run's log
        ├── output        => The run's result file(s)
        ├── stats         => Run metadata (timings, trigger, …)
        └── status        => processing / success / failed

Trigger a run by posting to the job's data endpoint (this is what the CLI's -R flag does). What you send becomes the run's input, mounted at /input inside the first chain step:

  • A JSON body (Content-Type: application/json) is stored as /input/input.json. The body must be a JSON document; an empty or non-JSON body is rejected with 400.
  • A multipart/form-data upload stores each file as /input/<filename>, original names preserved.
# trigger a run (input files each prefixed with @)
novem -j daily_report -R
novem -j daily_report -R @data.csv

# save the run's output to disk
novem -j daily_report -R -o ./out

The request stays open while the chain executes, and the response body is the run's result: a single output file is returned as-is, several are bundled into one .zip. See how your code runs for the /input / /output contract.

Triggering requires write access to the job; reading runs requires read access.

GET /v1/code/jobs/<job>/runs returns the 30 most recent runs as a JSON directory listing, newest first. Each entry's name is the run id, <YYYYMMDD>-<HHMMSS>-<request id>, with created_on set to when the run started and last_modified to when it completed (or started, while still running).

[
  {
    "name": "20260613-081502-f3a9c2d4...",
    "uri": "/v1/code/jobs/daily_report/runs/20260613-081502-f3a9c2d4...",
    "type": "dir",
    "permissions": ["r"],
    "actions": ["OPTIONS", "GET"],
    "created_on": "2026-06-13T08:15:02Z",
    "last_modified": "2026-06-13T08:15:31Z"
  }
]

GET .../runs/<run> lists the four per-run files described below.

EndpointReturns
runs/<run>/statusThe run's state as plain text
runs/<run>/statsRun metadata — timings, trigger, who started it
runs/<run>/logThe run's timestamped log
runs/<run>/outputThe run's result file(s)

A single plain-text value: processing while the chain executes, then success or failed. A run that never started because a permission check blocked it shows rejected.

Run metadata. Plain text key: value pairs by default; send Accept: application/json for a JSON object:

FieldDescription
nameThe run id
shortnameThe run's auto-generated shortname
statusSame value as the status endpoint
origin / origin_shortnameThe job the run belongs to
started_on / completed_onUTC timestamps; completed_on is null while running
durationSeconds, two decimals; null while running
triggerapi, email or schedule
sourceThe client that triggered it (cli, webpage, scheduler, …)
has_outputWhether output has anything to download
created_byUsername of whoever triggered the run

The run's log entries in chronological order. Plain text by default. With Accept: application/json you get an array of { "log_time", "severity", "message" } objects with UTC ISO timestamps. A run with no log entries returns an empty 200.

Downloads the run's result with its original filename and content type, the same payload the triggering request received. A run that produced no output returns 204 No Content.

Run logs and output are retained for 30 days. After that, log and output answer 410 Gone; the run listing, stats and status remain available indefinitely.

Two conveniences live directly on the job:

EndpointReturns
GET .../jobs/<job>/logThe latest run's log — same formats as a run's log
GET .../jobs/<job>/stats/runsThe full run history: one row per run with time, trigger, duration and status (plain-text table, or JSON with Accept: application/json)

stats/runs is not capped at 30 entries, so it's the place to look when the runs listing has rotated past what you're after.

Note: Runs are never public. Even when a job is shared with public, its runs, logs and output are only readable by authenticated users with read access to the job: the owner and explicit share grantees.

  • Jobs overview — the /input / /output contract.
  • Schedule — trigger runs on a cron schedule.
  • Config — every job configuration key.