Runner for generative models with local and W&B tracking.
Write a small Python script per model that declares params, outputs, and metrics.
lite-runner handles the rest: CLI parsing, interactive prompts for missing values,
subprocess execution, stdout/stderr capture, metric extraction, file uploads to W&B,
and code snapshots for reproducibility.
Create a run.py for your model:
#!/usr/bin/env -S uv run
# /// script
# dependencies = ["lite-runner @ git+https://github.com/moonmath-ai/LiteRunner"]
# ///
from lite_runner import Runner, Param, Metric
runner = Runner(
command="python generate.py",
params=[
Param("prompt", help="Text prompt"),
Param("seed", type="int", default=42),
Param("output-path", value="$output/video.mp4", type="path-video"),
],
metrics=[
Metric("loss", pattern=r"loss=([\d.]+)"),
],
)
if __name__ == "__main__":
runner.run()Then run it (requires uv):
chmod +x run.py
./run.py --prompt "a cat walking" # interactive TUI fills missing params
./run.py --prompt "a cat" --no-interactive # non-interactive, fail if missing
./run.py --prompt "a cat" --dry-run # print command, don't runEach runner.run() call:
- Parses CLI args (all params are optional in argparse; missing ones trigger TUI prompts)
- Creates an output directory at
~/lite_runs/<project>/<timestamp>_<run_name>/ - Inits a W&B run and logs all params, git info, and host metadata
- Saves a code snapshot (git archive + dirty diff) as a W&B artifact
- Builds and runs the subprocess, streaming stdout/stderr to terminal and log files
- Extracts metrics from stdout via regex
- Uploads output files (videos, images, artifacts) to W&B
- Logs duration, exit code, and status to W&B summary
Param("name") # basic string param
Param("seed", type="int", default=42) # typed with default
Param("mode", choices=["fast", "quality"]) # select from choices
Param("image", type="path-image") # file input, uploaded to W&B before run
Param(
"output-path",
value="$output/video.mp4", # fixed value, $output interpolated
type="path-video",
) # uploaded to W&B after run
Param(
"input-image",
type=["path-image", "float", "float"], # multi-value flag
labels=["img", "start", "strength"],
) # each part prompted separately in TUIvalue=makes a param fixed (never prompted, not in CLI)default=can be a callable (called at prompt time to compute the default)$outputin value is replaced with the run's output directorytype="path-*"encodes upload intent:"path-video"— upload as video to W&B"path-image"— upload as image"path-artifact"— upload as artifact"path-text"— upload as text"path"— file path, no auto-upload
log_when=auto-inferred:"before"for inputs,"after"for$outputpathstype=[...]gives per-element types for multi-value flags (nargs inferred from length)
For files the model writes to uncontrolled locations:
Output("model_metadata.json", log_as="artifact", copy_to="$output/model_metadata.json")Supports glob patterns and directory zipping:
Output("debug/**/*.png", log_as="image") # upload each matched png
Output("debug/", log_as="image") # upload each file in directory
Output("debug/", log_as="zip") # zip entire directory, upload as artifact
Output("$output/frames/*.jpg", log_as="zip") # zip glob matches into archiveExtract values from stdout:
Metric("loss", pattern=r"loss=([\d.]+)")
Metric("status", pattern=r"status: (\w+)", type="str")Last match wins. Stored in wandb.run.summary.
Loop with override(). Runs are grouped in W&B for easy comparison:
runner = Runner(
command="python gen.py",
params=[...],
run_group="lr-sweep", # groups all runs together in W&B UI
)
for lr in [1e-3, 1e-4, 1e-5]:
runner.override(learning_rate=lr).run(no_interactive=True)Each call creates a separate W&B run, all grouped under the same group.
You can also update metadata per-run:
runner.override(seed=42).with_metadata(tags=["baseline"]).run()Runner(
command="python gen.py", # str or list[str] (list avoids shell splitting)
params=[...],
outputs=[...],
metrics=[...],
tags=["experiment-1"], # W&B run tags
env={"CUDA_VISIBLE_DEVICES": "0"}, # extra env vars for subprocess
project="my-project", # default: git repo name
run_group="my-sweep", # W&B run group for sweeps (None = no grouping)
)Each method returns a new Runner (immutable copies), so you can branch:
base = runner.parse_cli() # parse sys.argv
r1 = base.override(seed=42) # override params by name
r2 = base.override(seed=99)
r1.run() # auto-resolves defaults & prompts
r2.run()Methods:
| Method | Description |
|---|---|
parse_cli(argv) |
Parse CLI args (default: sys.argv[1:]) |
override(**kwargs) |
Set param values by name |
with_metadata(project=, run_group=, tags=) |
Update W&B metadata |
resolve_defaults() |
Apply defaults and fixed values |
ask_user(no_interactive=) |
Prompt for missing values |
run(...) |
Auto-calls any unapplied steps, then executes |
run() accepts kwargs dry_run, min_free_space_gib, no_interactive, no_wandb, project, run_name as alternatives to CLI flags.
| Flag | Description |
|---|---|
--dry-run |
Print command and exit |
--min-free-space-gib N |
Minimum free disk space in GiB (default: 1.0) |
--no-interactive |
Fail if required params missing |
--no-wandb |
Skip W&B logging (still logs to JSON) |
--run-name NAME |
Override W&B run name |
--project NAME |
Override project name |
| Location | Content |
|---|---|
run.config["param/*"] |
All param values |
run.config["git/*"] |
commit, branch, repo, dirty |
run.config["meta/*"] |
hostname, datetime, command |
run.summary |
exit_code, duration_seconds, status, metrics |
| Artifacts | Log files, code snapshot, artifact-type outputs |
| Media | Videos and images from path-* type params/outputs |
Interested in contributing? See CONTRIBUTING.md for development setup and guideline.