Skip to content

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.

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 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.

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.

The Rust agent:

  1. opens Data/rel-data.sqlite3 and initializes the current schema when needed;
  2. opens the Chromium stdio bridge;
  3. starts profile proxy listeners;
  4. starts the serialized control worker;
  5. accepts HTTP on 127.0.0.1:17319 by 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.

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, and browser_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.

One Clark-patched CEF runtime is initialized under:

~/Library/Application Support/Rel/Data/Chromium

Each 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.

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.

The public session API exposes:

  • adblock_enabled;
  • image_blocking_mode, all or over_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.txt

Rules 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.

Logs are outside SQLite and outside RPC:

~/Library/Application Support/Rel/Data/Logs/global.ndjson
~/Library/Application Support/Rel/Data/Logs/sessions/<profile_id>.ndjson

Rust 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.

One process-wide cache lives at:

~/Library/Application Support/Rel/Data/Chromium/SharedAssets

It 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.

Database:

~/Library/Application Support/Rel/Data/rel-data.sqlite3

The 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.

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

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.

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.