Skip to main content

CI License: MIT Python 3.9+ TestPyPI version

maarg - Zero-Boilerplate Experiment Tracking

Experiment tracking with zero logging code.

Put @track on a function. Every execution—arguments, returns, metrics, execution timing, and failures—is automatically saved to local storage for instant querying.


How It Works

maarg sits transparently at function boundaries. It reads signature parameter defaults and runtime return payloads without requiring explicit parameter or metric logging statements inside your function logic.

  ┌────────────────────────┐
  │  @track decorated fn   │  ──► (Intercepts arguments & execution context)
  └───────────┬────────────┘
              │
              ▼
  ┌────────────────────────┐
  │   Function Execution   │  ──► (Captures return dict / scalars / figures)
  └───────────┬────────────┘
              │
              ▼
  ┌────────────────────────┐
  │   SQLite Persistence   │  ──► Saves to .maarg/runs.db (or custom backend)
  └───────────┬────────────┘
              │
              ▼
  ┌────────────────────────┐
  │  Query & Analysis API  │  ──► maarg.get_runs() ──► top_n() / filter_runs()
  └────────────────────────┘

Quickstart

from maarg import track, get_runs, top_n

@track(experiment="learning-rate-sweep")
def fit(learning_rate, epochs=100):
    w = 0.0
    for _ in range(epochs):
        grad = sum(2 * (w * x - 3 * x) * x for x in range(1, 6)) / 5
        w -= learning_rate * grad
    return {"error": abs(w - 3)}

# Run experiments across hyperparameters
for lr in (0.001, 0.003, 0.01):
    fit(learning_rate=lr)

# Query top 3 runs directly from default storage
for run in top_n(get_runs(), "error", n=3, higher_is_better=False):
    print(f"lr={run.inputs['learning_rate']:<6} epochs={run.inputs['epochs']}  error={run.metrics['error']:.2e}")
lr=0.01   epochs=100  error=4.86e-11
lr=0.003  epochs=100  error=3.25e-03
lr=0.001  epochs=100  error=3.24e-01

Project & Storage Structure

maarg enforces a clean public package API while automatically managing runtime tracking databases and artifact outputs.

Repository Layout

maarg/
├── .github/
│   └── workflows/
│       └── ci.yaml
├── docs/
├── src/
│   └── maarg/
│       ├── storage/             # Storage backends package
│       │   ├── __init__.py
│       │   ├── _base.py         # StorageBackend base interface
│       │   └── _sqlite.py       # SQLiteStorage implementation
│       ├── __init__.py          # Public API exports (track, get_runs, top_n, etc.)
│       ├── _capture.py          # Value parsing & scalar payload truncation
│       ├── _convenience.py      # get_runs() wrapper & top-level defaults
│       ├── _models.py           # Core Run and Storage schema dataclasses
│       ├── _query.py            # Pure analytical query engine (top_n, filter_runs)
│       └── _tracking.py         # @track decorator implementation
├── tests/                       # Full test suite matching internal modules
│   ├── test_capture.py
│   ├── test_convenience.py
│   ├── test_models.py
│   ├── test_query.py
│   ├── test_storage.py
│   └── test_tracking.py
├── LICENSE
├── PLANNING.md
├── pyproject.toml
└── README.md

Runtime Storage Directory (.maarg/)

When you execute tracked functions, maarg initializes a local directory relative to your working workspace:

your_project/
├── .maarg/
│   ├── runs.db                  # Local SQLite database containing experiment runs
│   └── artifacts/               # Generated PNG plots & exported binary files
│       └── <run_id>/
│           └── figure_1.png
├── train.py
└── notebook.ipynb

Installation

pip install maarg

Supports Python 3.9+ with zero required external server dependencies. To automatically capture Matplotlib plots into .maarg/artifacts/, install with plotting support:

pip install "maarg[plotting]"

Querying Runs

Query functions operate as pure functions on collections of Run objects. You can fetch runs effortlessly using the top-level get_runs() helper or pass custom storage backends explicitly.

