Export chat history from Cursor, Claude Code, and Codex and build a git-tracked, LLM-friendly project timeline.
The result is three artifacts that live inside your repo:
timeline/timeline.md— chronological, compact, ready for an LLM to read.timeline/contents/timeline.json— referenced content keyed by entry ID.timeline/sessions/session.md— full chat exports + git index context.
A built-in git pre-commit hook keeps the timeline in sync with your commits automatically.
Works on Windows, macOS, and Linux. Pure stdlib — no runtime dependencies.
pipx install chat-timeline && timeline initpipx not available? The equivalent is:
python -m pip install --user chat-timeline && timeline inittimeline init is idempotent and does everything for you:
- Resolves the project root (
git rev-parse --show-toplevel). - Creates
timeline/withchats/,sessions/,contents/, and the archive folder. - Writes
timeline/.gitignoreand a managed block in the project's.gitignore. - Installs
LLM_INSTRUCTIONS.mdfor downstream prompts. - Installs the git pre-commit hook (calls
timeline -pon each commit).
To reverse: timeline deinit removes the hook and the managed .gitignore
block. Your exported data is left untouched.
timeline # interactive selector → exports + session + timeline
timeline claude # claude only
timeline cursor 1-5 # cursor chats #1..#5
timeline -t # rebuild timeline only (incremental)
timeline -t -rt # rebuild timeline from scratch
timeline -p # pre-commit standalone (auto-detects modified chats)Equivalent: python -m chat_timeline ….
Full flag reference: timeline --help.
| Key | Action |
|---|---|
↑ ↓ |
move pointer |
PgUp PgDn |
page |
Home End |
jump to first/last |
Space |
toggle chat (or entry, when expanded) |
→ |
expand chat to entries |
← |
collapse / jump back to parent |
a |
toggle select-all |
t |
cycle tracking mode (chat) or toggle exclude/force-add (entry). Hold 3s to clear tracking. |
p |
toggle pre-commit auto mode |
o |
toggle timeline archive rotation for this run |
h |
toggle "hot entries only" filter |
Tab |
switch list ↔ numeric input |
Enter |
confirm · Esc cancel |
| Source | Storage location | Notes |
|---|---|---|
| Cursor | %APPDATA%/Cursor/User/workspaceStorage/ (Win), ~/Library/Application Support/Cursor/User/workspaceStorage/ (mac), ~/.config/Cursor/User/workspaceStorage/ (linux) |
SQLite |
| Claude Code | ~/.claude/projects/<slug>/*.jsonl |
Cross-runtime: Windows reads WSL data, WSL reads Windows data |
| Codex | ~/.codex/sessions/**/*.jsonl |
Same cross-runtime discovery |
Nothing is transmitted anywhere. Everything runs locally on your machine.
| Env var | Effect |
|---|---|
TIMELINE_PROJECT_ROOT |
Override the auto-detected git toplevel. |
TIMELINE_HOME |
Override the default <project>/timeline location. |
TIMELINE_AMEND |
Set by the pre-commit hook on git commit --amend. |
To keep wide-scope scans fast, parsed Codex session metadata is cached
under <TIMELINE_HOME>/.cache/sessions/codex/<sha1>.json, keyed by JSONL
mtime + size. The cache is regenerated on demand — safe to delete, and
already covered by the managed .gitignore block.
The hook is a POSIX shell script that:
- Detects
git commit --amendfrom the parent process'scmdline. - Calls the installed
timelineentry point, with fallbacks topython -m chat_timelineandwsl.exe timeline. - Stages any updated timeline files into the commit.
On Windows it runs under Git Bash (which ships with Git for Windows).
v0.2.0 ships the modular layout (sources/, tui/, markdown.py,
git_utils.py, session.py, timeline.py, precommit.py, app.py,
_state.py) with no _legacy/ block — the CLI and on-disk format are
unchanged from v0.1.x.
See CONTRIBUTING.md. Bug reports welcome — please include
the output of timeline --version and your OS + Python version.
MIT. See LICENSE.