Sessions
A Session represents a Claude Code execution context. Sessions manage conversation history, context persistence, and enable resume and fork capabilities across job executions. Understanding session management is essential for controlling how your agents maintain (or reset) their context over time.
What is a Session?
Section titled “What is a Session?”When Claude Code executes, it maintains a conversation context—the accumulated history of messages, tool uses, and responses. A session encapsulates this context, allowing herdctl to:
- Persist context across multiple job executions
- Resume interrupted work from exactly where it left off
- Fork existing sessions to explore alternative approaches
- Isolate conversations per channel in chat integrations
sequenceDiagram participant U as User/Schedule participant A as Agent participant T as Tools Note over U,T: SESSION: Claude's accumulated context U->>A: Check for ready issues and implement one A->>A: I found issue #42. Reading the spec... A->>T: Read src/api/users.ts T-->>A: (file contents) A->>A: I'll add the validation logic... Note over U,T: Metadata: id, agentId, mode, createdAt, lastActiveAt
Session Modes
Section titled “Session Modes”herdctl supports three session modes that control how context is managed across job executions:
fresh_per_job
Section titled “fresh_per_job”Each job starts with a completely fresh session—no prior context from previous runs.
session: mode: fresh_per_jobUse cases:
- Stateless tasks that should start clean each time
- Jobs where prior context might cause confusion
- High-security scenarios requiring context isolation
Behavior:
- New session created for every job execution
- No conversation history carried forward
- Previous sessions are archived but not used
Job 1 → Session A (fresh) → CompletedJob 2 → Session B (fresh) → Completed # No memory of Job 1Job 3 → Session C (fresh) → Completed # No memory of Jobs 1 or 2persistent
Section titled “persistent”Maintains context across multiple job executions. The agent “remembers” previous work.
session: mode: persistentUse cases:
- Long-running projects requiring continuity
- Agents that build on previous work
- Tasks where context improves performance
Behavior:
- Session persists across job executions
- Conversation history accumulates
- Context is automatically summarized when it grows large
Job 1 → Session A → Completed (context saved)Job 2 → Session A → Completed (continues with Job 1's context)Job 3 → Session A → Completed (continues with Jobs 1+2 context)Configuration options:
session: mode: persistent max_context_tokens: 100000 # Summarize when exceeded context_window: 50 # Keep last N messages in full detailper_channel
Section titled “per_channel”Creates separate sessions for each communication channel. Ideal for chat integrations where different channels represent different conversations or users.
session: mode: per_channelUse cases:
- Discord/Slack bot integrations
- Multi-user support scenarios
- Channel-specific context isolation
Behavior:
- Each channel gets its own persistent session
- Context is isolated between channels
- Sessions are identified by channel ID
Discord #general → Session A (persistent within channel)Discord #support → Session B (separate context)Slack #dev → Session C (separate context)Example configuration:
Each chat-enabled agent has its own Discord bot (created in Discord Developer Portal), appearing as a distinct “person” in chat.
name: project-supportdescription: "Answers questions in Discord channels"workspace: my-projectrepo: owner/my-project
chat: discord: bot_token_env: SUPPORT_DISCORD_TOKEN # This agent's own bot guilds: - id: "guild-id-here" channels: - id: "123456789" # #general mode: mention - id: "987654321" # #support mode: auto
session: mode: per_channel # Separate context per channel timeout: 24h # Session expires after 24h inactivitySession Properties
Section titled “Session Properties”| Property | Type | Description |
|---|---|---|
id | string | Unique session identifier |
agentId | string | Agent that owns this session |
mode | enum | Session mode (fresh_per_job, persistent, per_channel) |
channelId | string | Channel ID (for per_channel mode) |
status | enum | Current session status |
createdAt | timestamp | When session was created |
lastActiveAt | timestamp | Last activity timestamp |
messageCount | number | Number of messages in context |
tokenEstimate | number | Estimated context token count |
Session Lifecycle
Section titled “Session Lifecycle”Sessions progress through defined states:
CREATED → ACTIVE → PAUSED → COMPLETED → EXPIRED| Status | Description |
|---|---|
created | Session initialized, not yet used |
active | Claude is currently executing within this session |
paused | Session suspended, ready for resume |
completed | Session finished successfully |
expired | Session timed out due to inactivity |
Resume Capability
Section titled “Resume Capability”Sessions store Claude’s conversation context, enabling powerful recovery scenarios:
Automatic Resume
Section titled “Automatic Resume”When a job is interrupted (network issues, system restart), herdctl can automatically resume:
session: mode: persistent auto_resume: true # Automatically resume interrupted jobs resume_timeout: 1h # Only auto-resume within 1 hourManual Resume
Section titled “Manual Resume”Resume an agent’s session interactively with Claude Code:
# Resume the most recent sessionherdctl sessions resume
# Resume a specific session by ID (supports partial match)herdctl sessions resume a166a1e4
# Resume by agent nameherdctl sessions resume bragdoc-coderThis launches Claude Code in the agent’s workspace with the full conversation history restored, allowing you to continue the work interactively.
Resume Behavior
Section titled “Resume Behavior”When resuming:
- Full conversation history is restored
- Claude receives context about the interruption
- Execution continues from the last known state
Original Job: Message 1 → Message 2 → Message 3 → [INTERRUPTED]
Resumed Job: Message 1 → Message 2 → Message 3 → [System: Resuming...] → Message 4Fork Capability
Section titled “Fork Capability”Fork an existing session to explore alternative approaches without affecting the original:
# Fork a session at its current stateherdctl session fork <session-id>
# Fork and immediately start a new jobherdctl session fork <session-id> --run --prompt "Try a different approach"
# Fork from a specific point in historyherdctl session fork <session-id> --at-message 5Fork Use Cases
Section titled “Fork Use Cases”- Experimentation: Try different solutions without losing progress
- A/B Testing: Compare approaches from the same starting point
- Rollback: Return to a known good state
Original Session: M1 → M2 → M3 → M4 → M5 (current) ↓Forked Session: M4' → M5' (different approach)Example Configurations
Section titled “Example Configurations”Stateless Coder Agent
Section titled “Stateless Coder Agent”For a coder that should evaluate each issue fresh:
name: stateless-coderdescription: "Implements features without prior context"workspace: my-projectrepo: owner/my-project
schedules: - name: issue-check trigger: type: interval every: 5m prompt: "Check for ready issues and implement one."
session: mode: fresh_per_job # Clean slate each run timeout: 30m # Maximum job durationPersistent Research Agent
Section titled “Persistent Research Agent”For an agent that builds knowledge over time:
name: research-agentdescription: "Builds understanding of the codebase over time"workspace: my-projectrepo: owner/my-project
schedules: - name: daily-analysis trigger: type: cron cron: "0 9 * * *" prompt: | Continue your codebase analysis. Review what you learned yesterday and explore new areas. Update your findings in research-notes.md.
session: mode: persistent # Remember previous sessions max_context_tokens: 150000 # Allow large context context_window: 100 # Keep last 100 messages in detailMulti-Channel Support Bot
Section titled “Multi-Channel Support Bot”For a support agent handling multiple chat channels (each agent has its own Discord bot):
name: support-botdescription: "Answers questions across Discord channels"workspace: my-projectrepo: owner/my-project
chat: discord: bot_token_env: SUPPORT_DISCORD_TOKEN # This agent's own bot guilds: - id: "guild-id-here" channels: - id: "111222333" mode: mention - id: "444555666" mode: auto
session: mode: per_channel # Isolated context per channel timeout: 24h # Sessions expire after 24h idle_timeout: 2h # Or 2h of inactivityHybrid Configuration
Section titled “Hybrid Configuration”Combine session settings with agent-level defaults:
name: hybrid-agentdescription: "Different session behavior per schedule"workspace: my-projectrepo: owner/my-project
# Default session settings for this agentsession: mode: persistent timeout: 1h
schedules: - name: continuous-work trigger: type: interval every: 30m prompt: "Continue working on the current feature." # Uses default persistent session
- name: fresh-review trigger: type: cron cron: "0 9 * * 1" # Monday mornings prompt: "Review the codebase with fresh eyes." session: mode: fresh_per_job # Override: start fresh for reviewsSession Storage
Section titled “Session Storage”Session storage location varies by runtime and execution environment:
Storage Locations by Mode
Section titled “Storage Locations by Mode”| Runtime | Environment | Storage Location | Notes |
|---|---|---|---|
| Both | Local | ~/.claude/projects/ | Claude stores sessions; herdctl tracks metadata in .herdctl/sessions/ |
| Both | Docker | .herdctl/docker-sessions/ | Isolated from local sessions |
Key behaviors:
- Local SDK ↔ CLI: Sessions compatible (both use Claude Code session system)
- Docker SDK ↔ CLI: Sessions compatible (both use Docker mount)
- Local ↔ Docker: Sessions NOT compatible (different storage locations)
Session Compatibility
Section titled “Session Compatibility”Sessions persist when switching runtimes within the same environment:
# Local environment - sessions resumeruntime: sdk # Job 1runtime: cli # Job 2 resumes Job 1's session
# Enable Docker - new session startsdocker: enabled: trueruntime: sdk # Job 3 - fresh session (Docker isolation)runtime: cli # Job 4 resumes Job 3's session (both in Docker)Session File Structure
Section titled “Session File Structure”herdctl stores session metadata for tracking and management:
~/.herdctl/└── sessions/ ├── agent-name.json # Session info per agent └── ...
~/.herdctl/└── docker-sessions/ # Docker container sessions └── (mounted to containers)Example session metadata:
{ "session_id": "a1b2c3d4-5678-90ab-cdef-123456789abc", "agent_name": "bragdoc-coder", "created_at": "2024-01-15T09:00:00Z", "last_used_at": "2024-01-15T10:30:00Z", "working_directory": "/Users/you/projects/myapp"}Session Commands
Section titled “Session Commands”List and resume Claude Code sessions from the command line:
# List all sessionsherdctl sessions
# Filter by agentherdctl sessions --agent bragdoc-coder
# Show full resume commandsherdctl sessions --verbose
# JSON output for scriptingherdctl sessions --json
# Resume the most recent session in Claude Codeherdctl sessions resume
# Resume a specific session (supports partial ID match)herdctl sessions resume a166a1e4
# Resume by agent nameherdctl sessions resume bragdoc-coderThe sessions resume command launches Claude Code with --resume <session-id> in the agent’s configured workspace directory, making it easy to pick up where a Discord bot or scheduled agent left off.
See the CLI Reference for complete command options.
Session Discovery
Section titled “Session Discovery”The session modes above describe sessions that herdctl creates and manages directly. But herdctl can also discover sessions it didn’t create.
The SessionDiscoveryService scans Claude Code’s JSONL session files in ~/.claude/projects/ to find every session associated with a working directory that an herdctl agent uses. This means the web dashboard shows a complete picture of all Claude Code activity in a project, not just herdctl-initiated sessions:
- herdctl sessions — sessions started through scheduled jobs or interactive web chat
- Native sessions — sessions started by running
claudedirectly in the terminal, in a project directory that an herdctl agent also uses - Full conversation history — for any discovered session, the dashboard can display the complete message history
This is useful because developers often switch between herdctl-managed agents and direct Claude Code usage in the same project. Session discovery surfaces all of that activity in one place.
Session Attribution
Section titled “Session Attribution”Every discovered session is attributed to an origin that describes how it was started:
| Origin | Description |
|---|---|
herdctl | Started by herdctl — either through a scheduled job or interactive web chat. Attribution is determined by cross-referencing job metadata files and platform session records in .herdctl/sessions/. |
native | Started by running claude directly in the terminal, in a working directory that an herdctl agent also uses. These sessions are discovered and displayed but not managed by herdctl. |
ad hoc | A native session that a user chose to continue interactively from the web dashboard. herdctl creates a new interactive session that picks up the conversation. |
Attribution matters because it tells you at a glance whether a session is something herdctl is responsible for or something a developer started independently. In the dashboard, sessions are labeled with their origin so you can filter and distinguish between managed and unmanaged activity.
Sidechain Sessions
Section titled “Sidechain Sessions”Claude Code internally marks certain sessions as sidechain sessions. These include:
- Sub-agent sessions — created by the Task tool, typically single-message prompt-cache warmup sessions
- Resumed sessions — sessions started with the
--resumeflag
Sidechain sessions are automatically filtered from the dashboard because they are usually noise. A Task tool sub-agent session might contain only a single “Warmup” message and provides no useful context in the session list.
This filtering has a practical consequence for schedule configuration: herdctl defaults resume_session: false in schedule configuration. Setting it to true causes Claude Code to mark the resumed session as a sidechain, which hides it from the dashboard. If you need session continuity, use persistent mode instead of resume_session: true.
Session Names
Section titled “Session Names”Sessions are given human-readable names for display in the dashboard and CLI. The naming follows a priority order:
- Custom name — a name manually set by the user through the dashboard
- Auto-generated name — extracted from Claude Code’s automatic session summary (stored as
type: "summary"entries in the session JSONL file) - First message preview — the first ~100 characters of the first user message in the session
- Fallback — “New conversation”
Auto-generated names are cached in the SessionMetadataStore so that session lists load quickly without re-parsing JSONL files on every request. When Claude Code generates a new summary for a session, the cached name is updated on the next discovery pass.
Related Concepts
Section titled “Related Concepts”- Jobs - Individual executions that use sessions
- Agents - Configure session behavior per agent
- State Management - Session persistence details
- CLI Reference: sessions - Full command options for session management