Skip to content

About

MLOps-style tracking without touching the code.

Resources

Contributing

Stars

3 stars

Watchers

1 watching

Forks

Latest commit

 

History

275 Commits

Folders and files

Repository files navigation

LiteRunner

Tests codecov PyPI version PyPI platforms Total downloads
Made Using tsvikas/python-template GitHub Discussion PRs Welcome

Overview

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.

Quick start

Create a run.py for your model:

#!/usr/bin/env -S uv run
# /// script
# dependencies = ["lite-runner"]
# ///
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 run
./run.py --seed=-                           # unset a param (omit from command)
./run.py --image - - -                      # unset a multi-value param

What it does

Each runner.run() call:

  1. Parses CLI args (all params are optional in argparse; missing ones trigger TUI prompts)
  2. Creates an output directory at ~/lite_runs/<project>/<timestamp>_<run_name>/
  3. Inits a W&B run and logs all params, git info, and host metadata
  4. Saves a code snapshot (git archive + dirty diff) as a W&B artifact
  5. Builds and runs the subprocess, streaming stdout/stderr to terminal and log files
  6. Extracts metrics from stdout via regex
  7. Uploads output files (videos, images, artifacts) to W&B
  8. Logs duration, exit code, and status to W&B summary

Param

Param("name")                               # basic string param
Param("seed", type="int", default=42)       # typed with default
Param("mode", choices=["fast", "quality"])  # select from choices
Param("verbose", type="bool")               # --verbose flag (store_true, always defaults to False)
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",
)                                           # after the run, uploaded to W&B as a video
Param(
    "input-image",
    type=["path-image", "float", "float"],  # multi-value flag
    labels=["img", "start", "strength"],
)                                           # each part prompted separately in TUI

Type — controls parsing, casting, and file upload intent. All param values are logged to run.config. The path-* variants additionally upload the file at that path to W&B:

Type Parsed as File upload
"str" (default) str —
"int" int —
"float" float —
"bool" flag —
"path" str —
"path-image" str as image
"path-video" str as video
"path-artifact" str as artifact
"path-text" str as text

"bool" params are special: they generate a --flag (no value), always default to False (any other default= is ignored), and cannot appear in multi-value type lists.

Other fields:

  • value= makes a param fixed (never prompted, not in CLI). Can be a callable (called at resolve time).
  • default= can be a callable (called at resolve time to compute the default)
  • flag= overrides the CLI flag name (default: --<name with hyphens>)
  • prompt=False skips interactive prompting (falls through to default). Requires a default=. The param still accepts CLI flags and is logged normally.
  • $output in value is replaced with the run's output directory
  • log_when= auto-inferred: "before" for inputs, "after" for $output paths
  • type=[...] gives per-element types for multi-value flags (nargs inferred from length)
  • Pass - on CLI to unset a param (omit it from the subprocess command). For single-value: --seed=-. For multi-value: --image - - - (one - per element). This mirrors typing - at the interactive TUI prompt.

Output

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 archive
Output("weights/", log_as="zip", name="model-weights")  # name= sets the W&B key (disambiguates zips)

Metric

Extract values from stdout:

Metric("loss", pattern=r"loss=([\d.]+)")
Metric("status", pattern=r"status: (\w+)", type="str")
Metric("steps_per_sec", pattern=r"steps/s=([\d.]+)", type="int")
Metric(
    "elapsed", pattern=r"elapsed: ([\d:.]+)", type="timedelta"
)  # [[HH:]MM:]SS[.ddd] → seconds

Last match wins. Patterns are matched against both stdout and stderr. Stored in wandb.run.summary.

Supported types: "float" (default), "int", "str", "timedelta".

Sweeps

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 options

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",
        "NOISY_VAR": None,
    },                        # set or unset env vars
    secret_env={
        "HF_TOKEN": "hf_xxx",
    },                        # like env, but redacted in logs / recorded config
    project="my-project",     # default: git repo name
    run_group="my-sweep",     # W&B run group for sweeps (None = no grouping)
)

Pipeline API

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. It returns a RunResult with fields: output_dir, exit_code, duration, run_name, project, config, param_values, param_sources.

Built-in 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

What gets logged to W&B

Location Content
run.config["param/*"] All param values
run.config["param_source/*"] Where each param value came from (cli, default, fixed, override, prompt)
run.config["git/*"] commit, branch, repo, dirty
run.config["meta/*"] hostname, user, cwd, datetime, command, full_command, output_dir, env (secrets as ***)
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

Using with Claude Code

This repo is also a Claude Code plugin marketplace. Install the lite-runner skill so Claude Code writes idiomatic run.py scripts and drives sweeps correctly:

/plugin marketplace add moonmath-ai/LiteRunner
/plugin install lite-runner@lite-runner-marketplace

See plugins/lite-runner/ for the plugin source.

Contributing

Interested in contributing? See CONTRIBUTING.md for development setup and guidelines.

About

MLOps-style tracking without touching the code.

Resources

Contributing

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages