Skip to main content

Switchboard

Switchboard is a directory and an encrypted task mailbox for sharing selected local agent sessions with permitted people in your workspace. Readable prompts, answers and transcripts never leave the harness on the machine that ran them — the hosted service routes opaque ciphertext between permitted devices and stores nothing it can read.

Switchboard is in alpha. Calls between separate signed-in machines have completed end to end. Treat every other path as pilot material.

How it works

flowchart LR
    UI[Switchboard Web App<br/>or Desktop App]
    U[Caller asks a question] --> H[Caller harness<br/>any supported harness]
    H <-->|MCP over local stdio| L[Local MCP server]
    L <-->|local loopback| C[Caller Local Connector]
    UI -.->|local service health and sharing controls| L
    UI -.->|identity, pairing and sharing controls| M[Switchboard Network Backend<br/>directory, grants, opaque mailbox]
    C -->|signed encrypted envelope over HTTPS| M
    M -->|opaque ciphertext only| W[Owner Local Connector<br/>and mailbox worker]
    W -->|decrypt + recheck grant and policy| A[Local A2A task and harness adapter]
    A --> S[Owner source session<br/>or caller-isolated continuation]
    S --> A
    A -->|encrypted result follows the reverse path| H
Component What it does Where
Switchboard Web App Authenticated browser UI: directory, sharing, inbox, settings switchboard-control behind Cloudflare Access
Switchboard Desktop App Companion app: onboarding, agents, contacts, wallet and service controls apps/desktop (Tauri: Rust + React)
Switchboard Network Backend Hosted control plane: identity, grants, opaque mailbox routing, credit ledger switchboard-control, Docker + PostgreSQL
Local Connector Discovers local harnesses, enforces the answer-only policy, runs the mailbox worker and local MCP server src/switchboard/local, supervised per platform (LaunchAgent, systemd user service, Scheduled Task)

Local handle routing

ask:<handle> resolves against both the owner-local directory and callable network shares. An owner-local match stays on the machine and runs through the existing private A2A invocation; its source session is never published to the hosted directory. A remote match keeps using the encrypted mailbox. Conflicting local and remote matches are reported as ambiguous, and an incomplete directory leaves an unmatched handle unknown rather than unavailable. Local handle discovery reads the current mapping from the local API on each lookup.

Getting started

Open the dashboard

Your workspace administrator runs the Switchboard Network Backend and has the dashboard URL. Sign in with a permitted account and continue to the workspace. Workspace membership admits you to the directory; each agent's owner still chooses who may call it.

Set up a machine

The desktop app is the easy path: it checks for uv, installs the connector, registers your harnesses, runs the Verified A2A sign-in, pairs the machine and starts the resident service. No source checkout is involved. Download it from switchboard-releases; after that it updates itself from its About page. To build it yourself instead:

cd apps/desktop && pnpm install
pnpm tauri build --config '{"bundle":{"createUpdaterArtifacts":false}}'   # then open the built app

Prefer the terminal? The same steps, on macOS and Linux alike:

uv tool install switchboard-connector               # installs the `switchboard` CLI
switchboard install --switchboard-url <url>          # harnesses, Verified A2A, resident service
switchboard pair --device-name "my machine"

The PyPI distribution is switchboard-connector (the name switchboard belongs to an unrelated project); the command it installs is switchboard. Update it later with uv tool upgrade switchboard-connector.

install sets up a LaunchAgent on macOS, a systemd user service on Linux and a Scheduled Task on Windows; switchboard start, stop, status and uninstall manage it afterwards. Only the pair sign-in and the Share approval are manual, by design.

The control-plane address is set once per machine and stored locally; the connector worker and the harness-launched MCP both resolve that single setting, so they cannot point at different servers. The desktop onboarding offers https://switchboard-api.provably.ai (or SWITCHBOARD_API_URL, if the app was launched with it) under Advanced, checks that the server's /health answers before installing anything, and stores it. From the terminal, pass switchboard install --switchboard-url <url>. Without a stored address the connector uses SWITCHBOARD_API_URL, and otherwise the same production default.

The approval bridge on 127.0.0.1:8766 answers the control plane and the desktop app. If the Switchboard web app runs somewhere else, name it:

switchboard install --web-app-url https://app.example.com

Comma-separate more than one, say a deployed app and your own copy. It is stored as SWITCHBOARD_WEB_APP_URL, matched as an exact origin, and refused at startup unless it is a complete https address (http only for localhost). Unset, the bridge accepts exactly who it accepts today.

Linux notes

switchboard install writes ~/.config/systemd/user/switchboard.service; run loginctl enable-linger "$USER" to keep it running while you are logged out, and journalctl --user -u switchboard to read its log. The device credential and mailbox keys live in the macOS Keychain; on Linux they are 0600 files under ~/.local/state/ProvablySwitchboard/, protected by your disk encryption.

Windows

Windows runs Switchboard natively: switchboard install registers a per-user Scheduled Task that starts the connector at logon and restarts it if it fails, needing no elevation. Credentials are files under your profile directory, where Windows' own ACL keeps other standard users out. switchboard start, stop, status and uninstall drive the task exactly as they drive the service elsewhere.

Two caveats. Harness CLIs installed by npm or bun are .cmd shims, which Switchboard runs through cmd.exe — this path gets less real-world use than the Unix one, so report anything that misbehaves. And Hermes Desktop's automatic gateway discovery needs ps and lsof, so on Windows set HERMES_API_URL instead.

Windows (WSL2)

WSL2 is the alternative, and the better-travelled one: it is the Linux path above, with two requirements.

  • Enable systemd, so switchboard install can manage the service. Add this to /etc/wsl.conf, then run wsl --shutdown from Windows:

    [boot]
    systemd=true
    

    Without it, switchboard install says so and you run switchboard run in the foreground instead.

  • Install your harness CLIs inside the same distribution. Switchboard discovers sessions from the Linux home directory, so CLIs installed on Windows are invisible to it.

WSL forwards localhost, so the dashboard in a Windows browser still reaches the approval bridge on 127.0.0.1:8766.

Platform support

Platform State
macOS Supported: desktop app or CLI, LaunchAgent service, Keychain credentials
Linux Supported: desktop app or CLI, systemd user service, file-backed credentials
Windows Supported: desktop app or CLI, Scheduled Task service, file-backed credentials under the user profile. Less exercised than the others; WSL2 is the safe alternative

Self-host the control plane

Discovery failures are isolated per harness. Healthy sessions remain locally usable, and partial directory updates use /api/connector/heartbeat/partial. The control plane retains unavailable harnesses' agent identities and shares, disables their remote availability, and restores availability after discovery recovers. An actual removal from a successfully scanned harness still revokes the source's shares. Settings and agent rows distinguish harness unavailability from source removal; check the affected harness's connection or sign-in.

Deploy the matching control-plane support before this connector. Older servers reject the partial endpoint; the connector never retries that snapshot against the full endpoint. Completely empty discovery still preserves the last published directory. Neither a partial scan nor its failure prevents healthy local routing.

The hosted control plane (identity, directory, mailbox routing, credit ledger) lives in the separate switchboard-control repo — see that repo's README for docker compose up self-hosting.

Security model

Owner-local MCP listings deduplicate repeated session IDs within a harness, keeping the first record in discovery order. Different sessions with the same name remain distinct: pass the listed session_id to select one explicitly.

  • The Network Backend routes and revokes deliveries; it never sees a prompt, an answer or a transcript. Envelopes are opaque ciphertext at rest.
  • Sharing is one atomic action: the owner's fixed answer-only policy installs locally before a share can be created, and the mailbox worker rechecks the grant and policy before every invocation.
  • Revocation blocks future delivery immediately. It does not rewrite either person's local transcript.
  • Verified A2A (optional, QEDB-backed) adds route-and-record-integrity proofs, shown as green, orange or red marks on an answer.
  • Private caller (opt-in per share) shows the owner a caller-chosen alias instead of an account identity. The alpha credit ledger settles each answer in one double-entry transaction.

Development

Requires Python 3.12+ and uv. Verified A2A runs on sourcerykit, installed from PyPI with everything else.

uv sync
make check                      # pre-commit, full test suite, build — the CI gate

Common targets: make lint, make format, make typecheck (strict mypy on src), make test.

src/switchboard/
├── harness/          adapters for Codex, Hermes, Claude Code, OpenCode and OpenClaw
├── local/            the resident service: CLI, connector, approval bridge, policy
│   ├── owner_app/    the owner-local A2A app (task API, agent cards, state, web UI)
│   ├── mcp/          the harness-facing MCP server and its remote calls
│   ├── policy/       owner policy authoring and enforcement
│   └── skills/       the switchboard-ask skill installed into every harness
├── mailbox/          envelope crypto, client and worker, commitments, QEDB ledger
└── qedb/             A2A task store, task proofs and the A2A profile
apps/desktop/         Tauri desktop companion app
scripts/              MCP launcher and the verified-A2A smoke test
docs/                 harness registration and session publishing
tests/                mirrors src/switchboard

The hosted control plane (control/) lives in the separate switchboard-control repo — users installing this repo never pull down that server-side code.

Releases

The connector and the desktop app ship separately, each from its own tag, so a fix to one never forces a version bump of the other. Bump the version first and tag to match.

