moontrack

A MoonBit experiment tracking library for reproducible machine learning and scientific research.

experiment
tracking
mlflow
ml
research
moon add AlexenderSokolov/moontrack@0.1.0
Download zip
Version
0.1.0
License
Apache-2.0
Last updated
9 days ago
Downloads
2
README

#MoonTrack

MoonTrack is a MoonBit experiment tracking library for reproducible machine learning and scientific research. It records experiment parameters, metrics, artifacts, and run status, supports query/filter/sort/export, and provides strict JSON serialization.

The project addresses a recurring need in ML workflows: experiment metadata scattered across log files, spreadsheets, and chat messages. MoonTrack extracts a small but useful layer into a standalone library that describes what was run, what parameters were used, what metrics were produced, and what artifacts were left behind.

Chinese documentation is available in README.zh.md.

#What It Does

  • Defines experiments and runs with parameters, metrics, artifacts, and tags.
  • Tracks run lifecycle: created → running → completed/failed/killed.
  • Validates status transitions and rejects duplicate ids.
  • Logs parameters (int/float/bool/string) with type information.
  • Logs metrics with step, timestamp, direction, and threshold.
  • Logs artifacts with name, path, size, and checksum.
  • Records reproducibility info: code version, command, environment, seed.
  • Queries runs by status, tags, parameters, and metric ranges.
  • Sorts runs by metric or parameter values.
  • Compares two runs and computes metric deltas with improvement detection.
  • Exports Markdown reports, JSON snapshots, and CSV metric tables.
  • Searches experiments by name, description, or tags.
  • Tracks run lineage with parent-child relationships and cycle detection.
  • Computes metric statistics: median, percentile, correlation, std dev.
  • Validates store data integrity: empty names, unknown references, missing reproducibility.

#What It Deliberately Leaves Out

  • It does not persist to a database or filesystem.
  • It does not call LLM APIs or execute shell commands.
  • It does not provide a web UI or dashboard.
  • It does not manage secrets or credentials.

#Installation

Add the published package to a MoonBit project:

moon add AlexenderSokolov/moontrack

Import it from the consuming package's moon.pkg:

import { "AlexenderSokolov/moontrack", }

#Quick Start

let store = @moontrack.TrackingStore::new()
ignore(store.create_experiment("exp1", "My Experiment"))
ignore(store.start_run("run1", "exp1", "2026-01-01T00:00:00Z"))
ignore(store.log_param("run1", @moontrack.Param::new_float("lr", 0.01)))
ignore(store.log_metric("run1", @moontrack.Metric::new("accuracy", 0.95, 1, "t1")))
ignore(store.complete_run("run1", "2026-01-01T01:00:00Z"))

println(store.to_markdown())
println(store.to_json())

#CLI Tools

moon run cmd/demo # Full demo: experiments, runs, comparison, query, CSV moon run cmd/track # Tracking CLI: create experiment, record runs moon run cmd/query # Query CLI: filter, sort, export moon run cmd/bench # Benchmark: 20 experiments × 50 runs

#Project Layout

moontrack/ |-- experiment.mbt # Experiment data model |-- run.mbt # Run data model and lifecycle |-- param.mbt # Parameter model and type parsing |-- metric.mbt # Metric model, direction, threshold |-- artifact.mbt # Artifact model, checksum, metadata |-- reproducibility.mbt # Reproducibility info model |-- tracking.mbt # TrackingStore: core storage and state transitions |-- query.mbt # RunFilter and SortKey: query and sort |-- compare.mbt # RunComparison: metric delta and improvement |-- export.mbt # Markdown/JSON/CSV export |-- search.mbt # Experiment search and store statistics |-- lineage.mbt # Run lineage tracking with cycle detection |-- enhanced_export.mbt # Detailed CSV, comparison report, lineage trees |-- statistics.mbt # Metric statistics: median, percentile, correlation |-- validation.mbt # Store data integrity validation |-- tracking_test.mbt # Core behavior tests |-- query_test.mbt # Query and filter tests |-- compare_test.mbt # Comparison framework tests |-- export_test.mbt # Export format tests |-- search_test.mbt # Search and statistics tests |-- lineage_test.mbt # Lineage tracking tests |-- enhanced_export_test.mbt # Enhanced export tests |-- statistics_test.mbt # Statistics tests |-- validation_test.mbt # Validation tests |-- cmd/demo/ # Full demo CLI |-- cmd/track/ # Tracking CLI |-- cmd/query/ # Query CLI |-- cmd/bench/ # Benchmark CLI |-- docs/ # API, design, roadmap, acceptance |-- CHANGELOG.md # Versioned changes |-- README.zh.md # Chinese documentation `-- PROJECT.md # Project memory

#Repositories

#License

Apache-2.0. See LICENSE.

#
Artifact

pub struct Artifact {
// private fields
} derive(Eq,
Debug
)

An artifact produced by a run, such as a model file or a plot.

#
Artifact::checksum

fn Artifact::checksum(self : Artifact) -> String?

Return the checksum if set.

#
Artifact::metadata

fn Artifact::metadata(self : Artifact) -> Map[String, String]

Return a detached copy of artifact metadata.

#
Artifact::name

fn Artifact::name(self : Artifact) -> String

Return the artifact name.

#
Artifact::new

fn Artifact::new(name : String, path : String, size : Int) -> Artifact

Build a new artifact with empty metadata and no checksum.

#
Artifact::path

fn Artifact::path(self : Artifact) -> String

Return the artifact path.

#
Artifact::size

fn Artifact::size(self : Artifact) -> Int

Return the artifact size in bytes.

#
Artifact::with_checksum

fn Artifact::with_checksum(self : Artifact, checksum : String) -> Artifact

Set the checksum.

#
Artifact::with_metadata

fn Artifact::with_metadata(self : Artifact, metadata : Map[String, String]) -> Artifact

Set metadata entries.

#
Experiment

pub struct Experiment {
// private fields
} derive(
Debug
)

A container for a group of related experiment runs.

An experiment groups runs that share the same research question or hypothesis. Each run records its own parameters, metrics, and artifacts.

#
Experiment::created_at

fn Experiment::created_at(self : Experiment) -> String

Return the creation timestamp string.

#
Experiment::description

fn Experiment::description(self : Experiment) -> String

Return the experiment description.

#
Experiment::find_run

fn Experiment::find_run(self : Experiment, run_id : String) -> Run?

Return a run by id when it exists in this experiment.

#
Experiment::id

fn Experiment::id(self : Experiment) -> String

Return the experiment id.

#
Experiment::metadata

fn Experiment::metadata(self : Experiment) -> Map[String, String]

Return a detached copy of experiment metadata.

#
Experiment::name

fn Experiment::name(self : Experiment) -> String

Return the experiment name.

#
Experiment::new

fn Experiment::new(id : String, name : String) -> Experiment

Build an empty experiment.

#
Experiment::run_count

fn Experiment::run_count(self : Experiment) -> Int

Return the number of runs in this experiment.

#
Experiment::run_ids

fn Experiment::run_ids(self : Experiment) -> Array[String]

Return all run ids in this experiment.

#
Experiment::runs

fn Experiment::runs(self : Experiment) -> Array[Run]

Return a detached copy of all runs in this experiment.

#
Experiment::tags

fn Experiment::tags(self : Experiment) -> Array[String]

Return a detached copy of experiment tags.

#
Experiment::with_created_at

fn Experiment::with_created_at(self : Experiment, created_at : String) -> Experiment

Set the creation timestamp.

#
Experiment::with_description

fn Experiment::with_description(self : Experiment, description : String) -> Experiment

Add a short description to an experiment.

#
Experiment::with_metadata

fn Experiment::with_metadata(self : Experiment, metadata : Map[String, String]) -> Experiment

Set metadata entries.

#
Experiment::with_tags

fn Experiment::with_tags(self : Experiment, tags : Array[String]) -> Experiment

Add tags to an experiment.

#
ExperimentSearchFilter

pub struct ExperimentSearchFilter {
// private fields
} derive(
Debug
)

Search filter for experiments.

All specified conditions must match (AND semantics). An empty filter matches all experiments.

#
ExperimentSearchFilter::matches

fn ExperimentSearchFilter::matches(self : ExperimentSearchFilter, exp : Experiment) -> Bool

Test whether a single experiment matches this filter.

#
ExperimentSearchFilter::new

Build an empty experiment search filter.

#
ExperimentSearchFilter::with_description_contains

fn ExperimentSearchFilter::with_description_contains(self : ExperimentSearchFilter, substring : String) -> ExperimentSearchFilter

Restrict to experiments whose description contains the given substring.

#
ExperimentSearchFilter::with_name_contains

fn ExperimentSearchFilter::with_name_contains(self : ExperimentSearchFilter, substring : String) -> ExperimentSearchFilter

Restrict to experiments whose name contains the given substring.

#
ExperimentSearchFilter::with_tags_any

fn ExperimentSearchFilter::with_tags_any(self : ExperimentSearchFilter, tags : Array[String]) -> ExperimentSearchFilter

Restrict to experiments that have at least one of the given tags.

#
JsonImportError

pub(all) enum JsonImportError {
InvalidJsonSyntax(String)
UnsupportedSchemaVersion(String)
MissingRequiredField(String)
InvalidFieldType(String)
UnknownField(String)
DuplicateExperimentId(String)
DuplicateRunId(String)
UnknownExperimentForRun(String)
InvalidRunStatus(String)
InvalidParamType(String)
InvalidMetricDirection(String)
} derive(Eq,
Debug
)

Errors raised during JSON import and validation.

#
JsonImportError::message

fn JsonImportError::message(self : JsonImportError) -> String

Return a readable diagnostic for a JSON import error.

#
LineageError

pub(all) enum LineageError {
SelfParent(String)
ParentAlreadySet(String)
LineageCycle(String, String)
NoParent(String)
} derive(Eq,
Debug
)

Errors raised by lineage operations.

#
LineageError::message

fn LineageError::message(self : LineageError) -> String

Return a readable diagnostic for a lineage error.

#
LineageTracker

pub struct LineageTracker {
// private fields
} derive(
Debug
)

Run lineage tracking for parent-child relationships.

This module allows tracking which runs are derived from which other runs, forming a lineage tree. A run may have at most one parent. Cycles are rejected.

#
LineageTracker::ancestors

fn LineageTracker::ancestors(self : LineageTracker, child : String) -> Array[String]

Return the full ancestor chain from the given run to the root.

#
LineageTracker::children

fn LineageTracker::children(self : LineageTracker, parent : String) -> Array[String]

Return the children of a run.

#
LineageTracker::depth

fn LineageTracker::depth(self : LineageTracker, child : String) -> Int

Return the lineage depth (number of ancestors).

#
LineageTracker::descendants

fn LineageTracker::descendants(self : LineageTracker, root : String) -> Array[String]

Return the full descendant tree rooted at the given run.

#
LineageTracker::edge_count

fn LineageTracker::edge_count(self : LineageTracker) -> Int

Return the total number of parent-child edges.

#
LineageTracker::has_children

fn LineageTracker::has_children(self : LineageTracker, parent : String) -> Bool

Check if a run has children.

#
LineageTracker::has_parent

fn LineageTracker::has_parent(self : LineageTracker, child : String) -> Bool

Check if a run has a parent.

#
LineageTracker::lineage_path

fn LineageTracker::lineage_path(self : LineageTracker, child : String) -> Array[String]

Return the full lineage path from root to the given run.

#
LineageTracker::new

Build an empty lineage tracker.

#
LineageTracker::parent

fn LineageTracker::parent(self : LineageTracker, child : String) -> String

Return the parent run id, or empty string if no parent.

#
LineageTracker::remove_parent

fn LineageTracker::remove_parent(self : LineageTracker, child : String) -> Result[Unit, LineageError]

Remove a parent-child relationship.

#
LineageTracker::reparent

fn LineageTracker::reparent(self : LineageTracker, child : String, new_parent : String) -> Result[Unit, LineageError]

Change the parent of a run that already has a parent.

#
LineageTracker::root

fn LineageTracker::root(self : LineageTracker, child : String) -> String

Return the root ancestor of a run (the run with no parent in the chain).

#
LineageTracker::set_parent

fn LineageTracker::set_parent(self : LineageTracker, child : String, parent : String) -> Result[Unit, LineageError]

Set the parent of a run.

Rejects:
  • Self-parenting (child == parent)
  • Cycles (setting a parent that would create a cycle)
  • Overwriting an existing parent (use reparent instead)

#
Metric

pub struct Metric {
// private fields
} derive(Eq,
Debug
)

A metric value recorded at a specific step.

#
Metric::direction

fn Metric::direction(self : Metric) -> MetricDirection

Return the metric direction.

#
Metric::key

fn Metric::key(self : Metric) -> String

Return the metric key.

#
Metric::new

fn Metric::new(key : String, value : Double, step : Int, timestamp : String) -> Metric

Build a metric with default direction None and no threshold.

#
Metric::step

fn Metric::step(self : Metric) -> Int

Return the step number.

#
Metric::threshold

fn Metric::threshold(self : Metric) -> Double?

Return the threshold if set.

#
Metric::timestamp

fn Metric::timestamp(self : Metric) -> String

Return the timestamp string.

#
Metric::value

fn Metric::value(self : Metric) -> Double

Return the metric value.

#
Metric::with_direction

fn Metric::with_direction(self : Metric, direction : MetricDirection) -> Metric

Set the metric direction.

#
Metric::with_threshold

fn Metric::with_threshold(self : Metric, threshold : Double) -> Metric

Set the metric threshold.

#
MetricDelta

pub struct MetricDelta {
// private fields
} derive(
Debug
)

The difference between a metric value in two runs.

#
MetricDelta::baseline_value

fn MetricDelta::baseline_value(self : MetricDelta) -> Double

Return the baseline metric value.

#
MetricDelta::comparison_value

fn MetricDelta::comparison_value(self : MetricDelta) -> Double

Return the comparison metric value.

#
MetricDelta::delta

fn MetricDelta::delta(self : MetricDelta) -> Double

Return the absolute delta (comparison - baseline).

#
MetricDelta::direction

fn MetricDelta::direction(self : MetricDelta) -> MetricDirection

Return the metric direction.

#
MetricDelta::improved

fn MetricDelta::improved(self : MetricDelta) -> Bool

Return whether the comparison run improved on this metric.

#
MetricDelta::key

fn MetricDelta::key(self : MetricDelta) -> String

Return the metric key.

#
MetricDelta::percent_change

fn MetricDelta::percent_change(self : MetricDelta) -> Double

Return the percent change relative to baseline.

#
MetricDirection

pub(all) enum MetricDirection {
HigherBetter
LowerBetter
None_
} derive(Eq,
Debug
)

Direction indicating whether a higher or lower metric value is better.

#
MetricDirection::from_string

fn MetricDirection::from_string(s : String) -> MetricDirection?

Parse a metric direction from its string kind.

#
MetricDirection::kind

fn MetricDirection::kind(self : MetricDirection) -> String

Return a stable machine-readable direction kind string.

#
MetricDirection::label

fn MetricDirection::label(self : MetricDirection) -> String

Return a stable human-readable direction label.

#
MetricStats

pub struct MetricStats {
// private fields
} derive(
Debug
)

Aggregated metric statistics across multiple runs.

#
MetricStats::count

fn MetricStats::count(self : MetricStats) -> Int

Return the number of runs that have this metric.

#
MetricStats::key

fn MetricStats::key(self : MetricStats) -> String

Return the metric key.

#
MetricStats::max_val

fn MetricStats::max_val(self : MetricStats) -> Double

Return the maximum metric value.

#
MetricStats::mean_val

fn MetricStats::mean_val(self : MetricStats) -> Double

Return the mean metric value.

#
MetricStats::min_val

fn MetricStats::min_val(self : MetricStats) -> Double

Return the minimum metric value.

#
MetricStats::range

fn MetricStats::range(self : MetricStats) -> Double

Return the range (max - min) of metric values.

#
MetricStats::std_dev

fn MetricStats::std_dev(self : MetricStats) -> Double

Return the standard deviation of metric values.

#
MetricStats::values

fn MetricStats::values(self : MetricStats) -> Array[Double]

Return a detached copy of all metric values.

#
MetricStats::variance

fn MetricStats::variance(self : MetricStats) -> Double

Return the variance of metric values.

#
MetricSummary

pub struct MetricSummary {
// private fields
} derive(
Debug
)

A comprehensive summary of metric values across multiple runs.

This extends MetricStats with median, standard deviation, and percentile support for richer statistical analysis.

#
MetricSummary::coefficient_of_variation

fn MetricSummary::coefficient_of_variation(self : MetricSummary) -> Double

Return the coefficient of variation (stddev / mean). Returns 0.0 if mean is zero.

