Chrest: healthier window and tab hygiene
Chrest is a CLI tool and browser extension that lets you manage Chrome and
Firefox via REST. Chrest was inspired by (and somewhat forked from)
TabFS.
Chrest consists of two parts:
- Browser Extension: (/extension)
- Native Messaging Host & CLI Client:
chrest(/)
Note: to keep Chrest slim, Chrest does not include pretty-print JSON or HTTP
Request construction, but there are other wonderful tools you can use for that
like http and jq.
-
Getting all windows and tabs:
$ http --ignore-stdin --offline localhost/windows | $ chrest client | $ jq > [ > { > "alwaysOnTop": false, > "focused": false, > "height": 1400, > "id": 1531273373, > "incognito": false, > "left": 1411, > "state": "normal", > "tabs": [ > { > "active": true, > "audible": false, > "autoDiscardable": true, > "discarded": false, > "favIconUrl": "https://github.githubassets.com/favicons/favicon.svg", > "groupId": -1, > "height": 1279, > "highlighted": true, > "id": 1531273367, > "incognito": false, > "index": 0, > "mutedInfo": { > "muted": false > }, > "pinned": false, > "selected": true, > "status": "complete", > "title": "friedenberg/chrest", > "url": "https://github.com/friedenberg/chrest", > "width": 1128, > "windowId": 1531273373 > } > ], > "top": 20, > "type": "normal", > "width": 1128 > } > ] -
Creating a new window with some URL's:
$ http --ignore-stdin --offline localhost/windows \ $ urls[]=https://github.com/friedenberg/chrest | $ chrest client | $ jq > { > "alwaysOnTop": false, > "focused": false, > "height": 1400, > "id": 1531273390, > "incognito": false, > "left": 0, > "state": "normal", > "tabs": [ > { > "active": true, > "audible": false, > "autoDiscardable": true, > "discarded": false, > "groupId": -1, > "height": 1279, > "highlighted": true, > "id": 1531273391, > "incognito": false, > "index": 0, > "lastAccessed": 1708099951989.452, > "mutedInfo": { > "muted": false > }, > "pendingUrl": "https://github.com/friedenberg/chrest", > "pinned": false, > "selected": true, > "status": "loading", > "title": "", > "url": "", > "width": 1128, > "windowId": 1531273390 > } > ], > "top": 0, > "type": "normal", > "width": 1128 > } -
Closing a window:
$ http --ignore-stdin --offline DELETE localhost/windows/1531273390 | $ chrest client | $ jq
chrest capture drives a headless browser to render a URL and returns the
result in the format you ask for. Output streams to stdout by default; use
--output <path> to write atomically to a file.
Eleven formats are supported:
| Format | Media type | Notes |
|---|---|---|
pdf |
application/pdf |
flags: --landscape, --no-headers, --background |
screenshot-png |
image/png |
flag: --full-page |
screenshot-jpeg |
image/jpeg |
flags: --quality, --full-page |
mhtml |
multipart/related |
not yet functional |
a11y |
application/json |
not yet functional; accessibility tree |
text |
text/plain; charset=utf-8 |
document.body.innerText |
html-monolith |
text/html; charset=utf-8 |
self-contained HTML with assets inlined as data: URIs (via the monolith CLI) |
html-outer |
text/html; charset=utf-8 |
raw document.documentElement.outerHTML — no asset inlining |
markdown-full |
text/markdown; charset=utf-8 |
whole rendered DOM → markdown |
markdown-reader |
text/markdown; charset=utf-8 |
Readability-extracted main content → markdown |
markdown-selector |
text/markdown; charset=utf-8 |
CSS-selector scoped; requires --selector <css> |
Backend is headless Firefox via WebDriver BiDi.
Examples:
-
PDF to stdout:
$ chrest capture --format pdf --url https://example.com > page.pdf -
Full-page PNG to a file, atomically:
$ chrest capture --format screenshot-png --full-page \ $ --url https://en.wikipedia.org/wiki/Markdown \ $ --output wiki.png -
Self-contained archive of a blog post:
$ chrest capture --format html-monolith \ $ --url https://simonwillison.net/ \ $ --output blog.html -
Reader-mode markdown (boilerplate stripped):
$ chrest capture --format markdown-reader \ $ --url https://simonwillison.net/2026/Feb/15/gwtar/ -
Markdown scoped to one element:
$ chrest capture --format markdown-selector --selector "#bodyContent" \ $ --url https://en.wikipedia.org/wiki/Markdown
chrest capture-batch implements the Web Capture Archive Protocol (RFC 0001)
for pipelines that need multiple captures of the same page in a single pass,
with content-addressed artifacts and a JSON result envelope.
$ echo '{
"schema": "web-capture-archive/v1",
"writer": {"cmd": ["your-content-addressed-writer"]},
"url": "https://en.wikipedia.org/wiki/Ferris_wheel",
"defaults": {"browser": "firefox", "split": false},
"captures": [
{"name": "pdf", "format": "pdf"},
{"name": "md", "format": "markdown-reader"},
{"name": "archive", "format": "html-monolith"}
]
}' | chrest capture-batch | jq
The writer command is invoked once per artifact; chrest streams the bytes to
its stdin and expects a one-line JSON response of the form
{"id": "<content-addressed-id>", "size": N}. The final stdout JSON is a
result envelope with one entry per capture, each pointing at the writer's
returned IDs.
See docs/features/0001-web-page-capture.md for design intent, backend trade-offs, and a full list of known limitations.
Choose one:
- Go:
go install code.linenisgreat.com/chrest/go/cmd/chrest@latest - Nix:
nix profile install github:friedenberg/chrest
Chrome:
- Go to chrome://extensions/
- Enable Developer mode (top-right corner)
- Click "Load unpacked" and select the
extension/dist-chrome/folder
Firefox:
- Go to about:debugging#/runtime/this-firefox
- Click "Load Temporary Add-on" and select any file in
extension/dist-firefox/
$ chrest init --browser chrome
Or for Firefox:
$ chrest init --browser firefox
If you omit --browser, chrest will prompt you interactively.
Reload the extension in your browser, then:
$ chrest list-windows
- Chrome will turn off service workers when there are no windows left, so at
least 1 window needs to exist for
chrestto be running. I may add a fallback inchrestto useAppleScriptto create a new window if the server is not running.