crewx-bridge
v0.2.64
Published
Secure macOS and Linux machine bridge for CrewX agent runtimes.
Maintainers
Readme
crewx-bridge
CrewX Bridge is CrewX's default and recommended connection method for
persistent agents. It securely enrolls a macOS or Linux machine with a CrewX
workspace and lets workspace administrators launch native profiles or any
harness in CrewX's pinned [email protected] catalog in folders approved by that
machine's owner.
For a managed OpenClaw profile, CrewX creates the corresponding OpenClaw agent
inside the selected approved folder; it never approves a new local path from a
remote request.
Bridge is not a remote shell. It accepts only signed-in, server-authorized,
structured start_agent and stop_agent commands. It uses an outbound HTTPS
connection, per-machine credentials, run-bound agent credentials, command
leases, a durable idempotency journal, strict folder identities, fixed
shell: false process templates, and a local policy that the server cannot
loosen. Run credentials currently have no wall-clock expiry because live
runners cannot rotate them; the server authorizes them only while their exact
Bridge run is active and revokes them on every terminal path.
The enrolled OS account is the local trust boundary. Bridge's fixed command templates, one-shot credential pipe, and the CLI's loopback capability proxy prevent accidental credential inheritance and reduce the exposed API surface; they do not isolate hostile runtime code executing as the same user. Such code may inspect that user's files and processes, including protected Bridge state. Use a dedicated OS account, container, VM, or host for untrusted or full-access agents.
Requirements
- Node.js 22.13 or later
- macOS or Linux
- the coding runtimes you intend to use already authenticated for the OS user
- a CrewX account, or a one-time enrollment code if an administrator is connecting this machine on your behalf
Do not install or run Bridge as root. On a shared or production host, use a dedicated OS user.
Install
One command signs you in, connects this machine, and creates your first agent. It installs the per-user service too, so the machine keeps answering after you close the terminal.
npx crewx-bridge@latest installIt will ask you to approve the sign-in in a browser, pick a workspace if you belong to more than one, and choose the folder the agent may work in.
To pin it to a self-hosted CrewX, or to name the machine yourself:
npx crewx-bridge@latest install \
--url https://crewx.example \
--name "Build Mac" \
--workspace acmePrefer a global install for a long-lived machine — npx runs out of a cache
npm may prune, and a service installed from it stops working the day that
happens:
npm install --global crewx-bridge
crewx-bridge installSigning in separately
install does this for you. These exist for re-authenticating a machine that
is already connected:
crewx-bridge login
crewx-bridge logoutEnrolling with a one-time code
For a machine an administrator provisions on someone else's behalf, where signing in as yourself is not what you want:
crewx-bridge enroll \
--url https://crewx.example \
--code crwb_enroll_… \
--name "Build Mac"Approving folders
Register each project locally. The CrewX web application sees only the name, opaque ID, and filesystem identity—not the path.
crewx-bridge folder add ~/Development/product --name Product
crewx-bridge folder listThe daemon reloads local folder approvals and permission limits before each launch. You do not need to restart it after adding a folder. Removed folders and tightened permissions also take effect on the next launch. If the local configuration cannot be read safely, the launch fails rather than using stale approvals. Changing the machine's enrollment requires a service restart.
If an agent cannot start, check crewx-bridge runs --all for the failure and
recovery instructions, including failures that occur before a process starts.
Workspace administrators can also see the connection diagnostic in the agent's
direct conversation and open its connection details to retry.
If service status reports a different daemon version than the CLI, check
which -a crewx-bridge for multiple installations. Run
crewx-bridge service install from the intended installation, then
crewx-bridge service restart --no-resume-runs to load it without relaunching agents.
Running install again reuses a healthy enrollment in the same workspace.
It does not create another machine or replace credentials. A stopped or
outdated service gives recovery instructions instead. Use crewx-bridge update
--repair to upgrade and reload that service even when the CLI is already
current; this requires confirmation and safely restarts its supervised agents.
Global installs update their own prefix, so switching between Homebrew and
NVM does not silently update a different copy. Changing workspaces requires
an explicit install --replace.
Inspect the connection and runtimes:
crewx-bridge doctor
crewx-bridge status
crewx-bridge runsKeep Bridge, its service definition, and its health checks current with one command:
crewx-bridge updateUse crewx-bridge update --check to check npm without installing,
crewx-bridge update --yes for an unattended update, or
crewx-bridge update --to <version> to install an exact published version. An
update reinstalls and restarts the per-user service, runs status and doctor
checks, and shows the local run history. Supervised agents are stopped safely
and relaunched automatically after the updated service reconnects. The status
check confirms that CrewX received a current-version daemon heartbeat; a loaded
launchd or systemd unit alone is not treated as healthy.
Install the user service:
crewx-bridge service install
crewx-bridge service status
crewx-bridge service stop
crewx-bridge service start
crewx-bridge service restartRestarting Bridge safely stops the agent runners it supervises and relaunches
them automatically after the service returns.
crewx-bridge service restart --no-resume-runs for an intentional cold restart.
Use crewx-bridge runs --all to inspect active and historical local run
records.
When a supervised runner exits unexpectedly, Bridge keeps a rotating, owner-only local log capped at 256 KiB and retains at most 100 run logs. View a failed run and its log with:
crewx-bridge runs --all
crewx-bridge runs logs <run-id>CrewX receives only a short, token-redacted diagnostic. Full runner output and local filesystem paths remain on the enrolled machine.
If CrewX rejects a durable local command outcome, Bridge quarantines that single outcome, reports degraded health, and pauses new claims. Inspect and recover it explicitly while the service is stopped:
crewx-bridge service stop
crewx-bridge outcomes list
crewx-bridge outcomes retry <command-id> --yes
# Or, after reviewing the local run:
crewx-bridge outcomes resolve <command-id> --accept-server-state --yes
crewx-bridge service startRetry keeps the local outcome pending for another authenticated reconciliation. Resolve accepts CrewX server state, preserves an operator audit record, and refuses to proceed if the run ID, nonce, and process-group identity still verify a live runner. Authentication failures require re-enrolling the machine before retrying.
On Linux, unattended operation after logout may require an administrator to enable systemd user lingering. Bridge reports this but never runs a privileged command itself.
Local policy
Bridge allows read_only and standard by default and permits at most two
concurrent runs. Full access requires an explicit local opt-in:
crewx-bridge policy \
--adapters codex,claude,pi \
--permissions read_only,standard,full_access \
--max-runs 2 \
--allow-full-accessTreat full access as equivalent to giving that agent the OS user's filesystem
and command privileges. Prefer a dedicated host or OS account.
Disable that opt-in again with crewx-bridge policy --deny-full-access.
ACP harnesses execute on the host as the enrolled OS user. ACP permission decisions are consent controls, not a portable filesystem sandbox; use the harness's own sandbox or OS-level isolation for a hard boundary.
Foreground operation
For development or diagnostics:
crewx-bridge serve
crewx-bridge serve --onceCtrl+C stops supervised child agents before exiting.
Only one Bridge daemon may own an enrollment for an OS user at a time. A protected local lock rejects a second live daemon and recovers a stale lock after an unclean exit. If the process crashes inside the tiny lock-recovery critical section, Bridge fails closed with an actionable recovery-lock error instead of risking two daemons. Installed runtime capabilities are refreshed every five minutes.
Empty command claims back off with bounded full jitter from the server's minimum to 8 seconds and reset immediately when a command arrives. Heartbeats use their own deadline and remain fresh while a longer claim delay is pending.
Protected state
Credential files are written atomically with mode 0600 below a mode 0700
directory. Bridge refuses symlinks, unsafe ownership, and group/world-readable
state.
These file permissions separate OS users, not processes running as the same user. The run token travels through a one-shot pipe rather than the child's exec environment; that does not make a same-user shell or desktop a security sandbox. Do not treat either control as proof of routine policy enforcement against arbitrary commands on the machine.
- macOS:
~/Library/Application Support/CrewX Bridge/config.json - Linux:
${XDG_CONFIG_HOME:-~/.config}/crewx/bridge/config.json
The local command journal records prepared, accepted, and terminal outcomes
before they are reported, so a lost response or redelivered command cannot
start a second child or overwrite a recorded success. It contains command/run
IDs and PIDs, never run credentials. The supervised CLI keeps final assistant
messages, errors, and lifecycle outcomes in its own bounded owner-only outbox
until CrewX acknowledges them.
Each start command may include the agent profile's persisted opaque runner scope. It is a non-secret local-state key, not an authorization credential, and keeps the runner's outbox and owner lock stable across token rotation. Older servers may omit it; Bridge then derives a compatibility scope from server URL, agent ID, and adapter.
Compatibility and rollout
Deploy a server that accepts the optional runner scope and health fields before
updating pilot machines, then publish protocol, CLI, and Bridge in that order.
The new Bridge remains compatible with the previous server: it retries a
heartbeat without health only when a 422 explicitly identifies that field,
and retains terminal outcomes for legacy lease-bound completion when the
durable outcome endpoint returns 405 or a structured
endpoint_unsupported error. A structured command_missing 404 is quarantined
and pauses new claims so an ambiguous terminal result cannot disappear.
Unrelated validation failures are not hidden. Rolling a pilot machine back to the prior client remains safe
because the server treats the new fields as optional; use a cold restart only
when intentionally abandoning automatic run resumption.
See docs/BRIDGE_ARCHITECTURE.md in the
CrewX monorepo for the threat model, protocol, leasing lifecycle, and security
invariants.
Linux supervisor verification
From the monorepo, run pnpm --filter crewx-bridge test:linux-supervisor.
Docker and a locally available node:22-bookworm image are required; the command
does not pull an image. The full image supplies Git, required by checkout
ownership checks. The command builds protocol, CLI and Bridge, then runs the
supervisor tests as an unprivileged Linux user with no external network,
read-only package/dependency mounts and disposable writable home/temp storage.
It does not mount host credentials, the application environment or Docker's socket.
This includes the /proc credential-environment check skipped on macOS and a
real Bridge → CLI → ACP exchange with a fake Gemini executable and loopback
CrewX API. It is not a live provider test, all-harness acceptance, or proof of
isolation between the Bridge and same-user agent processes. Container cleanup
removes only the disposable test container and its temporary state.
