A local black box for your Janitor AI chats.
Keepsake saves every message the moment it happens, including the one you just
typed when a send fails. It runs only on janitorai.com, keeps everything in
your own browser, and makes no network requests of its own.
Every other Janitor AI extension is an exporter. You click a button and it hands you the conversation as it currently stands. That works right up until the moment you actually need it, because the failures that lose your work happen before there is anything to export:
- the send is refused and the bubble comes back blank
- the proxy rate limits you and the message vanishes from the box
- the stream cuts halfway through a reply
- the tab reloads and the last few turns were never saved server-side
Keepsake attacks that window. It records the request as it leaves the browser, so the text you wrote is already stored by the time the server decides to reject it. When something does fail, it tells you which of the failures it was, in plain language, and shows you the text it kept.
Records continuously. Both sides of the conversation, as they happen. No button to remember to press.
Saves your message before the network can eat it. The request body is captured at send time. A 429, a refusal, a dead proxy, a dropped connection: none of them cost you the text.
Explains failures where they happen. Nine distinct failure readings, each
with what it actually means and what usually clears it. moderated is a model
refusing the turn, not Janitor banning you, and the notice says so.
Keeps partial replies. A stream cut off mid-sentence still leaves you the part that arrived.
Exports properly. Markdown, plain text, or JSON, per conversation.
Stays out of the way. One small pill in the corner. No account, no sign-in, no sync, no telemetry.
This is the whole of it:
- Keepsake makes no network requests. Not to us, not to anyone. There is no server behind this extension.
- Everything is stored in the extension's own IndexedDB, inside your browser profile. It is deliberately not stored under the page's origin, so that clearing Janitor's site data does not wipe your archive, and the site itself cannot read it.
- It runs on
janitorai.comand nowhere else. - It requests two permissions:
storage(your settings) andalarms(to run retention housekeeping every few hours). - Erase everything at any time from the archive view. Retention defaults to 180 days and a 40,000 message ceiling, both adjustable.
From Firefox Add-ons, or load web-ext-style from source:
git clone https://github.com/Android-Tipster/keepsake
cd keepsake
# about:debugging -> This Firefox -> Load Temporary Add-on -> manifest.json
No build step and no dependencies. The source that ships is the source in this repository.
node test/run.js # 76 assertions: normalising and failure decoding
node test/hook.js # 32 assertions: live fetch/XHR interception
node test/content.js # 34 assertions: request/response correlation and notices
142 assertions in total, and all three suites have been mutation-tested: the code was deliberately broken seven ways and each break was confirmed to fail the suite. A suite that passes on its first run has not yet earned trust.
test/hook.js and test/content.js load the real src/page-hook.js and
src/content.js into a synthetic browser built from node:vm and drive traffic
through them. That is how the properties which cannot be read off the source get
checked: that the page always gets its own response back unconsumed, that the
request is reported before the response exists, and that when two sends are in
flight at once the failure notice quotes the message it actually belongs to.
| File | Role |
|---|---|
src/page-hook.js |
Page-context wrapper around fetch and XMLHttpRequest. Observes, never modifies. |
src/normalize.js |
Turns arbitrary JSON into chat turns by recognising shapes, not endpoints. |
src/decoder.js |
Turns an HTTP status and body into a plain-language failure reading. |
src/content.js |
Correlates requests with responses, renders the in-page notices. |
src/background.js |
Owns the IndexedDB archive, dedup, retention. |
src/panel.* |
The archive browser and exporter. |
The normaliser matches on shape rather than on URL patterns or field names specific to one version of the site. Janitor AI has broken the two most installed extensions in this niche at least once each by changing its API, so nothing here depends on an endpoint path staying put. Traffic whose shape is not recognised is ignored rather than guessed at, because a wrong turn in the archive is worse than a missing one. The test suite spends as much effort on what must not be captured as on what must.
MIT. See LICENSE.
Keepsake is an independent tool. It is not affiliated with, endorsed by, or connected to Janitor AI.