Background daemon that keeps a Playwright browser alive between CLI calls.
Listens on a Unix domain socket for JSON commands, executes them against the browser, and returns JSON responses. Each command is one JSON line; each response is one JSON line.
Usage: (start-daemon! {:session "default" :headless true}) ;; blocks (daemon-running? "default") ;; check (stop-daemon!) ;; cleanup
Background daemon that keeps a Playwright browser alive between CLI calls.
Listens on a Unix domain socket for JSON commands, executes them against
the browser, and returns JSON responses. Each command is one JSON line;
each response is one JSON line.
Usage:
(start-daemon! {:session "default" :headless true}) ;; blocks
(daemon-running? "default") ;; check
(stop-daemon!) ;; cleanup(auto-launch-browser! {:keys [channel session headless]
:or {channel "chrome" session "default" headless true}})Launches a browser with --remote-debugging-port on a free port. Uses a temp user-data-dir so the user's existing browser stays untouched.
Params:
channel - Browser channel (e.g. 'chrome', 'msedge'). Defaults to 'chrome'.
session - Session name, used for lock file ownership.
headless - Boolean, whether to launch headless.
Returns a map: :cdp-url - CDP endpoint URL (http://127.0.0.1:<port>) :port - The allocated port :browser-pid - PID of the launched browser process :tmp-dir - Path to the temp user-data-dir (for cleanup)
Launches a browser with --remote-debugging-port on a free port. Uses a temp user-data-dir so the user's existing browser stays untouched. Params: `channel` - Browser channel (e.g. 'chrome', 'msedge'). Defaults to 'chrome'. `session` - Session name, used for lock file ownership. `headless` - Boolean, whether to launch headless. Returns a map: :cdp-url - CDP endpoint URL (http://127.0.0.1:<port>) :port - The allocated port :browser-pid - PID of the launched browser process :tmp-dir - Path to the temp user-data-dir (for cleanup)
(cdp-route-lock-owner cdp-url)Returns the owning session name when cdp-url currently has an active
cross-session route lock, otherwise nil. Stale locks are cleared lazily.
Returns the owning session name when `cdp-url` currently has an active cross-session route lock, otherwise nil. Stale locks are cleared lazily.
(daemon-running? session)Checks if a daemon is running for the given session.
Checks if a daemon is running for the given session.
(dashboard-state)Returns a read-only snapshot of daemon state for the dashboard. Called by the dashboard HTTP server (runs in the same process).
Returns a read-only snapshot of daemon state for the dashboard. Called by the dashboard HTTP server (runs in the same process).
(discover-cdp-endpoint)Auto-discovers a running Chromium-based browser's CDP endpoint. Checks DevToolsActivePort files first across every known chromium-family user-data dir on the current OS (Chrome, Chromium, Edge, Brave, Vivaldi, Opera, Arc, Thorium — including snap/flatpak variants on Linux) and the ms-playwright cache, then probes common ports (9222, 9229). Returns a CDP URL string (http:// or ws://) suitable for Playwright connectOverCDP.
WSL awareness: when the DevToolsActivePort file was read from a
Windows-projected path (/mnt/c/Users/...), loopback inside WSL
doesn't reach the Windows-side Chrome under default NAT networking.
In that case we also probe the default-gateway IP (= Windows host),
and the winning host is baked into the returned URL so Playwright's
connectOverCDP uses the right one.
Chrome/Edge 136+ ignores --remote-debugging-port without --user-data-dir. Chrome/Edge 144+ chrome://inspect remote debugging uses WebSocket-only (no HTTP).
Auto-discovers a running Chromium-based browser's CDP endpoint. Checks DevToolsActivePort files first across every known chromium-family user-data dir on the current OS (Chrome, Chromium, Edge, Brave, Vivaldi, Opera, Arc, Thorium — including snap/flatpak variants on Linux) and the ms-playwright cache, then probes common ports (9222, 9229). Returns a CDP URL string (http:// or ws://) suitable for Playwright connectOverCDP. WSL awareness: when the DevToolsActivePort file was read from a Windows-projected path (`/mnt/c/Users/...`), loopback inside WSL doesn't reach the Windows-side Chrome under default NAT networking. In that case we also probe the default-gateway IP (= Windows host), and the winning host is baked into the returned URL so Playwright's `connectOverCDP` uses the right one. Chrome/Edge 136+ ignores --remote-debugging-port without --user-data-dir. Chrome/Edge 144+ chrome://inspect remote debugging uses WebSocket-only (no HTTP).
(discover-external-cdp-endpoints excluded-ports)Scans for running CDP browsers. Probes common ports (9222, 9229),
the spel auto-launch port range, and any ports advertised in
DevToolsActivePort files (Chrome/Edge/Chromium/Brave/Vivaldi/Opera/Arc/
Thorium data dirs + ms-playwright cache). Excludes any ports in
excluded-ports. Fast TCP liveness check first so closed ports cost
~microseconds, then HTTP-probes listening ports with a 200 ms timeout. If
HTTP /json/version returns non-200 (e.g. Chrome M144+ chrome://inspect is
WebSocket-only), falls back to the DevToolsActivePort ws-path to build a
ws:// URL. Returns [{:port :cdp_url :label}], where :label is the browser
identified via DevToolsActivePort source directory or the Browser field
from /json/version (or "unknown" as a last resort).
WSL awareness: for DTAP entries whose source path lives under /mnt/,
both loopback and the WSL default-gateway IP are probed per port.
The winning host is baked into the returned :cdp_url so downstream
connectOverCDP talks to the host that actually answered.
Scans for running CDP browsers. Probes common ports (9222, 9229),
the spel auto-launch port range, and any ports advertised in
DevToolsActivePort files (Chrome/Edge/Chromium/Brave/Vivaldi/Opera/Arc/
Thorium data dirs + ms-playwright cache). Excludes any ports in
`excluded-ports`. Fast TCP liveness check first so closed ports cost
~microseconds, then HTTP-probes listening ports with a 200 ms timeout. If
HTTP /json/version returns non-200 (e.g. Chrome M144+ chrome://inspect is
WebSocket-only), falls back to the DevToolsActivePort ws-path to build a
ws:// URL. Returns [{:port :cdp_url :label}], where :label is the browser
identified via DevToolsActivePort source directory or the `Browser` field
from /json/version (or "unknown" as a last resort).
WSL awareness: for DTAP entries whose source path lives under /mnt/,
both loopback and the WSL default-gateway IP are probed per port.
The winning host is baked into the returned :cdp_url so downstream
`connectOverCDP` talks to the host that actually answered.(discover-session-files)Single source of truth for enumerating spel session state on disk.
Scans the tmpdir for spel-<name>.sock files and returns a seq of
{:name :socket :alive?} maps — :alive? is true when the owning PID
file points to a running process. Pure; does NOT start any daemon.
Single source of truth for enumerating spel session state on disk.
Scans the tmpdir for `spel-<name>.sock` files and returns a seq of
`{:name :socket :alive?}` maps — `:alive?` is true when the owning PID
file points to a running process. Pure; does NOT start any daemon.(find-free-cdp-port)Finds an available CDP port starting from 9222. Checks both the OS-level port availability and spel auto-launch lock files to avoid collisions with other sessions. Returns the port number or throws if none found.
Finds an available CDP port starting from 9222. Checks both the OS-level port availability and spel auto-launch lock files to avoid collisions with other sessions. Returns the port number or throws if none found.
(flags-file-path session)Returns the launch flags persistence file path for a session.
Returns the launch flags persistence file path for a session.
(kill-auto-launched-browser! {:keys [port browser-pid tmp-dir]})Kills an auto-launched browser process and cleans up its lock file and temp dir.
Kills an auto-launched browser process and cleans up its lock file and temp dir.
(launch-lightpanda! {:keys [session] :or {session "default"}})Spawns a Lightpanda subprocess in CDP-server mode and returns a map with
the CDP URL and child process info, parallel to auto-launch-browser! but
scoped to the Lightpanda binary.
Lightpanda is a Zig-based lightweight headless browser that speaks a
subset of the CDP. The user must have lightpanda on PATH; if not, we
throw a clear ex-info with install hints instead of blowing up inside
ProcessBuilder.
Returns: :cdp-url — WebSocket CDP endpoint (ws://127.0.0.1:<port>) :port — Allocated port :process — java.lang.Process for the subprocess :browser-pid — PID of the child
Spawns a Lightpanda subprocess in CDP-server mode and returns a map with the CDP URL and child process info, parallel to `auto-launch-browser!` but scoped to the Lightpanda binary. Lightpanda is a Zig-based lightweight headless browser that speaks a subset of the CDP. The user must have `lightpanda` on PATH; if not, we throw a clear ex-info with install hints instead of blowing up inside ProcessBuilder. Returns: :cdp-url — WebSocket CDP endpoint (ws://127.0.0.1:<port>) :port — Allocated port :process — java.lang.Process for the subprocess :browser-pid — PID of the child
(list-active-cdp-endpoints)Scans /tmp/spel-auto-launch-*.json for active CDP endpoints owned by spel sessions. For each lock whose owning daemon is still alive and whose port responds to a CDP /json/version probe, returns {:session :port :cdp_url}. Stale entries are filtered out silently.
Scans /tmp/spel-auto-launch-*.json for active CDP endpoints owned by spel
sessions. For each lock whose owning daemon is still alive and whose port
responds to a CDP /json/version probe, returns {:session :port :cdp_url}.
Stale entries are filtered out silently.(log-file-path session)Returns the log file path for a session.
Returns the log file path for a session.
(pid-file-path session)Returns the PID file path for a session.
Returns the PID file path for a session.
(read-session-flags session)Reads persisted launch flags for a session from the flags file. Returns a map of flag-name->value, or empty map if file doesn't exist. Used by CLI to recover flags like --cdp without requiring them on every command.
Reads persisted launch flags for a session from the flags file. Returns a map of flag-name->value, or empty map if file doesn't exist. Used by CLI to recover flags like --cdp without requiring them on every command.
(resolve-browser-binary channel)Resolves the filesystem path to a Chrome/Edge binary based on the channel name. Supports: chrome, msedge, chrome-beta, chrome-canary, msedge-beta, msedge-dev. Falls back to 'chrome' if channel is nil. Returns the binary path string, or throws if not found.
Resolves the filesystem path to a Chrome/Edge binary based on the channel name. Supports: chrome, msedge, chrome-beta, chrome-canary, msedge-beta, msedge-dev. Falls back to 'chrome' if channel is nil. Returns the binary path string, or throws if not found.
(socket-path session)Returns the Unix socket path for a session.
Returns the Unix socket path for a session.
(start-daemon! opts)Starts the daemon server. Blocks until shutdown.
Params:
opts - Map:
:session - String (default 'default')
:headless - Boolean (default true)
:browser - String (optional, e.g. 'firefox', 'webkit')
:cdp - String (optional, CDP endpoint URL)
Starts the daemon server. Blocks until shutdown. Params: `opts` - Map: :session - String (default 'default') :headless - Boolean (default true) :browser - String (optional, e.g. 'firefox', 'webkit') :cdp - String (optional, CDP endpoint URL)
(stop-daemon!)Stops the daemon server and cleans up browser resources. Closes server socket first so new CLI invocations fail fast and start a fresh daemon. Only deletes PID/socket files if they still belong to THIS process (prevents nuking a replacement daemon's files).
Stops the daemon server and cleans up browser resources. Closes server socket first so new CLI invocations fail fast and start a fresh daemon. Only deletes PID/socket files if they still belong to THIS process (prevents nuking a replacement daemon's files).
(wsl-default-gateway-ip)Delegates to platform/wsl-default-gateway-ip. Kept as a public wrapper for call-site compatibility (tests, diagnostic script, etc.).
Delegates to platform/wsl-default-gateway-ip. Kept as a public wrapper for call-site compatibility (tests, diagnostic script, etc.).
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |