Docs › Cron, systemd, GitHub Actions and plain scripts

Cron, systemd, GitHub Actions and plain scripts

The rv client is a single Python file with no dependencies. It wraps a command, captures exit code, duration and output size, checks evidence files, and reports, and if RunVouch is unreachable your job still runs.

Install

pip install runvouch   # or: curl -fsSL https://runvouch.com/rv -o ~/bin/rv
export RUNVOUCH_KEY=rv_…   # put in ~/.profile or the cron env

Wrap a job

# crontab -e
0 2 * * * rv run nightly-etl --log /var/log/etl.log --evidence-file /data/out/today.parquet -- python3 etl.py

--log appends the job's stdout/stderr to a file (and counts as evidence if it grew). --evidence-file requires the file to exist, be non-empty and be modified during the run.

No client at all: the ping URL

If you would rather not install anything, every agent has its own ping URL. Anything that can call a URL can report: a crontab line, an n8n node, a GitHub Actions step, a Docker HEALTHCHECK, a Zapier or Make action.

# report the exit code of the job, nothing installed
0 3 * * * /usr/local/bin/nightly.sh; curl -fsS -m 10 https://api.runvouch.com/ping/<token>/$?

# bracket it so RunVouch also sees the duration and catches a job that never ends
0 3 * * * curl -fsS https://api.runvouch.com/ping/<token>/start; /usr/local/bin/nightly.sh && curl -fsS https://api.runvouch.com/ping/<token>

Nothing after the token means success, /start opens a run, /fail reports a failure, and a number is the exit code (0 is success). GET, POST and HEAD all work; a POST body up to 100 kB is kept as the error excerpt when the run failed. Ten pings per agent per minute.

rv agent NAME prints the URL, and so does the dashboard. The token is a write-only secret for that one agent: it reports runs and can do nothing else, so it may sit in a crontab or a shared workflow where your API key never should. It survives re-registering the agent, because by then the URL lives in someone else's crontab.

What you give up without the client: no evidence file check, no automatic cost from a transcript, no output-size drift unless you POST the output. Cadence, MISSED, STALLED, FAILED and the daily cost cap all work the same.

Hourly, weekly, monthly

rv agent hourly-sync --cadence 1h --grace 10m
rv agent weekly-digest --cadence 7d --grace 2h --max-runtime 30m

MISSED fires when cadence + grace passes without a start; STALLED when a run exceeds max runtime without ending.

Report cost from any LLM job

RID=$(rv start price-scraper)
rv tool $RID openai.chat --input '{"model":"gpt-5","prompt_hash":"…"}' --cost 0.012 --tokens 4100
rv end $RID --status ok --cost 0.35 --evidence '{"rows": true}'

Per-call reporting enables retry-storm and per-run budget detection; per-run reporting is enough for daily caps and drift.

GitHub Actions

- run: rv run nightly-build --evidence-file dist/report.html -- npm run build:report
  env:
    RUNVOUCH_KEY: ${{ secrets.RUNVOUCH_KEY }}

Need a key? Get a free key · Stuck? contact