Reproducibility

A model result is only useful if it can be reproduced. DearDiary addresses this by capturing the full Julia environment at the moment a run starts and storing it alongside the iteration's metrics and parameters.

What gets captured

Each Iteration can hold an EnvironmentSnapshot:

FieldContent
julia_versionstring(VERSION) at capture time
git_shaHEAD commit SHA, or "" outside a git repo
git_dirtytrue when the working tree had uncommitted changes
entrypointPath of the running script (PROGRAM_FILE), or "" in the REPL
project_tomlVerbatim Project.toml of the active environment
manifest_tomlVerbatim Manifest.toml of the active environment

The snapshot is taken by capture_environment and persisted on the iteration row by snapshot_environment!. Both functions never throw: a missing git repo, an unresolved environment, and a REPL session all degrade gracefully to empty strings.

Automatic capture

with_iteration calls snapshot_environment! right after creating the iteration, but only for driver (top-level) runs. Child iterations, created with parent_iteration_id set, skip the snapshot by default so HPO trials and distributed workers do not all capture redundant copies of the same environment. Pass snapshot=true to override.

Manual capture

To attach a snapshot outside the with_iteration flow, call snapshot_environment! directly:

iteration_id, _ = create_iteration(experiment_id)
snapshot_environment!(iteration_id)

capture_environment returns the snapshot struct without persisting it, which is useful for inspection or for shipping the capture across a process boundary in a distributed setup:

snap = capture_environment()
snap.julia_version  # "1.10.4"
snap.git_sha        # "a3f1c9..."

Restoring an environment

restore writes the captured Project.toml and Manifest.toml into a fresh directory. It does not activate the project or run Pkg.instantiate; those steps are left to the caller.

result = DearDiary.restore(iteration_id)

using Pkg
Pkg.activate(result.project_path)
Pkg.instantiate()

result is a RestoreResult that also carries julia_version, git_sha, git_dirty, and entrypoint, so you can check whether the captured commit was clean and optionally check out the exact SHA before re-running.

Why Manifest.toml over pip freeze

pip freeze records direct and transitive dependency versions as version constraints. On install, the solver re-runs and may pick different patch versions depending on what is available at that moment. Julia's Manifest.toml records the exact resolved tree, including hashes: Pkg.instantiate does not re-resolve, it fetches the pinned versions. The captured manifest reproduces the same tree regardless of how the registry has moved on since the original run.

For the complete how-to see Reproduce a past run.