Cascadedocs

API reference

Simulator endpoints

A simulator sends a heartbeat every few seconds and a log chunk whenever it has output. It can also send step timing and upload its output files before its final heartbeat. Every call is safe to retry. Bring your own simulator puts them together into a working client.

Send a heartbeat#

POST/api/sims/{sim_id}/heartbeatbearer token

Records that the sim is alive and, if state differs, moves the sim to it when SIM_TRANSITIONS allows the move. A running heartbeat brings a lost sim back. A heartbeat for a sim that already finished changes nothing and returns its final state. Send one every few seconds. A sim with no heartbeat for CASCADE_HEARTBEAT_TIMEOUT_S (60 by default) becomes lost.

Path parameters#

nametypedescription
sim_idstrThe sim's id, such as sim-6b4c91e71437. Find it in RunDetail.sims.

Request body#

JSON, Heartbeat.

fieldtypedescription
stateLiteral["running", "succeeded", "failed"]What the simulator reports. Send running while working and succeeded or failed once at the end.
exit_codeint | NoneYour process's exit code. Send it with the final heartbeat. default null
errorstr | NoneA short reason, with a failed heartbeat. default null

Returns#

200 with a HeartbeatAck. If cancel is true, stop simulating and exit.

Errors#

statuswhen
401The Authorization header is missing, is not Bearer <token>, or the token is wrong.
404No sim has this id.
422state is not running, succeeded or failed.

Example#

bash
curl -X POST "$CASCADE_URL/api/sims/sim-1047ddbdf5b1/heartbeat" \
  -H "Authorization: Bearer $CASCADE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"state": "running"}'
Response · 200 OK · application/json
{
  "state": "succeeded",
  "cancel": false
}
Response to a cancelled sim · 200 OK · application/json
{
  "state": "cancelled",
  "cancel": true
}
404 response · 404 Not Found · application/json
{
  "detail": "sim sim-000000000000 not found"
}

Send log lines#

POST/api/sims/{sim_id}/logsbearer token

Appends lines to the sim's log and parses any finished Accel-Sim kernel blocks out of them. Number chunks from 0 and add one each time. The app stores the first chunk it gets for each seq and ignores repeats, so a retry after a timeout is safe. Send lines without their trailing newline.

Path parameters#

nametypedescription
sim_idstrThe sim's id, such as sim-6b4c91e71437. Find it in RunDetail.sims.

Request body#

JSON, LogChunk.

fieldtypedescription
seqintPer-sim, increasing; a repeated seq is ignored. at least 0
lineslist[str]Lines of simulator stdout, without trailing newlines.

Returns#

204 with no body, whether the chunk was new or a repeat.

Errors#

statuswhen
401The Authorization header is missing, is not Bearer <token>, or the token is wrong.
404No sim has this id.
422seq is negative or lines is not a list of strings.

Example#

bash
curl -X POST "$CASCADE_URL/api/sims/sim-1047ddbdf5b1/logs" \
  -H "Authorization: Bearer $CASCADE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"seq": 0, "lines": ["replayed line"]}'
Response · 204 No Content
(empty body)

Send step timing#

POST/api/sims/{sim_id}/step-timelinebearer token

Stores the output of cascade simulate and cascade compare for this sim. cascade worker sends it after a successful sim on a trace with step timing, before its final heartbeat. Sending again replaces the earlier upload, so a retry is safe. The app checks only that simulated has a steps list and a summary object and stores both objects as they are.

Path parameters#

nametypedescription
sim_idstrThe sim's id, such as sim-6b4c91e71437. Find it in RunDetail.sims.

Request body#

JSON, StepTimelineUpload.

fieldtypedescription
simulateddict`cascade simulate` output (simulated_timeline.json), with steps and summary.
comparedict | None`cascade compare` output (compare.json) against the real timeline.

Returns#

204 with no body.

Errors#

statuswhen
401The Authorization header is missing, is not Bearer <token>, or the token is wrong.
404No sim has this id.
422simulated lacks a steps list or a summary object, or compare is neither an object nor null.

Example#

bash
curl -X POST "$CASCADE_URL/api/sims/sim-57c51b464fc9/step-timeline" \
  -H "Authorization: Bearer $CASCADE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"simulated": {"meta": {"run_name": "empty"}, "steps": [], "requests": [], "summary": {"simulation": {"host_model": "scaled-gaps", "host_fit": {}, "coverage": {"kernels": 0, "simulated_kernels": 0, "kernel_fraction": 0, "gpu_time_fraction": 0, "measured_gpu_ns": 0.0, "covered_measured_gpu_ns": 0.0, "unmodeled_gpu_ns": 0.0, "steps": []}, "request_assumption": "one request per repeat; queue + prefill/decode walls"}, "per_kind": {}}}, "compare": {"steps": [], "requests": [], "summary": {"wall_ns": {"count": 0, "mean_error": null, "mean_abs_error": null, "p50_abs_error": null, "p95_abs_error": null, "mean_error_pct": null, "mean_abs_error_pct": null, "p50_abs_error_pct": null, "p95_abs_error_pct": null}, "gpu_busy_ns": {"count": 0, "mean_error": null, "mean_abs_error": null, "p50_abs_error": null, "p95_abs_error": null, "mean_error_pct": null, "mean_abs_error_pct": null, "p50_abs_error_pct": null, "p95_abs_error_pct": null}}}}'
Response · 204 No Content
(empty body)

Upload an output file#

PUT/api/sims/{sim_id}/files/{name}bearer token

Stores the request body as the sim's file name, in $CASCADE_DATA_DIR/files/<sim_id>/. Putting the same name again replaces the file, so a retry is safe. cascade worker uploads every file the simulator wrote, then its own log as accelsim.log.gz, before its final heartbeat.

Path parameters#

nametypedescription
sim_idstrThe sim's id, such as sim-6b4c91e71437. Find it in RunDetail.sims.
namestrThe file's name, such as kernel-stats.csv. Letters, digits, ., _ and -, 1 to 128 characters, and not . or ...

Request body#

The file's raw bytes, sent as Content-Type: application/octet-stream. Not JSON and not a form.

Returns#

200 with the stored SimFile.

Errors#

statuswhen
401The Authorization header is missing, is not Bearer <token>, or the token is wrong.
404No sim has this id.
413The file is over 64 MiB.
413The sim's files would pass 256 MiB in all. The file a put replaces doesn't count.
422name has a character other than letters, digits, ., _ and -, is over 128 characters, or is . or ...

Example#

bash
curl -X PUT "$CASCADE_URL/api/sims/sim-57c51b464fc9/files/kernel-stats.csv" \
  -H "Authorization: Bearer $CASCADE_TOKEN" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @kernel-stats.csv
Response · 200 OK · application/json
{
  "name": "kernel-stats.csv",
  "size": 3829,
  "content_type": "text/csv",
  "created_at": "2026-11-08T08:59:06.686299Z"
}
413 response, file too big · 413 Content Too Large · application/json
{
  "detail": "file is over the 64 MiB per-file limit"
}
422 response, bad name · 422 Unprocessable Entity · application/json
{
  "detail": "file name 'my file.txt' must match ^(?!\\.\\.?$)[A-Za-z0-9._-]{1,128}$"
}