What Version in Tag Produces
Connector pyproject.toml connector-v0.1.1 A wheel and sdist, published to PyPI
Desktop app apps/desktop/src-tauri/tauri.conf.json (keep package.json and Cargo.toml in step) desktop-v0.1.1 A draft release in switchboard-releases
git tag connector-v0.1.1 && git push origin connector-v0.1.1
git tag desktop-v0.1.1   && git push origin desktop-v0.1.1

Release the connector first when the desktop app depends on its changes.

Connector. The tag publishes straight to PyPI, with no draft to review. Publishing uses trusted publishing through the pypi GitHub environment, so there is no token in the repo: configure the publisher once on PyPI (project → Publishing → GitHub, workflow release-connector.yml, environment pypi), and add a required reviewer to that environment if you want a deliberate click before anything goes out. Running the workflow from the Actions tab publishes too.

Desktop app. Each OS builds on its own runner (Tauri cannot cross-compile): .dmg for Apple silicon and Intel, .deb, .rpm and .AppImage, .msi and .exe. A tag run first checks the tag against tauri.conf.json, then creates one draft that every platform uploads to. A run from the Actions tab (where you can pick one platform) only builds: the bundles are attached to the run and no release is created.

Releases go to the public ProvablyAI/switchboard-releases repo, because the app's Check for updates (About page) downloads them without credentials. Besides the installers, each release carries a signed update bundle per platform and a latest.json. The app reads releases/latest/download/latest.json, so users get the update only once you publish the draft: check that every platform has its installer, its update bundle with a .sig, and that latest.json is there.

One-time setup, already done for this repo:

  • ProvablyAI/switchboard-releases exists, is public, and has a commit on main (release tags are created from it).
  • plugins.updater.pubkey in tauri.conf.json holds the updater public key. The workflow refuses to build while it is the placeholder.
  • Repo secrets: TAURI_SIGNING_PRIVATE_KEY and TAURI_SIGNING_PRIVATE_KEY_PASSWORD (the updater private key and its password, generated with pnpm tauri signer generate), and RELEASES_TOKEN (a fine-grained token with Contents: read and write on switchboard-releases only).
  • macOS signing and notarization secrets: APPLE_CERTIFICATE (the Developer ID Application .p12, base64), APPLE_CERTIFICATE_PASSWORD, APPLE_ID, APPLE_PASSWORD (an app-specific password) and APPLE_TEAM_ID.

The private key signs every future update. If it is lost, installed apps can no longer update and users must reinstall by hand.

The same About page checks the connector against PyPI; updating it runs uv tool install --force and restarts the service.

The macOS app is signed and notarized with the Developer ID secrets above. The Windows installer is not code-signed yet, so SmartScreen warns on it. (The updater signature above is separate from both.)

License

Business Source License 1.1 — see LICENSE.md. You may not offer the Software as a commercial hosted service without a commercial license from Provably Technologies Ltd. On the change date the license converts to GPL-3.0-or-later.

Release files for switchboard-connector 0.1.11

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for switchboard-connector 0.1.11
File Size Uploaded
switchboard_connector-0.1.11.tar.gz 623.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for switchboard-connector 0.1.11
File Interpreter ABI Platform
switchboard_connector-0.1.11-py3-none-any.whl Python 3 none any Details

Total release size: 807.3 kB

Release files / switchboard_connector-0.1.11.tar.gz

Download URL switchboard_connector-0.1.11.tar.gz
Size 623.9 kB
Tags Source
SHA-256 checksum
How to use checksums
ad43f7a21835a004de1fda9dc50ae1eeabe110755469247b0b13fb4f95b28747
BLAKE2b-256 checksum
How to use checksums
a8c0ca2532d9fb95c28a345be510e4f768aead08e75a1051e6d694fdd4296a46
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.

Transparency log

Release files / switchboard_connector-0.1.11-py3-none-any.whl

Download URL switchboard_connector-0.1.11-py3-none-any.whl
Size 183.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b42fe23f04f362e8a39b026b2940e4367d50fc1a226f134999bc819ed5b179bd
BLAKE2b-256 checksum
How to use checksums
9c9ff7b07c2b25476f7b6bf66f772b3ff1ed23a88dcc6c67a43b325401117544
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.

Transparency log

Release history Release notifications | RSS feed

0.1.15

2 release files

0.1.14

2 release files

0.1.13

2 release files

This release

0.1.11 This release

2 release files

0.1.10

1 release file

0.1.9

1 release file

0.1.8

1 release file

0.1.7

1 release file

0.1.6

1 release file

0.1.5

1 release file

0.1.4

1 release file

0.1.3

1 release file

0.1.2

1 release file

0.1.1

1 release file

0.1.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page