How it works

The honest version. What runs on your machine, what hits the network, what the extension actually does on each chat platform.

Local-first architecture

The whole archive lives on your filesystem. Three artifacts:

ArtifactLocationWhat it stores
Vault~/.kept/vault/One markdown file per conversation, plus assets/ for downloaded images
FTS index~/.kept/index.dbSQLite database with FTS5 tables. Rebuildable from the vault.
Knowledge graph~/.kept/kg.db/CozoDB store with topics, entities, embeddings. Rebuildable from the vault.

Delete the index and the graph; they regenerate on next launch. The vault is the source of truth.

The desktop app talks to all three. The Chrome extension talks only to the desktop app, via localhost:18241.

What hits the network

Three things, and only when you cause them:

  1. The Chrome extension fetches conversations from the chat platform you're authenticated to. Reading what your browser already has access to — same-origin requests with your existing session cookies.
  2. The agent (continuing a chat, Smart Recall, etc.) sends prompts to your selected model provider. Same trust boundary as any normal API call you'd make. Your API key, your bill.
  3. Updater checks for a new desktop app release on Tauri's updater endpoint, on a configurable interval. Disable in Settings → Updates if you don't want them.

That's the complete list of outbound traffic. The vault index, KG store, the embedding cache, the topic clustering — all local. Pointing the agent at Ollama makes (2) local too: zero outbound traffic end to end.

How the extension reads each platform

The extension uses your existing browser session — it doesn't store credentials, doesn't proxy through a third party. Each chat platform has its own provider script under extension/platforms/ that knows that platform's specifics:

ChatGPT

  • GET chatgpt.com/api/auth/session → access token from your existing session
  • GET chatgpt.com/backend-api/conversations?offset=&limit=&order=updated → list of your conversations
  • GET chatgpt.com/backend-api/conversation/{id} → the full conversation tree
  • Images: detects image_asset_pointer parts (file-service:// and sediment:// prefixes), fetches the signed download URL, saves the image to ~/.kept/vault/chatgpt/assets/

The conversation comes back as ChatGPT's mapping node tree. The extension walks it, filters to user / assistant / system / tool roles, sorts by create_time, and serializes to markdown.

Claude

  • GET claude.ai/api/organizations/{org}/conversations → list
  • GET claude.ai/api/organizations/{org}/conversations/{id} → detail with chat_messages array
  • Images: not currently downloaded (Claude's image hosting requires a re-auth flow we haven't implemented; conversations reference images by URL, but the URL won't work outside Claude's context)

Gemini

  • Uses Gemini's batchexecute RPC with two operation IDs: MaZiqc (list) and hNvQHb (detail)
  • Pagination via a token at parsed[1], max 100 conversations per page
  • Images: external CDN URLs (lh3.googleusercontent.com). Not downloaded — CORS blocks the fetch from extension context. Conversations reference these by URL.

Grok

  • POST grok.com/rest/app-chat/conversations/list → list
  • POST grok.com/rest/app-chat/conversations/{id}/load-responses → node map + messages
  • Two-step fetch: first get the node map, then fetch the response payload separately
  • Images: downloaded from assets.grok.com to ~/.kept/vault/grok/assets/

Kimi

  • kimi.com/api/chat/list → list
  • kimi.com/api/chat/{id}/messages → message blocks
  • Messages come as blocks[].text.content arrays in reverse-chronological order; the extension reverses them
  • Images: not currently implemented

The full per-platform breakdown lives at kept/extension/api_process_flow.md in the repo.

What the extension does NOT touch

  • It does not send anything to the chat platform — @kept is captured in the input box before submission and the trigger text is removed before any send event fires.
  • It does not request <all_urls> for general access. The only <all_urls> content script is the inline @kept palette renderer; it attaches a key listener and renders an in-DOM element, nothing else.
  • It does not store credentials. No password fields, no token storage, no cookies copied. It uses your existing browser session.

Permission model in detail

The extension's manifest.json requests:

  • Host permissions for the five chat platforms plus a few CDNs (files.oaiusercontent.com, lh3.googleusercontent.com, assets.grok.com, kimi-img.moonshot.cn) needed to download referenced images
  • Local connection to localhost:18241 and 127.0.0.1:18241 — the Kept desktop app's local HTTP server
  • storage for extension settings (vault path, sync interval, enabled platforms)
  • alarms for auto-sync scheduling
  • idle to pause auto-sync when the system is idle (avoids hammering platforms when you're away)

It does not request: tabs, webRequest (general), cookies, <all_urls> host access, nativeMessaging, or any other broad permission.

Code execution sandbox

Every code-execution request from the agent prompts you for explicit consent. There's no "always allow" toggle by design.

The sandbox:

  • Read access: vault directory, scratch directory, plus any directory you've explicitly added via Settings → Knowledge base
  • Write access: scratch directory only
  • No internet access (no urllib, requests, socket, subprocess for outbound)
  • No environment variables, no shell access, no other-process introspection

It's a Python interpreter with a restricted import list and a process boundary. Not isolated to the level of a separate VM, but tight enough that the failure mode of running an LLM-generated script is a wrong answer, not a compromised filesystem.

Updates

Tauri's auto-updater pings the configured update endpoint on launch (or on a schedule). If a new release is available, you get a prompt to install. The update is signed — Tauri verifies the signature against the public key bundled in the app. Settings → Updates controls the schedule and disables it.

Data export

The vault is plain markdown. Copy it to a backup, sync it to git, ship it to another machine — Kept doesn't lock anything. The only Kept-specific artifacts are the FTS index and the KG store, both rebuildable.

If you uninstall Kept, your vault remains. If you delete ~/.kept/, you lose the index and graph but the markdown vault is untouched (assuming you've moved it elsewhere; the default is inside ~/.kept/, in which case it goes with the rest).