AI Conversation Capture
Overview
This is a design blueprint for capturing full AI chat transcripts — Claude.ai, ChatGPT, and similar browser-based AI tools — directly from the browser, with built-in detection for UI changes.
It is written in the “paste-this-into-your-agent” style: a blueprint to build from, not a finished tool. The basic version writes each captured chat turn to a SQL database à la OpenBrain. Later, those chats can be grouped by topic, searched, summarized, or used as part of a personal memory system. That later memory layer is not covered here. This document is only about reliable capture.
The gap this fills
Most personal-memory systems capture what you explicitly send them: a note, a Slack message, a “save this to my brain” call, or a one-time migration prompt. They usually do not capture the conversation itself. (I had been copying large chats into Word documents and saving them manually. That works, but it does not scale.)
The real thinking often happens inside the AI chat: the back-and-forth, the corrections, the false starts, the discovery of what you actually meant. When the tab closes, much of that reasoning evaporates. What lands in memory is whatever you remembered to forward afterward — a fraction of the conversation, and a curated-after-the-fact fraction at that.
AI Conversation Capture closes that gap. Every message in and out of the chat UI is recorded automatically, as it happens, with no extra user action. The conversation becomes a first-class source, not an afterthought. (And this approach is great for the “lazy person” like me.)
The hard part of the build is not the basic capture. The hard part is that AI chat UIs change without warning. A browser scraper can silently break while still reporting that it is healthy. That is the most dangerous failure mode in any memory system: stale capture looks exactly like working capture unless you explicitly test for blindness.
This design treats UI-change detection as a primary engineering problem, not an add-on.
The approach, in four parts
A browser extension is built for each AI platform. Each extension does four jobs.
1. Capture outgoing messages
Listen for the user’s send action: Send button click, Enter handler, or equivalent platform-specific action.
When the user sends a message, read the composed text from the input area and record it as a user turn.
This is usually the reliable half. The user’s own text exists in the page before it is sent.
2. Capture incoming messages
The AI reply streams back into the page. There are two viable capture points:
DOM observation.
Watch the message area with a MutationObserver, then read the completed assistant turn once streaming settles.
Network observation.
Observe the platform’s own completion or streaming response — for example, the stream that the UI consumes to render the assistant reply — and reconstruct the assistant text from those events.
The network tap is usually more robust against visual UI changes, but it couples you to the platform’s internal API shape. The DOM tap is easier to reason about visually, but it is more exposed to layout and markup changes.
A resilient build can do both and reconcile them.
3. Disambiguate role
The capture system must know which turn came from the human and which came from the assistant.
Do not infer role only from position, color, styling, or message order. Those can change.
Instead, identify a role-specific UI signal: something that appears on one kind of message but not the other. For example, an assistant message may have feedback controls, copy controls, model metadata, or other affordances that user messages do not have.
In this document, I’ll call those platform-dependent signals UI anchors.
A UI anchor is any observable feature of the live page that the extension depends on in order to find or classify something. In code, a UI anchor might be implemented as a CSS selector, ARIA label, DOM relationship, text pattern, data attribute, button role, or network event. The point is not the particular mechanism. The point is that the capture system depends on it, so the system must continuously test whether it still works.
4. Buffer locally, then send
Each captured turn should be written first to a local browser-side buffer, such as IndexedDB. That way, nothing is lost if the local capture process is briefly unavailable.
Then the extension s the captured turn to wherever your memory system lives: a local daemon, a database API, an POSTMCP endpoint, or another ingestion process.
Each message should have a stable, content-derived ID — for example, a hash over platform, conversation ID, turn content, timestamp/ordinal, and role. This lets replays and re-captures deduplicate cleanly instead of creating duplicate rows.
The centerpiece: the UI modification indicator
This is the important part.
DOM scrapers do not usually fail loudly. They fail silently and confidently.
The fix is to make the extension continuously prove that it can still see what it is supposed to see, and to surface that proof where a human will notice when it goes stale.
The system needs three mechanisms.
1. Walk-up failure logging
When a UI anchor fails, do not just return null.
Walk up the DOM a bounded number of levels — for example, eight levels — and capture what is actually there. Log that context with a failure counter.
Maintain two counters:
- lifetime failures
- failures in the last 24 hours
A rising 24-hour count is an early-warning signal that the platform shipped a UI change. You want to know that before the system silently misses a day of conversations.
2. UI-anchor heartbeat
On a timer — for example, every 15 minutes — test each critical UI anchor against the live page.
Record a last-seen timestamp for each one.
Expose the results in a diagnostics view:
- green: matched recently
- yellow: stale
- red: not matched in too long
This turns “my capture silently stopped working last Tuesday” into “the assistant-role anchor went red Tuesday at 2 PM.”
That is a very different kind of failure.
3. Round-trip indicator
The browser extension should not merely report that it captured a turn. It should also ask the receiving process whether the turn actually landed.
The local capture process should report back the last time it successfully received and stored a capture. Show that timestamp in the same diagnostics view.
The heartbeat proves the extension can still see the page.
The round-trip check proves captures are actually landing in the store.
Both green means the pipe is live. If one is red, the system can localize the break.
The principle underneath all three mechanisms is simple:
A capture system must be able to detect its own blindness.
A scraper that does not know when it has stopped seeing is worse than no scraper, because it launders silence as data. The same discipline good memory systems apply at synthesis — flag contradictions, do not smooth them away — should be pushed earlier, into ingestion.
How it is built: the extension and the daemon
There are two pieces.
The browser extension captures the conversation.
The local daemon writes it to the database.
Everything else hangs off one of those two pieces.
The extension: the browser half
The extension runs on the AI chat pages. It captures each turn as the user sends it and as the assistant replies. It determines the role of each turn, buffers locally, and sends the captured data onward.
It also runs the page-side health checks:
- walk-up failure logging
- UI-anchor heartbeat
- diagnostics display
Those checks have to live in the extension because they need access to the live page.
Under the hood, this is likely a Manifest V3 extension with a content script that reads the page and a background worker that manages timers, buffering, and retry logic. But conceptually, treat it as one thing: the browser half.
The daemon: the machine half
The daemon is a small local process running on your computer, listening on a local address such as 127.0.0.1:8000.
It receives captured turns from the extension, validates them, writes them to the SQL database, and answers round-trip health checks.
This is the “Chat-Capture-Process” referred to throughout this blueprint.
The simple version is a local daemon writing to . But the destination could just as easily be SQLitePostgres, an MCP endpoint, a flat archive, or some other personal-memory store.
How they talk
The extension s each captured turn to the daemon over local HTTP.POST
The daemon validates the payload, writes it, deduplicates if needed, and reports success.
That is the core system:
The UI anchors and page-watching live in the extension.
The database write and round-trip confirmation live in the daemon.
What you need to add for your own build
This blueprint deliberately omits platform-specific details.
1. Current UI anchors
Every platform-specific page dependency has to be resolved by inspecting the live page at build time.
That includes:
- message container anchor
- input/composer anchor
- send-action anchor
- user-message anchor
- assistant-message anchor
- role-disambiguation anchor
- streaming-complete signal
- network stream shape, if using the network tap
These are intentionally not listed here.
They go stale quickly, and a widely posted scraper with hardcoded live anchors invites breakage. Treat them as configuration that the indicator watches, not as permanent constants baked into the design.
2. Your Chat-Capture-Process
Point the extension at whatever store you actually use:
- local SQLite
- Postgres
- MCP capture tool
- flat files
- private API
- another memory pipeline
The capture pattern and health indicator are independent of where the bytes land.
3. Auth and pairing
If the receiving process needs authentication, add a one-time pairing step between the extension and the local daemon.
The daemon should know which extension build sent each row. Include version metadata in every capture payload so later migrations and bug analysis are possible.
Why the UI modification indicator matters
People have already built content scripts that read message bubbles.
The missing piece is usually not capture. The missing piece is survival.
AI platforms change their UIs constantly. If your memory system depends on browser capture, then silent capture failure is not a minor bug. It is data corruption by omission.
The walk-up logger, UI-anchor heartbeat, and round-trip indicator are what keep the capture system honest.
They make the system answer three questions continuously:
- Can I still see the page?
- Can I still classify the turns?
- Are the captures actually landing in the store?
Without those checks, the system may look alive while quietly forgetting everything.
Format note
This is an “idea file” in the Karpathy/Jones sense: a high-level blueprint meant to be pasted into a coding agent, which then works out the specifics with you for your stack and the current state of each platform’s UI.
It is not a distributable scraper.
It deliberately contains no live platform anchors.