Skip to main content

Long-job companion: phone notifications when your training finishes, fails, or silently hangs.

Project description

English 简体中文

runmon

Long-job companion — when a training run, crawler, or long script is running on your server, your phone knows the moment it "finished, failed, or silently stalled." Zero-instrumentation, not a line of training code changed.

runmon is the Python CLI (mon) you install on the server that runs your jobs. It does two things: it pushes notifications to your phone when something happens, and — paired with the RunMon app — it streams a live view you can watch and remote-control from your phone.

Install

pip install runmon

Requires Python ≥ 3.10. GPU metrics use NVIDIA NVML; on a machine without a GPU it degrades gracefully (everything else keeps working).


Two ways to use it

A · Notifications only — no app, no relay

The lightest setup: you just want your phone to buzz when a job finishes, fails, or stalls. No RunMon app needed — notifications arrive in the ntfy / Bark / WeCom / Telegram app you already have.

# 1. Configure a channel (pick one)
mon init --ntfy-topic my-secret-topic-2333   # ntfy: install the ntfy app, subscribe to this topic
mon init --wecom-key <webhook>               # WeCom (企业微信) group bot — most reliable in China
mon init --bark-key <key>                    # iOS Bark

# 2. Wrap your command
mon run -- python train.py

Done — the six event types below get pushed to your phone.

B · Live monitoring on your phone — RunMon app + relay

The full experience: watch the live terminal, resource charts, progress/ETA, and remote-control the job from the RunMon app.

# 1. Pair with the app (one time). Prints a QR code — scan it in the app.
mon pair

# 2. Keep the connection alive. The phone sees live data ONLY while this runs.
#    Run it in tmux/nohup so it survives after you disconnect (see "mon daemon" below).
mon daemon

# 3. Run your job (in another shell)
mon run -- python train.py

Now open the app: live terminal, GPU/CPU/memory curves, progress/loss/ETA, and buttons to stop / re-run / pull logs / open a terminal.

First time? Run mon demo instead of a real job to test the whole chain end-to-end.


Command reference

Command What it does
mon run -- <cmd> Run and monitor a command (the everyday wrapper)
mon attach Take over a job already running in tmux — no restart
mon daemon Keep the live connection to your phone open
mon pair Pair with the RunMon app (prints a QR code)
mon init Configure notification channels
mon ls List jobs (progress / elapsed)
mon status <job> Job details + output tail + ETA/loss
mon stop <job> Stop a job (SIGINT → SIGTERM → SIGKILL)
mon logs -f <job> Follow a job's output live
mon demo Run a fake training job to test the setup

mon run — wrap and monitor

mon run -- python train.py                          # simplest — your command after the --
mon run --name exp1 --gpu 0,1 -- python train.py    # name the job + bind specific GPUs

Progress, ETA, and loss are parsed automatically from stdout (works with tqdm / Epoch x/y / loss=…) — no instrumentation needed. Try mon demo / mon demo --fail first to see it in action.

mon attach — take over a tmux job

Already have a job running in a tmux session (maybe you started it days ago)? Take it over without restarting:

mon attach            # attach to the job in the current tmux pane

From then on it's monitored exactly like a mon run job — events, live view, and remote control all apply.

mon daemon — keep the phone connection alive

mon daemon is the bridge to your phone: it syncs job state to the relay and receives your remote commands. The live view in the app only works while the daemon is running. (Notifications from mon run do not need it — those go out directly.)

By default it runs in the foreground and holds the terminal. To run it in the background so it survives closing your SSH session:

mon daemon -d      # detach: runs in the background and frees the terminal
                   # prints the pid + log path; stop it later with: kill <pid>

Prefer to manage it yourself? Use tmux or nohup instead:

tmux new -s mon; mon daemon          # Ctrl+B then D to detach; tmux attach -t mon to return
nohup mon daemon > ~/mon-daemon.log 2>&1 &

mon pair — pair with the app

mon pair                                  # uses the default public relay; prints a QR code
mon pair --relay https://your-relay.com   # point at your own self-hosted relay

Scan the printed QR code in the RunMon app to link this server to your phone. One-time per server.

mon logs — follow output

mon logs -f exp1      # tail -f style; works even for backgrounded re-runs

mon ls / mon status / mon stop — manage jobs

mon ls                # all jobs, with progress and elapsed time
mon status exp1       # details + output tail + ETA/loss
mon stop exp1         # stop (SIGINT → SIGTERM → SIGKILL)

What lands on your phone (six events)

Event Trigger (default, configurable) Level
✅ Done exit code 0 info
❌ Failed non-zero exit code critical
⚠️ Error output log shows Traceback / CUDA OOM / Segfault critical
🧊 GPU stall process alive but GPU utilization <5% for 10 min critical
🤫 Log silence no new output for 30 min warning
💾 Disk alert any mount point over 90% used warning

The same kind of event notifies at most once per 30 minutes; failed notifications retry with exponential backoff (up to 1 hour) and are persisted locally so nothing is lost.

Notification channels

mon init accepts combinations and can push to several channels at once:

mon init --ntfy-topic TOPIC [--ntfy-server https://your-self-hosted-ntfy]
mon init --bark-key KEY                  # iOS Bark
mon init --wecom-key WEBHOOK_URL         # WeCom (企业微信) group bot — most reliable in China
mon init --telegram BOT_TOKEN:CHAT_ID    # Telegram bot
mon init --webhook https://your/hook     # generic webhook (Feishu / DingTalk / custom)

Config

Config lives in ~/.config/runmon/config.toml; all thresholds are adjustable:

hang_gpu_minutes = 20      # GPU-stall detection window
silence_minutes = 60       # log-silence alert
disk_threshold_pct = 85

Notes

  • GPU sampling relies on NVIDIA NVML; on machines without a GPU it degrades gracefully.
  • For the phone app, self-hosting the relay, and the big picture, see the project README.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

runmon-1.0.5.tar.gz (39.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

runmon-1.0.5-py3-none-any.whl (32.5 kB view details)

Uploaded Python 3

File details

Details for the file runmon-1.0.5.tar.gz.

File metadata

  • Download URL: runmon-1.0.5.tar.gz
  • Upload date:
  • Size: 39.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.2

File hashes

Hashes for runmon-1.0.5.tar.gz
Algorithm Hash digest
SHA256 70b6bc5ae2e0730dd3d638688d1f09031d1e7aaab2163e7e1559fe82f0929029
MD5 453acb067e8c5964dd4512e4ab30a5a2
BLAKE2b-256 8f2efc1c72db0b93df2692f2c9e01dc2e17bb15ff12a1498b9565bdf7d4f91f3

See more details on using hashes here.

File details

Details for the file runmon-1.0.5-py3-none-any.whl.

File metadata

  • Download URL: runmon-1.0.5-py3-none-any.whl
  • Upload date:
  • Size: 32.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.2

File hashes

Hashes for runmon-1.0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 388471a0fde61a8fbcf64b2f7dfe1f7d108f0923eaab1aff52873d113455eb16
MD5 1693b6fe2bc840464691366b0308b295
BLAKE2b-256 6ec70780b4e26f7607e88437f50f9c74b6199bd144493a42438d36caf1609f23

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page