Fast workspace tools for multi-repo management.
pip install fastws-cliCreate a repos.txt file listing your repos (one per line):
AnswerDotAI/fastcore
AnswerDotAI/fastgit
AnswerDotAI/fastship
AnswerDotAI/fastws
Clone all repos from your repos file:
ws-clone
ws-clone --repos-file myrepos.txt
ws-clone --workers 8Pull updates for all repos (parallel):
ws-pullShow uncommitted changes and unpushed commits:
ws-status
ws-status --branchesCheck if all repos are on the expected branch:
ws-branches
ws-branches --expected developSync the workspace metadata, pull local repos, and install updates.
By default it uses the active venv parent as the workspace root, so you do not need to cd first.
It respects tool.uv.workspace.members and exclude when scanning local projects, and if any
member directory isn't a Python project yet (no pyproject.toml, e.g. a fresh empty clone), it
warns and skips the uv sync step instead of letting uv fail on the whole workspace.
At most once per day (tracked by a stamp file inside the workspace's .git, so git never
sees it), the sync also floats dependencies: uv sync -U instead of plain uv sync, plus
a parallel cargo update in every member with a Cargo.toml, printing what moved. Pass
--upgrade to force that pass regardless of when it last ran.
ws-sync
ws-sync --workspace ~/aai-ws
ws-sync --upgradeAdd a repo to repos.txt, then run ws-sync. Given owner/repo, it clones; given the
name of an existing local folder (e.g. one just scaffolded with nbdev-new or ship-new),
it resolves owner/repo from the folder's origin remote instead, telling you exactly
what's missing if the folder has no git repo, no GitHub origin, or no pyproject.toml:
ws-add AnswerDotAI/fastws
ws-add answerdotai/fastws
ws-add fastws # existing local folder, resolved via its origin remoteRemove a repo: delete its clone, and drop it from repos.txt and the workspace
pyproject.toml, then run uv sync. It refuses if the directory has uncommitted
changes, unpushed commits, no origin remote, or isn't a clean git checkout, and
always prompts for confirmation before deleting anything:
ws-remove AnswerDotAI/fastws
ws-remove fastws # bare folder name also works if the directory existsReport repos with commits since their newest GitHub release, so nothing reviewed sits unshipped:
ws-releases # sweep every repo in repos.txt
ws-releases solveit # only solveit's transitive workspace dependencies
ws-releases --skip 'wip' # extra start-of-message regex for commits that need no releaseEach pending repo lists its unreleased commit summaries; repos with no releases yet get one quiet no releases: line, and fully-released repos appear in up to date:. The newest release is picked by version number (publish timestamps can be out of order), and repos whose default branch isn't main are handled automatically.
Commits whose message matches a start-anchored regex from the skip set need no release and aren't reported. The built-in set covers version bumps and housekeeping (bump, nbdev regen, .gitignore, docs, CI, ...: DEFAULT_SKIP in fastws.releases); [tool.fastws] in the workspace root pyproject.toml adds to it, and names repos that should never be swept (apps that deploy rather than release):
[tool.fastws]
release_skip = ["docs only"]
release_exclude = ["solveit", "md_site"]From Python (the primary interface - the CLI is a thin wrapper over fastws.releases):
from fastws import check_releases, check_release
await check_releases() # ReleaseReport: the repr is the report
await check_releases('solveit') # dependency-closure mode
await check_release('mdhtml') # one repo: list of unreleased commit summaries (None = no releases)