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.
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.
The JSON response from that initial call contains everything you need. Here is the full payload:
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
| Flag | Behavior | Scope |
|---|---|---|
—resume SESSION_ID | Resumes a specific session by UUID | Works from any directory |
—continue | Resumes the most recent session | Current directory only |
—resume (no args) | Opens interactive session picker | Interactive 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:
claude -p "Quick question" --no-session-persistence --output-format jsonThe 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.
# Step 1: PlanPLAN=$(claude -p "Plan a refactoring of auth.py" \ --permission-mode plan --output-format json)SESSION=$(echo "$PLAN" | jq -r '.session_id')
# Step 2: Reviewecho "$PLAN" | jq -r '.result'
# Step 3: Execute (same session, full context)claude -p "yes, proceed" --resume "$SESSION" --permission-mode bypassPermissionsStep 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.
—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.
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:
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 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.
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.