#
MetricSummary::count

fn MetricSummary::count(self : MetricSummary) -> Int

Return the number of data points.

#
MetricSummary::iqr

fn MetricSummary::iqr(self : MetricSummary) -> Double

Return the interquartile range (Q3 - Q1).

#
MetricSummary::key

fn MetricSummary::key(self : MetricSummary) -> String

Return the metric key.

#
MetricSummary::max_val

fn MetricSummary::max_val(self : MetricSummary) -> Double

Return the maximum value.

#
MetricSummary::mean_val

fn MetricSummary::mean_val(self : MetricSummary) -> Double

Return the mean value.

#
MetricSummary::median_val

fn MetricSummary::median_val(self : MetricSummary) -> Double

Return the median value.

#
MetricSummary::min_val

fn MetricSummary::min_val(self : MetricSummary) -> Double

Return the minimum value.

#
MetricSummary::percentile

fn MetricSummary::percentile(self : MetricSummary, p : Double) -> Double

Return the p-th percentile (0-100) of the values.

#
MetricSummary::q1

fn MetricSummary::q1(self : MetricSummary) -> Double

Return the first quartile (25th percentile).

#
MetricSummary::q3

fn MetricSummary::q3(self : MetricSummary) -> Double

Return the third quartile (75th percentile).

#
MetricSummary::range

fn MetricSummary::range(self : MetricSummary) -> Double

Return the range (max - min).

#
MetricSummary::stddev_val

fn MetricSummary::stddev_val(self : MetricSummary) -> Double

Return the standard deviation.

#
MetricSummary::values

fn MetricSummary::values(self : MetricSummary) -> Array[Double]

Return a detached copy of all values.

#
MetricSummary::variance

fn MetricSummary::variance(self : MetricSummary) -> Double

Return the variance (stddev^2).

#
Param

pub struct Param {
// private fields
} derive(Eq,
Debug
)

A parameter key-value pair with type information.

#
Param::description

fn Param::description(self : Param) -> String

Return the parameter description.

#
Param::key

fn Param::key(self : Param) -> String

Return the parameter key.

#
Param::new_bool

fn Param::new_bool(key : String, value : Bool) -> Param

Build a boolean parameter.

#
Param::new_float

fn Param::new_float(key : String, value : Double) -> Param

Build a float parameter.

#
Param::new_int

fn Param::new_int(key : String, value : Int) -> Param

Build an integer parameter.

#
Param::new_string

fn Param::new_string(key : String, value : String) -> Param

Build a string parameter.

#
Param::new_typed

fn Param::new_typed(key : String, value : String, type_ : ParamType) -> Param

Build a parameter with an explicit type and string value.

This is intended for JSON import tools that already have the type information and the value as a string.

#
Param::type_

fn Param::type_(self : Param) -> ParamType

Return the parameter type.

#
Param::value

fn Param::value(self : Param) -> String

Return the parameter value as a string.

#
Param::with_description

fn Param::with_description(self : Param, description : String) -> Param

Add a description to a parameter.

#
ParamType

pub(all) enum ParamType {
IntParam
FloatParam
BoolParam
StringParam
} derive(Eq,
Debug
)

The type of a parameter value.

#
ParamType::from_string

fn ParamType::from_string(s : String) -> ParamType?

Parse a parameter type from its string kind.

#
ParamType::kind

fn ParamType::kind(self : ParamType) -> String

Return a stable machine-readable type kind string.

#
ParamType::label

fn ParamType::label(self : ParamType) -> String

Return a stable human-readable type label.

#
ReproducibilityInfo

pub struct ReproducibilityInfo {
// private fields
} derive(Eq,
Debug
)

Reproducibility information for a run.

This captures enough context for another session to reproduce the run: the code version, the exact command, the environment, and the random seed.

#
ReproducibilityInfo::code_version

fn ReproducibilityInfo::code_version(self : ReproducibilityInfo) -> String

Return the code version string (e.g. git commit hash).

#
ReproducibilityInfo::command

fn ReproducibilityInfo::command(self : ReproducibilityInfo) -> String

Return the exact command used to run the experiment.

#
ReproducibilityInfo::dependencies

fn ReproducibilityInfo::dependencies(self : ReproducibilityInfo) -> Array[String]

Return a detached copy of dependency list.

#
ReproducibilityInfo::environment

fn ReproducibilityInfo::environment(self : ReproducibilityInfo) -> Map[String, String]

Return a detached copy of the environment map.

#
ReproducibilityInfo::new

fn ReproducibilityInfo::new(code_version : String, command : String) -> ReproducibilityInfo

Build reproducibility info with empty environment and no seed.

#
ReproducibilityInfo::random_seed

fn ReproducibilityInfo::random_seed(self : ReproducibilityInfo) -> Int?

Return the random seed if set.

#
ReproducibilityInfo::with_dependencies

fn ReproducibilityInfo::with_dependencies(self : ReproducibilityInfo, deps : Array[String]) -> ReproducibilityInfo

Set the dependency list.

#
ReproducibilityInfo::with_environment

fn ReproducibilityInfo::with_environment(self : ReproducibilityInfo, env : Map[String, String]) -> ReproducibilityInfo

Set the environment map.

#
ReproducibilityInfo::with_random_seed

fn ReproducibilityInfo::with_random_seed(self : ReproducibilityInfo, seed : Int) -> ReproducibilityInfo

Set the random seed.

#
Run

pub struct Run {
// private fields
} derive(
Debug
)

A single experiment run recording parameters, metrics, and artifacts.

#
Run::add_artifact

fn Run::add_artifact(self : Run, artifact : Artifact) -> Unit

Append an artifact to this run.

#
Run::add_metric

fn Run::add_metric(self : Run, metric : Metric) -> Unit

Append a metric to this run.

#
Run::add_note

fn Run::add_note(self : Run, note : String) -> Unit

Append a note to this run.

#
Run::add_param

fn Run::add_param(self : Run, param : Param) -> Unit

Append a parameter to this run.

#
Run::artifact_count

fn Run::artifact_count(self : Run) -> Int

Return the number of artifacts.

#
Run::artifacts

fn Run::artifacts(self : Run) -> Array[Artifact]

Return a detached copy of all artifacts.

#
Run::end_time

fn Run::end_time(self : Run) -> String

Return the end timestamp string.

#
Run::error_message

fn Run::error_message(self : Run) -> String

Return the error message attached to a failed run.

#
Run::experiment_id

fn Run::experiment_id(self : Run) -> String

Return the experiment id this run belongs to.

#
Run::find_param

fn Run::find_param(self : Run, key : String) -> Param?

Find a parameter by key.

#
Run::id

fn Run::id(self : Run) -> String

Return the run id.

#
Run::latest_metric

fn Run::latest_metric(self : Run, key : String) -> Metric?

Find the latest metric value for a key.

#
Run::metric_count

fn Run::metric_count(self : Run) -> Int

Return the number of metrics.

#
Run::metrics

fn Run::metrics(self : Run) -> Array[Metric]

Return a detached copy of all metrics.

#
Run::metrics_for

fn Run::metrics_for(self : Run, key : String) -> Array[Metric]

Return all metric values for a key in step order.

#
Run::new

fn Run::new(id : String, experiment_id : String) -> Run

Build a new run in Created status.

#
Run::notes

fn Run::notes(self : Run) -> Array[String]

Return a detached copy of run notes.

#
Run::param_count

fn Run::param_count(self : Run) -> Int

Return the number of parameters.

#
Run::parameters

fn Run::parameters(self : Run) -> Array[Param]

Return a detached copy of all parameters.

#
Run::reproducibility

fn Run::reproducibility(self : Run) -> ReproducibilityInfo?

Return the reproducibility info if present.

#
Run::set_end_time

fn Run::set_end_time(self : Run, end_time : String) -> Run

Set the end time directly.

#
Run::set_reproducibility

fn Run::set_reproducibility(self : Run, info : ReproducibilityInfo?) -> Unit

Set reproducibility info directly on this run.

#
Run::set_status

fn Run::set_status(self : Run, status : RunStatus) -> Run

Set the status directly. Intended for importers and replay tools.

#
Run::start_time

fn Run::start_time(self : Run) -> String

Return the start timestamp string.

#
Run::status

fn Run::status(self : Run) -> RunStatus

Return the current run status.

#
Run::tags

fn Run::tags(self : Run) -> Array[String]

Return a detached copy of run tags.

#
Run::with_error_message

fn Run::with_error_message(self : Run, msg : String) -> Run

Set the error message for a failed run.

#
Run::with_reproducibility

fn Run::with_reproducibility(self : Run, info : ReproducibilityInfo) -> Run

Set reproducibility information.

#
Run::with_start_time

fn Run::with_start_time(self : Run, start_time : String) -> Run

Set the start timestamp.

#
Run::with_tags

fn Run::with_tags(self : Run, tags : Array[String]) -> Run

Add tags to a run.

#
RunComparison

pub struct RunComparison {
// private fields
} derive(
Debug
)

The result of comparing a run against a baseline run.

For each metric key present in both runs, a MetricDelta is computed. Metrics only in the baseline are noted as removed; metrics only in the comparison run are noted as added.

#
RunComparison::added_keys

fn RunComparison::added_keys(self : RunComparison) -> Array[String]

Return a detached copy of metric keys only in the comparison run.

#
RunComparison::baseline_id

fn RunComparison::baseline_id(self : RunComparison) -> String

Return the baseline run id.

#
RunComparison::comparison_id

fn RunComparison::comparison_id(self : RunComparison) -> String

Return the comparison run id.

#
RunComparison::deltas

Return a detached copy of all metric deltas.

#
RunComparison::removed_keys

fn RunComparison::removed_keys(self : RunComparison) -> Array[String]

Return a detached copy of metric keys only in the baseline run.

#
RunFilter

pub struct RunFilter {
// private fields
} derive(
Debug
)

A composite filter for searching runs.

All specified conditions must match (AND semantics). An empty filter matches all runs.

#
RunFilter::matches

fn RunFilter::matches(self : RunFilter, run : Run) -> Bool

Test whether a single run matches this filter.

#
RunFilter::new

fn RunFilter::new() -> RunFilter

Build an empty run filter that matches everything.

#
RunFilter::with_metric_max

fn RunFilter::with_metric_max(self : RunFilter, key : String, max : Double) -> RunFilter

Restrict to runs whose latest metric for key is at most max.

#
RunFilter::with_metric_min

fn RunFilter::with_metric_min(self : RunFilter, key : String, min : Double) -> RunFilter

Restrict to runs whose latest metric for key is at least min.

#
RunFilter::with_param

fn RunFilter::with_param(self : RunFilter, key : String, value : String) -> RunFilter

Restrict to runs that have a parameter with the given key and value.

#
RunFilter::with_statuses

fn RunFilter::with_statuses(self : RunFilter, statuses : Array[RunStatus]) -> RunFilter

Restrict to runs with one of the given statuses.

#
RunFilter::with_tags_any

fn RunFilter::with_tags_any(self : RunFilter, tags : Array[String]) -> RunFilter

Restrict to runs that have at least one of the given tags.

#
RunStatus

pub(all) enum RunStatus {
Created
Running
Completed
Failed
Killed
} derive(Eq,
Debug
)

Lifecycle status of a run.

#
RunStatus::from_string

fn RunStatus::from_string(s : String) -> RunStatus?

Parse a run status from its string kind.

#
RunStatus::kind

fn RunStatus::kind(self : RunStatus) -> String

Return a stable machine-readable status kind string.

#
RunStatus::label

fn RunStatus::label(self : RunStatus) -> String

Return a stable human-readable status label.

#
SortKey

pub struct SortKey {
// private fields
} derive(
Debug
)

Sort key for ordering runs by a metric or parameter value.

#
SortKey::by_metric_ascending

fn SortKey::by_metric_ascending(key : String) -> SortKey

Build a sort key that sorts runs by a metric value in ascending order.

#
SortKey::by_metric_descending

fn SortKey::by_metric_descending(key : String) -> SortKey

Build a sort key that sorts runs by a metric value in descending order.

#
SortKey::by_param_ascending

fn SortKey::by_param_ascending(key : String) -> SortKey

Build a sort key that sorts runs by a parameter value in ascending order.

#
SortKey::by_param_descending

fn SortKey::by_param_descending(key : String) -> SortKey

Build a sort key that sorts runs by a parameter value in descending order.

#
TrackingError

pub(all) enum TrackingError {
DuplicateExperiment(String)
ExperimentNotFound(String)
DuplicateRun(String)
RunNotFound(String)
InvalidStatusTransition(String, RunStatus, RunStatus)
ParamAlreadyExists(String, String)
} derive(Eq,
Debug
)

Errors raised by the tracking store.

#
TrackingError::message

fn TrackingError::message(self : TrackingError) -> String

Return a readable diagnostic for a tracking error.

#
TrackingStore

pub struct TrackingStore {
// private fields
} derive(
Debug
)

The central in-memory store for experiments and runs.

All mutations go through the store so that invariants (unique ids, valid transitions) are enforced uniformly. The store uses arrays internally because expected experiment counts are small; this keeps traversal and mutation straightforward while the public API settles.

#
TrackingStore::add_experiment_tag

fn TrackingStore::add_experiment_tag(self : TrackingStore, experiment_id : String, tag : String) -> Result[Unit, TrackingError]

Add a tag to an experiment in the store.

#
TrackingStore::add_note

fn TrackingStore::add_note(self : TrackingStore, run_id : String, note : String) -> Result[Unit, TrackingError]

Add a note to a run.

#
TrackingStore::add_run_tag

fn TrackingStore::add_run_tag(self : TrackingStore, run_id : String, tag : String) -> Result[Unit, TrackingError]

Add a tag to a run in the store.

#
TrackingStore::aggregate_all_metrics

fn TrackingStore::aggregate_all_metrics(self : TrackingStore, experiment_id : String) -> Result[Array[MetricStats], TrackingError]

Aggregate metric statistics for all metric keys across all runs in an experiment.

Returns a map from metric key to MetricStats. Only the latest metric value for each run is considered.

#
TrackingStore::aggregate_metric

fn TrackingStore::aggregate_metric(self : TrackingStore, experiment_id : String, metric_key : String) -> Result[MetricStats, TrackingError]

Aggregate metric statistics for a specific metric key across all runs in an experiment.

Only the latest metric value for each run is considered. Runs without the specified metric are skipped.

#
TrackingStore::all_metric_summaries

fn TrackingStore::all_metric_summaries(self : TrackingStore, experiment_id : String) -> Result[Array[MetricSummary], TrackingError]

Compute metric summaries for all metric keys in an experiment.

#
TrackingStore::all_runs

fn TrackingStore::all_runs(self : TrackingStore) -> Array[Run]

Return all runs in the store as detached copies.

#
TrackingStore::best_run

fn TrackingStore::best_run(self : TrackingStore, experiment_id : String, metric_key : String) -> Result[Run, TrackingError]

Find the best run in an experiment by a specific metric.

"Best" is determined by the metric direction: for HigherBetter, the run with the highest metric value; for LowerBetter, the run with the lowest metric value. If direction is None, the run with the highest value is returned.

#
TrackingStore::compare_runs

fn TrackingStore::compare_runs(self : TrackingStore, baseline_id : String, comparison_id : String) -> Result[RunComparison, TrackingError]

Compare two runs from the store by metric.

Both runs must exist in the store. The comparison uses the latest metric value for each key. If a metric exists in only one run, it is recorded in added_keys or removed_keys rather than producing a delta.

#
TrackingStore::comparison_report

fn TrackingStore::comparison_report(self : TrackingStore, metric_key : String) -> String

Export a multi-experiment comparison report as Markdown.

For each experiment, the report shows:
  • Experiment name and id
  • Number of runs
  • Best run by the specified metric (if any runs exist)
  • Run status summary

#
TrackingStore::complete_run

fn TrackingStore::complete_run(self : TrackingStore, run_id : String, end_time : String) -> Result[Run, TrackingError]

Transition a run to Completed.

#
TrackingStore::create_experiment

fn TrackingStore::create_experiment(self : TrackingStore, id : String, name : String) -> Result[Experiment, TrackingError]

Create a new experiment. Rejects duplicate experiment ids.

#
TrackingStore::detailed_csv

fn TrackingStore::detailed_csv(self : TrackingStore, experiment_id : String) -> Result[String, TrackingError]

Export a detailed CSV with run id, status, all parameters, and all metrics for an experiment.

The CSV has the following columns:
  • run_id
  • status
  • start_time
  • end_time
  • one column per parameter key (value as string)
  • one column per metric key (latest value as number)

#
TrackingStore::experiment_count

fn TrackingStore::experiment_count(self : TrackingStore) -> Int

