| Crates.io | sprout-cli |
| lib.rs | sprout-cli |
| version | 0.1.0 |
| created_at | 2025-10-20 09:42:35.572171+00 |
| updated_at | 2025-10-20 09:42:35.572171+00 |
| description | A symlink and source dependency manager that just works |
| homepage | https://github.com/patwie/sprout |
| repository | https://github.com/patwie/sprout |
| max_upload_size | |
| id | 1891688 |
| size | 322,074 |
... because "just works" beats "highly configurable" every single time.
Sprout is a symlink and source dependency manager that just works. It's boring in the best possible way.
All I wanted was to organize my dotfiles and tools. Then I blinked, and
suddenly I had a new Rust CLI and very strong opinions about symlinks. Could've
gone outside, touch grass. Instead I implemented ln -s, but in fancy and with
unit tests and colors.
You might be wondering: Why build yet another symlink tracker and source-based dependency manager? Why reinvent the wheel, the wrench, and the garage it lives in? Well...
Sprout is simpler! It stays out of your way and does exactly what you ask: track configs, fetch sources, and builds dependencies. All versioned. All in one place. All in plain sight. No templating languages. No Turing-complete DSLs. No server orchestration cosplay just to install Neovim.
Just you, your tools, and your ${HOME} ... sprouted by hand.
/sprout/symlinkssprout symlinks add [--recursive] creates a symlink back to $HOMEsprout symlinks status [--all] shows modifications, deletions, and optionally up-to-date filessprout symlinks restore repairs any missing or broken symlinkssprout symlinks rehash recalculates symlink hashes after manual changessprout symlinks undo <path> removes symlinks and copies files back to original location.gitignore and .sproutignoremanifest.sproutsprout modules fetch [package] pulls and unpacks dependenciesmanifest.sproutsprout modules build [package] [--dry-run] runs it in context (or just prints a readyβtoβrun script)sprout modules install [package] fetches and builds in one stepsprout modules status [--expand] [--all] shows module status with build information and dependenciessprout modules hash [-i] computes and displays/updates module hashessprout modules clean [--dry-run] removes unused cache/source directoriesmanifest.sproutsprout env edit [environment] interactively edit environment (toggle modules)sprout env list [environment] list environment sets and their modulessprout env generate [environment] generate environment export statements for a specific set/sprout)sprout init --empty [path]
module cmake {
depends_on = []
exports = {
PATH = "/bin"
}
fetch {
http = {
url = [https://github.com/Kitware/CMake/releases/download/v4.0.3/cmake-4.0.3-linux-x86_64.tar.gz](https://github.com/Kitware/CMake/releases/download/v4.0.3/cmake-4.0.3-linux-x86_64.tar.gz)
}
}
build {
ln -sf ${SOURCE_PATH}/cmake-4.0.3-linux-x86_64/bin ${DIST_PATH}
}
}
module gcc {
depends_on = []
exports = {
PATH = "/bin"
}
fetch {
http = {
url = [https://mirrors.ibiblio.org/gnu/gcc/gcc-15.1.0/gcc-15.1.0.tar.xz](https://mirrors.ibiblio.org/gnu/gcc/gcc-15.1.0/gcc-15.1.0.tar.xz)
}
}
build {
cd gcc-15.1.0
./contrib/download_prerequisites
mkdir -p build
cd build
../configure --disable-multilib --enable-languages=c,c++ --prefix=${DIST_PATH}
make -j8
make install
}
}
environments {
default = [cmake, gcc]
}
sprout modules install cmake
sprout modules install gcc
.zshrc):eval "$(sprout env generate)"
sprout status shows complete status (modules, symlinks, and git)sprout commit [-m "message"] commits all changes to gitsprout push pushes changes to remote git repositorysprout edit [path] edits manifest.sprout with $EDITOR and validates syntaxsprout format [-i] [path] verifies and reformats manifest.sprout/sprout
βββ symlinks/ # Tracked symlinks
β βββ .zshrc
βββ sprout.lock # Lockfile (portable hashes)
βββ dist/ # Build artifacts (install output)
β βββ neovim/
β βββ ...
β βββ ripgrep/
βββ sources/
β βββ git/ # Git repos (as submodules)
β βββ http/ # Extracted HTTP downloads (tarballs, zip files)
βββ cache/
β βββ http/ # Cached downloads (.tar.gz, .zip, etc.)
βββ manifest.sprout # Metadata manifest (alphabetically sorted)
βββ .gitignore # Sensible defaults
βββ .git # Your own Git repo (optional)
Dependencies in manifest.sprout can declare environment variables they need:
Note: Comments in .sprout files start with #. However, Sprout may
reformat the manifest when adding/removing modules, which will remove comments.
Keep important documentation in a separate README or inline in build scripts.
See the example manifest.
When you run sprout env, it generates shell export statements.
Sprout includes a Tree-sitter grammar for syntax highlighting .sprout files.
cd tree-sitter-sprout
tree-sitter generate
tree-sitter build
# Copy queries to Neovim config
mkdir -p ~/.config/nvim/queries/sprout
cp queries/*.scm ~/.config/nvim/queries/sprout/
# Add to your Neovim config (init.lua)
vim.filetype.add({
extension = { sprout = "sprout" },
})
local parser_config = require("nvim-treesitter.parsers").get_parser_configs()
parser_config.sprout = {
install_info = {
url = "~/git/github.com/patwie/sprout/tree-sitter-sprout",
files = {"src/parser.c"},
},
filetype = "sprout",
}
Note: Neovim loads queries from ~/.config/nvim/queries/sprout/ first,
then from nvim-treesitter's cache. After updating the grammar, copy the updated
queries to both locations and restart Neovim.
# Add to ~/.config/tree-sitter/config.json
{
"parser-directories": [
"/path/to/sprout/tree-sitter-sprout"
],
"language-associations": {
"sprout": "sprout"
}
}
# Test highlighting
tree-sitter highlight file.sprout