The .modal CSS display:flex override the hidden attribute, so the empty job
modal was always visible on load and closeModal() could not hide it - the
'non-dismissable empty error'. Add .modal[hidden] { display:none } so the
hidden attribute wins.
The blanket errorhandler(Exception) also converted normal HTTP 404s (e.g.
/favicon.ico, /apple-touch-icon-*.png requested by the browser) into 500s,
flooding the log. Return HTTPException instances unchanged so only genuine
500s are logged as errors.
Cross-Py-Builder
Cross-Py-Builder is a remote build tool for compiling Python projects with PyInstaller on different platforms (Linux, macOS, Windows) across a local network.
It has two parts:
- Controller — a small web service with a browser UI for submitting builds (upload a zip or point at a git repo), tracking live progress, and downloading the resulting binaries.
- Agent (worker) — one per target OS/CPU. Runs the actual PyInstaller builds and exposes them over HTTP; the controller dispatches builds to an agent matching the requested OS + CPU.
System Requirements
- Ubuntu/Debian & macOS: 2GB+ RAM
- Windows: 4GB+ RAM
- Python 3.10 or later installed on each host
- Local network between the controller and the agents
How it's packaged
This is a Python package installed with setuptools (setup.py). Installing it (editable, for
development) makes two commands available on your PATH:
| Command | Runs | Purpose |
|---|---|---|
cross-py-controller |
ctrl.app:main |
Web UI + scheduler (the machine you browse to) |
cross-py-agent |
agent.build_agent:main |
Worker agent (one per target OS/CPU) |
Start by installing the package into a virtualenv on every machine that will act as a controller or agent:
cd cross-py-builder
python3 -m venv venv
source venv/bin/activate
pip install -e . # editable install: installs deps + links to your working dir
-e (editable) links the install to your checkout, so code changes take effect without
reinstalling. On the LXC workers you can alternatively copy the source and just run the .py
files (see below).
Running a worker (agent)
On each target OS/CPU machine (e.g. each Ubuntu LXC):
cd cross-py-builder
python3 -m venv venv
source venv/bin/activate
pip install -e .
cross-py-agent
The agent binds on port 9001 and announces itself on the local network. To run it
directly without the package command:
pip install -r requirements.txt
python agent/build_agent.py
Running the controller
On the machine that will serve the browser UI:
cd cross-py-builder
python3 -m venv venv
source venv/bin/activate
pip install -e .
Set the static worker list (JSON array of host:port, matching where your agents are
listening) and start it:
CROSS_PY_WORKERS='["192.168.1.40:9001","192.168.1.41:9001"]' \
cross-py-controller
Then open http://<controller-ip>:8080 in a browser.
Controller environment variables
| Variable | Default | Purpose |
|---|---|---|
CROSS_PY_WORKERS |
(none) | JSON array of agent host:port strings |
CROSS_PY_PORT |
8080 |
HTTP port the controller UI listens on |
CROSS_PY_MAX_CONCURRENT |
1 |
Max simultaneous builds (across distinct agents) |
CROSS_PY_DATA |
<repo>/data |
Data dir (jobs DB, uploaded sources) |
CROSS_PY_BUILDS |
<data>/builds |
Dir where finished build artifacts are saved |
CROSS_PY_DEBUG |
off | Use Flask dev server instead of waitress |
Using the UI
- Open the controller in a browser.
- Pick the target OS and CPU (or "any").
- Either upload a
.zipof your project (PyInstaller spec + source) or paste a gitrepo_url. - Submit. The job is queued → dispatched to a matching agent → built → artifacts fetched.
- Watch live per-step progress, then download the built binaries from the job detail.
A submitted project only needs the source plus at least one *.spec file; each spec file in
the archive produces a build.
Retired CLI
The original single-command CLI (./cross-py-builder.py --build ..., agent_manager.py) has been
removed and replaced by the controller + agent model above.