Return the number of experiments.

#
TrackingStore::experiments_by_name

fn TrackingStore::experiments_by_name(self : TrackingStore, substring : String) -> Array[Experiment]

Find experiments by name substring (case-sensitive).

#
TrackingStore::experiments_by_tag

fn TrackingStore::experiments_by_tag(self : TrackingStore, tag : String) -> Array[Experiment]

Find experiments by tag.

#
TrackingStore::experiments_table_markdown

fn TrackingStore::experiments_table_markdown(self : TrackingStore) -> String

Export a summary table of all experiments as Markdown.

#
TrackingStore::fail_run

fn TrackingStore::fail_run(self : TrackingStore, run_id : String, end_time : String, error_message : String) -> Result[Run, TrackingError]

Transition a run to Failed.

#
TrackingStore::from_json

fn TrackingStore::from_json(input : String) -> Result[TrackingStore, JsonImportError]

Import a tracking store from a JSON string with strict validation.

The JSON must have schema_version: 1, an experiments array, and a runs array. Unknown fields are rejected. All experiment and run ids must be unique, and every run must reference an existing experiment.

#
TrackingStore::get_experiment

fn TrackingStore::get_experiment(self : TrackingStore, id : String) -> Result[Experiment, TrackingError]

Return a detached copy of an experiment by id.

#
TrackingStore::get_run

fn TrackingStore::get_run(self : TrackingStore, run_id : String) -> Result[Run, TrackingError]

Return a detached copy of a run by id.

#
TrackingStore::import_run

fn TrackingStore::import_run(self : TrackingStore, run : Run) -> Result[Unit, TrackingError]

Import a pre-constructed run directly into the store.

This bypasses the normal start_run lifecycle and is intended for JSON import tools that reconstruct historical state. Duplicate run ids are rejected.

#
TrackingStore::kill_run

fn TrackingStore::kill_run(self : TrackingStore, run_id : String, end_time : String) -> Result[Run, TrackingError]

Transition a run to Killed.

#
TrackingStore::lineage_json

fn TrackingStore::lineage_json(self : TrackingStore, lineage : LineageTracker, experiment_id : String) -> Result[String, TrackingError]

Export a JSON representation of the lineage tree.

#
TrackingStore::lineage_tree_markdown

fn TrackingStore::lineage_tree_markdown(self : TrackingStore, lineage : LineageTracker, experiment_id : String) -> Result[String, TrackingError]

Export a run lineage tree as a Markdown nested list.

#
TrackingStore::list_experiments

fn TrackingStore::list_experiments(self : TrackingStore) -> Array[String]

Return a detached list of all experiment ids.

#
TrackingStore::list_runs

fn TrackingStore::list_runs(self : TrackingStore) -> Array[String]

Return all run ids in the store.

#
TrackingStore::log_artifact

fn TrackingStore::log_artifact(self : TrackingStore, run_id : String, artifact : Artifact) -> Result[Unit, TrackingError]

Log an artifact on a run.

#
TrackingStore::log_metric

fn TrackingStore::log_metric(self : TrackingStore, run_id : String, metric : Metric) -> Result[Unit, TrackingError]

Log a metric on a run.

#
TrackingStore::log_param

fn TrackingStore::log_param(self : TrackingStore, run_id : String, param : Param) -> Result[Unit, TrackingError]

Log a parameter on a run. If a parameter with the same key already exists, it is replaced.

#
TrackingStore::metric_correlation

fn TrackingStore::metric_correlation(self : TrackingStore, experiment_id : String, key_a : String, key_b : String) -> Result[Double, TrackingError]

Compute the Pearson correlation coefficient between two metrics across all runs in an experiment.

Only runs that have both metrics are considered. At least 2 data points are required.

#
TrackingStore::metric_summary

fn TrackingStore::metric_summary(self : TrackingStore, experiment_id : String, metric_key : String) -> Result[MetricSummary, TrackingError]

Compute a comprehensive metric summary for a specific metric key across all runs in an experiment.

Only the latest metric value for each run is considered. Runs without the specified metric are skipped.

#
TrackingStore::metrics_csv

fn TrackingStore::metrics_csv(self : TrackingStore, experiment_id : String) -> Result[String, TrackingError]

Export metrics for all runs in an experiment as CSV.

#
TrackingStore::new

Build an empty tracking store.

#
TrackingStore::run_count

fn TrackingStore::run_count(self : TrackingStore) -> Int

Return the number of runs.

#
TrackingStore::run_markdown

fn TrackingStore::run_markdown(self : TrackingStore, run_id : String) -> Result[String, TrackingError]

Render a detailed Markdown report for a single run.

#
TrackingStore::run_status_summary

fn TrackingStore::run_status_summary(self : TrackingStore) -> Map[String, Int]

Count experiments by status of their runs.

Returns a map from run status label string to the count of runs with that status across all experiments.

#
TrackingStore::runs_for_experiment

fn TrackingStore::runs_for_experiment(self : TrackingStore, experiment_id : String) -> Array[Run]

Return all runs belonging to an experiment.

#
TrackingStore::search_experiments

fn TrackingStore::search_experiments(self : TrackingStore, filter : ExperimentSearchFilter) -> Array[Experiment]

Search experiments in the store that match the given filter.

#
TrackingStore::search_runs

fn TrackingStore::search_runs(self : TrackingStore, filter : RunFilter, sort : SortKey?) -> Array[Run]

Search runs in the store that match the given filter. Returns detached copies sorted by the given sort key (if any).

#
TrackingStore::set_reproducibility

fn TrackingStore::set_reproducibility(self : TrackingStore, run_id : String, info : ReproducibilityInfo) -> Result[Unit, TrackingError]

