Skip to content

Instantly share code, notes, and snippets.

@lee-fuhr
Last active January 13, 2026 21:07
Show Gist options
  • Select an option

  • Save lee-fuhr/d6b67af5b0f584e3596fb240f6a08eea to your computer and use it in GitHub Desktop.

Select an option

Save lee-fuhr/d6b67af5b0f584e3596fb240f6a08eea to your computer and use it in GitHub Desktop.
Claude Code Session Renamer - reliably rename sessions from within Claude (marker approach for concurrent sessions)

Claude Code Session Renamer

Reliably rename Claude Code sessions from within Claude itself, even with multiple concurrent sessions.

The Problem

Claude Code stores sessions as JSONL files. To rename a session, you append a custom-title entry. Simple, right?

Wrong. Three problems:

  1. Concurrent sessions: With multiple Claude windows open, "most recently modified file" heuristics fail. You might rename the wrong session.

  2. Wrong field name: The field is customTitle, not title. Took reverse-engineering to discover.

  3. Concatenation bug: If you write with a leading newline ('\n' + entry), Claude's next write concatenates directly after your entry, breaking JSONL parsing:

    {"type":"custom-title",...}{"parentUuid":...}  # BROKEN - two JSON objects on one line
    

The Solution: Marker Approach

The marker approach definitively identifies THIS session:

  1. Generate unique marker (UUID-based string)
  2. Echo it → marker appears in Claude's tool output → gets written to THIS session's JSONL file
  3. Search all session files for that marker → found file = THIS session
  4. Append custom-title entry with trailing newline

Why Two Steps?

# Step 1: Generate and echo marker
MARKER=$(python3 rename_session.py marker) && echo "$MARKER"

# Step 2: Find session and rename
python3 rename_session.py rename "Session Name" "$MARKER"

The marker gets written to the session file when Step 1 completes. Step 2 searches for it. A single command can't work because the search would run before the marker is written.

Usage

From Claude (two bash calls required)

# Step 1
MARKER=$(python3 "/path/to/rename_session.py" marker) && echo "$MARKER"

# Step 2 (use marker from step 1)
python3 "/path/to/rename_session.py" rename "My Session Name" "__RENAME_MARKER_abc123__"

Direct (outside Claude)

If you're not in a Claude session, you can still use the fallback:

python3 rename_session.py rename "Name" "no-marker"
# Falls back to time-based heuristics (less reliable)

Entry Format

{"type": "custom-title", "customTitle": "Session Name", "sessionId": "uuid-here"}

Requirements:

  • Field is customTitle (not title)
  • Must include sessionId
  • Must end with newline (not start with one)
  • Must be valid JSON on its own line

File Structure

session-renamer/
├── rename_session.py   # Main script
├── identify_session.py # Standalone session identification utility
└── README.md           # This file

How Claude Code Sessions Work

Sessions are stored at:

~/.claude/projects/[project-key]/[uuid].jsonl

Where [project-key] is your working directory with / replaced by -.

Each line is a JSON object:

  • User messages
  • Assistant responses (including tool calls)
  • Tool results
  • Metadata (like custom-title)

Claude Code reads these files to populate /resume and restore conversations.

Discovery Process

This solution came from debugging why auto-rename kept failing:

  1. Initial approach: Most recently modified file → failed with concurrent sessions
  2. Second attempt: Smallest recent file → still unreliable
  3. Time window (5 seconds): Better but still prone to race conditions
  4. Marker approach: 100% reliable - unique marker only exists in one file

We also discovered:

  • The field is customTitle not title (found by examining working renamed sessions)
  • Trailing newline is critical (Claude was concatenating our entries with its next write)
  • fsync() doesn't help - the issue was format, not flushing

Related Scripts

  • _ Operations/poke/parkit.py - Uses marker approach for /pause command
  • ~/.claude/commands/wrapup.md - Uses marker approach for session wrapup
  • ~/.claude/commands/pause.md - Uses marker approach for pausing sessions

Gists

Public gists:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment