Status: written and verified 2026-09-30, after the first attempt on the PC found this gap. The satellite package
ships only run-satellite.bat — a Windows file. On a Linux PC, double-clicking it hands the file to Wine, which
installs itself and then finds no Windows browser and no Windows Python: the window prints its message and closes when you
press a key. Nothing is broken and nothing was sent anywhere — the package simply has no launcher for this PC.
This page is the Linux equivalent. It is the same steps in the same order as the .bat, and it is the file the
package should eventually ship beside it. Its source of record is
veripath-ops/scripts/satellite-launcher-linux.sh (321624d).
On the PC, in the folder that contains satellite/ (so the folder you extracted into — the launcher steps out of
satellite/ to run the program):
Which folder, exactly: the one that contains satellite/ — usually ~/Desktop if you extracted there. If your
prompt already ends in /satellite, you are one level too deep: cd .. first. The program is run as
python3 -m satellite, which needs a directory called satellite beside it, so running it from inside that directory
finds nothing and says so.
And leave the & on the end of the browser line. Without it Chrome takes the terminal and holds it — the command
you type next is never executed, and no error is printed, which is exactly what it looks like when nothing happens. (If
that has already happened: leave that window alone and open a second terminal for the satellite, or press Ctrl+C to
stop Chrome and start again.)
python3 -m pip install --user websocket-client # once, if it is missing
google-chrome --remote-debugging-port=9222 --user-data-dir="$PWD/satellite/browser-profile" &
Then, in the browser window that opens: log in to the app and open the order page you mean to hand over. Then:
python3 -m satellite --port 9222
chromium instead of google-chrome if that is what the PC has. That is exactly what the launcher does for you.
Put this file inside the satellite/ folder as run-satellite-linux.sh, make it executable, and run it:
chmod +x satellite/run-satellite-linux.sh
bash satellite/run-satellite-linux.sh
It finds a browser (Chrome, Chromium, Edge, Brave or Vivaldi), reads the port out of config.json, starts that browser
on its own profile with the debugging port, waits up to thirty seconds for the port, asks you to open the order page and
press Enter, runs the program, and keeps the window open so the report can be read. It installs nothing, registers no
service or autostart, changes nothing outside its own folder, opens no portal and holds no credential.
#!/usr/bin/env bash
# The Linux launcher for the order satellite — the equivalent of
# satellite/run-satellite.bat, and the same steps in the same order:
# find a browser, read the port out of config.json, start that browser on a
# dedicated profile with the debugging port, wait a bounded 30 s for the port,
# wait for the user to open the order page, run python3 -m satellite on that
# port, and keep the window open so the report can be read.
#
# It installs nothing, registers no service or autostart, changes nothing
# outside its own folder, opens no portal and holds no credential.
#
# Copy it into the extracted package's satellite/ directory and run it from
# there, exactly as a pharmacy would double-click run-satellite.bat:
#
# bash satellite/run-satellite-linux.sh
#
# Two environment variables exist for verification rigs, not for a pharmacy PC:
# SATELLITE_CHROME_BIN an exact browser path to use instead of the search
# SATELLITE_CHROME_FLAGS extra browser flags (e.g. --headless=new)
# SATELLITE_BROWSER_DIR a directory to search for chrome-*/chrome builds
set -u
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$HERE/.." || exit 2
# --- the interpreter and its one dependency -------------------------------
PYTHON="$(command -v python3 2>/dev/null || true)"
if [ -z "$PYTHON" ]; then
echo "Python 3 was not found on this PC."
echo "This launcher needs it, and one small package alongside it."
echo "Nothing has been sent anywhere."
echo
if [ -t 0 ]; then read -r -p "Press Enter to close." _; fi
exit 2
fi
if ! "$PYTHON" -c 'import websocket' >/dev/null 2>&1; then
echo "This PC has Python 3, but not the one small package the launcher needs."
echo "Install it with:"
echo
echo " python3 -m pip install --user websocket-client"
echo
echo "Then run this file again. Nothing has been sent anywhere."
echo
if [ -t 0 ]; then read -r -p "Press Enter to close." _; fi
exit 2
fi
# --- the port, from the config the app generated --------------------------
PORT=9222
if [ -f "$HERE/config.json" ]; then
READ="$("$PYTHON" -c 'import json,sys;print(json.load(open(sys.argv[1])).get("port",9222))' \
"$HERE/config.json" 2>/dev/null || true)"
[ -n "${READ:-}" ] && PORT="$READ"
fi
# --- find a browser -------------------------------------------------------
BROWSER=""
for candidate in "${SATELLITE_CHROME_BIN:-}" \
"$(command -v google-chrome 2>/dev/null || true)" \
"$(command -v google-chrome-stable 2>/dev/null || true)" \
"$(command -v chromium 2>/dev/null || true)" \
"$(command -v chromium-browser 2>/dev/null || true)" \
"$(command -v microsoft-edge 2>/dev/null || true)" \
"$(command -v microsoft-edge-stable 2>/dev/null || true)" \
"$(command -v brave-browser 2>/dev/null || true)" \
"$(command -v vivaldi-stable 2>/dev/null || true)" \
${SATELLITE_BROWSER_DIR:-/root/.agent-browser/browsers}/chrome-*/chrome; do
if [ -n "$candidate" ] && [ -x "$candidate" ]; then
BROWSER="$candidate"
break
fi
done
if [ -z "$BROWSER" ]; then
echo "No Chrome, Chromium or Edge was found on this PC."
echo "This launcher needs one of them. Nothing has been sent anywhere."
echo
if [ -t 0 ]; then read -r -p "Press Enter to close." _; fi
exit 2
fi
# --- start it on its own profile, and wait for the port -------------------
PROFILE="$HERE/browser-profile"
[ -d "$PROFILE" ] || mkdir -p "$PROFILE"
echo "Starting the browser on its own profile and debug port $PORT ..."
# shellcheck disable=SC2086
"$BROWSER" --remote-debugging-port="$PORT" --user-data-dir="$PROFILE" \
${SATELLITE_CHROME_FLAGS:-} about:blank >/dev/null 2>&1 &
TRIES=0
while true; do
TRIES=$((TRIES + 1))
if "$PYTHON" - "$PORT" <<'PY'
import socket, sys
try:
socket.create_connection(('127.0.0.1', int(sys.argv[1])), timeout=1).close()
except OSError:
sys.exit(1)
PY
then
break
fi
if [ "$TRIES" -ge 30 ]; then
echo "The browser did not open its debug port ($PORT) in time."
echo "Close the browser, then run this file again."
echo "Nothing has been sent anywhere."
echo
if [ -t 0 ]; then read -r -p "Press Enter to close." _; fi
exit 2
fi
sleep 1
done
# --- wait for the human, then run the program ----------------------------
echo "A browser window has opened. In it, log in to the app and open the"
echo "order page you want to hand over."
echo
echo "When the order page is open, come back to this window and press Enter."
echo "The program then reads the page and prints its report. There is no timer."
echo
read -r -p "" _ || true
"$PYTHON" -m satellite --port "$PORT"
STATUS=$?
echo
echo "Nothing has been sent anywhere. Nothing has been opened."
if [ -t 0 ]; then read -r -p "Press Enter to close." _; fi
exit $STATUS
Run on the server against a real extracted copy of the package (2026-09-30), with a real Chrome:
What that does not prove: the run on this PC's desktop browser. That is the point of putting it on the PC, and the
report it prints is what settles it.