Skip to content
/ sprout Public

Sprout is a tiny and completely local tool for managing machine learning runs and experiments. It uses BorgBackup under the hood to snapshot and deduplicate experiment folders, keeping your models, logs, and checkpoints consistent without heavy frameworks or cloud dependencies

Notifications You must be signed in to change notification settings

rouming/sprout

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 

Repository files navigation

🌱 Sprout - Local AI Runs Manager

Sprout is a tiny, hackable, and completely local tool for managing machine learning runs and experiments. It uses BorgBackup under the hood to snapshot and deduplicate experiment folders, keeping your models, logs, and checkpoints consistent without heavy frameworks or cloud dependencies.


Motivation

When training reinforcement learning agents or fine-tuning models, it's easy to end up with dozens of runs - each slightly different in configuration, parameters or seed. Keeping them organized, reproducible, and comparable is tedious.

Sprout was built to be simple and local-first:

  • One file - ~2k lines of Python, easy to read and modify
  • Fully local - stores everything in plain folders and Borg archives
  • Snapshotting with deduplication - each run is an immutable state stored efficiently by Borg
  • Human-friendly structure - make runs active, compare folders, or restore states easily
  • Integrates with your workflow - especially handy when dumping or restoring Torch models

It's designed to be hackable, scriptable, and available as an API - ideal for personal workflows and small research projects.

For example, the following code can be used to create a snapshot of an existing model before training starts:

# Create Sprout instance
spr = sprout.Sprout("models")

# Build a model directory using any model name
model_dir = os.path.join("models/active", model_name)

if not os.path.isdir(model_dir):
    # Create a model state specifying the model name and all model parameters
    spr.create(group=group_name, head=model_name, params_str=model_params)
elif not args.cont:
    # Create a snapshot of the model state
    spr.create(from_head=model_name, params_str=model_params)

Requirements

  • Python 3.9+
  • BorgBackup CLI tool (borg) available in your $PATH

Install Borg (Debian/Ubuntu):

sudo apt install borgbackup

Or via pip (optional Python wrapper):

pip install borgbackup

How Sprout organizes a working directory

Sprout expects a working directory (we'll call it WORK/). Typical layout:

WORK/
├── .borg/          # Borg repository (snapshots)
├── .heads/         # Active states (folders restored for work)
├── active/         # Symlinks pointing to current active runs
└── metadata.json   # Run metadata (models, runs, parents, params)
  • .heads/ contains the actual restored folders (active states).
  • active/ contains human-friendly symlinks (e.g. active/A -> .heads/<runid>).
  • Borg archives are stored in .borg.

Common Commands

All commands require --working WORK to point to a working folder.

create

Create a new run (fresh or fork from an existing run):

./sprout.py --working WORK create ModelA
./sprout.py --working WORK create --from RUN_ID
./sprout.py --working WORK create --from RUN_ID --head A --params "--lr 0.01" --description "note"

--head makes the new run active under a human-friendly name (creates a symlink in active/).

persist

Persist a head back into Borg and remove its working folder:

./sprout.py --working WORK persist HEAD_NAME
# or persist all:
./sprout.py --working WORK persist

remove

Remove runs, branches, heads, or entire models. Use --whole-branch to delete recursively.

./sprout.py --working WORK remove RUN_ID
./sprout.py --working WORK remove --model ModelA
./sprout.py --working WORK remove --head A
./sprout.py --working WORK remove RUN_ID --force

edit

Edit alias, created date, params (table style), and description in your $EDITOR. Template is YAML-style and params is a block:

./sprout.py --working WORK edit RUN_ID

Example editor contents:

alias: quick-run
created: 2025-09-22T11:07:39
params: |
  lr = 5e-05
  batch_size = 10240
  frames = 50000000
description: |
  Short free-form description.
  Keep indentation of this block.

If description is left unchanged from the template, it will be stored as empty.

log / tree

Pretty-print hierarchical run tree with inline short param summary and active-head markers:

./sprout.py --working WORK log
# or
./sprout.py --working WORK tree

Symbols used:

  • - active head (green in terminals that support color)
  • - no params
  • - params exist but unchanged vs parent
  • Δ - shows which params changed (short summary)

history

Show ancestry chain for a run and parameter diffs:

./sprout.py --working WORK history RUN_ID

verify

Check consistency between Borg archives, metadata.json, .heads/, and active/ symlinks. Detect missing or extra runs.


Output formats

Sprout provides two main human-facing views:

  • Tree (tree) - hierarchical, shows ancestry and active heads with simple param diffs inline.

  • Flat list (log) - compact, one-line-per-run summary with parent and short param summary (good for quick scanning or scripting).

Both formats aim to be terminal-friendly and easy to parse visually.


Design & Implementation notes

  • Single-source approach: the main implementation is intentionally kept in one file (easy to inspect and modify).
  • Metadata: stored as JSON under .borg/metadata.json to keep everything inside the Borg repo.
  • Heads vs active: .heads/ stores restored run folders; active/ contains symlinks that name those active folders.
  • Borg usage: Sprout relies on Borg for create, extract, and delete operations. You should have Borg installed and available in $PATH.
  • No background work: Sprout runs commands synchronously - no daemon or server process required.

Tests

The sprout.py source file includes basics unit-tests, which can be executed as follows:

./sprout.py test

License

MIT License - use, modify, and share.


Contributing

PRs, issues, and feature suggestions are welcome. If you want help splitting into modules, adding a tiny UI, or integrating with other tools, open an issue or submit a PR.


About

Sprout is a tiny and completely local tool for managing machine learning runs and experiments. It uses BorgBackup under the hood to snapshot and deduplicate experiment folders, keeping your models, logs, and checkpoints consistent without heavy frameworks or cloud dependencies

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages