Repository navigation
Let the connector run on macOS - #812
Conversation
The connector was Linux-only because the CLI only sealed inherited descriptors there, and the task token arrives on one. macOS can seal them too: list /dev/fd and mark each close-on-exec, as Linux's fallback already does with /proc/self/fd. The token reader is built for both, and the platform check allows macOS. The background service stays Linux-only, since it writes a systemd unit. Also, found running the connector's tests on a Mac: - macOS refuses any signal to a process group whose only members are zombies, where Linux delivers it. A finished worker's group read as "probably still there" and couldn't be confirmed gone. Such a group is now the absent group it is everywhere else, when the kernel's own listing shows nothing running. - The claude driver's "deaf" test worker blocked on an empty select, which the runtime ends as a deadlock on macOS before the pipe fills. It sleeps.
…fused macOS answers LOCAL_PEERPID only while the peer is connected (it still names the user). A worker's MCP server that closed before its token was read was recorded as an untrusted connection and spent the socket; it is now undelivered, as on Linux, and its next start gets the token.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The Darwin fallback can leave high-numbered inherited descriptors unsealed, and shipped skills still reject macOS.
Review effort: Balanced
Findings: 1
Open (3)
What changed in this PR
Enables the connector on macOS by sealing inherited descriptors and handling Darwin-specific process and socket behavior.
Changes:
- Adds macOS descriptor sealing and token handoff support.
- Handles closed peers and zombie-only process groups on macOS.
- Keeps systemd service management Linux-only and updates platform tests.
[!TIP]
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or rungh pr ready --undo.
Click "Ready for review" or rungh pr readyto reengage.
| File | Description |
|---|---|
internal/connector/tokensocket.go |
Handles closed same-user peers as undelivered. |
internal/connector/tokensocket_test.go |
Tests closed-peer handoffs. |
internal/connector/tokensocket_darwin.go |
Recognizes disconnected macOS peers. |
internal/connector/driver/worker_unix.go |
Handles zombie-only process groups. |
internal/connector/driver/claude/claude_test.go |
Avoids deadlocking fake workers. |
internal/connector/admission/policy.go |
Updates platform documentation. |
internal/commands/mcp_token_sealed.go |
Enables token reading on macOS. |
internal/commands/mcp_token_other.go |
Updates unsupported-platform handling. |
internal/commands/connect.go |
Documents macOS support. |
internal/commands/connect_setup_guided_test.go |
Moves unsupported-platform coverage to Windows. |
internal/commands/connect_service.go |
Keeps systemd services Linux-only. |
internal/commands/connect_service_test.go |
Tests service platform gates. |
internal/commands/connect_run.go |
Enables connector execution on macOS. |
internal/commands/connect_run_test.go |
Tests Linux and macOS support. |
internal/commands/connect_operator_test.go |
Updates doctor platform expectations. |
internal/cli/token_handover_platforms_test.go |
Tracks the shared sealing implementation. |
internal/cli/inherited_fds_seal.go |
Shares descriptor sealing across Linux and macOS. |
internal/cli/inherited_fds_other.go |
Excludes macOS from the no-op implementation. |
internal/cli/inherited_fds_linux.go |
Reuses shared sealing helpers. |
internal/cli/inherited_fds_darwin.go |
Implements macOS descriptor sealing. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
All reported issues were addressed across 20 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
- The /dev/fd fallback fails closed: it refuses when the descriptor limit can't be read or is too large to scan, rather than checking a smaller range. - The zombie-only group refusal applies on macOS alone: on Linux, EPERM is a group this process may not signal, and /proc mounted hidepid can't list its members to say otherwise. - The token's taker is the peer the trust check named before the write, not a second reading: a server that reads its token and closes at once would come back unnamed on macOS and hold the attempt. - The other platforms' token refusal names --connect-token-fd. - Both skills say the connector runs on Linux and macOS. - Comments and names that still said Linux only. - Tests: macOS sealing (/dev/fd walk and fallback), the token reader and the MCP connect flow now build and run on macOS too.
There was a problem hiding this comment.
All reported issues were addressed across 16 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
- connect doctor's Platform hint and comment name Linux and macOS. - The /dev/fd fallback runs only when /dev/fd can't be opened; a descriptor the walk fails to seal is that error. Its messages tell a zero limit from one too large to scan. - macOS tests for a zombie-only group (no such group) beside one with a live member (still signaled), and for a real socket peer that closed (gone, with its user). - The connect skill no longer mentions the hidden service.
There was a problem hiding this comment.
All reported issues were addressed across 6 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
The descriptor limit doesn't bound which descriptors are open: a parent can open one high and then lower the limit. /dev/fd is always mounted on macOS, so there's no fallback; if it can't be read, sealing fails.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The token receiver’s process identity is captured after delivery, leaving a PID-reuse race that can record the wrong process.
Review effort: Balanced
Findings: 1
Open (1)
Resolved since last review (1)
Once the worker has read its token and gone, its pid could belong to another process. Looked up before the write, the taker is the process that was checked.
There was a problem hiding this comment.
All reported issues were addressed across 2 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic



basecamp connectrefused to run on a Mac: "The connector runs on Linux only, not darwin: … Linux is the only platform that seals the descriptors a process inherits". Most of us are on Macs, so most people couldn't connect an agent at all.That reason turned out not to be true. When the connector hands a worker its one-time token, it passes it on an inherited file descriptor. The CLI's first job at startup is to mark every inherited descriptor close-on-exec, so nothing it starts can pick the token up. It only did that on Linux. macOS can do the same: list
/dev/fdand mark each one, exactly as the Linux fallback for older kernels already does with/proc/self/fd. I checked this on a Mac first. Without the marking, a child process could see the descriptor; with it, it couldn't.What changes
/dev/fd. If that can't be read, it refuses to start rather than guess which descriptors are open.basecamp connectruns on macOS. On other platforms it now says "Linux and macOS only".Found by running the connector's tests on a real Mac
CI only runs the Go tests on Linux, so this was the first time they'd run on macOS. Three things came up, and the first two are real behaviour differences:
select. It sleeps now.Tried on a Mac
basecamp, the setup wizard) fail on macOS onmaintoo. They're unrelated to the connector and not touched here.auth agent connect,connect setupandconnect doctorall passed. The connector picked up a mention, boosted 👀, replied and completed the task. The worker was the e2e stand-in, because over SSH macOS keeps the Keychain locked and Claude Code reports itself logged out.Summary by cubic
Lets
basecamp connectrun on macOS. Previously it refused to start on a Mac because the CLI only sealed inherited descriptors on Linux; macOS can seal its own by listing/dev/fd, so the token handover now works there. macOS always mounts/dev/fd, so if it can't be opened the CLI fails closed rather than guessing. The background service stays Linux-only since it writes a systemd unit, and now says so on a Mac.Fixes found by running the connector's tests on a real Mac:
select(a runtime deadlock on macOS) now sleeps instead.Written for commit 352932e. Summary will update on new commits.