Skip to content

feat: switchboard mode (dial openab-sb /vm/attach) - #53

Merged
chaodu-agent merged 1 commit into
mainfrom
feat/switchboard-mode
Oct 3, 2026
Merged

chaodu-agent merged 1 commit into
mainfrom
feat/switchboard-mode

Conversation

@chaodu-agent

Copy link
Copy Markdown
Contributor

Closes #52.

Summary

oab-instance-mcp --switchboard wss://…/vm/attach --switchboard-secret-file <path> [--switchboard-profile observe|desktop|owner] dials an openab-sb switchboard and serves this computer's tools on that socket. The switchboard's callers (Connect, agents, and later Muse, openab-sb#3) can then reach a Mac that only dials out.

The change reuses ReverseAttachClient, which already spoke the same plain-MCP-over-WS. A new Kind (.openabPty, the default and unchanged, or .switchboard) selects what differs between the two modes:

openab-pty (unchanged) switchboard
URL base + /tools/attach/{session} as given
lifetime ends at grant deadline none; runs as long as the process
stop 4001, 4002, 4004, 4010, handshake 4xx 4002 replaced, 4003 secret revoked
redial 4006, 1000, drops 4005, 1001, 1000, drops, 5xx; 1 s → 60 s ±20 %, reset after 60 s up
401/403 stop retry every ~5 min (waitForCredentials)

Other changes:

  • The secret is re-read from --switchboard-secret-file on every dial, so rotating it is a file write.
  • A new Sources/InstanceMCPCore/Switchboard.swift holds three things:
    • URL validation: wss://, or ws:// to loopback only; the path must end in /vm/attach.
    • Profile instructions that say the caller came through the switchboard, not Connect.
    • The client factory.
  • The profile defaults to observe, and the switchboard's per-caller allowlist applies on top.
  • Terminal.secretRevoked adds the secret_revoked label.
  • README: new section "Serving a switchboard".

Tested (macmini, macOS 15.7)

  • swift test: 136/136 pass. 14 of them are new in SwitchboardTests.swift: policy, URL validation, instructions, secret re-read, and end to end against a fake switchboard (4003 stop, 4002 stop, 4005 redial, no deadline).

  • Mutation check: each of these breaks at least one new test:

    • 4003 → redial
    • switchboard URL → /tools/attach
    • 401 → stop
    • secret not re-read

    The last one first survived because the test called the helper directly; it now asserts on the dial request's Authorization header.

  • Live, release build against a real openab-sb (18/18):

    • observe: tools/list = sys_info, screenshot, vm_status; sys_info works; exec is refused.
    • desktop + Playwright upstream: there is no exec*, browser_navigate to example.com works, and browser_snapshot sees "Example Domain".
    • Rotating the VM secret on the switchboard with SIGHUP gives 4003; the attach stops and the HTTP endpoint keeps serving.
    • Wrong secret gives 401, then redial in 243s, with exactly one auth failure in the switchboard audit.
    • With two daemons on one secret, the older stops on 4002 and nothing flaps.
    • After a switchboard restart (1001), the daemon redials and reattaches.
  • Flag validation: ws:// to a tailnet IP and a secret file without --switchboard both exit 64 with a message.

Not tested

  • screenshot through the switchboard returned the TCC error, because the test binary was unsigned. The relay of that tool error was verified, but not an actual image.
  • wss:// from this daemon. The wss path through tailscale serve was verified with openab-sb's Python reference daemon, not this binary.
  • LaunchAgent / menu-bar integration: there is no UI for the switchboard state yet.

@chaodu-agent
chaodu-agent merged commit 386b8ac into main Oct 3, 2026
7 checks passed
@chaodu-agent
chaodu-agent deleted the feat/switchboard-mode branch October 3, 2026 16:13
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.

Switchboard mode: dial openab-sb /vm/attach and serve this computer's tools

1 participant