Capture chats
Capture is what gets a conversation off the vendor's servers and onto your filesystem. It happens in the browser via the Chrome extension; the desktop app is the receiver.
Supported platforms
The extension knows how to read chats from these five today:
- ChatGPT (
chatgpt.com) - Claude (
claude.ai) - Gemini (
gemini.google.com) - Grok (
grok.com) - Kimi (
kimi.com)
Each platform has its own provider script under extension/platforms/. Each script knows how to walk that platform's conversation list, fetch a single conversation in full, and download referenced images. See How it works for the per-platform details.
Two ways to capture
@kept palette (manual control)
Type @kept in any supported chat's input box. A small palette appears inline over the trigger text with options:
- Save current conversation — the whole thread
- Save last N messages — a slice
- Save this branch — for branched conversations (ChatGPT, Claude)
Pick one and the extension fetches the conversation, hands it to the desktop app, and writes a markdown file under ~/.kept/vault/<platform>/.
The trigger text is removed from your input box on selection — it doesn't get sent to the chat platform.
Auto-sync (background capture)
Open the extension popup → enable Auto-sync. The extension polls the platforms you've toggled on, on a configurable interval (default: every 10 minutes), and writes any new conversations to the vault automatically.
Auto-sync uses SHA-256 deduplication: if a conversation hasn't changed since the last sync, it isn't rewritten. If it grew (new messages), only the diff gets appended to the existing file.
Where files land
~/.kept/vault/
├── chatgpt/
├── claude/
├── gemini/
├── grok/
└── kimi/
One directory per platform, one markdown file per conversation. Filenames are YYYY-MM-DD-<slug>.md.
You can move the vault by setting KEPT_VAULT_DIR in your shell environment, or via Settings → Vault → Vault directory in the desktop app.
File format
Each file is plain markdown with YAML frontmatter:
---
platform: claude
title: RLS rollout
date: 2026-04-24
messages: 23
tags: [postgres, security]
source_id: 8f3a-claude-conversation-id
---
# RLS rollout
> User: We have to roll out row-level security across the tenant tables...
The frontmatter is what's queryable. The body is just markdown — code blocks, math, tool calls (rendered as YAML), images (downloaded to assets/ and referenced by relative path).
What the extension does and doesn't touch
- Reads what you're already authorized to read. The extension uses your existing session — it doesn't store credentials, doesn't proxy through a third party, doesn't have its own server-side state.
- Writes only to the local Kept app via
localhost:18241. Never out to the internet. - Doesn't post anything to the chat platform.
@keptis intercepted in the input box before submission.
For provider-by-provider details on what API endpoints get called and how images are handled, see How it works.
Permissions
The extension's manifest.json requests host permissions for the five chat domains plus a couple of CDN domains (files.oaiusercontent.com, assets.grok.com, etc.) needed to download referenced images. It also requests storage, alarms, and idle for auto-sync scheduling.
It does not request <all_urls> for general data access. The one all-URLs content script is command-palette.js, which is the inline @kept trigger handler — it only attaches a key listener and renders an in-DOM palette element.