Deployment
This page shows where each piece of bproxy actually runs — what machine hosts it, what process boundary contains it, and what files it persists on disk. The arrows show what crosses each boundary and over what wire, but not the sequence of events on those wires; behaviour, internal component structure, and concrete scenarios live in the other pages linked at the bottom.
--- title: bproxy — Deployment --- flowchart TB Operator(["Operator
[Person]
Owns the browser session and runs bproxy"]) subgraph host ["Operator's machine — [Deployment Node: macOS / Linux]"] Agent["Code Agent
[External Software System]
Process invoking the CLI"] CLI["CLI
[Process: Node.js + citty]
One-shot command, spawned per invocation"] Daemon["bproxy daemon
[Process: Node.js + Fastify, bound to 127.0.0.1:9615]
Long-running localhost service, routes and paces requests"] subgraph stateDir ["BPROXY_HOME / ~/.bproxy — [Deployment Node: Filesystem, mode 0700]"] Token["token
[State file, 0600]
Daemon bearer for HTTP clients"] ExtToken["extension-token
[State file, 0600]
Bearer for the extension's WebSocket"] Logs["logs/
[State directory]
Structured request logs"] Lock["bproxy.pid + port
[State files]
Lifecycle handles"] end subgraph browser ["Chrome profile — [Deployment Node: Chrome browser, operator-owned]"] Popup["Extension popup
[Process: HTML page]
Pairing UI"] BG["Background service worker
[Process: MV3 service worker]
Holds the daemon WS link and dispatches actions"] CS["Runtime content script
[Process: ISOLATED-world script]
Reads and writes the page DOM"] Storage["chrome.storage
[State: local + session]
Extension token and per-session caches"] Tab["Real browser tab
[Browsing context]
Operator's signed-in session"] end end Site["Remote website
[External Software System]
Target site reachable over the public internet"] Operator ~~~ Agent Operator -- "pairs the extension via" --> Popup Agent -- "invokes" --> CLI CLI -- "sends action requests to
[HTTPS, Bearer]" --> Daemon Popup -- "claims a pairing code from
[HTTPS]" --> Daemon BG -- "maintains action link with
[WebSocket, extension token]" --> Daemon Daemon -. "reads and writes" .-> Token Daemon -. "reads and writes" .-> ExtToken Daemon -. "writes" .-> Logs Daemon -. "reads and writes" .-> Lock Popup -. "writes" .-> Storage BG -. "reads and writes" .-> Storage BG -- "dispatches actions into" --> CS CS -- "reads and modifies" --> Tab Tab -- "loads and submits to" --> Site Site ~~~ Legend subgraph Legend["Legend"] direction LR LP(["Person"]):::person LC["Container
instance"]:::system LS["State
file"]:::state LE["External
system"]:::external LP ~~~ LC ~~~ LS ~~~ LE end classDef person fill:#08427b,color:#fff,stroke:#052e56; classDef system fill:#1168bd,color:#fff,stroke:#0b4884; classDef state fill:#5d7da3,color:#fff,stroke:#3e577a; classDef external fill:#999999,color:#fff,stroke:#6b6b6b; class Operator person; class CLI,Daemon,BG,CS,Popup system; class Token,ExtToken,Logs,Lock,Storage state; class Agent,Tab,Site external;
Figure 3. Deployment view of bproxy — where each runtime process lives on the operator’s machine, what state the daemon and the extension own, and how the agent and the operator reach the system from outside the boundary.
What this picture tells you
Section titled “What this picture tells you”Every bproxy runtime piece lives on the operator’s own machine. The CLI is short-lived — spawned per invocation, gone after a single command. The daemon is a long-running localhost service whose network surface is bound to 127.0.0.1 by design, not a LAN address and not an internet endpoint. The Chrome extension runs inside the operator’s existing Chrome profile, not in a separate automation browser. The whole control plane stops at the machine boundary.
State is split into two domains, each tied to the process that owns it. The daemon writes its bearer tokens, lifecycle handles, and structured logs under BPROXY_HOME (defaulting to ~/.bproxy), with the directory and the credential files locked down to the operator. The extension keeps its bootstrap token and per-session caches in chrome.storage, scoped to the Chrome profile. Neither side reads the other’s domain — the only thing they share is the authenticated WebSocket between the daemon and the background service worker.
Only the browser tab reaches the public internet, and it does so as the operator’s regular browsing traffic. The CLI never makes outbound calls; neither does the daemon. The content script reads and writes the page’s DOM but does not initiate network requests outside the page’s own context. From a remote server’s point of view, every request looks like the operator browsing normally — same cookies, same identity, same fingerprint.
See also
Section titled “See also”- Context — bproxy seen from the outside, the people and external systems it interacts with.
- Containers — the same processes from a logical perspective: their responsibilities and the protocols between them.
- Session state — the behaviour the daemon imposes on every forwarded action.
- Threat model — the security properties of these placements and the wires between them.
For normative implementation details on the daemon and the extension, see Proxy Daemon and Browser Extension.