Skip to main content

Overview

A Session is a single chat conversation with an AI assistant within a worktree. Each worktree can have multiple sessions, allowing you to work on different tasks simultaneously or organize your work by topic.

Session Structure

Session Type

interface Session {
  id: string                           // Unique session identifier (UUID v4)
  name: string                         // Display name ("Session 1" or custom)
  order: number                        // Tab ordering (0-indexed)
  created_at: number                   // Unix timestamp
  updated_at: number                   // Last activity timestamp
  messages: ChatMessage[]              // Full conversation history
  message_count?: number               // Cached count (for efficiency)
  
  // AI Backend Configuration
  backend?: Backend                    // 'claude', 'codex', or 'opencode'
  claude_session_id?: string           // Claude CLI session ID (for resuming)
  codex_thread_id?: string             // Codex CLI thread ID
  opencode_session_id?: string         // OpenCode session ID
  selected_model?: string              // Model for this session
  selected_thinking_level?: ThinkingLevel
  selected_provider?: string           // Custom provider name
  
  // Session Metadata
  session_naming_completed?: boolean   // Auto-naming attempted
  archived_at?: number                 // Archived timestamp (soft delete)
  last_opened_at?: number              // Last viewed timestamp
  
  // Session-Specific UI State
  answered_questions?: string[]        // Answered AskUserQuestion IDs
  submitted_answers?: Record<string, QuestionAnswer[]>
  fixed_findings?: string[]            // Fixed code review findings
  pending_permission_denials?: PermissionDenial[]
  review_results?: ReviewResponse      // AI code review results
  is_reviewing?: boolean               // Marked for review
  waiting_for_input?: boolean          // Waiting for user response
  waiting_for_input_type?: 'question' | 'plan' | null
  approved_plan_message_ids?: string[] // Approved plans (NDJSON storage)
  plan_file_path?: string              // Current plan file path
  pending_plan_message_id?: string     // Pending plan awaiting approval
  enabled_mcp_servers?: string[]       // Per-session MCP override
  digest?: SessionDigest               // Recap summary
  last_run_status?: RunStatus          // Status of last run
  last_run_execution_mode?: ExecutionMode
  label?: LabelData                    // User-assigned label with color
}

Chat Message

interface ChatMessage {
  id: string
  session_id: string                   // Belongs to this session
  role: MessageRole                    // 'user' or 'assistant'
  content: string                      // Text content
  timestamp: number
  tool_calls: ToolCall[]               // Tools executed (assistant only)
  content_blocks?: ContentBlock[]      // Ordered text/tool/thinking blocks
  cancelled?: boolean                  // Cancelled mid-stream
  plan_approved?: boolean              // Plan was approved
  model?: string                       // Model used (user messages)
  execution_mode?: ExecutionMode       // Mode when sent
  thinking_level?: ThinkingLevel       // Thinking level when sent
  effort_level?: EffortLevel           // Effort level (Opus 4.6)
  recovered?: boolean                  // Recovered from crash
  usage?: UsageData                    // Token usage (assistant)
}

Tool Calls

Assistant messages contain tool calls representing AI actions:
interface ToolCall {
  id: string                           // Tool call ID from Claude
  name: string                         // Tool name ("Read", "Edit", "Bash", etc.)
  input: unknown                       // Input parameters (JSON)
  output?: string                      // Tool execution output
  parent_tool_use_id?: string          // Parent for sub-agent attribution
}
Tool calls are displayed inline in the chat, showing what the AI is doing (reading files, running commands, editing code).

Session Lifecycle

1. Creation

Sessions are created automatically when you open a worktree for the first time, or manually via the “New Session” button.
await invoke('create_session', {
  worktreeId,
  name: 'Session 1',  // Auto-generated or custom
})

2. Active Session Management

Jean tracks the active session per worktree:
interface WorktreeSessions {
  worktree_id: string
  sessions: Session[]
  active_session_id: string | null     // Currently displayed session
  default_model?: string
  version: number                      // Storage format version
  branch_naming_completed?: boolean
}
When you switch tabs, Jean updates active_session_id and persists it to disk.

3. Running a Session

When you send a message:
  1. Message is added to session.messages
  2. AI backend starts streaming response
  3. Tool calls are executed in real-time
  4. Assistant message is saved when complete
  5. Session updated_at timestamp is updated
Multiple sessions can run concurrently. Jean tracks sending/waiting state per session, so you can queue work across different sessions.

4. Archiving

Archive a session to hide it from the active list:
await invoke('archive_session', { sessionId, worktreeId })
  • Sets archived_at timestamp
  • Hidden from session tabs
  • Viewable in “Archived Sessions” modal
  • Deleted after retention period (default: 7 days)

5. Deletion

Permanently delete a session:
await invoke('delete_session_permanent', { sessionId, worktreeId })
Deleting a session removes all messages, tool calls, and run logs permanently. This cannot be undone.

Session Naming

Jean can automatically name sessions based on your first message:
interface Session {
  session_naming_completed?: boolean   // Has auto-naming been attempted?
}
Auto-naming workflow:
  1. User sends first message
  2. AI generates a short, descriptive name (max 4-5 words)
  3. Session name is updated (e.g., “Fix login button bug”)
  4. session_naming_completed is set to true
The default naming prompt is:
<task>Generate a short, human-friendly name for this chat session based on the user's request.</task>

<rules>
- Maximum 4-5 words total
- Use sentence case (only capitalize first word)
- Be descriptive but concise
- Focus on the main topic or goal
- No special characters or punctuation
- No generic names like "Chat session" or "New task"
- Do NOT use commit-style prefixes like "Add", "Fix", "Update"
</rules>
You can customize this in Settings → Advanced → Magic Prompts.

Context Management

Session Context (JSONL Logs)

Each session stores full conversation logs in JSONL format:
~/Library/Application Support/<app>/sessions/<worktree_id>/
  <session_id>.json           # Session metadata
  <session_id>/               # Session directory
    runs/
      <run_id>.jsonl          # Full run log (1 per message sent)
    manifest.json             # Run metadata

Saving Context

Save important context for reuse:
await invoke('save_context_file', {
  sessionId,
  worktreeId,
  worktreePath,
  projectName,
})
This:
  1. Generates an AI summary of the session
  2. Saves as markdown file with frontmatter
  3. Stored in ~/Library/Application Support/<app>/session-context/
  4. Can be loaded into any future session

Loading Context

Load saved context into a session:
// In chat, type: /load
// Or click "Load Context" in session menu
Context files are appended to your message as references the AI can read.

Session Recovery

Jean automatically recovers from crashes:
interface Session {
  last_run_status?: RunStatus  // 'running' | 'completed' | 'cancelled' | 'crashed' | 'resumable'
}

interface ChatMessage {
  recovered?: boolean          // Message was recovered after crash
}
On startup, if a session has last_run_status: 'running':
  1. Jean detects the crash
  2. Recovers the partial message from JSONL logs
  3. Marks message with recovered: true
  4. Shows recovery banner in UI

Session Digests (Recaps)

When you return to a session that was active in the background, Jean can generate a brief recap:
interface SessionDigest {
  chat_summary: string         // One sentence: overall goal and progress
  last_action: string          // One sentence: what was just completed
  created_at?: number          // When digest was generated
  message_count?: number       // Message count at generation time
}
Experimental feature. Enable in Settings → Advanced → Session Recap.
Digests help you quickly remember what you were working on without reading through the entire conversation.

Waiting for Input States

Sessions can wait for user input in two scenarios:

1. AskUserQuestion

The AI asks for clarification:
interface Session {
  waiting_for_input: true
  waiting_for_input_type: 'question'
  answered_questions?: string[]        // IDs of answered questions
  submitted_answers?: Record<string, QuestionAnswer[]>
}
UI shows a question form. Session remains blocked until answered.

2. ExitPlanMode (Plan Approval)

In plan mode, the AI proposes a plan and waits for approval:
interface Session {
  waiting_for_input: true
  waiting_for_input_type: 'plan'
  pending_plan_message_id?: string     // Message containing the plan
}
UI shows “Approve” / “Reject” buttons. On approval, plan is executed.
You can queue messages while a session is waiting. They’ll execute after you respond.

Permission Denials

When tools require approval (in plan mode or restricted tools):
interface Session {
  pending_permission_denials?: PermissionDenial[]
}

interface PermissionDenial {
  tool_name: string            // e.g., "Bash"
  tool_use_id: string
  tool_input: unknown          // What the tool would do
  rpc_id?: number              // Codex JSON-RPC ID (for approval)
}
UI shows a permission dialog. User can approve/deny, and the approval is sent back to the CLI.

Code Review Results

Sessions can store AI code review results:
interface Session {
  review_results?: ReviewResponse
  is_reviewing?: boolean
  fixed_findings?: string[]    // Finding keys marked as fixed
}

interface ReviewResponse {
  summary: string
  findings: ReviewFinding[]
  approval_status: 'approved' | 'changes_requested' | 'needs_discussion'
}
Code reviews are triggered via the “Review” button or magic command, and results are displayed in a sidebar panel.

Labels

Organize sessions with custom labels:
interface LabelData {
  name: string         // e.g., "Needs testing"
  color: string        // Hex color (e.g., "#eab308")
}

interface Session {
  label?: LabelData
}
Labels appear as colored badges on session cards in canvas view.

Token Usage Tracking

interface UsageData {
  input_tokens: number                  // Context sent to AI
  output_tokens: number                 // Generated by AI
  cache_read_input_tokens?: number      // Reused from cache (cost reduction)
  cache_creation_input_tokens?: number  // Cached for future requests
}

interface ChatMessage {
  usage?: UsageData    // Per-message usage (assistant only)
}
Jean tracks token usage per message and aggregates totals per session.

Storage Format

Sessions are stored in JSON:
~/Library/Application Support/<app>/sessions/
  <worktree_id>.json          # All sessions for this worktree
{
  "worktree_id": "abc-123",
  "sessions": [
    {
      "id": "session-xyz",
      "name": "Fix login bug",
      "messages": [...],
      "backend": "claude",
      "selected_model": "opus",
      "created_at": 1704067200,
      "updated_at": 1704070800
    }
  ],
  "active_session_id": "session-xyz",
  "version": 2
}

Projects and Worktrees

Learn about project organization and worktree management

AI Chat

Configure AI backends, models, and chat settings

Build docs developers (and LLMs) love