Skip to content

feat(windows): TCP loopback IPC for daemon (Windows compat)#205

Open
andromeda-vinicius wants to merge 1 commit intobrowser-use:mainfrom
andromeda-vinicius:windows-tcp-loopback
Open

feat(windows): TCP loopback IPC for daemon (Windows compat)#205
andromeda-vinicius wants to merge 1 commit intobrowser-use:mainfrom
andromeda-vinicius:windows-tcp-loopback

Conversation

@andromeda-vinicius
Copy link
Copy Markdown

@andromeda-vinicius andromeda-vinicius commented Apr 26, 2026

Summary

Adds Windows compatibility for the daemon-runner IPC. Python on Windows lacks socket.AF_UNIX, so the original Unix-domain-socket-based IPC fails immediately on Windows with AttributeError: module 'socket' has no attribute 'AF_UNIX'.

This patch adds a small _ipc.py abstraction that:

  • Uses AF_UNIX + /tmp/bu-<NAME>.sock on macOS/Linux (unchanged behaviour)
  • Uses TCP loopback (127.0.0.1:<random_port>) on Windows
  • Persists the chosen port to %TEMP%�u-<NAME>.sock (re-purposed as port marker)
  • Exposes connect_daemon, start_daemon_server, runtime_path, cleanup_endpoint cross-platform helpers

Changes

File Change
_ipc.py (new) Platform-aware IPC helpers (~110 lines)
daemon.py start_daemon_server + cleanup_endpoint; removes inline AF_UNIX
admin.py connect_daemon + runtime_path; subprocess uses CREATE_NEW_PROCESS_GROUP on Windows
helpers.py connect_daemon for IPC _send
pyproject.toml Registers _ipc as py-module

Test

Tested on Windows 11 + Python 3.13 + uv 0.11. End-to-end:

uv tool install --editable . --force
browser-harness --doctor      # OK
browser-harness -c "print(page_info())"  # returns real page from local Chrome

Backwards compatibility

Zero behaviour change on macOS/Linux: same paths, same socket type, same chmod 0600. Just the call sites are routed through _ipc.py helpers that branch on platform.system().

Notes

  • Subprocess on Windows uses CREATE_NEW_PROCESS_GROUP (vs start_new_session=True on Unix) to detach from parent's console group
  • os.kill(pid, signal.SIGTERM) works on Windows since Python 3.x (emulates via TerminateProcess)
  • No new external deps

Summary by cubic

Adds Windows-compatible IPC for the daemon by using TCP loopback on Windows while keeping Unix domain sockets on macOS/Linux. This enables running the daemon and CLI on Windows with no behavior change on Unix.

  • New Features
    • Added _ipc.py with cross‑platform helpers: connect_daemon, start_daemon_server, runtime_path, cleanup_endpoint.
    • Windows uses 127.0.0.1:<random_port> and writes the port to %TEMP%\bu-<NAME>.sock; Unix remains /tmp/bu-<NAME>.sock with 0600 perms.
    • Updated daemon.py, admin.py, and helpers.py to use the abstraction; Windows daemon launch uses CREATE_NEW_PROCESS_GROUP. Registered _ipc in pyproject.toml.

Written for commit 52da586. Summary will update on new commits.

Python on Windows lacks socket.AF_UNIX, blocking the original Unix-domain-socket
based daemon-runner IPC. This patch adds a small _ipc.py abstraction that:

- Uses AF_UNIX + /tmp/bu-<NAME>.sock on macOS/Linux (unchanged)
- Uses TCP loopback (127.0.0.1:<random_port>) on Windows
- Persists chosen port to %TEMP%\bu-<NAME>.sock (re-purposed as port marker)
- Cross-platform: connect_daemon, start_daemon_server, runtime_path, cleanup_endpoint

Files patched:
- _ipc.py (NEW) — platform-aware IPC helpers
- daemon.py — uses start_daemon_server + cleanup_endpoint
- admin.py — uses connect_daemon + runtime_path; subprocess uses CREATE_NEW_PROCESS_GROUP on Windows
- helpers.py — uses connect_daemon
- pyproject.toml — registers _ipc as py-module

Tested on Windows 11 + Python 3.13 + uv 0.11. browser-harness --doctor + page_info()
work end-to-end against local Chrome with remote-debugging.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 5 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="_ipc.py">

<violation number="1" location="_ipc.py:88">
P1: Windows daemon startup uses a racy two-step port allocation and writes the port marker before successful bind, which can cause intermittent bind failures and invalid endpoint discovery.</violation>

<violation number="2" location="_ipc.py:92">
P1: Windows IPC uses unauthenticated loopback TCP, removing Unix socket permission-based access control and allowing unauthorized local processes to issue daemon commands.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

Comment thread _ipc.py
# Persist port to .sock file (acts as port marker on Win)
with open(sock_path, "w") as f:
f.write(str(port))
server = await asyncio.start_server(handler, "127.0.0.1", port)
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Windows IPC uses unauthenticated loopback TCP, removing Unix socket permission-based access control and allowing unauthorized local processes to issue daemon commands.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At _ipc.py, line 92:

<comment>Windows IPC uses unauthenticated loopback TCP, removing Unix socket permission-based access control and allowing unauthorized local processes to issue daemon commands.</comment>

<file context>
@@ -0,0 +1,111 @@
+        # Persist port to .sock file (acts as port marker on Win)
+        with open(sock_path, "w") as f:
+            f.write(str(port))
+        server = await asyncio.start_server(handler, "127.0.0.1", port)
+        return server, f"127.0.0.1:{port}"
+    # Unix
</file context>
Fix with Cubic

Comment thread _ipc.py
"""
sock_path = runtime_path(name, SOCK_EXT)
if is_windows():
port = _alloc_port()
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Windows daemon startup uses a racy two-step port allocation and writes the port marker before successful bind, which can cause intermittent bind failures and invalid endpoint discovery.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At _ipc.py, line 88:

<comment>Windows daemon startup uses a racy two-step port allocation and writes the port marker before successful bind, which can cause intermittent bind failures and invalid endpoint discovery.</comment>

<file context>
@@ -0,0 +1,111 @@
+    """
+    sock_path = runtime_path(name, SOCK_EXT)
+    if is_windows():
+        port = _alloc_port()
+        # Persist port to .sock file (acts as port marker on Win)
+        with open(sock_path, "w") as f:
</file context>
Fix with Cubic

@qodo-ai-reviewer
Copy link
Copy Markdown

Hi, _read_port() does not handle PermissionError/OSError when opening the port-marker file, so Windows temp-directory access issues can surface as unexpected exceptions and break connect_daemon() callers.

Severity: remediation recommended | Category: reliability

How to fix: Handle PermissionError/OSError

Agent prompt to fix - you can give this to your LLM of choice:

Issue description

_ipc._read_port() has incomplete exception handling when reading the Windows port marker, which can break IPC in environments where %TEMP% file access is restricted or transiently locked.

Issue Context

helpers._send() and admin/daemon health checks depend on connect_daemon().

Fix Focus Areas

  • _ipc.py[48-52]
    • Decide whether to: (a) treat PermissionError/OSError as "no port" and return None, or (b) propagate with a clearer error.
    • If treating as None, include these exceptions in the except tuple.
    • Consider brief retry/backoff if file is transiently locked.
  • helpers.py[28-39]
    • Optionally add clearer error messaging around connection failures on Windows.

Found by Qodo code review

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants