Sessions are persistent conversation contexts. 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:
—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 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.
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:
claude -p "Try approach B instead" \ --resume "$SESSION" --fork-session --output-format jsonThis 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
—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.
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:
# Both run simultaneously, no lockingclaude -p "Review auth module" --output-format json > review_auth.json &claude -p "Review database module" --output-format json > review_db.json &waitThere 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
| Scenario | Result |
|---|---|
| One session in directory | Picks that session |
| Multiple sessions in directory | Picks the most recently created |
| Sessions in parent and subfolder | Only sees sessions from current directory |
| No sessions in current directory | Error: 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.
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.