Add `glimpse serve` which starts geckodriver + Firefox and proxies WebDriver requests through a Unix socket at $XDG_RUNTIME_DIR/glimpse-<uid>.sock. All commands auto-discover the socket and reuse the running browser session (~300ms vs ~2-3s per command). The proxy intercepts session create/delete to keep Firefox alive: new session requests return the existing session ID, delete session navigates to about:blank instead of closing Firefox. - `glimpse serve` starts in foreground, logs to stderr - `glimpse serve --stop` sends shutdown via socket - `glimpse serve --status` prints JSON status - SIGTERM/SIGINT do full cleanup (Firefox + geckodriver + socket) - Second instance detected and rejected with exit code 1 - GLIMPSE_SOCKET_PATH env var for test isolation - Three new smoke tests for serve lifecycle
glimpse
Small Firefox/Selenium browser utilities packaged with Nix.
The project provides a glimpse CLI with subcommands for page automation and provider-backed search. It runs Firefox headless by default. The Nix package wraps the binary so firefox and geckodriver are available on PATH.
Requirements
Nix Usage
Nix is the easiest way to run this project. It provides Node.js, Firefox, and geckodriver.
nix run .#glimpse -- exec https://example.com --js='return document.title'
Local Node Usage
If running directly with Node.js, install dependencies and make sure firefox and geckodriver are available on PATH.
npm install
npm run build
node dist/src/index.js exec https://example.com --js='return document.title'
Glimpse CLI
glimpse <command> [options]
Common options:
--config=<file>- read config from a custom path instead of~/.config/glimpse/config.json--no-headless- show Firefox instead of running headless--url=<server>- connect to an existing WebDriver server--timeout=<ms>- maximum wait time in milliseconds for command waits (default:10000)--wait-js=<code>- poll JavaScript until it returns a truthy value before command-specific behavior--wait-until=<state>- wait for document readiness:none,interactive, orcomplete(default:none)--js=<code>- execute inline JavaScript after loading the page and before command-specific behavior--script=<file>- execute JavaScript from a file after loading the page and before command-specific behavior
Running glimpse with no arguments or with --help prints human-readable help. Runtime and validation errors are emitted as structured JSON on stderr with ok: false, a stable error code, a human-readable message, and elapsedMs.
Snapshot A Page
Return an agent-friendly structured view of a page.
nix run .#glimpse -- snapshot https://example.com
Wait for asynchronous page state before extracting the snapshot:
nix run .#glimpse -- snapshot https://example.com --wait-until=complete --wait-js='return document.body.innerText.length > 0'
Output:
{
"ok": true,
"url": "https://example.com/",
"title": "Example Domain",
"result": {
"text": "Example Domain\nThis domain is for use in illustrative examples...",
"headings": [
{
"level": 1,
"text": "Example Domain"
}
],
"links": [
{
"text": "More information...",
"href": "https://www.iana.org/domains/example"
}
],
"buttons": [],
"inputs": [],
"forms": []
}
}
Snapshot includes page text, headings, links, buttons, inputs, and forms. Heading extraction is best-effort and does not fail the snapshot if heading metadata cannot be extracted.
Reader View To Markdown
Open a page with Firefox Reader View and print the readable article content as Markdown.
nix run .#glimpse -- reader https://example.com/article
Write Markdown to a file:
nix run .#glimpse -- reader https://example.com/article --output=article.md
Other formats are available:
nix run .#glimpse -- reader https://example.com/article --format=json
nix run .#glimpse -- reader https://example.com/article --format=html
nix run .#glimpse -- reader https://example.com/article --format=text
Options:
--format=<format>- outputmarkdown,html,text, orjson(default:markdown)--output=<file>- write output to a file
Execute JavaScript
JavaScript execution is available as a top-level option for every glimpse command. The script runs after loading the page and before command-specific behavior.
Use the exec command when you only want to print the returned JavaScript value.
Inline JavaScript:
nix run .#glimpse -- exec https://example.com --js='return document.title'
JavaScript from a file:
nix run .#glimpse -- exec https://example.com --script=extract.js
The script should explicitly return a value:
return {
title: document.title,
links: Array.from(document.querySelectorAll("a")).map((a) => a.href),
};
Objects and arrays are printed as formatted JSON. Primitive values are printed directly.
Screenshot A Page
Save a PNG screenshot after loading a page.
nix run .#glimpse -- screenshot https://example.com --output=example.png
Run JavaScript before taking the screenshot:
nix run .#glimpse -- screenshot https://example.com --js='document.body.style.zoom = "80%"' --output=example.png
If --output is omitted, the screenshot is saved to screenshot.png.
Output:
{
"ok": true,
"result": {
"path": "example.png"
},
"elapsedMs": 842
}
Search With A Provider
Search using a supported provider and print a JSON array of results. Currently only Kagi is supported.
Kagi requires a token from --token=<token>, KAGI_TOKEN, or the glimpse config file. The token is validated by the Kagi provider and sent to Kagi as the token query parameter.
Default config path:
~/.config/glimpse/config.json
Example config:
{
"search": {
"provider": "kagi"
},
"providers": {
"kagi": {
"token": "your-kagi-token"
}
}
}
Then search without exposing the token in command arguments:
nix run .#glimpse -- search "nix flakes selenium webdriver"
Local usage:
./result/bin/glimpse search "nix flakes selenium webdriver"
Options:
--provider=<provider>- search provider:kagi(default: config orkagi)--token=<token>- Kagi token (default:KAGI_TOKENor config)--no-headless- show Firefox instead of running headless--url=<server>- connect to an existing WebDriver server--timeout=<ms>- wait time for results before returning[](default:10000)
Output is a JSON array of search results:
[
{
"title": "Result title",
"url": "https://example.com",
"description": "Result description"
}
]
Build
Build the default package, which contains glimpse:
nix build .#default
Run the built tool:
./result/bin/glimpse exec https://example.com --js='return document.title'
./result/bin/glimpse search "example query"
Development
Enter the dev shell:
nix develop
Run linting:
npm run lint
Run smoke tests. These require Firefox and geckodriver on PATH and use local data: HTML pages.
npm test
Run focused smoke tests by tag when iterating on a specific area:
npm run test:list
npm run test:snapshot
npm run test:wait
npm run test:errors
node test/smoke.js snapshot js
Useful local commands:
npm run build
node dist/src/index.js snapshot 'data:text/html,<title>Hello</title><h1>Hello</h1>'
node dist/src/index.js exec 'data:text/html,<title>Hello</title>' --js='return document.title'
node dist/src/index.js screenshot 'data:text/html,<title>Hello</title>' --output=/tmp/page.png
node dist/src/index.js reader 'https://example.com/article'
Project Structure
src/index.ts-glimpseCLI with subcommands, including Firefox Reader View extraction and provider-backed searchsrc/config.ts- home-dir config loading for CLI defaults and provider settingssrc/driver.ts- Firefox WebDriver creation and geckodriver resolutionsrc/providers/kagi.ts- reusable Kagi search provider implementationtsconfig.json- TypeScript compiler settings; build output goes todist/flake.nix- Nix dev shell, package, wrappers, and appsKAGI.md- Kagi-specific notes