Whitelist-driven cleanup for shared Skyrim modlist archive directories (Wabbajack + Nolvus)
Project description
mod-sweep
Whitelist-driven cleanup for a Skyrim archive directory shared by multiple
modlists (Wabbajack lists + Nolvus). Mod Sweep builds a union whitelist
from your modlist manifests, classifies every file in the downloads
directory against it, and sweeps only the true leftovers. Nothing is
deleted outright: sweeps move candidates to a restorable quarantine, and
only purge (or an explicit sweep --apply --delete) is permanent.
Installation
- Standalone executables (no Python required): grab the archive for
your platform from the latest release -
each contains the
modsweepCLI and themodsweep-guiapp. - PyPI:
uv tool install "modsweep[gui]"(orpipx install "modsweep[gui]") installs both commands; drop the[gui]extra for the CLI only. Upgrade later withuv tool upgrade modsweep. - From source: clone,
uv sync --extra gui, thenuv run modsweep/uv run modsweep-gui.
Quick start
modsweep.toml declares the downloads dir, the active sources of truth,
and the quarantine dir - with it in place the commands need no arguments.
Start from modsweep.example.toml, or let the
GUI's Edit Config dialog write the file for you (new users never need to
touch TOML). Then:
modsweep report # read-only inventory: what is protected, what is left over
modsweep hash --only-candidates # hash-check the leftovers (the pre-sweep safety gate)
modsweep sweep # dry run: preview exactly what would be quarantined
modsweep sweep --apply # move candidates to a restorable quarantine batch
modsweep restore <batch-dir> # change your mind
modsweep purge # age out old batches (dry run; --apply to act)
(Running from source, prefix with uv run.) Every command takes
--log-level debug|info for diagnostics, and modsweep <cmd> --help
documents its flags.
How it stays safe
- Forgetting a list keeps its files. Every manifest found is active by
default; only explicit action (an exclude, an old version losing under
latest_only) exposes files for sweeping - and every resolution decision is announced, never silent. - The hash gate. Wabbajack renames archives on disk, so name-only matching produces false candidates. Sweeps refuse any file whose hash was never verified against the whitelist; renamed archives a list still needs are rescued by hash.
- Quarantine first. Sweeps move files into timestamped batches with a
restore manifest;
restoreputs a batch back untouched. Purging is a separate, dry-run-by-default step with a trust period.
Documentation
- Usage guide - every command and config key in depth: source resolution and retirement, the hashing policy, quarantine lifecycle, snapshots, drift detection, manifest formats.
- GUI tour - the desktop app: source tree states, report tables, config editor, per-file actions, restore/purge semantics.
- Maintaining - release procedure, manifest bumps, CI notes.
Bundled Nolvus manifests
Nolvus InstallPackage.xml files are not distributed publicly, so this
project bundles them (gzipped) as package data - please do not contact
the Nolvus author for these files; new guide releases are contributed to
this project instead. The bundled entry in the nolvus config key
resolves to the shipped manifests plus in-app updates
(modsweep update-manifests / Tools > Update Nolvus Manifests), fetched
straight from this repository - no new executable required for a manifest
bump.
Platform support
Cross-platform is a standing requirement: Windows is the primary platform, Linux support matters (modlist tooling increasingly runs there), and macOS must not be broken even though MO2 itself doesn't run on it. Concretely:
- All filesystem work goes through
pathlib/os- no OS-specific APIs. - Relative paths inside modsweep (scan results, sweep batches, CSVs) use
/on every platform;pathlibaccepts it on Windows too. - Name matching is case-insensitive (Windows semantics). On case-sensitive filesystems this only errs toward keeping files - the safe direction.
meta.inivalues may contain Windows-style paths even when read on POSIX (installs created under Wine/Proton), so they are split on both separators.- Console output sticks to ASCII; file output is UTF-8.
Development
uv run pytest runs the suite (~96% coverage with --cov=modsweep): unit
tests per module, property-based tests for version ordering, GUI smoke
tests (offscreen), and end-to-end tests that drive the CLI through the
full lifecycle - classification, hash-gate refusal, hashing, sweep,
restore, and purge aging. uvx ruff check and uv run pyright must stay
clean; CI enforces both and runs the tests on Windows/Linux/macOS plus
Debian and Arch containers, on Python 3.12, 3.14, and latest.
Acknowledgements
Special thank you to vektor9999 for sharing the Nolvus InstallPackages this project bundles.
License
MIT - do what you like with it, keep the attribution (the copyright notice in LICENSE).
Roadmap
- App self-update beyond notify-and-link (exe self-replacement) if users ask for it; package-manager installs already upgrade via uv/pipx.
- Performance note (settled): parsed manifests are cached under
.modsweep/manifest_cachekeyed by source size/mtime (12.5s to 0.9s resolution on the reference setup). File-level parallel hashing is deliberately skipped - hashing is drive-bound on HDDs - though reads and hashing are pipelined within each file. - Nolvus sibling list: the author's next guide is expected to use the same InstallPackage format - bundle its manifests as they are released.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file modsweep-0.2.2.tar.gz.
File metadata
- Download URL: modsweep-0.2.2.tar.gz
- Upload date:
- Size: 1.9 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
13a6f76b171971e552673ffb6bf2dd91f64f0bf00d1234a38a5d884b4cd92e35
|
|
| MD5 |
bc10df5aae3fbf05985bbddd8f121caf
|
|
| BLAKE2b-256 |
99d853e9ae5179f95ce24f9dc1cedbab6d249717bb06a95946bdc2128e06b215
|
Provenance
The following attestation bundles were made for modsweep-0.2.2.tar.gz:
Publisher:
release.yml on zspatter/mod-sweep
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
modsweep-0.2.2.tar.gz -
Subject digest:
13a6f76b171971e552673ffb6bf2dd91f64f0bf00d1234a38a5d884b4cd92e35 - Sigstore transparency entry: 2090454440
- Sigstore integration time:
-
Permalink:
zspatter/mod-sweep@c0105252e851e4719c57823dce51fe66232d21d7 -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/zspatter
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c0105252e851e4719c57823dce51fe66232d21d7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file modsweep-0.2.2-py3-none-any.whl.
File metadata
- Download URL: modsweep-0.2.2-py3-none-any.whl
- Upload date:
- Size: 1.8 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d00d73262c13afa6023e43d655a40c808f8411723b326b32a45203d403c25ce2
|
|
| MD5 |
f17b744ddeb033485f14323879f1aff5
|
|
| BLAKE2b-256 |
64909fd09ce655080b550b99b1cc8f26bdd9e4e01b394b91a0897e5862ec11e5
|
Provenance
The following attestation bundles were made for modsweep-0.2.2-py3-none-any.whl:
Publisher:
release.yml on zspatter/mod-sweep
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
modsweep-0.2.2-py3-none-any.whl -
Subject digest:
d00d73262c13afa6023e43d655a40c808f8411723b326b32a45203d403c25ce2 - Sigstore transparency entry: 2090454711
- Sigstore integration time:
-
Permalink:
zspatter/mod-sweep@c0105252e851e4719c57823dce51fe66232d21d7 -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/zspatter
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c0105252e851e4719c57823dce51fe66232d21d7 -
Trigger Event:
push
-
Statement type: