Reproduce a past run

Every Iteration can carry a bit-exact snapshot of the Julia environment that produced it: julia_version, the HEAD commit SHA, the verbatim Project.toml and Manifest.toml active at run start, and the entrypoint script. Months later, restore writes that snapshot back to disk so the exact dependency tree can be Pkg.instantiate-d in a fresh depot. Other ML trackers capture environments as pip freeze strings that re-resolve transitive dependencies on install. Julia's Manifest.toml is byte-exact, so the captured tree round-trips with no resolution drift.

Capture happens automatically on the driver iteration

DearDiary.with_iteration calls snapshot_environment! right after creating the iteration, but only when the new run has no parent. Driver runs capture; child runs (HPO trials, distributed workers) inherit. Override with the snapshot keyword for different behavior.

julia> project_id, _ = create_project("Repro Project");
julia> experiment_id, _ = create_experiment(project_id, DearDiary.IN_PROGRESS, "Training");
julia> iteration_id = DearDiary.with_iteration(experiment_id) do iter create_parameter(iter.id, "lr", 1e-3) iter.id end;
julia> iteration = get_iteration(iteration_id);
julia> iteration.julia_version"1.12.6"
julia> iteration.git_sha |> length40
julia> iteration.entrypoint, iteration.git_dirty("docs/make.jl", false)

Capture an iteration manually

To attach a snapshot outside the with_iteration flow (for example, in a long-lived service that opens iterations imperatively), call snapshot_environment! directly:

julia> manual_id, _ = create_iteration(experiment_id);
julia> DearDiary.snapshot_environment!(manual_id; entrypoint="train.jl");
julia> get_iteration(manual_id).entrypoint"train.jl"

DearDiary.capture_environment returns the snapshot without persisting it, useful for inspection or shipping the capture across a process boundary:

julia> snapshot = DearDiary.capture_environment();
julia> snapshot.julia_version"1.12.6"

Replay an environment

restore writes the captured Project.toml and Manifest.toml into a fresh directory under depot. It does not activate the project or run Pkg.instantiate. That is left to the caller so the function stays side-effect-free outside the temp tree.

julia> depot = mktempdir();
julia> result = DearDiary.restore(iteration_id; depot=depot)RestoreResult("/tmp/jl_dM1Akv/iteration_1", "1.12.6", "8aba6a9fb5e303d76908bfce5877228738ff9cf7", false, "docs/make.jl")
julia> isfile(joinpath(result.project_path, "Project.toml")), isfile(joinpath(result.project_path, "Manifest.toml"))(true, true)

The on-disk files are byte-identical to what was captured. Loading them with using Pkg; Pkg.activate(result.project_path); Pkg.instantiate() reconstructs the exact dependency tree the iteration ran against:

using Pkg
Pkg.activate(result.project_path)
Pkg.instantiate()
# ...then optionally check out the captured commit and run the entrypoint:
# `git checkout $(result.git_sha)` and `julia --project=$(result.project_path) $(result.entrypoint)`

What is and isn't captured

CapturedNot captured
Julia version (string(VERSION))OS / kernel / glibc
HEAD commit SHA + dirty bitThe actual code if git_dirty == true and changes are uncommitted
Active Project.toml (verbatim)Per-package C library versions outside the JLL system
Active Manifest.toml (verbatim)Datasets used by the run (separate concern)
Entrypoint script pathRuntime config files outside the project

If git_dirty is true, the captured Manifest alone is not sufficient for full reproducibility. Uncommitted source changes must be reapplied manually. Run reproducible jobs from a clean working tree; the snapshot lets you verify after the fact whether the tree was clean.