Services
This is the operational inventory for the supported installed-app runtime. Exact HTTP and private-pipe payloads are in RPC. See CLI, Rust SDK, and Architecture for the client surface and end-to-end flows.
Service catalog
Section titled “Service catalog”| Component | Process | Interface |
|---|---|---|
| Rel host/UI | Contents/MacOS/Rel |
macOS windows, menu bar, and lifecycle |
| Agent supervisor | Rel process | Starts, monitors, and stops the bundled agent |
| Local agent | Contents/Resources/rel --agent |
Loopback-only HTTP RPC v1 |
| Chromium bridge | Rel and agent | Private framed JSON protocol v4 over child pipes |
| Embedded browser | Rel plus CEF helpers | App-internal ClarkBrowserKit/CEF API |
| Profile proxies | Agent threads | Per-session loopback HTTP/CONNECT listeners |
| Persistence | Agent | Current-schema-only SQLite store |
| Log files | Agent and Rel | Append-only NDJSON files displayed by the app’s Logs view |
| Adblock | Rel/CEF | Brave lists evaluated by Brave adblock-rust |
| Shared asset cache | Rel/CEF | Process-wide public asset cache |
| Terminal | Rel | One lazy Ghostty session per browser workspace |
Rel host
Section titled “Rel host”Rel is an installed macOS menu-bar app. It owns the browser window, Settings window, session stores, process-wide CEF runtime, Chromium bridge endpoint, and Ghostty sessions. Closing the main window hides it; the app and agent remain resident.
Quit stops the agent and immediately returns .terminateNow. It does not wait
for asynchronous CEF browser closure, so an active page load cannot delay app
termination.
Agent supervisor
Section titled “Agent supervisor”AgentSupervisor launches the bundled binary with exactly --agent and
REL_CHROMIUM_BRIDGE=stdio. It creates stdin/stdout pipes for bridge v4 and
drains stderr.
Before launch, it calls GET /v1/health and terminates a stale process only when
the reported PID resolves to this bundle’s agent executable. Health polling
starts after 500 ms and repeats every two seconds; three consecutive failures
restart the child. Stop sends SIGTERM and escalates after a short deadline.
Local agent
Section titled “Local agent”The Rust agent:
- opens
Data/rel-data.sqlite3and initializes the current schema when needed; - opens the Chromium stdio bridge;
- starts profile proxy listeners;
- starts the serialized control worker;
- accepts HTTP on
127.0.0.1:17319by default.
REL_AGENT_PORT changes the HTTP port. GET /v1/health and GET /v1/status
bypass the control queue; browser and configuration operations are serialized.
Page attachment IDs and bridge correlation state are process-local.
Only the versioned routes in RPC exist. Every ordinary success
uses {status, request_id, data} and every failure uses the one structured
error object. There are no unversioned aliases or compatibility response
shapes.
The public rel-client crate provides typed access to every route.
The bundled CLI uses this client rather than duplicating transport, envelopes,
or resource types.
Chromium bridge
Section titled “Chromium bridge”The agent cannot call CEF directly because the GUI process owns the runtime. Bridge protocol v4 crosses that boundary:
- four-byte unsigned big-endian length followed by UTF-8 JSON;
- 128 MiB maximum frame;
- operations
capture,browser_attach, andbrowser_action; - correlation by opaque bridge ID;
{version,id,status,data}success responses;{version,id,status,error}failures using the RPC error type.
The agent writes requests to its stdout and reads responses from stdin. Rel decodes on a serial queue, resolves the selected session on the main actor, and executes the request in ClarkBrowserKit. Both sides reject wrong versions, oversized frames, mismatched IDs, and malformed success/error payloads.
Chromium runtime
Section titled “Chromium runtime”One Clark-patched CEF runtime is initialized under:
~/Library/Application Support/Rel/Data/ChromiumEach persistent session gets an isolated request context and directory:
~/Library/Application Support/Rel/Data/Chromium/Tab-<profile_id>The context owns cookies, site storage, private HTTP cache, preferences, and its optional fixed loopback proxy. Browser activation is lazy.
Browser status distinguishes main-frame readiness from continuing background activity. Pause cancels active requests and blocks new network work; resume removes the gate and reloads when necessary. Blocked, failed, cancelled, and shared-cache requests do not increase downloaded network bytes.
Profile proxy listeners
Section titled “Profile proxy listeners”The base port is 17400, overridden by REL_BROWSER_PROXY_PORT. Profile N
uses:
base_port + (profile_id - 1)Each connection reloads the current session proxy assignment from SQLite. For a proxied session, CEF receives only its loopback address. Rust performs upstream HTTP relay or HTTPS CONNECT and constructs proxy authorization from credentials stored in SQLite; Swift and CEF never receive the password. Direct sessions do not route through the listener.
Filtering and adblock
Section titled “Filtering and adblock”The public session API exposes:
adblock_enabled;image_blocking_mode,allorover_limit;image_size_limit_kb.
There is no block_images wire alias and no custom ruleset API.
Global adblock enablement lives in UserDefaults. Rel downloads EasyList, EasyPrivacy, Brave Specific, and Brave Unbreak from Brave’s maintained mirror, combines their network rules, and caches the result at:
~/Library/Application Support/Rel/AdBlock/default-network-filters.txtRules refresh after four days. Brave’s adblock-rust engine evaluates the
request URL, initiator, resource type, and method. Effective adblock requires
both global and per-session enablement. Image filtering remains independent.
CEF filter events are written directly to the selected session’s NDJSON log; there is no filter-event ingestion RPC.
Log files
Section titled “Log files”Logs are outside SQLite and outside RPC:
~/Library/Application Support/Rel/Data/Logs/global.ndjson~/Library/Application Support/Rel/Data/Logs/sessions/<profile_id>.ndjsonRust and Swift append one complete JSON object per line. A record contains:
{ "id": "opaque-id", "created_at": 1785860000, "session_id": "machine-....Session12", "category": "network.filtered", "level": "info", "message": "Blocked GET https://... (adblock)", "data": {}}session_id and data are optional. Global process events go to
global.ndjson; session-scoped events go to the profile-ID file. The app’s
Logs view tails the selected session file, tolerates incomplete or malformed
lines, and resets its cursor when a file is replaced or truncated. Clear Logs
removes only the selected session file; the next append recreates it.
There are deliberately no HTTP routes to read, append, or clear logs.
Shared asset cache
Section titled “Shared asset cache”One process-wide cache lives at:
~/Library/Application Support/Rel/Data/Chromium/SharedAssetsIt is enabled by default at 512 MiB. Direct sessions share partition direct;
proxied sessions share only within proxy:<proxy_id>.
Only safe public HTTP(S) GET assets—images, stylesheets, scripts, fonts, and favicons—qualify. Requests with cookies, authorization, ranges, validators, or no-cache directives are excluded. Stored responses must be fresh, explicitly public, status 200, identity encoded, and at most 32 MiB; personalized or content-disposition responses are rejected. Size pruning uses last access.
The shared cache is separate from each session’s private CEF HTTP cache. The Info view can clear one session’s browser data; Settings can clear all private caches or the shared asset cache.
SQLite persistence
Section titled “SQLite persistence”Database:
~/Library/Application Support/Rel/Data/rel-data.sqlite3The current store owns:
| Table | Purpose |
|---|---|
requests |
Capture history, result, output, and proxy traffic totals |
events |
Capture events keyed to requests |
proxies |
Upstream endpoints, credentials, stable IDs, Oxylabs settings |
browser_profiles |
Session identity, name, proxy, adblock, and image policy |
rel_metadata |
Stable installation machine ID |
Rel creates and validates only the current schema. It does not assign a schema version, migrate earlier schemas, or import another database.
Older root-level ~/Library/Application Support/Rel/rel.sqlite3, Logs, and
Chromium data is ignored and is not automatically imported into Data.
SQLite uses WAL, synchronous=NORMAL, a five-second busy timeout, automatic
checkpointing, and bounded request/event history. It is not a public client API.
New profiles reserve an autoincrement ID and receive Session<ID> plus
machine-<UUID>.Session<ID>. The visible name is editable; the federated
session ID and numeric profile ID are immutable.
Configuration ownership
Section titled “Configuration ownership”| Location | Owner/data |
|---|---|
Data/rel-data.sqlite3 |
Agent: sessions, proxies/secrets, captures/events, machine ID |
Data/Logs/*.ndjson |
Agent and app: global and session observability |
Data/Chromium/Tab-<id> |
CEF: session-private browser data |
Data/Chromium/SharedAssets |
CEF: safe shared public assets |
AdBlock/default-network-filters.txt |
App: combined Brave network lists |
| UserDefaults | Global adblock and shared-cache settings |
Terminal
Section titled “Terminal”Each browser workspace owns one Ghostty terminal session. Its shell and Metal surface are created only when the Terminal bottom-panel tab is first displayed. It starts in the user’s home directory with the user’s Ghostty configuration. This is an app-internal component interface, not RPC.
Packaging
Section titled “Packaging”make install-app builds and signs one bundle containing the Swift host, Rust
CLI/agent, Brave adblock integration, Ghostty runtime, Clark-patched CEF
framework, and CEF helper apps. /Applications/Rel.app and its bundled agent
are the only supported runtime path.