Set reproducibility info on a run.

#
TrackingStore::start_run

fn TrackingStore::start_run(self : TrackingStore, run_id : String, experiment_id : String, start_time : String) -> Result[Run, TrackingError]

Start a new run in Running status. Rejects duplicate run ids and unknown experiment ids.

#
TrackingStore::statistics_report

fn TrackingStore::statistics_report(self : TrackingStore, experiment_id : String) -> Result[String, TrackingError]

Generate a comprehensive statistics report in Markdown format.

Includes metric summaries (count, min, max, mean, median, std dev) and pairwise metric correlations.

#
TrackingStore::summary

fn TrackingStore::summary(self : TrackingStore) -> String

Return a summary of the store's contents as a human-readable string.

#
TrackingStore::tag_summary

fn TrackingStore::tag_summary(self : TrackingStore) -> Map[String, Int]

Count experiments by tag.

Returns a map from tag to the count of experiments with that tag.

#
TrackingStore::to_json

fn TrackingStore::to_json(self : TrackingStore) -> String

Render the entire tracking store as a JSON string.

#
TrackingStore::to_markdown

fn TrackingStore::to_markdown(self : TrackingStore) -> String

Render a human-readable Markdown report for the entire tracking store.

#
TrackingStore::total_artifact_count

fn TrackingStore::total_artifact_count(self : TrackingStore) -> Int

Return the total number of artifacts across all runs.

#
TrackingStore::total_metric_count

fn TrackingStore::total_metric_count(self : TrackingStore) -> Int

Return the total number of metrics across all runs.

#
TrackingStore::total_param_count

fn TrackingStore::total_param_count(self : TrackingStore) -> Int

Return the total number of parameters across all runs.

#
TrackingStore::validate

Validate the entire tracking store for data integrity.

Checks performed:
  • Experiments have non-empty names
  • Experiments have non-empty ids
  • Runs have non-empty ids
  • Runs reference existing experiments
  • Runs have at least one metric (warning)
  • Runs have at least one parameter (warning)
  • Runs have reproducibility info (warning)
  • Metric steps are non-negative
  • Artifacts have non-empty paths

#
ValidationIssue

pub struct ValidationIssue {
// private fields
} derive(
Debug
)

A single validation issue found during store validation.

#
ValidationIssue::code

fn ValidationIssue::code(self : ValidationIssue) -> String

Return the issue code (e.g. "empty_experiment_name").

#
ValidationIssue::experiment_id

fn ValidationIssue::experiment_id(self : ValidationIssue) -> String?

Return the experiment id associated with this issue, if any.

#
ValidationIssue::message

fn ValidationIssue::message(self : ValidationIssue) -> String

Return the human-readable issue message.

#
ValidationIssue::new

fn ValidationIssue::new(severity : ValidationSeverity, code : String, message : String) -> ValidationIssue

Build a validation issue with the given severity, code, and message.

#
ValidationIssue::run_id

fn ValidationIssue::run_id(self : ValidationIssue) -> String?

Return the run id associated with this issue, if any.

#
ValidationIssue::severity

Return the severity level.

#
ValidationIssue::with_experiment_id

fn ValidationIssue::with_experiment_id(self : ValidationIssue, experiment_id : String) -> ValidationIssue

Attach an experiment id to this issue.

#
ValidationIssue::with_run_id

fn ValidationIssue::with_run_id(self : ValidationIssue, run_id : String) -> ValidationIssue

Attach a run id to this issue.

#
ValidationResult

pub struct ValidationResult {
// private fields
} derive(
Debug
)

The result of validating a tracking store.

#
ValidationResult::add_issue

fn ValidationResult::add_issue(self : ValidationResult, issue : ValidationIssue) -> Unit

Add an issue to the result.

#
ValidationResult::count_by_severity

fn ValidationResult::count_by_severity(self : ValidationResult, severity : ValidationSeverity) -> Int

Return the number of issues with the given severity.

#
ValidationResult::error_count

fn ValidationResult::error_count(self : ValidationResult) -> Int

Return the number of error-severity issues.

#
ValidationResult::is_valid

fn ValidationResult::is_valid(self : ValidationResult) -> Bool

Return true if there are no error-severity issues.

#
ValidationResult::issue_count

fn ValidationResult::issue_count(self : ValidationResult) -> Int

Return the total number of issues.

#
ValidationResult::issues

Return a detached copy of all validation issues.

#
ValidationResult::new

Build an empty validation result.

#
ValidationResult::summary

fn ValidationResult::summary(self : ValidationResult) -> String

Generate a human-readable summary of the validation result.

#
ValidationResult::warning_count

fn ValidationResult::warning_count(self : ValidationResult) -> Int

Return the number of warning-severity issues.

#
ValidationSeverity

pub(all) enum ValidationSeverity {
Error
Warning
} derive(Eq,
Debug
)

Severity level for a validation issue.

#
ValidationSeverity::kind

fn ValidationSeverity::kind(self : ValidationSeverity) -> String

Return a stable machine-readable severity kind string.

#
ValidationSeverity::label

fn ValidationSeverity::label(self : ValidationSeverity) -> String

Return a stable human-readable severity label.

#
array_contains_string

fn array_contains_string(arr : Array[String], s : String) -> Bool

Check if an array contains a string.

#
median_doubles

fn median_doubles(values : Array[Double]) -> Double

Compute the median of a non-empty array of doubles.

#
percentile_doubles

fn percentile_doubles(values : Array[Double], p : Double) -> Double

Compute the p-th percentile (0-100) using linear interpolation.

#
sort_doubles

fn sort_doubles(values : Array[Double]) -> Array[Double]

Sort a copy of the input array in ascending order using selection sort.