Projects & Workers¶
A project is a single [[project]] entry in
project.toml. A worker is the running
process that Pypen spawns from that entry. The worker/
package is responsible for the full lifecycle of every worker.
Worker Lifecycle¶
- Plan.
worker/config_loader.pyparsesproject.toml, applies defaults, and produces a normalised list of project specs. - Provision.
worker/pyenv_utils.pyensures the requested Python version is available;uvcreates a fresh venv at./.venvs/<id>/. - Clone.
worker/project_manager.pyclones the repo (with token injection for private repos) into./projects/<id>/. - Install. If the repo has a
requirements.txt/pyproject.toml,uv pip installpopulates the venv. - Generate service.
worker/s6_config.pywrites arunscript under/etc/s6/services/<id>/with the correct env vars and venv-awareexecline. - Start.
worker/s6_svc.pycallss6-svc -uto bring the service up. - Watch. If the worker exits,
s6-overlayrestarts it. The dashboard shows the new state via Socket.IO.
Isolation¶
Every project gets its own:
- Working directory —
./projects/<id>/ - Python interpreter — via
pyenv - Virtual environment — via
uv - Environment variables — from
[project.env] - Log directory —
/var/log/s6/<id>/with bounded rotation - s6 service definition —
/etc/s6/services/<id>/
This means two projects can run wildly different stacks — one on
Python 3.9 with pyrogram, another on Python 3.13 with
aiohttp — in the same container, without ever
touching each other.
Running Many Forks of the Same Repo¶
A common pattern is to spin up several copies of the same bot with
different env vars. Just give each one a unique id:
[[project]] id = "tg-bot-a" git_url = "https://github.com/example/tg-bot" branch = "main" run_command = "bot.py" [project.env] BOT_TOKEN = "TOKEN_A" [[project]] id = "tg-bot-b" git_url = "https://github.com/example/tg-bot" branch = "main" run_command = "bot.py" [project.env] BOT_TOKEN = "TOKEN_B"
Private Repositories¶
Set repo = "private" and provide an
access_token (per-project, or globally in
[defaults]). Pypen rewrites the clone URL to
https://x-access-token:<token>@github.com/…
so that git can authenticate without an SSH key.