Every session with Claude Code, Codex or Cursor is hard-won context โ the bugs you chased, the decisions you made, the code you shipped. It's a valuable asset. But all three tools title a chat from your first message and then freeze it forever. An hour later the work has moved on, yet the sidebar still says "Check if branches are synced." Multiply that by hundreds of sessions and your most valuable history becomes an unsearchable graveyard.
That asset is too good to waste on a stale title.
retitle runs quietly in the background and, once a session goes idle, rewrites its title to
match what the work actually became โ across all three tools. Then retitle search lets you
mine that history: find any past session across Claude Code, Codex and Cursor at once.
English ยท ็ฎไฝไธญๆ
30-second try โ no install, writes nothing:
uvx --from git+https://github.com/study8677/retitle.git retitle listEvery AI coding tool titles a session once, from its opening prompt, and freezes it there:
| Tool | What the sidebar says | What the session is now about |
|---|---|---|
| Cursor | Add a loading spinner |
migrating the database to Postgres |
| Codex | Fix a typo in the README |
debugging a flaky CI pipeline |
| Claude Code | Check if branches are synced |
implementing the audit-log feature |
The title is a lie within ten minutes. So a week later, when you know you solved this exact
bug with the AI before, you can't find the conversation โ the asset is there, but it's buried.
retitle keeps the title honest, so the goldmine stays searchable.
(Examples are illustrative โ retitle reads your sessions locally and never publishes them anywhere.)
$ retitle list
Claude Code
16m Check if branches are synced โ Implement the audit-log feature
34m โ โ Fix dashboard white-screen on load
2m Refactor the deploy script ยท active
Codex
1.2h Set up the new service โ Design the session auto-rename flow
2.1h Review the API changes ยท no new content since last rename
Cursor
29m Add a loading spinner โ ไฟฎๅค็ปๅฝ้กต้ข็ๆ ทๅผ้ฎ้ข
2.4h First sync question โ Track down the duplicate-error bug
7 session(s) would be renamed next pass (idle โฅ 5m, namer=heuristic).
Run `retitle once` to apply, or `retitle install` to do it continuously.Accurate titles are only half the point โ the other half is finding the session
again. retitle search looks across Claude Code, Codex and Cursor at once:
$ retitle search "stripe webhook"
๐ "stripe webhook" โ 2 matches
Cursor 3h Wire up the Stripe webhook handler payments-api
Claude Code 2d Debug the Stripe webhook signature billing-svc
$ retitle search postgres --content # also grep message text, with snippetsretitle is pure Python with zero dependencies. Install it as an isolated CLI:
# with pipx (recommended)
pipx install git+https://github.com/study8677/retitle.git
# or with uv
uv tool install git+https://github.com/study8677/retitle.git
# or from source
git clone https://github.com/study8677/retitle.git && cd retitle
pip install -e .Then:
retitle status # what did it detect on this machine?
retitle list # preview: current title โ proposed title (writes nothing)
retitle once # do one rename pass right now
retitle install # run it forever in the background (launchd / systemd)That's it. With retitle install it wakes up every minute, finds sessions that have been idle
for 5 minutes, and retitles the ones whose content has changed since it last looked.
โโโโโโโโโโโโโ every poll_seconds (default 60s) โโโโโโโโโโโโโ
โ โ
discover โโโบ for each session idle โฅ 5m with NEW content โโโบ namer โโโบ write title back
(per tool) โ โ โ
Claude Code โ skip if still active โ โโ Claude Code: append an `ai-title` line
Codex โ skip if unchanged since last rename โ โโ Codex: UPDATE threads SET title
Cursor โ skip if a human renamed it (until โ โโ Cursor: patch composerHeaders + composerData
โ the conversation moves on) โ
The decision rule for each session is deliberately conservative:
- Still in use? Idle for less than your threshold โ leave it alone.
- Nothing new? Content hash matches the title we last wrote โ skip (re-runs are free).
- Renamed by hand? We never clobber a human edit โ until you send new messages and it goes idle again.
- Otherwise: generate a fresh title and write it.
This makes the whole thing idempotent and safe to run continuously.
Where the title comes from. By default retitle shells out to the claude
(or codex) CLI you're already logged into โ claude --model haiku -p "โฆ" โ so
titles are real LLM summaries of the conversation, with no API key. No CLI
installed? It falls back to the offline heuristic.
Rename past sessions on demand. To work through a backlog without calling your
CLI on everything at once, a pass renames at most batch_size sessions
(default 25), most-recent first; the daemon finishes the rest over later passes.
retitle once # rename the latest batch right now
retitle once --limit 50 # rename the 50 most-recent eligible sessions
retitle once --all # rename ALL eligible history (idle 0, any age; slower)
retitle once --all --dry-run # preview the whole backlog without writing| Tool | Reads | Writes | Status |
|---|---|---|---|
| Claude Code | ~/.claude/projects/**/<id>.jsonl |
appends an ai-title line (append-only โ the safest write) |
โ stable |
| Codex | ~/.codex/state_*.sqlite + rollout files |
UPDATE threads SET title |
โ stable |
| Cursor | state.vscdb (composerHeaders + composerData) |
patches both title fields | |
| Antigravity (Google) | state.vscdb (antigravityUnifiedStateSync.trajectorySummaries) |
rewrites the summary field of one CascadeTrajectorySummary |
A note on writing while the app is open. Codex, Cursor and Antigravity keep their data in live SQLite databases.
retitlewrites carefully (read-only reads,busy_timeouton writes), and only ever touches idle sessions. Still, the host apps cache chats in memory, so a title you change on disk may be overwritten if you reopen that exact chat in the running app. For the most reliable results, letretitlerun while the app is closed. Claude Code's append-only format has no such caveat.
Antigravity is a VS Code fork. Its conversation transcripts live at
~/.gemini/antigravity/conversations/<uuid>.pb and are encrypted at rest (uniform-byte
ciphertext, key held by the OS keychain). But its sidebar reads titles from a separate,
plaintext store: a base64-encoded protobuf at
ItemTable['antigravityUnifiedStateSync.trajectorySummaries'] inside
state.vscdb โ same pattern as Cursor.
retitle reads and rewrites that store directly (SQL UPDATE, no extension, no key
extraction). And while the raw chat is encrypted, Antigravity's agent itself writes
plain-text working artifacts to ~/.gemini/antigravity/brain/<uuid>/ while it works
(task.md, implementation_plan.md, walkthrough.md and matching *.metadata.json
summaries) โ those are the material retitle feeds to the namer.
- โ
Antigravity sessions show up in
retitle list,retitle search,retitle stats - โ Automatic rename works for any conversation that has produced brain artifacts (longer / planning-heavy chats โ the ones whose title most often drifts). Short chats with no artifacts are skipped by the substance gate, which is fine โ there'd be nothing to title with anyway.
- โ
Manual
retitle once --tool antigravityworks regardless.
If Antigravity ships an extension API exposing raw chat-session transcripts later, we'll wire it in for full coverage. Track at #1.
The default, auto, needs no API key at all. retitle reuses the claude or
codex CLI you're already logged into to write good, LLM-quality titles, and falls
back to a fully-offline heuristic if neither is installed. You never paste a key.
namer |
What it does | API key? |
|---|---|---|
auto |
your logged-in claude / codex CLI, else heuristic |
none ยท default |
heuristic |
a cleaned-up snippet of your latest message; instant, offline | none |
claude |
always the claude CLI (fast Haiku model) |
none โ your login |
codex |
always the codex CLI (gpt-5-codex) |
none โ your login |
anthropic |
Anthropic API directly | ANTHROPIC_API_KEY |
openai |
OpenAI API directly | OPENAI_API_KEY |
Out of the box โ nothing to configure, no key to paste โ you get LLM-quality titles
using credits you already have. Prefer zero cost / fully offline? Set namer = "heuristic".
retitle status # shows what auto resolved to, e.g. "namer=auto โ claude"retitle config creates and prints ~/.config/retitle/config.toml:
idle_seconds = 300 # rename after 5 minutes idle
poll_seconds = 60 # scan once a minute
batch_size = 25 # rename at most N sessions per scan (0 = no limit)
tools = ["claude-code", "codex", "cursor"]
namer = "heuristic" # heuristic | claude | codex | anthropic | openai
max_age_days = 7 # ignore sessions older than a week
min_user_messages = 1 # need at least this many real messages
dry_run = false
[anthropic]
model = "claude-haiku-4-5"
[openai]
model = "gpt-4o-mini"Any field can be overridden per-invocation: retitle run --idle 600 --namer anthropic --tool cursor.
| Command | Description |
|---|---|
retitle list |
Preview every discovered session and its proposed title (writes nothing) |
retitle search <q> |
Find sessions across all tools by title (add --content to grep message text) |
retitle stats |
A quick overview: sessions per tool, how many are untitled / stale |
retitle once |
Rename the latest batch now (--limit N, --all, --dry-run) |
retitle run |
Run continuously in the foreground (add --once, --dry-run) |
retitle install |
Install + start the background service (launchd on macOS, systemd on Linux) |
retitle uninstall |
Stop and remove the background service |
retitle status |
Show config, detected tools, and daemon status |
retitle config |
Create / print the config file |
retitle list,retitle searchandretitle statsalso accept--jsonfor scripting.
- No key to paste; titling uses your own logged-in tool. The default
autonamer asks theclaude/codexCLI you're already signed into to write the title, so a short transcript excerpt goes to that provider (credits you already have โ no API key needed). Want nothing to leave your machine at all? Setnamer = "heuristic"and it's 100% offline. - It only ever changes titles.
retitlereads transcripts and writes a single title field / appends a single line. It never edits, deletes, or reorders your conversations. - It's reversible and idempotent. A bad title is just a title โ send a message and it gets re-evaluated. Re-running does nothing unless content changed.
Will it fight with the tool's own auto-naming?
No. The tools title once and stop; retitle only acts after a session is idle, so they aren't
writing at the same time.
Will it overwrite titles I set myself? No โ not until you add new messages to that session. Manual titles are respected until the conversation actually moves on.
Do I need an API key?
No. The default reuses the claude / codex CLI you're already logged into โ no key to
paste. It spends credits you already have; for zero cost, set namer = "heuristic" (offline).
Is it safe to run all the time? Yes โ that's the design. See How it works. The one caveat is editing Cursor's DB while Cursor is open (above).
Curious how it works under the hood โ including the reverse-engineered session storage format of each tool? See ARCHITECTURE.md.
Adding support for another tool is one file โ implement four methods (available, discover,
read_transcript, set_title) in src/retitle/adapters/. See CONTRIBUTING.md.
git clone https://github.com/study8677/retitle.git && cd retitle
pip install -e ".[dev]"
pytestYour AI sessions are an asset worth keeping. If retitle helps you reclaim yours, a โญ helps
other people find it โ and motivates more adapters (Aider, Continue, Zed, โฆ). Issues and PRs welcome.
- @xiongaox filed #1
asking for Antigravity support. That issue is what unlocked the whole Antigravity adapter โ
the protobuf schema reverse-engineering, the
brain/artifacts discovery, all of it. Thank you ๐.
MIT ยฉ JingWen Fan