Skip to content

[4.0.0-beta desktop] Tray deps are not in requirements.txt; frozen app can exit immediately #253

Closed

Description

@Fujio-Turner

PROBLEM

Desktop UX depends on app/tray.py (macOS rumps menubar, Windows pystray + Pillow).

  1. rumps, pystray, and Pillow are not in app/requirements.txt. Only the workflow pip installs them. Anyone running pyinstaller build_*.spec locally gets no tray.
  2. Committed build_mac.spec does not list tray or rumps in hiddenimports, and sets console=False.
  3. In app.py __main__, Flask is started on a daemon thread, then run_tray() is supposed to block. If tray import/start fails:
flask_thread = threading.Thread(..., daemon=True)
flask_thread.start()
tray_ok = run_tray(PORT) if run_tray else False
if not tray_ok:
    flask_thread.join()

If run_tray raises before returning False, or if is_supported() is True but rumps is missing and the except path sets run_tray = None after is_supported was already bound — the process can exit because the only remaining thread is daemon.

  1. CI Mac build uses console=True and a Dock icon and the menubar, so three UIs appear. That is why the CI build stays alive (Terminal owns the process), not because tray is solid.

Suggested RCA

Tray was added as a desktop-only extra in the workflow, never as a declared dependency. The committed spec was not updated to match tray.py. console=False was copied from the "GUI app" design while tray reliability was still best-effort.

Suggested FIX

# app/requirements-desktop.txt
-r requirements.txt
pyinstaller>=6,<7
rumps>=0.4.0; sys_platform == "darwin"
pystray>=0.19.0; sys_platform == "win32"
Pillow>=10,<12
openai>=1.0.0,<2

Workflow: pip install -r requirements-desktop.txt.

Mac spec: hiddenimports += ['tray', 'rumps'].
Win spec: hiddenimports += ['tray', 'pystray', 'PIL.Image', 'PIL.ImageDraw'].

Keep Flask on a non-daemon thread so a tray failure cannot kill the server:

flask_thread = threading.Thread(
    target=lambda: app.run(host="127.0.0.1", port=PORT, debug=False, use_reloader=False),
    daemon=False,
    name="flask-server",
)

Bind 127.0.0.1 in the desktop build (not 0.0.0.0) — it is a local helper, not a LAN server.

Unit tests

# tests/python/test_tray.py
from unittest.mock import patch
import tray

def test_is_supported_on_darwin():
    with patch("tray._is_macos", return_value=True), patch("tray._is_windows", return_value=False):
        assert tray.is_supported() is True

def test_is_supported_on_linux_is_false():
    with patch("tray._is_macos", return_value=False), patch("tray._is_windows", return_value=False):
        assert tray.is_supported() is False

def test_run_tray_returns_false_when_rumps_missing():
    with patch("tray._is_macos", return_value=True), \
         patch("tray._run_macos_tray", side_effect=ImportError("No module named rumps")):
        assert tray.run_tray(8080) is False

def test_requirements_desktop_lists_tray_libs():
    text = open("app/requirements-desktop.txt").read()
    assert "rumps" in text
    assert "pystray" in text

Context: found on branch release-4.0.0-beta while reviewing standalone macOS .app / Windows .exe packaging. Issues in this batch share the title prefix [4.0.0-beta desktop].

Activity

  1. Fujio-Turner commented on Sep 15, 2026

    @Fujio-Turner
    OwnerAuthor

    Fixed on release-4.0.0-beta via #263

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions