weasel review
Weasel is Explosion's command-line workflow format for repository-based data and machine-learning projects. A project.yml file names assets, directories, variables, commands, file dependencies, outputs, ordered workflows, and remote stores. Its CLI can clone a template, fetch checked assets, skip work recorded as unchanged in project.lock, archive outputs to content-addressed remote paths, restore matching outputs, generate project documentation, and translate one workflow into DVC configuration. Version 1.0.0 moves its models to Pydantic 2, swaps requests for httpx, replaces typer-slim with an open-ended typer dependency, and opens dependency ranges. That last choice matters now: our clean install could not import weasel because Click was absent.
Do not depend on an unpinned `pip install weasel` today: our clean 1.0.0 environment installed successfully and then failed at import because Click was missing. It remains a narrow fit for existing Explosion-style workflows after you lock and verify a repaired dependency set.
We installed it
| Install | ✓ · 0.8s | 27 packages on disk · 26 MB |
| Import | ✗ | import weasel · pure Python · requires Python >=3.7 |
| Known vulns | 0 | (pip-audit) |
Answers from our run
Does weasel install cleanly?
Yes. In a fresh container with an empty cache, pip install weasel finished in 0.8s, leaving 27 packages and 26 MB on disk. pip-audit reported no known vulnerabilities.
What does weasel need to run?
Python >=3.7, and nothing compiled: it is pure Python. In our run import weasel failed, so it needs extra system packages.
weasel or dvc: which should you use?
dvc: Use it when datasets, models, remote versioning, reproducible stages, and a dependency graph are central rather than an optional export. Do not depend on an unpinned pip install weasel today: our clean 1.0.0 environment installed successfully and then failed at import because Click was missing.
When should you not use weasel?
You need a fresh install to run without repair. Our 1.0.0 import failed with ModuleNotFoundError for click after the resolver installed the declared dependencies
Use it if
- You already maintain spaCy Projects or Explosion templates and want their project.yml conventions in a standalone package
- A short ordered workflow for download, preprocessing, training, evaluation, and packaging is enough without a scheduler service
- File checksums and declared command strings can decide whether a local step needs to run again
- Your team benefits from Git-clonable templates and generated README sections tied to the actual workflow file
- You need a fresh install to run without repair. Our 1.0.0 import failed with ModuleNotFoundError for click after the resolver installed the declared dependencies
- You need dependency-graph scheduling, parallel stages, automatic upstream execution, retries, resource queues, or a web control plane. Weasel executes named workflow commands in listed order
- You need full data lineage or long-term model version management. The docs point advanced tracking to DVC and expose a generator for one DVC pipeline
- Your project commands rely on pipes, redirects, shell expansion, or shell built-ins. Weasel splits strings with shlex and calls subprocess without shell mode
- Remote storage must enforce retention automatically. Push stores new hash-addressed archives and the documentation leaves deletion of obsolete objects to the operator
- You expect spaCy Projects files to transfer unchanged. The migration notes remove old configuration keys and Git-version behavior and rename configuration overrides to WEASEL_CONFIG_OVERRIDES
Setup reality
We installed weasel 1.0.0 in a clean Python 3.12 container in 0.8 seconds. The environment contained 27 packages and used 26 MB. The distribution declared 9 direct dependencies, required Python 3.7 or newer, and shipped pure Python without py.typed. pip-audit found no known vulnerabilities. import weasel failed with ModuleNotFoundError: No module named 'click'. Since weasel imports Typer while creating its CLI, the installed command is not usable in that measured environment.
The 1.0.0 metadata requires typer>=0.3.0 but does not name Click directly. Current Typer metadata fetched during review also omitted Click, which explains how resolution can finish without the module that the import path needs. Installing Click explicitly addresses the missing name, but our lab did not rerun after changing the environment, so treat that as a workaround to verify in your own lockfile. Pin the complete resolved set rather than relying on Weasel's newly opened version ranges.
Every project needs project.yml. Template cloning invokes Git and uses the machine's existing access to public or private repositories. Asset URLs pass through smart-open, while remote output stores use cloudpathlib; S3 and GCS can require provider extras and credentials beyond Weasel's base install. Checksums are optional. Add them for downloaded or private assets when detecting the wrong file matters. Remote push keeps old hash-addressed archives, so storage cleanup is an operator task.
Commands are split into argument lists and launched without a shell. Map required environment names under env and interpolate ${env.NAME}; do not expect $NAME, pipes, or redirects to behave as they do in a terminal. project.lock records command text plus declared dependency and output checksums. An undeclared input can leave stale output marked unchanged. Running one command does not execute missing upstream commands, while workflows remain sequential. DVC export also requires DVC to be installed and initialized first.
Patterns
Make the missing runtime dependency explicit repair-missing-click
python -m pip install weasel click
python -c "import weasel; print(weasel.__version__ if hasattr(weasel, '__version__') else 'imported')"Our untouched install failed because click was missing. Adding Click targets that exact error, but the lab did not retest this modified environment; lock versions and run the import check before adopting it.
Clone one template directory clone-project-template
python -m weasel clone pipelines/tagger_parser_ud ./tagger-projectThe default source is Explosion's projects repository. A custom private repo uses your existing Git credentials, and sparse checkout support depends on the installed Git.
Track a preprocessing step define-tracked-command
commands:
- name: preprocess
help: Convert raw records
script:
- "python scripts/preprocess.py assets/raw.json corpus/train.json"
deps:
- scripts/preprocess.py
- assets/raw.json
outputs:
- corpus/train.jsonproject.lock can only account for files listed in deps and outputs. Add every input whose change should invalidate this result.
Fetch an asset only when needed download-checked-asset
assets:
- dest: assets/training.spacy
url: https://example.com/data.spacy
checksum: 63373dd656daa1fd3043ce166a59474c
# Fetch project assets
python -m weasel assets .The checksum is the value used in the upstream documentation example. Replace the URL and checksum together with values from your actual data source.
Mark a large download as extra keep-asset-optional
assets:
- dest: assets/development.spacy
url: gs://your-bucket/corpora
checksum: 5113dc04e03f079525edd8df3f4f39e3
extra: true
# Include optional assets
python -m weasel assets . --extraThe upstream example uses this checksum as a placeholder. A GCS URL can need cloud provider packages and credentials that the base Weasel install does not configure.
Name and execute a workflow run-ordered-workflow
workflows:
all:
- preprocess
- train
- package
# Commands run in this order
python -m weasel run all .A workflow is an ordered list, not a dependency graph. Failure stops the sequence, and independent steps are not scheduled in parallel.
Inspect a run without starting scripts preview-workflow
python -m weasel run all . --dryDry mode shows the planned command sequence. It cannot discover undeclared file dependencies or side effects hidden inside the scripts.
Ignore the lockfile decision once force-step-rerun
python -m weasel run train . --forceForce reruns the selected command even when its tracked state is unchanged. It does not delete previous local outputs or old remote archives.
Expose one environment value interpolate-environment
env:
MODEL_BUCKET: MODEL_BUCKET
commands:
- name: show-bucket
script:
- "python scripts/show_bucket.py ${env.MODEL_BUCKET}"The left name is used inside project.yml and maps to a process environment variable. Weasel does not launch a shell, so direct $MODEL_BUCKET expansion will not occur.
Archive outputs to a named remote push-command-outputs
remotes:
default: s3://my-weasel-bucket
# Push existing declared outputs
python -m weasel push default .Weasel addresses archives with output path, command context, dependencies, and content hashes. It does not remove older objects from the remote.
Pull only compatible cached results restore-matching-outputs
python -m weasel pull default .Pull compares the current output path, command string, and dependency hashes. A cached artifact created from different inputs is left alone.
Export one workflow to DVC generate-dvc-config
git init
dvc init
python -m weasel dvc . allInstall DVC separately and initialize the repository first. The Weasel docs say a DVC project accepts one generated pipeline, so select the intended workflow.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| dvc | PyPI | Use it when datasets, models, remote versioning, reproducible stages, and a dependency graph are central rather than an optional export |
| kedro | PyPI | Use it for a structured Python data application with named datasets, modular pipelines, hooks, and a larger project framework |
| doit | PyPI | Use it for general Python task automation with dependency-aware incremental execution outside Explosion's ML project convention |
More cli & tooling guides
chalk · commander · typescript · esbuild · yargs · click · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

