Skip to content
Agent

Install the agent

The Denpex agent is a single Python file. It wraps your training command, heartbeats every 2 minutes, and ships the last 500 log lines on a non-zero exit. Stdlib only, no dependencies, no kernel module, no root.

Install & verify

# 1. download the agent (single file) + the signed checksum manifest
curl -O https://denpex.com/agent/denpex.py
curl -O https://denpex.com/agent/SHA256SUMS

# 2. verify integrity before you run anything on your cluster
sha256sum --ignore-missing -c SHA256SUMS
# denpex.py: OK

# 3. read it. It's one auditable file, stdlib only
less denpex.py

Python 3.8+. No third-party packages, no kernel module, no root, no daemon. The agent never modifies the training process and never installs anything. It's a single readable file. Verify the checksum, read the source, then run it.

Preview exactly what leaves your cluster (before you trust it)

You don't have to take our word for it. DENPEX_DRY_RUN=1 prints the exact, already-masked payload that would be sent and transmits nothing. DENPEX_PRIVACY=strict ships only anonymized failure signatures (raw logs never leave), and DENPEX_LOCAL=1 runs the whole engine on-host with zero egress.

DENPEX_DRY_RUN=1 DENPEX_PRIVACY=strict python denpex.py run -- python train.py

Wrap a training command

export DENPEX_API_KEY=dpx_...

# PyTorch DDP / FSDP / DeepSpeed
python denpex.py run --job llama3-finetune -- torchrun --nproc_per_node=8 train.py

# Megatron-LM
python denpex.py run --job megatron-70b -- bash megatron/run_pretrain.sh

# Single-GPU
python denpex.py run --job debug -- python train.py --batch-size 32

Diagnose one saved log

The standalone diagnose command uses the same cloud engine as the homepage, console, API, and MCP server. Without a key it uses the three-per-day test drive; with a key it also records history and applies your plan entitlements.

# zero-signup test drive
python denpex.py diagnose ./crash.log

# authenticated diagnosis
DENPEX_API_KEY=dpx_... python denpex.py diagnose ./crash.log

Environment variables

DENPEX_API_KEY*
API key from your dashboard. Required.
DENPEX_PRIVACY
mask (default). Redact PII/PHI client-side before egress · strict. Ship only anonymized failure signatures, raw logs never leave · off, send raw logs.
DENPEX_DRY_RUN
Set to 1 to print the EXACT (masked) payload that would be sent and send nothing. Audit egress before trusting the agent with sensitive logs.
DENPEX_HEARTBEAT_SEC
Cloud liveness heartbeat interval in seconds. Default 120 (clamped 5 to 3600). Fault detection stays frequent regardless. This only throttles the liveness ping, which cuts request volume ~4x at fleet scale.
DENPEX_TAIL_LINES
Lines to ship on crash. Default 500, max 5000.
DENPEX_LOCAL
Set to 1 for AIR-GAPPED mode. The canonical deterministic diagnosis pipeline runs entirely on-host and monitoring is served as local Prometheus metrics; no logs, signatures, or heartbeats leave. Needs denpex_local.py, denpex_patterns.json, denpex_canonical.mjs, Python 3.8+, and Node.js 18+. No API key required.
DENPEX_METRICS_PORT
Expose a Prometheus /metrics endpoint on this port (denpex_up, denpex_gpus_total, denpex_anomalies, denpex_gpu_anomaly). Auto-on at 9836 in air-gapped mode; set explicitly to enable in cloud mode too.
DENPEX_INCIDENT_DIR
Air-gapped mode: directory for local incident JSON logs (one per on-host diagnosis). Default ./denpex-incidents.
DENPEX_API_URL
Override the API base URL.
DENPEX_EVIDENCE
Set to 0 to disable incident evidence capture entirely. On by default. When on, the agent records a run fingerprint at launch and a failure evidence bundle at termination.
DENPEX_CHECKPOINT_DIR
Where your checkpoints are written. With it the agent validates the newest checkpoints at failure time and reports which one is actually safe to resume from. Without it, resumability is not checked, the agent will not guess a directory.
DENPEX_IMAGE_DIGEST
The immutable image digest this job ran (for example sha256:...). Kubernetes will not tell a pod its own image digest without the downward API, and SLURM/pyxis does not either, so export it in the prolog if you want exact 'was this the same image?' answers.
DENPEX_EVIDENCE_DEADLINE
Seconds the evidence capture may take before it is abandoned. Default 45 (clamped 5 to 300). A launch hook must never become a launch delay, so a wedged nvidia-smi is abandoned rather than waited on.
DENPEX_FINGERPRINT_SCOPE
node or rank. By default local rank 0 captures the node-wide software inventory and every other rank captures only its own GPU binding, so a 512-rank job does not run 512 concurrent pip lists against one shared filesystem.
DENPEX_DCGM_INTERVAL_MS
DCGM job-statistics sampling interval. Default 5000. DCGM's own default is 1000, which is more overhead than a training job should pay for observability.
DENPEX_RAS_DISABLE
Set to 1 to never query NCCL RAS. The agent already queries it once per incident and never polls, because NVIDIA has open reports of frequent RAS polling corrupting memory and killing jobs at scale.

Make the next failure conclusive

Some evidence cannot be recovered after a job dies. DCGM job statistics are accumulated between an explicit start and stop marker, so a run that finished without them simply has none, there is no later command that reconstructs the power draw, clock-throttle time or per-GPU Xid tally over the window the job occupied. The PyTorch Flight Recorder is the same: it records into a ring buffer that has to be enabled before init_process_group.

Every diagnosis tells you which of these were missing and what to set, so you do not have to remember this page. Setting them ahead of time is what turns “we think it was rank 42” into “it was rank 42, on this serial number, and here is the power trace.”

# Flight Recorder: names the rank and collective that stalled
export TORCH_NCCL_TRACE_BUFFER_SIZE=2000
export TORCH_NCCL_DUMP_ON_TIMEOUT=1
# Makes the rank→GPU mapping exact rather than inferred
export CUDA_DEVICE_ORDER=PCI_BUS_ID
# Lets the agent tell you which checkpoint is safe to resume from
export DENPEX_CHECKPOINT_DIR=/scratch/checkpoints/$SLURM_JOB_ID

DCGM job statistics need nothing from you if you run training through denpex.py run, the agent marks the job's start and stop itself. If you launch some other way, call denpex_dcgm.start_job_stats() in your scheduler prolog.

Verify a fix actually worked

A repair command exiting 0 means the command was accepted, not that the node recovered. nvidia-smi -r returning 0 does not mean the GPU came back, and handing that node to the next job is how one fault becomes two. denpex verify reads back the actual state instead: GPU enumeration, new Xids, ECC movement, fabric links, scheduler admission, finite loss, throughput against the last healthy run, and whether the failure stayed away.

python denpex.py verify --gpus 8 --node $SLURMD_NODENAME \
--fixed-at $(date +%s)

It reports one of six outcomes, and only one of them exits 0. These are the same names the control plane uses, so an agent verdict and a dashboard verdict always mean the same thing.

verified_recovered
Exit 0. Every check in the plan passed and every observation window elapsed. Safe to return to service.
awaiting_observation
Exit 75. Nothing has failed, but a required negative observation has not had its full window yet. A GPU healthy for forty seconds is not a fixed GPU.
partially_recovered
Exit 76. Nothing required failed, but something could not be evaluated. Each unevaluated check names what would make it conclusive.
failed_verification
Exit 77. A required check failed. Do not return this node.
recurrence_detected
Exit 78. The same incident came back. One recurrence disproves the fix, whatever else passed.
inconclusive
Exit 79. Nothing failed and nothing passed either, so nothing was proven.

Observation windows are per check and are not settable from the command line, “no fatal Xid” means nothing fifteen seconds after a reset, and an operator should not be able to shorten it into a verdict that means nothing. A check that cannot be performed reports as unavailable, and one that is merely too early reports as pending. Neither is ever counted as a pass.

Kubernetes

Run the read-only node monitor as a DaemonSet. Create the API-key Secret yourself first; the published manifest deliberately contains no placeholder Secret that could overwrite a real credential.

kubectl -n kube-system create secret generic denpex-secret \ --from-literal=api-key=dpx_YOUR_KEY kubectl apply -f https://denpex.com/agent/daemonset.yaml # confirm every intended GPU node is reporting kubectl -n kube-system rollout status daemonset/denpex-daemon kubectl -n kube-system logs daemonset/denpex-daemon --tail=50

Self-hosted / air-gapped (Helm)

For data centers that can't let telemetry leave their network, run the whole platform on your own hardware with one command. The agent diagnoses failures on-host and serves fleet health as Prometheus metrics, your own Prometheus + Grafana watch the cluster, with zero egress and no per-request cost. Ships as a DaemonSet (one pod per GPU node) from the Denpex on-prem kit.

# 1. add the chart repo (once)
helm repo add denpex https://denpex.com/charts
helm repo update

# 2a. air-gapped. Nothing leaves the cluster, no API key
helm install denpex denpex/denpex-agent --set airGapped=true

# 2b. or cloud mode. Agents report to api.denpex.com
helm install denpex denpex/denpex-agent --set airGapped=false --set apiKey=dpx_...

# the agent then serves :9836/metrics. Point your Prometheus at it:
denpex_up · denpex_gpus_total · denpex_anomalies · denpex_gpu_anomaly{gpu,code,severity}

The chart ships a pinned, scripts-baked-in container image. No repo checkout, no manual ConfigMap. A runnable starter stack (Prometheus + VictoriaMetrics + Grafana + the agent, pre-wired) and the full architecture + zero-egress verification live in the on-prem kit under deploy/onprem/. Air-gapped crash diagnoses are saved to a local incident log (DENPEX_INCIDENT_DIR), never transmitted. Fully-disconnected clusters mirror the image into their own registry.

SLURM & Ray

The agent is launched as a wrapper around your command, so it works under any scheduler with no per-scheduler setup. It auto-captures the scheduler's environment (SLURM job/node/proc id, Ray job/node id, K8s pod/namespace) so the dashboard shows exactly which job, node, and rank failed.

# SLURM (sbatch), wrap srun's payload srun python denpex.py run --job $SLURM_JOB_NAME -- torchrun --nproc_per_node=8 train.py # Ray. Wrap the entrypoint of each worker ray job submit -- python denpex.py run --job $RAY_JOB_ID -- python train.py

Proactive monitoring. Live, GPU telemetry, schedulers

Beyond wrapping a command, the agent bundle ships three drop-in tools that catch problems earlier and remove the manual paste entirely. Each is a single stdlib-only file.

# 1. Live early-warning. Catch NaN / grad-spike / divergence as it happens
curl -O https://denpex.com/agent/denpex_live.py
# from denpex_live import LiveMonitor / DenpexLiveCallback (auto-checkpoints on divergence)

# 2. Native GPU telemetry. Read DCGM-Exporter or NVML directly (Xid, ECC, thermal, row-remap)
curl -O https://denpex.com/agent/denpex_telemetry.py
python denpex_telemetry.py --dcgm http://localhost:9400/metrics --watch
python denpex_telemetry.py --nvml # read the driver directly on-node

# 3. Zero-touch scheduler hooks. Auto-diagnose FAILED SLURM / Kubernetes jobs
curl -O https://denpex.com/agent/denpex_scheduler.py
curl -O https://denpex.com/agent/denpex-epilog.sh # SLURM: EpilogSlurmctld=/opt/denpex/denpex-epilog.sh

The telemetry collector is read-only and low-overhead; most clusters already run DCGM-Exporter as part of the NVIDIA GPU Operator, so you can point Denpex at the metrics endpoint you already expose. Findings are diagnosed and routed to your alert channels, see the integrations guide for the live monitor and experiment-tracker connectors.

Privacy & data minimization

Masking runs client-side, before any byte leaves your cluster. Set the mode with DENPEX_PRIVACY:

  • mask (default). Emails, IPs, MACs, SSNs, API keys, tokens, JWTs, credentials, and home/Windows paths are redacted before egress. Error text, stack traces, and Xid/CUDA/NCCL signatures are preserved (that's the diagnostic signal; it carries no PII).
  • strict. Raw logs never leave. The agent extracts only anonymized failure signatures (e.g. Xid 79, CUDA out of memory, RuntimeError) and ships those. Recommended for regulated / PHI workloads.
  • off. Send raw logs unchanged (opt-in).
# preview EXACTLY what would leave (sends nothing)
DENPEX_DRY_RUN=1 DENPEX_PRIVACY=strict python denpex.py run -- python train.py

Air-gapped / in-VPC (zero egress)

With DENPEX_LOCAL=1, the agent diagnoses failures entirely on the host using the same canonical deterministic pipeline as the hosted wrapper: 10,800+patterns, causal detectors, the Xid → node-action router, cross-rank cascade localization, and the 700+-entry encyclopedia. Nothing leaves the cluster: no logs, no signatures, no heartbeats, no API key. Only the LLM fallback and live research are unavailable offline.

# download the agent + its offline engine + pattern DB (once) curl -O https://denpex.com/agent/denpex.py curl -O https://denpex.com/agent/denpex_local.py curl -O https://denpex.com/agent/denpex_patterns.json curl -O https://denpex.com/agent/denpex_canonical.mjs curl -O https://denpex.com/agent/SHA256SUMS sha256sum --ignore-missing -c SHA256SUMS # run fully offline. Diagnosis prints on-host, nothing is transmitted DENPEX_LOCAL=1 python denpex.py run --job llama3 -- torchrun --nproc_per_node=8 train.py # or diagnose a saved log file offline DENPEX_LOCAL=1 python denpex.py diagnose-local ./crash.log

What gets shipped

  • Heartbeat (job name, hostname, status, timestamp) every 2 minutes by default.
  • On non-zero exit: the last 500 log lines, after client-side masking, with the failure type inferred from exit code.
  • For hangs (no heartbeat for 5+ minutes. DENPEX_HANG_TIMEOUT, default 300s): the agent exits with code 137, and the orchestration stack records the failure.
  • Nothing else. We do not read source code, model weights, datasets, environment variables, or any other files.