Skip to content

Advanced Session Patterns

Fork strategies, concurrent sessions, and deterministic session IDs

7 min read
Session fork tree: trunk session branching into multiple forks with context inheritanceCreateReviewTeam Intel--resumeDiscussion #3Discussion #7context inheritedcontext inherited

Your multi-step pipeline works in sequence but takes 20 minutes. You try to parallelize by forking the session — and discover that forked sessions share the initial context but not subsequent updates from sibling forks. Advanced session patterns require understanding what state transfers and what doesn’t.

This chapter covers advanced session patterns. For session basics (create, resume, continue), see Working with Sessions.

Branching with —fork-session

The --fork-session flag creates a new session with a copy of the conversation history. The original session is left untouched:

Terminal window
claude -p "Try approach B instead" \
--resume "$SESSION" --fork-session --output-format json

This gives you a clean branch point. The forked session has its own UUID and its own future, while the original remains available for --resume. Use cases include:

  • A/B testing approaches — fork at the same decision point and compare results
  • Exploring alternatives — try a risky refactor without losing the main thread
  • Chain forks — fork a fork to create tree-shaped exploration (each fork gets a fresh UUID)

Here is a real fork response showing the new session ID:

fork_sessionclaude -p --resume $SID --fork-session --output-format json
1{
2 "type": "result",
3 "subtype": "success",
4 "is_error": false,
5 "duration_ms": 3605,
6 "num_turns": 1,
7 "result": "FORKED_MESSAGE",A
8 "session_id": "b9395772-b2e3-4f46-b380-c81f9d766afe",B
9 "total_cost_usd": 0.01683075,
10 "modelUsage": {
11 "claude-opus-4-6": {
12 "inputTokens": 3,
13 "outputTokens": 8,
14 "cacheReadInputTokens": 14269,
15 "cacheCreationInputTokens": 1517,
16 "costUSD": 0.01683075
17 }
18 }
19}
ANEW UUID — different from the original session
BNormal turn cost — fork is cheap

The original session (4b8101c6-...) still returns “BASE_MESSAGE” when resumed — forking is completely non-destructive.

Try This

Fork a session and test context isolation:

SID=$(claude -p “Remember: the code is 42” —output-format json | jq -r ‘.session_id’)

claude -p “What is the code?” —resume “$SID” —output-format json | jq ‘.result’

claude -p “Change the code to 99. What is the code now?” —resume “$SID” —output-format json | jq ‘.result’

Does the second resume see the change from the first resume, or does each fork get the original state?

Concurrent Sessions

Multiple claude -p calls can run in parallel in the same directory without conflicts. Each gets a unique session ID and independent context:

Terminal window
# Both run simultaneously, no locking
claude -p "Review auth module" --output-format json > review_auth.json &
claude -p "Review database module" --output-format json > review_db.json &
wait

There is no session locking mechanism. Parallel calls do not interfere with each other.

Which Session Does —continue Pick?

When multiple sessions exist in a directory, --continue picks the most recently created one. It does not pick the most recently modified or the one that ran longest.

--continue Resolution Rules

ScenarioResult
One session in directoryPicks that session
Multiple sessions in directoryPicks the most recently created
Sessions in parent and subfolderOnly sees sessions from current directory
No sessions in current directoryError: no session to continue

Sessions are stored in ~/.claude/projects/<encoded-dir-path>/, which is why --continue is directory-scoped. Use --resume SESSION_ID when you need to target a specific session regardless of directory.

Tip

For parallel workflows where you need to continue specific sessions later, capture the session_id from each JSON response and use —resume instead of —continue. This eliminates ambiguity about which session gets continued.

Deterministic Session IDs

The --session-id flag assigns a specific UUID to a new session, enabling deterministic naming for CI correlation:

Terminal window
# Assign a deterministic session ID for CI traceability
claude -p "Run linting" \
--session-id "$(uuidgen)" \
--output-format json

Key behaviors confirmed experimentally:

  • The returned session_id is exactly the UUID you provide — no prefix or suffix added
  • The value must be a valid UUID (8-4-4-4-12 hex format). Non-conforming strings silently produce empty output
  • Reusing an already-active session ID produces: Error: Session ID <uuid> is already in use
  • --session-id is for assignment only — it does NOT resume. Use --resume for that
  • Combining --resume with --session-id requires --fork-session (fork-to-new-ID semantics)
Terminal window
# Fork a session to a new deterministic ID
claude -p "Continue with approach B" \
--resume "$OLD_SESSION" \
--session-id "$NEW_UUID" \
--fork-session
Concurrent Instance Corruption

While concurrent claude -p sessions are safe in practice (each gets a unique session ID and independent context), community reports indicate that interactive sessions can corrupt .claude.json state files when multiple instances modify them simultaneously. This is because .claude.json uses no file locking. For headless (-p) mode, sessions are stored in ~/.claude/projects/ with per-session isolation and are not affected. For interactive sessions, avoid running multiple instances in the same project directory.

See This in Action

See how —resume + —fork-session powers a real discussion system with three branching strategies in Build an MR Reviewer, Part 4: Fork Sessions for Discussions.

Now Do This

Fork a session: capture a session ID, then resume it twice with different prompts. Verify that each fork gets the original context but doesn’t see the other fork’s changes. This is the pattern for parallel task execution — branch from a common plan, execute independently.