Skip to main content

Emry

Gentle observability for long training runs.

CI PyPI Python License

Emry watches your training run the way you'd want a good colleague to: quietly, without ever getting in the way. A training loop calls run.emit(); metrics flow through a lock-free ring into an event-sourced engine that persists an append-only log and serves a live dashboard. No accounts, no phone-home — just your metrics, on your machine, in a file you can read.

Emry's terminal dashboard streaming a live training run

The terminal dashboard (emry watch) — live loss curve with a dashed amber baseline overlay for run comparison, phase bands, checkpoint markers, metric cards, and alerts. Full parity with the web dashboard.

Emry's web dashboard with a live loss curve, baseline overlay, phase bands and checkpoint markers

The self-hosted web dashboard (emry web) — live chart with a dashed baseline overlay for run comparison, phase bands, and checkpoint markers. No CDN; works air-gapped.

  • Stays out of the way. emit() targets well under 10 µs amortized (tens of nanoseconds in our benchmarks) and never blocks the training thread — every queue is bounded and drops-and-counts under load, so observability can never harm the run.
  • Event-sourced. An append-only events.jsonl is the audit trail; a wide metrics.jsonl is plain JSONL you can read with jq, pandas, or anything.
  • Observe live or after the fact. A terminal dashboard and a self-hosted web dashboard (no CDN — air-gap friendly) at full parity — live chart, phase bands, checkpoint markers, and a baseline overlay to compare against a prior run — or just tail the files.
  • Built for clusters. Embedded, sidecar, or file modes; auto-detects SSH/SLURM. The training process survives an engine crash.

Install

pip install emry

Quickstart

Your training loop calls emry.run(...) and run.emit(...). That's it:

import emry

with emry.run("llama-sft", config={"lr": 2e-5}, metrics=["loss", "lr"]) as run:
    for step in run.steps(10_000):
        loss = train_step()
        run.emit(loss=loss, lr=scheduler.get_last_lr()[0])

run.steps(n) yields steps and advances Emry's step counter for you; emit() takes any metrics as keyword arguments. Mark phases with run.phase = emry.Phase.EVAL, and iterate epochs with run.epochs(n) to track the epoch automatically. Values are duck-typed — tensors and numpy scalars are coerced, so you can pass loss directly without .item(). When an NVIDIA GPU is present, Emry samples nvidia-smi automatically and charts GPU utilization, memory, and temperature alongside your metrics (gpu=False to disable). Pass alert_webhook= (or set EMRY_ALERT_WEBHOOK) to get a Slack/Discord ping the moment a metric goes NaN/Inf.

By default Emry writes a run directory under ./logs/ and, when attached to a TTY, brings up the live terminal dashboard. Set EMRY_MODE (embedded | sidecar | file) to control how it runs, or observe any run after the fact with the commands below.

Observe a run

emry runs                                   # list runs under ./logs
emry watch ./logs/llama-sft_…               # live terminal dashboard
emry web   --run-dir ./logs/…               # live web dashboard at http://127.0.0.1:8787
emry watch ./logs/new --compare ./logs/old  # overlay a prior run as a baseline (TUI or web)
emry compare run_a/ run_b/                  # final metrics side by side
emry export csv --run-dir ./logs/… --output history.csv

The dashboard binds loopback and is unauthenticated by default. To expose it (e.g. from a container), bind a public interface and turn on auth + TLS:

export EMRY_AUTH_TOKEN=$(openssl rand -hex 32)   # require this token; /healthz stays open
emry web --project ./logs --host 0.0.0.0 \
  --tls-cert cert.pem --tls-key key.pem          # serve HTTPS from your own PEM files

Prefer the EMRY_AUTH_TOKEN env var over --auth-token so the token stays out of your shell history and process list. Binding a non-loopback --host without a token prints a warning — anyone who can reach the host can read the metrics.

EMRY_AUTH_TOKEN is the full-access (admin) token. For read-only access, hand out EMRY_VIEWER_TOKEN (--viewer-token): viewers can watch a single run's dashboard but not the multi-run --project overlay, which requires admin.

On a cluster, run the engine as a sidecar so observability outlives the training process — see the SLURM runbook.

Documentation

Development

Prerequisites

  • Rust 1.88+ (rust-toolchain.toml pins the toolchain)
  • llvm-tools-preview for coverage: rustup component add llvm-tools-preview
  • cargo-llvm-cov: cargo install cargo-llvm-cov
  • Python 3.10+

Commands

# Full local CI (fmt, clippy, test, ≥90% coverage)
./scripts/pre-commit-rust.sh

# Coverage only
./scripts/check-coverage.sh

# Python tests
pip install -e ".[dev]"
pytest

# Build the native extension locally (maturin)
pip install maturin && maturin develop

# Run the demos
cargo run -p emry-tui --example tui_demo
cargo run -p emry-web --example web_demo   # http://127.0.0.1:8788

Pre-commit

pip install pre-commit
pre-commit install

Hooks run: trailing whitespace, YAML/TOML checks, then ./scripts/pre-commit-rust.sh (fmt + clippy + test + 90% line coverage gate).

Quality bar

Check Threshold
cargo clippy -D warnings (pedantic)
Rust line coverage ≥ 90% (workspace)
Python line coverage ≥ 90% (pytest --cov-fail-under=90)

License

Apache License 2.0 — see LICENSE.

Download files

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

Source Distribution

emry-0.2.0.tar.gz (91.0 kB view details)

Uploaded Source

Built Distribution

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

emry-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (484.5 kB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ x86-64

File details

Details for the file emry-0.2.0.tar.gz.

File metadata

  • Download URL: emry-0.2.0.tar.gz
  • Upload date:
  • Size: 91.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for emry-0.2.0.tar.gz
Algorithm Hash digest
SHA256 818d684214bb7c2d4d8ff0aa2181e0ad8f13d5c556f2f988e5696f01712a211c
MD5 9f8581db7e48b3a30e2e8574130bd612
BLAKE2b-256 a9d80ba2398abeab8fa752d8ccc3c4a839a83dff81662a840fcf52ca09fa2d14

See more details on using hashes here.

Provenance

The following attestation bundles were made for emry-0.2.0.tar.gz:

Publisher: release.yml on femboyisp/emry

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file emry-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for emry-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 1bd4f23e57f36004219ef91167b87fca7c1b958a768a7576762919f535be61f4
MD5 93c2b812938d97e68c53ed6710ffcb7f
BLAKE2b-256 f4bacacb50dea4c4d924ec5a5aaade2fa985dfdc09cc94cf5b481fca79fb7912

See more details on using hashes here.

Provenance

The following attestation bundles were made for emry-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on femboyisp/emry

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

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