A single-file Python tool for managing virtual environments, dependencies, and script execution. Designed to feel natural and get out of your way.
Latest Version: 1.0
# Initialize a new project
fl init
# Add dependencies
fl add requests flask
# Add from requirements.txt
fl add req
# Run a script
fl main.py
# Enter the project environment
fl shell
# List dependencies
fl list
# Check project health
fl doctorCopy fl to your PATH:
curl -fsSL https://raw.githubusercontent.com/Antonymwangi20/fl/main/fl -o ~/.local/bin/fl
chmod +x ~/.local/bin/flOr download directly:
wget https://example.com/fl -O ~/.local/bin/fl
chmod +x ~/.local/bin/flRequirements:
- Python 3.8+
- No external dependencies (uses only stdlib)
Initialize a new project with pyproject.toml, .gitignore, and .venv setup.
$ fl init
✓ Created pyproject.toml
✓ Created .gitignoreAdd dependencies and automatically install them.
$ fl add requests flask
✓ Added requests
✓ Added flask
✓ Virtual environment created
✓ Dependencies installedAdd from requirements.txt:
$ fl add req
✓ Added 5 packages from requirements.txt
✓ Dependencies installedRun a Python script in the project environment. Can be abbreviated to just fl script.py.
$ fl run main.py --port 8000
# OR
$ fl main.py --port 8000Flags:
-v, --verbose- Show which Python interpreter is being used
Drop into an interactive shell with the project environment activated.
$ fl shell
Entering project environment (.venv)
Type 'exit' to leave
(.venv) $ python --versionShow declared dependencies and installed packages.
$ fl list
Dependencies:
• requests
• flask
Installed (13 packages)
Lock records 13 packagesRemove packages from dependencies and uninstall them.
$ fl remove requests
✓ Removed requests from pyproject.toml
Found existing installation: requests 2.32.5
Successfully uninstalled requests-2.32.5Upgrade packages to the latest available versions.
$ fl upgrade flask
Requirement already satisfied: flask in ./.venv/lib/python3.13/site-packages (3.1.3)Completely clear the project environment and dependencies.
$ fl purge
✓ Cleared dependencies in pyproject.toml
✓ Removed virtual environment
✓ Environment purgedRun comprehensive diagnostics on the project environment.
Checks:
- ✅
pyproject.tomlsyntax validity - ✅ Python version constraint compatibility
- ✅ Virtual environment presence
- ✅ Dependency installation status
- ✅ Lock file vs. installed sync
- ✅
.gitignoreconfiguration - ✅ State file presence
$ fl doctor
Examining project...
✓ pyproject.toml syntax OK
✓ Python 3.13.12 meets requirement: >=3.8
✓ virtual environment exists
2 dependencies declared in pyproject.toml
✓ lock file matches installed packages
✓ .gitignore is properly configured
✓ state file present
✓ everything looks healthyCheck for dependency conflicts and invalid version specifications.
$ fl check
Analyzing dependencies...
✓ No dependency conflicts detectedDetects:
- Multiple conflicting version specs for the same package
- Invalid version operators (only
>=,<=,==,!=,~=,>,<are valid)
Check which packages have newer versions available on PyPI.
$ fl audit
Checking 13 packages for updates...
✓ All packages are up to dateOr with outdated packages:
Found 2 outdated package(s):
requests 2.30.0 → 2.32.5
flask 3.0.0 → 3.1.3
Run 'fl upgrade requests' to update a packageSearch PyPI for packages using the modern JSON API (no pip search deprecation).
$ fl search flask
Searching PyPI for 'flask'...
Results:
flask 3.1.3 Web development, one drop at a time
To add: fl add flaskCompare lock file with currently installed packages to detect divergences.
$ fl lock-diff
Comparing lock file to installed packages...
✓ Lock file and installed packages matchOr when differences exist:
In lock file but not installed (1):
- deprecated-pkg 1.0.0
Installed but not in lock file (2):
+ new-pkg 2.0.0
Version mismatches (1):
requests lock: 2.30.0 installed: 2.32.5
Run 'fl install --force' to sync to dependencies
Auto-fix common project issues.
Auto-repairs:
- ✅ Missing or incomplete
.gitignore - ✅ Malformed
pyproject.toml(missing[project]section, dependencies list) - ✅ Missing state files
- ✅ Missing lock files
$ fl fix
Scanning for issues...
✓ pyproject.toml syntax OK
✓ Fixed .gitignore (added 2 entries)
✓ Fixed 1 issue(s)Manage the global wheel cache at ~/.cache/fl/.
Show cache info:
$ fl cache info
Cache directory: /home/user/.cache/fl
Wheels cached: 42
Total size: 156.32 MBPrune old wheels (older than 30 days):
$ fl cache prune
✓ Pruned 5 old wheelsBenefit: Wheels are cached globally, so reinstalling the same versions across projects is instant.
Save a snapshot of the current environment (dependencies + installed versions).
$ fl snapshot save production
✓ Snapshot saved: .fl-snapshots/production.jsonUse cases:
- Save before making changes for easy rollback
- Archive known-good environments for CI
- Document dependency state at release time
Compare current environment against a saved snapshot.
$ fl snapshot compare production
Comparing against snapshot 'production'...
Updated (2):
requests lock: 2.30.0 installed: 2.32.5
flask lock: 3.0.0 installed: 3.1.3Shows:
- Packages added since snapshot
- Packages removed since snapshot
- Version changes
List all saved snapshots in .fl-snapshots/.
$ fl snapshot list
Saved snapshots:
• dev
• production
• testingAfter fl init, your project looks like:
my-project/
├── .venv/ # Auto-created virtual environment
├── pyproject.toml # Project metadata & dependencies
├── .gitignore # Venv + cache exclusions
├── .fl.state.json # Internal state tracking
├── .fl.lock.json # Lock file (like requirements.lock)
└── .fl-snapshots/ # Environment snapshots (optional)
├── latest.json
├── production.json
└── testing.json
Files created by fl:
.venv/– Virtual environment (gitignored).fl.state.json– Tracks declared dependencies (gitignored).fl.lock.json– Lock file with exact versions (gitignored).fl-snapshots/– Environment snapshots directory
Minimal example:
[project]
name = "my-project"
version = "0.1.0"
description = "My awesome project"
requires-python = ">=3.8"
dependencies = [
"requests>=2.28",
"flask>=3.0",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"fl respects:
dependencies– List of packages to installrequires-python– Validated byfl doctorproject.name– Used in initialization
Wheels are automatically cached in ~/.cache/fl/. This speeds up reinstalling common dependencies across projects:
$ fl add numpy
# First time: Downloads and caches wheel
$ cd ../another-project && fl add numpy
# Second time: Instant install from cacheCheck cache usage:
$ fl cache info
Wheels cached: 156
Total size: 2.34 GB
$ fl cache prune # Remove wheels older than 30 daysfl automatically handles lock files:
- On
fl add: Downloads and records exact versions in.fl.lock.json - On
fl run: Skips reinstall if lock matches declared deps - On
fl audit: Compares lock against PyPI for available updates
Manual lock management:
$ fl lock-diff # See what's out of sync
$ fl snapshot save ci # Archive current state
$ fl snapshot compare ci # Verify reproducibilityGitHub Actions example:
- name: Setup Python project
run: |
pip install .../fl
fl fix # Auto-create missing files
fl doctor # Verify health
fl snapshot save ci-run
- name: Run tests
run: |
fl pytest tests/
- name: Check for regressions
run: |
fl snapshot compare ci-run # Ensure no surprise installsCheck for conflicts before committing:
$ fl check
Analyzing dependencies...
✓ No dependency conflicts detectedAudit before deploying:
$ fl audit
Checking 42 packages for updates...
Found 3 outdated package(s):
[list of upgradeable packages]Skip the run verb—just use the script name:
# These are equivalent:
fl main.py
fl run main.pySee which Python interpreter is being used:
$ fl run main.py -v
Using: /path/to/.venv/bin/pythonEach project gets its own .venv:
$ cd project-a && fl add flask
$ cd ../project-b && fl add flask
# project-b gets its own Flask installation, no conflictsBroken project state is auto-detected:
$ fl doctor
⚠ .gitignore missing venv or lock file entry
$ fl fix
✓ Fixed .gitignore (added 1 entries)Run doctor to diagnose:
$ fl doctor
⚠ pkg is not installed
$ fl fix
✓ Recreated lock file
$ fl run script.py # Try againRecreate it:
$ fl purge
$ fl init
$ fl add ... # Re-add dependenciesForce reinstall:
$ fl lock-diff # See what's different
$ fl add ... # Add new package
# (This auto-syncs the lock file)Use fl search instead (uses PyPI JSON API):
$ fl search requests
# Modern, faster, works offline| Operation | Time | Notes |
|---|---|---|
fl init |
2-5s | Creates venv + basic files |
fl add (first) |
10-60s | Downloads wheels, depends on package size |
fl add (cached) |
<1s | Uses global cache, instant |
fl run |
<1s | Reuses lock file, no reinstall |
fl doctor |
1-2s | Local checks only (no network) |
fl audit |
5-30s | Checks PyPI for each package |
fl search |
1-3s | One PyPI API call |
fl snapshot save |
<1s | Writes JSON file |
- Python versions: 3.8+
- Operating systems: Linux, macOS, Windows (with git bash)
- pip versions: 20.0+
- Dependencies: None (stdlib only)
Q: Is this a replacement for poetry/pipenv?
A: Not exactly. It's simpler and faster for small projects. Good for scripts, prototypes, and CI. Poetry is better for complex multi-package projects.
Q: Will my .venv be portable?
A: No, virtualenvs are platform/Python-specific. Use fl snapshot + CI for reproducibility.
Q: Can I use fl for production?
A: Yes, with snapshots. Save a snapshot, version it, and compare in CI.
Q: What about private packages?
A: Use pip's standard authentication. fl passes everything to pip.
Q: Does fl lock dependencies recursively?
A: Yes, via pip. The lock file records exact versions of all transitive dependencies.
Q: Can I import from requirements.txt?
A: Yes! Use fl add req to read requirements.txt and add all packages to your project. Each package gets added to pyproject.toml and installed.
Found a bug? Create a snapshot, check logs, and report:
$ py doctor
$ py snapshot save latest
$ py cache infoMIT