projscan
Scanner for local git repositories and uv tools installed from git.
Answers one simple question: am I up to date?
Quick start
No installation needed — run directly with uvx:
uvx projscan repos .
uvx projscan tools
Installation
uv tool install projscan
Or in development mode:
git clone ...
cd projscan
uv sync
uv run projscan --help
Commands
projscan repos [PATHS]...
Recursively scans one or more directories and displays the status of each git repository.
╭──────────────────────┬─────────┬─────────┬─────────────────────┬────────┬────────────────────┬─────────────╮
│ Name │ Version │ Branch │ Status │ Commit │ Message │ When │
├──────────────────────┼─────────┼─────────┼─────────────────────┼────────┼────────────────────┼─────────────┤
│ my-api │ 2.1.0 │ main │ behind (↓3) │ a4f2c1 │ fix: timeout retry │ 2 days ago │
│ my-dashboard │ 1.0.0 │ main │ diverged (↓1 ↑2) │ b8e3d9 │ feat: dark mode │ 5 hours ago │
│ projscan │ 0.1.0 │ main │ up to date │ c1a2b3 │ initial commit │ 1 hour ago │
╰──────────────────────┴─────────┴─────────┴─────────────────────┴────────┴────────────────────┴─────────────╯
3 repos, 1 up to date, 2 to update
Options:
| Option | Description |
|---|---|
--no-fetch |
Skip git fetch — use local cache (fast) |
--depth INTEGER |
Max recursion depth (default: 3) |
--json |
Machine-readable JSON output |
--concurrency INTEGER |
Parallel scans (default: 16) |
# Scan ~/code and ~/work
projscan repos ~/code ~/work
# Fast, no network
projscan repos --no-fetch ~/code
# Pipe JSON to jq
projscan repos --no-fetch --json ~/code | jq '.[] | select(.status != "up to date")'
projscan tools
Scans tools installed via uv tool install git+https://... and checks whether updates are available (via git ls-remote, without cloning).
╭────────────────┬─────────┬───────────────────────────────┬────────┬──────────┬────────────────╮
│ Name │ Version │ Source │ Ref │ Commit │ Status │
├────────────────┼─────────┼───────────────────────────────┼────────┼──────────┼────────────────┤
│ my-tool │ 1.2.0 │ github.com/org/my-tool.git │ main │ f10c2123 │ update avail. │
│ other-tool │ 0.9.1 │ github.com/org/other-tool.git │ main │ fc9e74c5 │ up to date │
╰────────────────┴─────────┴───────────────────────────────┴────────┴──────────┴────────────────╯
2 tools, 1 up to date, 1 to update
Options:
| Option | Description |
|---|---|
--tool-dir PATH |
uv tools root directory (auto-detected by default) |
--no-remote |
List locally without checking remotes |
--json |
Machine-readable JSON output |
projscan tools
projscan tools --no-remote --json
projscan tools --tool-dir ~/.local/share/uv/tools
Exit codes
| Code | Meaning |
|---|---|
0 |
Everything is up to date |
1 |
At least one item needs updating (or has an error) |
2 |
Fatal execution error |
130 |
Keyboard interrupt (Ctrl-C) |
Useful in scripts or CI:
projscan repos --no-fetch ~/code || echo "Some repos are behind!"
Status colors
| Status | Color | Meaning |
|---|---|---|
up to date |
green | In sync with upstream |
behind (↓N) |
red | N remote commits not yet pulled |
ahead (↑N) |
cyan | N local commits not yet pushed |
diverged (↓N ↑M) |
magenta | Branches have diverged |
update avail. |
yellow | New version of the tool available |
no upstream |
grey | No tracking branch configured |
not git |
grey | Tool installed from PyPI, not git |
unknown |
grey | Remote unreachable (offline, auth…) |
error |
bold red | Error during scan |
Usage as a library
projscan is designed to be imported in a Textual app or any other async code.
from pathlib import Path
from projscan import scan_paths, scan_tools, RepoInfo, ToolInfo
# Scan git repositories
repos: list[RepoInfo] = await scan_paths(
[Path("~/code")],
fetch=True,
max_depth=3,
concurrency=16,
)
for repo in repos:
print(f"{repo.name}: {repo.status}")
# Scan uv tools
tools: list[ToolInfo] = await scan_tools(check_remote=True)
for tool in tools:
if tool.status == "update avail.":
print(f"Update available: {tool.name}")
Dataclasses expose an .as_dict() method for JSON serialization:
import json
print(json.dumps([r.as_dict() for r in repos], ensure_ascii=False))
Full public API:
from projscan import (
# Git
RepoInfo, scan_paths, scan_repo, find_repos,
# UV tools
ToolInfo, scan_tools, scan_tool, uv_tool_dir,
)
Development
uv sync
uv run pytest # 52 tests, ~5s
uv run projscan repos . # real-world test
uv run projscan tools # real-world test
Metadata
Release files for projscan 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| projscan-0.1.2.tar.gz | 29.6 kB | Without provenance | Details for projscan-0.1.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| projscan-0.1.2-py3-none-any.whl | Python 3 | none | any | Details for projscan-0.1.2-py3-none-any.whl |
Total release size: 44.5 kB
Release files / projscan-0.1.2.tar.gz
| Download URL | projscan-0.1.2.tar.gz |
|---|---|
| Size | 29.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
908e83801fc17e54fd55fa6e5e4f091cf893601cf7298022399885ff8b1565c3
|
|
BLAKE2b-256 checksum How to use checksums |
cce21505bba979126945db28d8c57e0939917e1bef6144c32906d9d63cf2ed42
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / projscan-0.1.2-py3-none-any.whl
| Download URL | projscan-0.1.2-py3-none-any.whl |
|---|---|
| Size | 15.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2b2034cbaded0e0b8a1de8b2482d31654c1992828d172caa986d104e01dccdeb
|
|
BLAKE2b-256 checksum How to use checksums |
9bcc8d03eb9bc55e64b1cadc5113e7f8080999e715e16df705b24923bc751488
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for projscan 0.1.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.