ClaudeCode.History (ClaudeCode v0.36.3)
View SourceUtilities for reading and parsing Claude Code session history files.
Claude Code stores conversation history in JSONL files at:
~/.claude/projects/<encoded-project-path>/<session-id>.jsonl
This module provides functions to:
- List sessions with rich metadata (
list_sessions/1) - Read and parse session JSONL files
- Extract conversation history with proper chain building (
get_messages/2)
Session File Format
Session files contain various message types:
user- User messages (prompts and tool results)assistant- Assistant responsessystem- System events (errors, etc.)summary- Conversation summaryfile-history-snapshot- File tracking metadataqueue-operation- Internal operations
Examples
# List sessions with metadata
{:ok, sessions} = ClaudeCode.History.list_sessions(directory: ".")
Enum.each(sessions, fn s -> IO.puts("#{s.summary} (#{s.session_id})") end)
# Get messages with proper chain building
{:ok, messages} = ClaudeCode.History.get_messages("abc123-def456")
# Read raw session entries
{:ok, entries} = ClaudeCode.History.read_session("abc123-def456")
Summary
Functions
Decodes an encoded project path back to a path format.
Encodes a project path to the format used by Claude Code.
Finds the file path for a session ID.
Reads a session's conversation messages using parentUuid chain building.
Lists all projects that have session history.
Lists sessions with rich metadata extracted from stat + head/tail reads.
Reads a session JSONL file from a specific path and returns all entries as normalized maps.
Reads a session JSONL file by session ID and returns all entries as normalized maps.
Sanitizes a project path matching the Python SDK's _sanitize_path behavior.
Port of the JS simpleHash function (32-bit integer hash, base36).
Gets the conversation summary from a session, if available.
Types
@type session_id() :: String.t()
Functions
Decodes an encoded project path back to a path format.
Replaces - with /. Note that this encoding is lossy - if the original
path contained - or _ characters, they cannot be distinguished from path
separators. For example, /a/b-c, /a/b_c, and /a/b/c all encode to -a-b-c.
This function is primarily useful for display purposes. For matching against
known paths, use encode_project_path/1 instead.
Examples
iex> ClaudeCode.History.decode_project_path("-Users-me-project")
"/Users/me/project"
Encodes a project path to the format used by Claude Code.
Replaces / and _ with - in the path to match the CLI's encoding.
Examples
iex> ClaudeCode.History.encode_project_path("/Users/me/project")
"-Users-me-project"
iex> ClaudeCode.History.encode_project_path("/Users/me/my_project")
"-Users-me-my-project"
@spec find_session_path( session_id(), keyword() ) :: {:ok, Path.t()} | {:error, term()}
Finds the file path for a session ID.
Searches through all project directories in ~/.claude/projects/.
Options
:project_path- Specific project path to search in (optional):claude_dir- Override the Claude directory (default:~/.claude)
Examples
{:ok, "/Users/me/.claude/projects/-my-project/abc123.jsonl"} =
ClaudeCode.History.find_session_path("abc123")
{:error, {:session_not_found, "abc123"}} =
ClaudeCode.History.find_session_path("nonexistent")
@spec get_messages( session_id(), keyword() ) :: {:ok, [ClaudeCode.History.SessionMessage.t()]} | {:error, term()}
Reads a session's conversation messages using parentUuid chain building.
Parses the full JSONL, builds the conversation chain via parentUuid
links, and returns visible user/assistant messages in chronological order.
Options
:project_path- Project directory to find the session in:limit- Maximum number of messages to return:offset- Number of messages to skip from the start (default: 0):claude_dir- Override~/.claude(for testing)
Examples
{:ok, messages} = ClaudeCode.History.get_messages("abc123-def456")
# With pagination
{:ok, page} = ClaudeCode.History.get_messages(session_id, limit: 10, offset: 20)
Lists all projects that have session history.
Options
:claude_dir- Override the Claude directory (default:~/.claude)
Examples
{:ok, ["/Users/me/project1", "/Users/me/project2"]} =
ClaudeCode.History.list_projects()
@spec list_sessions(keyword()) :: {:ok, [ClaudeCode.History.SessionInfo.t()]}
Lists sessions with rich metadata extracted from stat + head/tail reads.
When :project_path is provided, returns sessions for that project directory
(and optionally its git worktrees). When omitted, returns sessions across
all projects.
Options
:project_path- Project directory to list sessions for (nil = all projects):limit- Maximum number of sessions to return:include_worktrees- Scan git worktrees (default:true):claude_dir- Override~/.claude(for testing)
Examples
# List sessions for the current project
{:ok, sessions} = ClaudeCode.History.list_sessions(project_path: ".")
# List all sessions across all projects
{:ok, sessions} = ClaudeCode.History.list_sessions()
# With limit
{:ok, recent} = ClaudeCode.History.list_sessions(project_path: ".", limit: 10)
Reads a session JSONL file from a specific path and returns all entries as normalized maps.
Returns every line as a snake_case string-keyed map, preserving all entry types (user, assistant, system, summary, queue operations, etc.). Keys are normalized from camelCase to snake_case for consistency with live CLI output.
Examples
{:ok, entries} = ClaudeCode.History.read_file("/path/to/session.jsonl")
@spec read_session( session_id(), keyword() ) :: {:ok, [map()]} | {:error, term()}
Reads a session JSONL file by session ID and returns all entries as normalized maps.
Searches through all project directories to find the session file.
Returns every line as a snake_case string-keyed map, including metadata entries
(summaries, queue operations, etc.) that have no SDK struct representation.
Use get_messages/2 to get properly chain-built conversation messages.
Options
:project_path- Specific project path to search in (optional):claude_dir- Override the Claude directory (default:~/.claude)
Examples
{:ok, entries} = ClaudeCode.History.read_session("abc123-def456")
# Search in a specific project
{:ok, entries} = ClaudeCode.History.read_session("abc123", project_path: "/my/project")
Sanitizes a project path matching the Python SDK's _sanitize_path behavior.
Replaces all non-alphanumeric characters with hyphens. For paths exceeding 200 characters, truncates and appends a hash suffix.
Examples
iex> ClaudeCode.History.sanitize_path("/Users/me/project")
"-Users-me-project"
Port of the JS simpleHash function (32-bit integer hash, base36).
@spec summary( session_id(), keyword() ) :: {:ok, String.t() | nil} | {:error, term()}
Gets the conversation summary from a session, if available.
Returns the summary text or nil if no summary exists.
Examples
{:ok, "User asked about..."} = ClaudeCode.History.summary("abc123-def456")
{:ok, nil} = ClaudeCode.History.summary("new-session-id")