feat: add list_sessions and get_session_messages top-level functions#622
Merged
Conversation
Ports listSessions() from the TypeScript SDK as a filesystem-reading implementation (not a CLI passthrough). Scans ~/.claude/projects/ for .jsonl session files and extracts metadata via stat + head/tail reads without full JSONL parsing. - Add SDKSessionInfo dataclass to types.py (session_id, summary, last_modified, file_size, custom_title, first_prompt, git_branch, cwd) - Add _internal/sessions.py with path sanitization, JSON field extraction, first-prompt parsing, and git worktree detection - Export list_sessions() and SDKSessionInfo from __init__.py - Filter sidechain sessions and empty metadata-only sessions (no '(session)' placeholder fallback) - Support include_worktrees option (default True) to scan all git worktree paths for a project - 38 tests covering helpers and integration scenarios
Ports getSessionMessages() from the TypeScript SDK. Reads a single session JSONL file fully, reconstructs the conversation chain via parentUuid links, and returns user/assistant messages in chronological order. - Add SessionMessage dataclass to types.py (type, uuid, session_id, message, parent_tool_use_id) - Add get_session_messages() to _internal/sessions.py, reusing existing path sanitization, config dir resolution, and worktree detection helpers from list_sessions - Chain algorithm: find terminal entries (no children), walk each back to nearest user/assistant leaf, pick main-chain leaf with highest file position, then walk leaf→root via parentUuid and reverse - Filters: isMeta, isSidechain, teamName; keeps isCompactSummary (matches VS Code IDE behavior post-compaction) - Supports limit/offset pagination - Returns empty list for invalid UUID or missing session (no raise) - 21 new tests covering chain building, filtering, pagination, cycles
blois
approved these changes
Mar 3, 2026
qing-ant
added a commit
that referenced
this pull request
Mar 18, 2026
Four fixes from a 43-agent adversarial review against the TS reference
(claude-cli-internal src/utils/listSessionsImpl.ts @ main):
1. Tag extraction scoped to {"type":"tag"} lines (sessions.py:455)
Bare _extract_last_json_string_field(tail, "tag") matches ANY "tag":"..."
in the 64KB tail — including tool_use inputs from Docker builds, git tag
via MCP, cloud resource tagging. Proven: test_tag_none_when_only_tool_use_tag
returned tag='prod' from tool input before the fix.
TS scopes to lines starting with '{"type":"tag"' at column 0
(listSessionsImpl.ts:132, sessionStorage.ts:629 with the canonical
comment about this exact collision class).
Tests now use separators=(",", ":") to match real on-disk format
(CLI jsonStringify, SDK tag_session, TS sessionMutationsImpl all write
compact JSON). 2 regression tests added.
2. custom_title chain: + head scan, + aiTitle fallback (sessions.py:426)
TS chain is tail.customTitle || head.customTitle || tail.aiTitle ||
head.aiTitle (listSessionsImpl.ts:97-102). Pre-existing drift from TS
PRs #21333 (aiTitle) and #20390 landing after Python #622 — fixing here
since this PR touches the exact block.
3. summary chain: + lastPrompt fallback (sessions.py:436)
TS inserts tail.lastPrompt between custom_title and summary
(listSessionsImpl.ts:115-119). Same drift class as (2).
4. created_at: float -> int (types.py:998, sessions.py:465)
last_modified is int; both are epoch-ms. Wrapped
datetime.timestamp() * 1000 in int().
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
list_sessions()andget_session_messages()as top-level functions, matching the TypeScript SDK'slistSessions()andgetSessionMessages().These are filesystem-reading implementations (not CLI passthroughs) — they scan
~/.claude/projects/directly, same as the TS SDK.list_sessions(directory=None, limit=None, include_worktrees=True) -> list[SDKSessionInfo]~/.claude/projects/(orCLAUDE_CONFIG_DIR).jsonlfile (does not load entire large transcripts)session_id,summary,last_modified,file_size,custom_title,first_prompt,git_branch,cwdinclude_worktrees=Trueexpands to active git worktree session dirs;Falsefilters them out'(session)'placeholder)get_session_messages(session_id, directory=None, limit=None, offset=0) -> list[SessionMessage].jsonlfullyparentUuidbackward traversal (leaf → root, reversed)user/assistantmessages only[]for nonexistent/invalid session IDs (never raises)list_sessions()andget_session_messages()top-level functionsSDKSessionInfoandSessionMessagedataclassesTest plan
list_sessions: verified against 637 real sessions — all shape checks pass,include_worktreesexpansion confirmed on a 16-worktree repo (270 → 274 sessions), nonexistent dir → clean[]get_session_messages: 8 real sessions (~14MB JSONL) — chain reconstruction proven (0 broken links across 1,581 entries), 254-branch session correctly walks main-line, isMeta filtering verified, pagination matches exact slicing