[BUG] -p mode sessions write valid .jsonl but never get registered in sessions-index.json (invisible to --resume picker / title resume)
Summary
When Claude Code is launched in -p (--print) mode with --output-format stream-json --input-format stream-json, the resulting conversation:
- Does write a complete, valid
~/.claude/projects/<encoded-cwd>/<session-id>.jsonl - Does remain resumable via direct UUID:
claude --resume <session-id>works flawlessly - Does NOT appear in
sessions-index.jsonfor that project — in fact, noentries[]row is ever appended for-p-created sessions - Cannot be resumed via
--resume <title>(the title-based resolver depends on the index) - Cannot be discovered through the interactive
--resumepicker (which reads the index)
This is a discoverability gap: the conversation transcript exists on disk, has full content, and is fully resumable when you happen to know its UUID — but there is no UI / CLI surface that lists it.
Environment
- Claude Code: 2.1.145 (also reproduced anecdotally on 2.1.132 / 2.1.143)
- OS: Linux (Amazon Linux 2023, kernel 6.1)
- Auth: Bedrock
- Invocation: piped stdin/stdout (no TTY) — typical for SDK / gateway / IM-bridge integrations
Reproduction
# fresh project dir, no prior CC state
mkdir -p /tmp/cc-pipe-repro && cd /tmp/cc-pipe-repro
# spawn a real -p stream-json session and send one message
claude -p --output-format stream-json --input-format stream-json --verbose --setting-sources "" <<'EOF'
{"type":"user","message":{"role":"user","content":[{"type":"text","text":"reply with a single word: pong"}]}}
EOF
# captures session_id from system/init, e.g. b5563b87-e7b2-45e7-a7a7-572333aa9cc6
After the call returns:
$ ls -la ~/.claude/projects/-tmp-cc-pipe-repro/
-rw-------. 1 ec2-user ec2-user 6622 May 21 04:58 b5563b87-e7b2-45e7-a7a7-572333aa9cc6.jsonl
drwxrwxr-x. 2 ec2-user ec2-user 6 May 21 04:58 memory/
# ↑ jsonl is there, sessions-index.json is NOT there at all
$ cat ~/.claude/projects/-tmp-cc-pipe-repro/sessions-index.json
cat: No such file or directory
Compare to a project that has been used in interactive mode at least once:
$ cat ~/.claude/projects/-home-ec2-user-workspace-daydream/sessions-index.json | jq '.entries[0]'
{
"sessionId": "45799210-8e9f-4f68-b333-daf9ca6e9b62",
"fullPath": "/home/ec2-user/.claude/projects/-home-ec2-user-workspace-daydream/45799210-8e9f-4f68-b333-daf9ca6e9b62.jsonl",
"fileMtime": 1769990497445,
"firstPrompt": "redis6-cli",
"summary": "Redis CLI Tool Name Error",
"messageCount": 2,
"created": "2026-02-01T14:19:36.177Z",
"modified": "2026-02-01T14:20:35.027Z",
"gitBranch": "dev",
"projectPath": "/home/ec2-user/workspace/daydream",
"isSidechain": false
}
Now confirm the session is, in fact, fully resumable when you know its UUID:
$ cd /tmp/cc-pipe-repro && claude -p --resume b5563b87-... --output-format stream-json --input-format stream-json --verbose --setting-sources "" <<'EOF'
{"type":"user","message":{"role":"user","content":[{"type":"text","text":"what was the previous word you said?"}]}}
EOF
# → assistant correctly replies referencing "pong" — full context is preserved
But title-based resume fails:
$ claude -p --resume "pong" < /dev/null
Error: --resume requires a valid session ID or session title when used with --print.
Provided value "pong" is not a UUID and does not match any session title.
…because there is no index entry to search against.
Why this matters (real-world impact)
I maintain naozhi (github.com/KevinZhao/naozhi), a Go-based gateway that bridges Claude Code into IM channels (Feishu first, more planned). The architecture is the documented pattern from #37045 (TELAUDE) and similar projects: spawn long-lived claude -p --output-format stream-json --input-format stream-json child processes, route IM messages over stdin/stdout. We pick -p because:
- Interactive mode (no
-p) renders a TUI prompt, which breaks stream-json framing. - The Agent SDK is ToS-restricted for OAuth/subscription auth.
-pis the only documented programmatic surface that preserves native session management, MCP, plugins, hooks, etc.
The breakage:
- A user starts a conversation in Feishu → naozhi spawns
claude -p --resume <uuid>→ conversation lives normally on disk under~/.claude/projects/.... - The user sits down at their terminal, runs
claudeinteractively, hits/resume→ none of their Feishu conversations show up. They exist, they're complete, they're resumable — but undiscoverable without copy-pasting UUIDs from a separate dashboard. - Same goes for
claude -p --resume "<title>"for any scripted flow. Title-based search can't find what isn't indexed.
I suspect the same affects every third-party claude -p consumer (TELAUDE, OpenClaw-style bridges, custom SDKs that wrap the CLI) — they all silently produce sessions invisible to the official discovery UI.
What I think is happening (not authoritative — guessing from observed file IO)
sessions-index.json appears to be appended-to only by the path that creates "named" / interactive sessions. The -p spawn path is treated as ephemeral and skips index registration even though --no-session-persistence exists (and is opt-out, not opt-in — implying persistence is the default for -p).
Possibly relevant: --no-session-persistence's help text reads:
Disable session persistence - sessions will not be saved to disk and cannot be resumed (only works with --print)
So the public contract is that -p sessions are persisted (and the file proves they are). The contract-breaker is that "persisted" doesn't currently include "indexed."
Suggested fixes (any one would help)
- (Preferred) Always write a
sessions-index.jsonentry for-psessions when persistence is on (i.e.--no-session-persistenceis NOT set). This matches the documented contract and is the smallest change. - (Opt-in) Add a flag like
--register-session(or--persist-session-index) so consumers can opt in explicitly without changing default behavior. - (Adopt-on-demand) A
claude project reindexsubcommand that scans~/.claude/projects/<cwd>/*.jsonland rebuildssessions-index.jsonfrom the on-disk transcripts. Useful for recovery on top of either of the above.
Option 1 has the highest leverage: it fixes the gap silently for every existing third-party tool with zero migration. Option 2 is the most conservative if there are reasons -p sessions are intentionally not indexed (please clarify if so).
Workaround (current)
Third-party tools have to:
- Track session UUIDs themselves (we keep our own session DB keyed by
{channel}:{chatType}:{id}) — fine for our internal use, but useless for end users dropping into the CLI. - Optionally reverse-engineer
sessions-index.jsonschema and write entries directly. (See #58670 for a Desktop-app-side equivalent of this DIY approach — same root cause family.)
Neither workaround is sustainable; the index format is internal and can change between releases.
Related issues (similar symptoms / same family — but distinct root cause)
- #38340 (closed/stale) —
/resumepicker doesn't filesystem-scan; same symptom but discusses interactive-mode index drift, not-pregistration gap - #58670 (open) — Desktop "Code" tab missing pre-existing CLI sessions; also an index-population gap, different surface
- #37045 (closed/stale) — TELAUDE author asking if
claude -pbridging is officially supported; same use case, didn't surface this specific gap - #33979 (open/stale) — meta request for a built-in
claude sessionsmanager; would subsume this if implemented
This issue is specifically the -p → sessions-index.json write gap, with current-version repro and a concrete fix path. Please don't auto-dedupe against the broader cluster — the fix surface is narrower and more tractable than any of those.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