Skip to content

Working with Sessions

Create, resume, continue, and fork conversations

6 min read

You run two claude -p calls in a row. The second one has no memory of the first. Your careful multi-step workflow just became two disconnected conversations with no shared context. Sessions fix this.

Every claude -p call creates a session with a unique ID. You can resume it later with --resume, continue the most recent one with --continue, or disable persistence with --no-session-persistence. This is what makes multi-step workflows possible — a plan-review-execute chain, a staged migration, or a CI pipeline that picks up where a previous run left off.

Session lifecycle: create, resume, fork, expireCreateResumeForkExpireBranch

Create and Capture

The first step in any session workflow is capturing the session ID from the initial call. Pass --output-format json so you can extract the session_id field with jq.

Create & Capture a Session
$ RESULT=$(claude -p "Analyze the codebase" --output-format json)
$ SESSION_ID=$(echo "$RESULT" | jq -r '.session_id')
$ echo "Session: $SESSION_ID"
Session: d25a595e-22f0-4206-87d8-20cce15c6355

The JSON response from that initial call contains everything you need. Here is the full payload:

create_sessionclaude -p --output-format json
1{
2 "type": "result",
3 "subtype": "success",
4 "is_error": false,
5 "duration_ms": 3071,
6 "num_turns": 1,
7 "result": "session test 1",A
8 "session_id": "d25a595e-22f0-4206-87d8-20cce15c6355",B
9 "total_cost_usd": 0.015954
10}
AStore this UUID to resume later
BCost for this turn only
Try This

Try a two-step session right now:

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

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

Does Claude remember? Now try without —resume — the context is gone.

—resume vs —continue

These two flags both resume a session, but they find it in very different ways. Choosing the wrong one is one of the most common mistakes in session-based workflows.

Session Resumption Flags

FlagBehaviorScope
—resume SESSION_IDResumes a specific session by UUIDWorks from any directory
—continueResumes the most recent sessionCurrent directory only
—resume (no args)Opens interactive session pickerInteractive mode only

For automation, always use --resume SESSION_ID. The --continue flag is convenient for interactive use, but in scripts it introduces ambiguity: another process could create a newer session in the same directory, and --continue would pick that one instead of yours.

Ephemeral Sessions

Add --no-session-persistence (requires --print) when you do not want the session saved to disk:

Terminal window
claude -p "Quick question" --no-session-persistence --output-format json

The response still includes a session_id field, but the session is not saved to disk. Attempting to --resume it later will fail. This is the right choice for:

  • CI/CD pipelines — do not pollute the session store with one-off runs
  • Batch processing — thousands of independent queries do not need persistence
  • Privacy — sensitive prompts are not stored on disk

The JSON response looks identical to a normal session. You cannot tell from the payload alone whether the session was persisted. This is by design — the calling code decides persistence, not the response format.

Session-Aware Workflows

The real power of sessions is chaining multiple calls into a single coherent workflow. The classic pattern is plan-review-execute: Claude plans in a restricted mode, a human reviews, and then Claude executes with full permissions in the same conversational context.

Terminal window
# Step 1: Plan
PLAN=$(claude -p "Plan a refactoring of auth.py" \
--permission-mode plan --output-format json)
SESSION=$(echo "$PLAN" | jq -r '.session_id')
# Step 2: Review
echo "$PLAN" | jq -r '.result'
# Step 3: Execute (same session, full context)
claude -p "yes, proceed" --resume "$SESSION" --permission-mode bypassPermissions

Step 3 resumes the exact session from Step 1. Claude has the full plan in context and does not need to re-analyze the codebase. The --permission-mode flag changes between steps, letting you enforce a review gate before granting write access.

Gotcha

—continue is directory-scoped. If you created a session in /project-a/ and run —continue from /project-b/, it will not find it. Use —resume SESSION_ID for cross-directory resumption.

Tip

Sessions share the 200K context window. Long sessions hit auto-compaction, which summarizes earlier turns to free space. Plan for this in long workflows — critical instructions should live in CLAUDE.md so they survive compaction.

Resume Payload

When you resume a session, the payload confirms continuity. Here is the response after asking “What was my previous message?” in a resumed session:

resume_sessionclaude -p --resume SESSION_ID --output-format json
1{
2 "type": "result",
3 "subtype": "success",
4 "is_error": false,
5 "duration_ms": 3523,
6 "num_turns": 1,
7 "result": "Your previous message was:\n\n> Say: session test 1",A
8 "session_id": "d25a595e-22f0-4206-87d8-20cce15c6355",B
9 "total_cost_usd": 0.01628525
10}
AClaude correctly recalled the previous turn
BSame session ID -- conversation continuity confirmed

The result field shows Claude recalling the exact content from the previous turn. The session_id matches the original, confirming this is the same conversation context — not a new session that happened to receive similar instructions.

For advanced patterns like forking and concurrent sessions, see Advanced Session Patterns.

See This in Action

See how a production system forks review sessions for threaded discussions — first message forks the trunk, follow-ups resume the fork — in Build an MR Reviewer, Part 4: Fork Sessions for Discussions.

Now Do This

Capture a session ID from your next automation call: SID=$(claude -p “Analyze this codebase” —output-format json | jq -r ‘.session_id’). Then resume it with a follow-up question: claude -p “What did you find?” —resume “$SID”. You just built a multi-step workflow.