Runner lifecycle in FANGS is explicit: a runner process registers itself once at startup, then repeatedly polls for work and sends heartbeats to keep its registration alive. Three endpoints manage this lifecycle. Registration validates the protocol version and returns timing parameters that govern the rest of the connection. Heartbeats carry optional in-flight status so the orchestrator can surface “what’s running where” without a separate polling mechanism. Job polling uses HTTP long-polling — the server holds the connection open for up to 25 seconds before responding 204 No Content, letting runners avoid tight polling loops.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/irchaosclub/FANGS/llms.txt
Use this file to discover all available pages before exploring further.
POST /v1/runners/register
Registers a runner with the orchestrator. The runner calls this once at startup, before polling for jobs. If a runner with the samerunner_id already exists in the registry, the previous record is replaced — this handles runner restarts transparently.
Request body
Stable operator-supplied identifier. Defaults to the runner’s hostname when not explicitly set. Used as the path parameter in all subsequent runner endpoints.
The machine hostname, for display in the UI and logs.
Advertised capabilities, e.g.
["sensor", "sandbox.docker"]. The orchestrator logs these but does not yet use them for job routing — all registered runners are currently equivalent.Output of
uname -r. Logged at registration time; useful for debugging eBPF compatibility issues across kernel versions.Must equal
1 (the current CurrentProtoVersion). The orchestrator returns HTTP 400 if this does not match, preventing silent version-skew bugs when the wire format evolves.true when registration succeeded.The orchestrator’s stable identifier. The runner logs this for cross-referencing in multi-orchestrator deployments.
How frequently the runner should call
GET /v1/runners/{id}/jobs when idle, in nanoseconds. Currently 5000000000 (5 seconds).How frequently the runner should call
POST /v1/runners/{id}/heartbeat, in nanoseconds. Currently 30000000000 (30 seconds). Runners not seen for 3× this interval (90 seconds) are evicted.| Status | Condition |
|---|---|
| 400 | runner_id is missing or empty |
| 400 | proto_version does not match the orchestrator’s CurrentProtoVersion |
Re-registering an already-known
runner_id silently replaces the existing record. This is the intended recovery path when a runner restarts or the orchestrator restarts with existing runners.POST /v1/runners//heartbeat
Keeps a runner’s registration alive and optionally reports in-flight status. The orchestrator updates the runner’sLastSeen timestamp on every heartbeat. Runners not seen for more than 90 seconds are pruned from the in-memory registry by the background pruner.
Path parameter
The
runner_id supplied during registration.Content-Length is zero the orchestrator still processes the heartbeat and only updates LastSeen.
Echo of the runner’s own ID. Informational — the path parameter is authoritative.
Hex-encoded run ID of the job currently being processed. Omitted or empty string when the runner is idle. The orchestrator stores this for the UI’s “what is this runner doing” display.
Runner’s self-reported status. Valid values:
"idle", "running", "draining". Omitted when idle.Depth of the runner’s internal outbound event buffer. A consistently high value indicates the runner is producing events faster than it can flush them to the orchestrator.
true when the runner is recognized and the heartbeat was recorded. false when the runner is unknown.Present and
true when ok is false. The runner must call POST /v1/runners/register to rejoin before it can receive jobs.GET /v1/runners//jobs
Long-polls for the next job assigned to this runner. The server holds the connection open for up to 25 seconds. If a job becomes available within that window, it is returned immediately with HTTP 200. If the wait expires with no work, the server responds HTTP 204 No Content and the runner polls again afterjob_poll_interval.
The 25-second cap is deliberate: it stays safely below common load-balancer and proxy idle-connection timeouts while still dramatically reducing polling frequency compared to a naïve short-poll.
Path parameter
The
runner_id supplied during registration.16-byte binary run identifier encoded as a JSON array of 16 unsigned integer values (0–255). Use the hex string returned by
POST /v1/scans for display and database lookups.Job type. Two shapes are supported:
npm package name. Used as the baseline-keying identifier — all runs for the same package share a baseline fingerprint table.
Package version string, e.g.
"1.7.9".Relevant only for
sensor_only jobs. Ignored for sandbox_scan.Paths the eBPF sensor should observe for file-access events. Each entry has:
How long the runner should let the sandbox run, in nanoseconds. Default is 10 seconds for
sensor_only, set by the orchestrator when the job’s duration was zero.RFC 3339 timestamp stamped by
SubmitScan when the job was enqueued.Present only for
sandbox_scan jobs. Describes the container the runner must spawn.job_poll_interval before polling again.
Response — 404 Not Found