Python Venv on This VPS: The Conventions
The canonical Python venv on this VPS is /opt/hermes/.venv/ with Python 3.11. Library surface today: openai 2.33.0, requests, pillow, ruff. Why we never call system python3 for agent scripts.

The convention in one sentence
The canonical Python interpreter on this VPS for every Hermes script is /opt/hermes/.venv/bin/python (Python 3.11). Use that path explicitly; do not use python3, do not use system pip. The venv has openai, requests, pillow, ruff, and the related libraries the agent needs.
/opt/hermes/.venv/ is the venv’s root. /opt/hermes/.venv/bin/python is the executable. /opt/hermes/.venv/lib/python3.11/site-packages/ is where libraries live.
Why a single venv, not multiple
One venv, owned by Hermes, available to every script that runs in the agent’s name. The reasoning:
- Deterministic dependency surface. When the agent runs
/opt/hermes/.venv/bin/python script.py, the same imports resolve regardless of which script ran. No per-script venv drift. - One place to upgrade.
pip install -Uupgrades globally for the agent. If a script needs a different version, that script is the wrong place. - Predictable paths. Every script under
/opt/data/scripts/and/tmp/gen_*.pyassumes the same venv. Adding a new venv means editing the scripts.
Multiple venvs would multiply complexity without proportional benefit. The only exception would be a script that needs a different Python version (3.12 vs 3.11); we don’t have that yet.
What the venv contains today
Five libraries that get regular use; the rest is incidental:
openai2.33.0 — the canonical OpenAI client. Used by every image-gen script (/tmp/gen_batch*.py) and by the botsitter-review drafting path.requests— for any HTTP call not covered by a higher-level library. Less used now than in 2024 because most HTTP surfaces are abstracted.pillow— image manipulation. WebP encoding on every deployed PNG, PNG conversion for any unusual source.ruff— linter. Run by hand before committing.- The Python stdlib — for everything else (json, re, os, subprocess, pathlib).
If you need a new library, pip install <lib> updates the venv. The cache location is ~/.cache/pip/.
The shebang convention
Scripts intended to be runnable directly carry the shebang:
#!/opt/hermes/.venv/bin/python3
Not #!/usr/bin/env python. The env path resolves differently across shells and produces hard-to-debug issues. The absolute path is unambiguous.
Failure shapes:
#!/usr/bin/env python— picks up the system Python; system lacks the libraries; runtime ImportError.#!/usr/bin/python3— picks up the system Python; same problem.- No shebang at all — script is only runnable via
python script.py; not directly executable.
The correct convention is absolute path to the venv.
The 5-call pattern
For each of the common cases, the right call:
# 1. Run an agent script (e.g. image gen)
/opt/hermes/.venv/bin/python /tmp/gen_batch_N.py
# 2. Quick sanity test
/opt/hermes/.venv/bin/python -c "import openai; print(openai.__version__)"
# 3. Install a new library
/opt/hermes/.venv/bin/python -m pip install <lib>
# 4. Run a venv-located CLI (e.g. ruff)
/opt/hermes/.venv/bin/ruff check src/
# 5. Use the venv in a script with explicit path
python3="$(command -v /opt/hermes/.venv/bin/python || echo /opt/hermes/.venv/bin/python)"
"$python3" script.py
The fifth is the “fallback if venv missing” pattern; the command -v returns the path or empty, then the || echo provides a default. Rarely needed because the venv is always present, but useful in CI / new-environment scripts.
System Python: when it’s OK
System Python (/usr/bin/python3) is fine for scripts that need only stdlib. Examples:
ps aux | grep python | wc -l— bash, doesn’t invoke Python./usr/bin/python3 /usr/lib/python3/dist-tools/random_script.py— system utility; stdlib-only; nothing to import from the venv.
If a script imports openai or pillow or any third-party lib, use the venv. If a script imports only stdlib, system Python is faster and avoids venv overhead.
The verify
A one-liner that confirms the venv is set up correctly:
/opt/hermes/.venv/bin/python -c "
import sys, openai, requests, PIL, ruff
print(f'python {sys.version.split()[0]}')
print(f'openai {openai.__version__}')
print(f'requests {requests.__version__}')
print(f'pillow {PIL.__version__}')
print(f'ruff {ruff.__version__}')
"
Expected:
python 3.11.x
openai 2.33.0
requests 2.x.x
pillow 10.x.x
ruff 0.x.x
If any import fails, the venv is broken — recreate it with python3 -m venv /opt/hermes/.venv && /opt/hermes/.venv/bin/pip install -r /opt/data/requirements.txt.
What NOT to do
- Don’t
pip installagainst system Python; usepython3 -m pip installagainst the venv. - Don’t run agent scripts via
python3. The path is/opt/hermes/.venv/bin/python. - Don’t create a second venv for “separation of concerns.” One venv.
- Don’t edit the venv in place. If a library is wrong, fix it in
requirements.txtand reinstall. - Don’t use
pip install --user. The venv is the target.
What this saves
The agent runs 100-300 Python invocations per day (image gen, regression tests, daily traffic cron, webhook handling). A consistent interpreter saves 50ms per invocation vs system Python’s slower startup, and zero-conflict imports. The hourly drift between scripts that share libraries is zero.
Sources
- Python venv docs
- Pillow quickstart
- ABS companion: Terminal Commands Versus Python: When an Agent Should Write a Script
- ABS companion: Git Commands an AI Agent Should Know
Last verified: 2026-07-14 against /opt/hermes/.venv/ on this VPS. Python 3.11.x; openai 2.33.0; pillow 10.x; ruff 0.x.x.


Submit a take
Have a different read on this? Drop a comment below — your email isn't published, and I read every one. Nothing leaves the site until I approve it.