Normalize once, at the end
Three AI coding assistants, three completely different ideas of what a “session” even is.
Three shapes
- Claude Code writes line-by-line JSON logs.
- Codex keeps an embedded database.
- Copilot uses a separate, sandboxed config directory entirely, because it’s bridged into an IDE rather than run as a standalone CLI.
None of them were built with the other two in mind. There was no reason for them to be.
The tempting move
The tempting move is to define one schema on day one and force all three into it at the point of reading. It looks tidy. It also couples every part of the system to every tool’s quirks, and it means a format change in one tool can ripple through everything.
What we did instead
Each source gets read in whatever native shape it already comes in, by its own reader. Normalization happens exactly once — right at the end, just before the unified view gets built.
The payoff is isolation. When one of these tools changes how it stores things, only that one reader needs to change. Nothing downstream notices.
Did it hold up?
It isn’t the most elegant-looking code on day one. But it has already survived three separate upstream format changes without anything else in the system noticing — which is the test that matters when you’re building on top of tools you don’t control.