Reproduce a past run
Every Iteration can carry a 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. restore later writes that snapshot back to disk so the pinned dependency tree can be Pkg.instantiate-d in a fresh depot. Unlike a pip freeze file, which records version numbers and can re-resolve transitive dependencies on install, Manifest.toml pins each package to a specific version and tree hash, so Pkg.instantiate reinstalls the same package versions without re-resolving them.
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 a snapshot; child runs (HPO trials, distributed workers) skip it and rely on the driver's copy. The snapshot keyword overrides this default in either direction.
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.7"
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.7"
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_43yR2Z/iteration_18e9428b-7ae6-45d3-9b72-e35290a6d2c1", "1.12.7", "bdf032f10d4912e395fe26ff1c576aed3a2731a5", 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() reinstalls the same pinned package versions 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 is not captured
| Captured | Not captured |
|---|---|
Julia version (string(VERSION)) | OS / kernel / glibc |
| HEAD commit SHA + dirty bit | The 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 path | Runtime config files outside the project |
If git_dirty is true, the captured Manifest alone does not describe the code that ran: uncommitted source changes must be reapplied manually. Reproducible jobs should be run from a clean working tree, and the git_dirty flag records whether the tree was clean at capture time.