Skip to main content

Module 12: Session Fork

Creating parallel conversation branches for exploration.

What You’ll Learn

  • Forking a session to create independent branches
  • Using CLIOptions.forkSession(true)
  • When forking is preferable to continuing

Fork vs Resume

OperationContextHistory
ResumeContinues same sessionAdds to original history
ForkCopies contextCreates new, independent history

Why Fork?

Forking creates a snapshot you can explore without affecting the original:
  • Try alternative approaches
  • Run “what if” scenarios
  • Parallel experimentation
  • Safe exploration without side effects

Forking a Session

import org.springaicommunity.claude.agent.sdk.ClaudeClient;
import org.springaicommunity.claude.agent.sdk.ClaudeSyncClient;
import org.springaicommunity.claude.agent.sdk.config.PermissionMode;
import org.springaicommunity.claude.agent.sdk.transport.CLIOptions;
import org.springaicommunity.claude.agent.sdk.types.Message;
import org.springaicommunity.claude.agent.sdk.types.ResultMessage;
import java.nio.file.Path;

// Original session - extract session ID
String originalSessionId = null;
try (ClaudeSyncClient client = ClaudeClient.sync()
        .workingDirectory(Path.of("."))
        .model(CLIOptions.MODEL_HAIKU)
        .permissionMode(PermissionMode.BYPASS_PERMISSIONS)
        .build()) {

    for (Message msg : client.connectAndReceive("We're building an app with PostgreSQL.")) {
        System.out.println(msg);
        if (msg instanceof ResultMessage rm) {
            originalSessionId = rm.sessionId();
        }
    }
}

// Fork for alternative exploration
CLIOptions forkOptions = CLIOptions.builder()
    .model(CLIOptions.MODEL_HAIKU)
    .permissionMode(PermissionMode.BYPASS_PERMISSIONS)
    .forkSession(true)  // Enable forking
    .build();

try (ClaudeSyncClient forkedClient = ClaudeClient.sync(forkOptions)
        .workingDirectory(Path.of("."))
        .build()) {

    forkedClient.connect();
    forkedClient.query("What if we used MongoDB instead?", originalSessionId);

    // Creates a new branch with different session ID
    String forkedSessionId = null;
    for (Message msg : forkedClient.messages()) {
        System.out.println(msg);
        if (msg instanceof ResultMessage rm) {
            forkedSessionId = rm.sessionId();
            // forkedSessionId != originalSessionId
        }
    }
}

How Forking Works

                    ┌──────────────────────┐
                    │  Original Session    │
                    │  "Using PostgreSQL"  │
                    └──────────┬───────────┘

           ┌───────────────────┴───────────────────┐
           │                                       │
           ▼                                       ▼
┌──────────────────────┐             ┌──────────────────────┐
│  Continue Original   │             │  Forked Session      │
│  "ORM for PostgreSQL?"│             │  "What about MongoDB?"│
│  Context: PostgreSQL │             │  Context: PostgreSQL  │
│                      │             │  (copied at fork)     │
└──────────────────────┘             └──────────────────────┘

Fork Use Cases

ScenarioBenefit
A/B testing promptsCompare approaches side-by-side
Exploring alternatives”What if we did X instead?”
Safe experimentationTry risky changes without affecting main flow
User branchingLet users explore different paths

Key Points

  • Fork copies context but creates a new session ID
  • Original session remains unchanged
  • Both branches can continue independently
  • Forked sessions can be forked again

Tradeoffs

  • Storage multiplication: Each fork creates a full copy of the session state. Forking a large conversation multiple times increases storage proportionally.
  • No merge capability: Forked branches cannot be merged back. Insights from one branch must be manually transferred to another.
  • Coordination complexity: Managing multiple active branches requires tracking multiple session IDs and their relationships.
  • Context duplication cost: Each forked branch carries the full history. Querying both branches costs the same as two independent conversations of that length.
Avoid forking for routine follow-up questions. Fork only when you need to preserve the original session state for later use.

Source Code

View on GitHub

Running the Example

mvn compile exec:java -pl module-12-session-fork

Next Module

Module 13: Advanced Async Patterns - Cross-turn handlers and advanced reactive patterns.