from maarg import get_runs, filter_runs, top_n, best_run, compare

# Fetch runs from default local storage (.maarg/runs.db)
runs = get_runs()

# Optionally scope by experiment
exp_runs = get_runs(experiment="learning-rate-sweep")

# Identify top performers
best = best_run(runs, "error", higher_is_better=False)
top_3 = top_n(runs, "error", n=3, higher_is_better=False)

# Filter by input configuration
specific = filter_runs(runs, learning_rate=0.01)

# Tabulate run comparisons
comparison = compare(top_3)

By default, failed runs are filtered out of ranking queries (only_successful=True). Pass only_successful=False to include failed executions.


What Gets Recorded

Field Description
run_id Unique UUID generated automatically per call
timestamp ISO 8601 UTC timestamp of call execution
function Name of the decorated function
experiment Experiment grouping label (defaults to function name)
inputs Captured function call parameters (including defaults)
metrics Numeric dictionary outputs returned by the function
artifacts Saved files/figures stored as {name, path, type}
other Unclassified outputs, strings, booleans, or truncated repr() representations
duration_sec Execution duration in seconds

Value Safety & Limits

  • Inputs: Simple scalar values (numbers, strings, booleans) and collections with ≤ 20 elements or ≤ 1000 bytes are recorded. Large arrays, dataframes, or complex objects are automatically skipped to avoid database bloat.
  • Outputs: Dictionary return values with numeric scalars become metrics. Returned Matplotlib figures are serialized to PNG artifacts inside .maarg/artifacts/<run_id>/.
  • Failures: Exceptions are caught, recorded with other["status"] = "failed" along with the exception class and traceback message, and then re-raised unchanged.

Configuration

Pass optional controls directly to the @track decorator:

from maarg import track
from maarg.storage import SQLiteStorage

@track(
    experiment="hyperparameter-sweep",
    storage=SQLiteStorage("results/custom_experiment.db"),
    artifacts_dir="results/artifacts"
)
def train(lr, batch_size):
    ...
Option Default Description
experiment Function name Label for grouping related runs
storage SQLite at .maarg/runs.db Target storage engine instance
artifacts_dir .maarg/artifacts Directory path for stored plots/files
max_scalar_bytes 1000 Max byte size allowed for individual scalar inputs
max_collection_length 20 Max items allowed in recorded input lists/dicts

Custom Storage Backends

You can define custom storage targets by subclassing StorageBackend and implementing save, get_by_id, list_by_function, list_by_experiment, and list_all:

from maarg.storage import StorageBackend

class CustomStorage(StorageBackend):
    # Implement persistence methods
    ...

Roadmap

  • Command-line interface (CLI) for browsing and inspecting runs directly in the terminal
  • Event hooks triggered on run completion (e.g., Slack or webhook notifications)
  • Web dashboard extension package
  • Additional remote storage backends

About the Name

maarg (मार्ग) is Hindi for "path" or "route".


License

MIT — see LICENSE.

Metadata

Release files for maarg 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for maarg 0.2.0
File Size Uploaded
maarg-0.2.0.tar.gz 22.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for maarg 0.2.0
File Interpreter ABI Platform
maarg-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 38.4 kB

Release files / maarg-0.2.0.tar.gz

Download URL maarg-0.2.0.tar.gz
Size 22.6 kB
Tags Source
SHA-256 checksum
How to use checksums
46b705d02aa116df0b2b06e3c3aa2a750d2a45f211a102f9e04a48f28bf8ebcf
BLAKE2b-256 checksum
How to use checksums
2fef967c53bba2636b6ae251e7c624168f4b0c920d7bc597dc16328b44260231
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release files / maarg-0.2.0-py3-none-any.whl

Download URL maarg-0.2.0-py3-none-any.whl
Size 15.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2691e84e7acd09a52e4363dbdf0ed3091eb63abb141c7985fde1e62fccac74b5
BLAKE2b-256 checksum
How to use checksums
b7e9a4932f8d1e996785fb3e29d209107421a9df7ca5a61ca9da3b03433837cf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page