Published June 2026 · Status: draft — may change until in-app import ships
Talekeep's goal is that your conversations — from any messenger or AI service — live in one encrypted archive you own. We can't build every connector at once, so we're doing the next best thing: documenting a simple import format now, so you (or your scripts, or your favorite AI) can convert any export into it today.
Built into Talekeep 1.0. In the app: sidebar ➕ → Import archive…, pick your.jsonl, done — the source appears in your sidebar, message text encrypted at rest like everything else. Imported sources are namespaced (import-…) and kept separate from live-synced sources, so when an official connector for your service arrives, both coexist — nothing needs migrating. Re-importing a file with the samesource.idupdates instead of duplicating.
Every service lets you export your own data. Get the file out first — then bring it in. Native importers for these are landing in an upcoming release (drop the export straight in); until then, convert to the format below. Either way everything stays on your Mac.
| App | How to export | File |
|---|---|---|
| Open the chat → Export Chat → Without Media | _chat.txt | |
| LINE | Open the chat → menu → Export chat history | .txt |
| Discord | No built-in export — use DiscordChatExporter to save a channel or DM as JSON | .json |
| ChatGPT | Settings → Data controls → Export data, then unzip the emailed file | conversations.json |
| Claude | Settings → Privacy → Export data, then unzip (rename .dms → .zip) | conversations.json |
| Gemini | Google Takeout → deselect all → My Activity → Gemini Apps (not the “Gemini” option — that's Gems, not your chats) | .json |
| Slack | A workspace admin exports the data, then unzip it | export folder |
Most services export text only — WhatsApp and LINE don't include photos or videos in the text export (their limitation, not ours).
A single UTF-8 JSON Lines file (.talekeep.jsonl): one JSON
object per line. The first line declares the file; the rest are conversations and
messages, in any order (a message's conversation should appear before it).
{"type":"talekeep-import","version":0,"source":{"id":"whatsapp-jane","name":"WhatsApp (Jane's iPhone)"}}
{"type":"conversation","id":"family-group","title":"Family group","kind":"group"}
{"type":"message","conversationId":"family-group","id":"1001","date":"2023-04-01T12:30:00Z","sender":"Mum","text":"Dinner at 7?"}
{"type":"message","conversationId":"family-group","id":"1002","date":"2023-04-01T12:31:12Z","sender":"me","text":"On my way!"}
{"type":"message","conversationId":"family-group","id":"1003","date":"2023-04-01T12:35:00Z","sender":"Mum","text":"Photo of the table","media":{"path":"media/table.jpg","kind":"photo"}}
talekeep-import (first line, required)| field | type | notes |
|---|---|---|
version | int | 0 |
source.id | string | stable, unique per imported account/source — re-importing the same id updates rather than duplicates |
source.name | string | shown in the sidebar, e.g. "ChatGPT (export 2026-06)" |
conversation| field | type | notes |
|---|---|---|
id | string | unique within the source |
title | string | |
kind | string | optional: direct · group · channel · ai (default direct) |
message| field | type | notes |
|---|---|---|
conversationId | string | must match a conversation record |
id | string | unique within the conversation |
date | string | int | ISO-8601 (2023-04-01T12:30:00Z) or unix seconds |
sender | string | display name; use "me" for yourself (right-aligned bubbles) |
text | string | message body (encrypted at rest on import) |
media | object | optional: {"path": "relative/to/jsonl.jpg", "kind": "photo|video|audio|document"} — files are copied into the archive |
source.id, conversation.id and
message.id are the same across re-exports. If your source has no native
message ids (e.g. WhatsApp .txt), synthesize one deterministically — for
example a hash of date + sender + text — never a random or sequential
counter that changes between runs.