Automatic Session Interruption and Resumption Patterns

This guide explores patterns for implementing automatic interruption and resumption of Claude Code background sessions based on various conditions, with user notification and seamless handoff between automatic and interactive modes.

Overview

While Claude Code doesn’t natively support automatic conditional interruption of background sessions, you can implement sophisticated patterns using its existing features combined with external orchestration tools.

Core Components

1. Background Session Management

Claude Code provides several flags for non-interactive operation:

# Run in headless mode without UI
claude-code --headless --no-interactive "Your task here"
 
# Continue previous session non-interactively
claude-code --continue --print "Continue processing"

2. Session State Monitoring

Implement a wrapper script that monitors Claude Code’s output and state:

// monitor-claude-session.ts
import { spawn } from 'child_process';
import { EventEmitter } from 'events';
 
interface SessionMonitor extends EventEmitter {
  start(): void;
  interrupt(): void;
  resume(): void;
}
 
class ClaudeSessionMonitor extends EventEmitter implements SessionMonitor {
  private process: any;
  private sessionId: string;
  private outputBuffer: string[] = [];
  
  constructor(
    private prompt: string,
    private conditions: InterruptCondition[]
  ) {
    super();
  }
 
  start() {
    this.process = spawn('npx', [
      '@anthropic-ai/claude-code',
      '--headless',
      '--no-interactive',
      this.prompt
    ], {
      stdio: ['pipe', 'pipe', 'pipe']
    });
 
    this.process.stdout.on('data', (data: Buffer) => {
      const output = data.toString();
      this.outputBuffer.push(output);
      
      // Check interrupt conditions
      for (const condition of this.conditions) {
        if (condition.check(output, this.outputBuffer)) {
          this.interrupt();
          this.emit('interrupted', {
            reason: condition.name,
            context: this.getContext()
          });
          break;
        }
      }
    });
  }
 
  interrupt() {
    // Send Ctrl+Z to suspend the process
    this.process.kill('SIGTSTP');
    this.saveSessionState();
  }
 
  resume() {
    // Resume using Claude's --continue flag
    this.process = spawn('npx', [
      '@anthropic-ai/claude-code',
      '--continue',
      '--no-interactive'
    ]);
  }
 
  private saveSessionState() {
    // Session state is automatically saved by Claude Code
    // Additional state can be saved here if needed
  }
 
  private getContext() {
    return {
      lastOutput: this.outputBuffer.slice(-10).join(''),
      totalOutput: this.outputBuffer.length,
      sessionId: this.sessionId
    };
  }
}

3. Interrupt Conditions

Define conditions that trigger automatic interruption:

interface InterruptCondition {
  name: string;
  check(currentOutput: string, fullBuffer: string[]): boolean;
}
 
// Example conditions
const conditions: InterruptCondition[] = [
  {
    name: 'error-threshold',
    check: (output, buffer) => {
      const errorCount = buffer.filter(line => 
        line.includes('ERROR') || line.includes('FAILED')
      ).length;
      return errorCount > 5;
    }
  },
  {
    name: 'time-limit',
    check: (output, buffer) => {
      // Interrupt after 30 minutes
      return Date.now() - startTime > 30 * 60 * 1000;
    }
  },
  {
    name: 'memory-usage',
    check: (output, buffer) => {
      const usage = process.memoryUsage();
      return usage.heapUsed > 1024 * 1024 * 1024; // 1GB
    }
  },
  {
    name: 'user-requested-review',
    check: (output, buffer) => {
      return output.includes('REVIEW_REQUIRED') || 
             output.includes('USER_INPUT_NEEDED');
    }
  },
  {
    name: 'milestone-reached',
    check: (output, buffer) => {
      return output.includes('MILESTONE:') || 
             output.includes('CHECKPOINT:');
    }
  }
];

4. User Notification System

Implement notifications when sessions are interrupted:

interface NotificationService {
  notify(message: NotificationMessage): Promise<void>;
}
 
interface NotificationMessage {
  title: string;
  body: string;
  urgency: 'low' | 'normal' | 'critical';
  actions?: NotificationAction[];
}
 
interface NotificationAction {
  label: string;
  command: string;
}
 
class MultiChannelNotifier implements NotificationService {
  async notify(message: NotificationMessage) {
    // System notification
    await this.systemNotify(message);
    
    // Terminal notification
    this.terminalNotify(message);
    
    // Optional: Slack, email, etc.
    if (message.urgency === 'critical') {
      await this.slackNotify(message);
    }
  }
 
  private async systemNotify(message: NotificationMessage) {
    const { exec } = await import('child_process');
    
    // macOS
    exec(`osascript -e 'display notification "${message.body}" with title "${message.title}"'`);
    
    // Linux (requires notify-send)
    exec(`notify-send "${message.title}" "${message.body}"`);
  }
 
  private terminalNotify(message: NotificationMessage) {
    console.log('\n🔔 SESSION INTERRUPTED');
    console.log(`📋 ${message.title}`);
    console.log(`💬 ${message.body}`);
    console.log('\nActions:');
    message.actions?.forEach((action, i) => {
      console.log(`  ${i + 1}. ${action.label}: ${action.command}`);
    });
  }
 
  private async slackNotify(message: NotificationMessage) {
    // Implement Slack webhook notification
  }
}

5. Session Handoff Orchestrator

Manage the handoff between automatic and interactive modes:

class SessionHandoffOrchestrator {
  private monitor: ClaudeSessionMonitor;
  private notifier: NotificationService;
  private isInteractive = false;
 
  constructor(
    private initialPrompt: string,
    private conditions: InterruptCondition[]
  ) {
    this.monitor = new ClaudeSessionMonitor(initialPrompt, conditions);
    this.notifier = new MultiChannelNotifier();
  }
 
  async start() {
    // Start in background mode
    this.monitor.start();
    
    // Listen for interruptions
    this.monitor.on('interrupted', async (event) => {
      await this.handleInterruption(event);
    });
  }
 
  private async handleInterruption(event: any) {
    // Notify user
    await this.notifier.notify({
      title: `Claude Session Interrupted: ${event.reason}`,
      body: `Session requires your attention. Context: ${event.context.lastOutput.slice(0, 100)}...`,
      urgency: this.getUrgency(event.reason),
      actions: [
        {
          label: 'Resume Interactive',
          command: 'claude --continue'
        },
        {
          label: 'View Full Context',
          command: `claude --continue --show-context`
        },
        {
          label: 'Resume Background',
          command: 'npm run resume-background'
        }
      ]
    });
 
    // Wait for user decision
    await this.waitForUserDecision();
  }
 
  private async waitForUserDecision() {
    // Implement decision handling
    // Could use a web interface, CLI prompt, or file watcher
  }
 
  async resumeInteractive() {
    this.isInteractive = true;
    console.log('Resuming in interactive mode...');
    
    // Resume with full interactive Claude Code
    const { spawn } = await import('child_process');
    spawn('npx', ['@anthropic-ai/claude-code', '--continue'], {
      stdio: 'inherit'
    });
  }
 
  async resumeBackground() {
    this.isInteractive = false;
    console.log('Resuming in background mode...');
    
    // Resume monitoring
    this.monitor.resume();
  }
 
  private getUrgency(reason: string): 'low' | 'normal' | 'critical' {
    const urgencyMap: Record<string, 'low' | 'normal' | 'critical'> = {
      'error-threshold': 'critical',
      'memory-usage': 'critical',
      'user-requested-review': 'normal',
      'milestone-reached': 'low',
      'time-limit': 'normal'
    };
    return urgencyMap[reason] || 'normal';
  }
}

Implementation Patterns

Pattern 1: Error-Aware Background Processing

Automatically interrupt when errors accumulate:

// error-aware-processor.ts
const orchestrator = new SessionHandoffOrchestrator(
  'Process all data files and handle errors gracefully',
  [
    {
      name: 'critical-error',
      check: (output) => output.includes('CRITICAL ERROR')
    },
    {
      name: 'error-accumulation',
      check: (output, buffer) => {
        const recentErrors = buffer.slice(-20)
          .filter(line => line.includes('ERROR')).length;
        return recentErrors > 3;
      }
    }
  ]
);
 
orchestrator.start();

Pattern 2: Milestone-Based Progress Tracking

Interrupt at key milestones for review:

// milestone-tracker.ts
const milestoneConditions = [
  {
    name: 'phase-complete',
    check: (output) => {
      const milestones = [
        'Setup Complete',
        'Data Processing Complete',
        'Tests Passing',
        'Deployment Ready'
      ];
      return milestones.some(m => output.includes(m));
    }
  }
];

Pattern 3: Resource-Aware Processing

Monitor system resources and interrupt when limits approach:

// resource-monitor.ts
const resourceConditions = [
  {
    name: 'memory-limit',
    check: () => {
      const usage = process.memoryUsage();
      return usage.heapUsed / usage.heapTotal > 0.85;
    }
  },
  {
    name: 'cpu-threshold',
    check: async () => {
      const cpuUsage = await getCPUUsage();
      return cpuUsage > 90;
    }
  }
];

Pattern 4: Interactive Decision Points

Implement specific markers that trigger user interaction:

// decision-points.ts
const decisionConditions = [
  {
    name: 'design-decision',
    check: (output) => output.includes('DECISION_REQUIRED:')
  },
  {
    name: 'breaking-change',
    check: (output) => output.includes('BREAKING_CHANGE_DETECTED')
  },
  {
    name: 'security-review',
    check: (output) => output.includes('SECURITY_REVIEW_NEEDED')
  }
];

Advanced Orchestration

Multi-Stage Pipeline with Handoffs

class MultiStagePipeline {
  private stages = [
    {
      name: 'analysis',
      prompt: 'Analyze the codebase and identify refactoring opportunities',
      conditions: [
        { name: 'analysis-complete', check: (o) => o.includes('Analysis Complete') }
      ]
    },
    {
      name: 'planning',
      prompt: 'Create a detailed refactoring plan',
      requiresReview: true,
      conditions: [
        { name: 'plan-ready', check: (o) => o.includes('Plan Ready for Review') }
      ]
    },
    {
      name: 'implementation',
      prompt: 'Implement the approved refactoring plan',
      conditions: [
        { name: 'tests-failing', check: (o) => o.includes('Test Failed') },
        { name: 'implementation-complete', check: (o) => o.includes('Refactoring Complete') }
      ]
    }
  ];
 
  async execute() {
    for (const stage of this.stages) {
      console.log(`Starting stage: ${stage.name}`);
      
      const orchestrator = new SessionHandoffOrchestrator(
        stage.prompt,
        stage.conditions
      );
      
      await orchestrator.start();
      
      if (stage.requiresReview) {
        await this.requestUserReview(stage);
      }
    }
  }
 
  private async requestUserReview(stage: any) {
    // Force interactive review
    console.log(`\n⚡ Stage '${stage.name}' requires your review`);
    console.log('Please run: claude --continue');
    
    // Wait for review completion
    await this.waitForReviewCompletion();
  }
}

State Machine for Complex Workflows

enum SessionState {
  BACKGROUND = 'background',
  INTERRUPTED = 'interrupted',
  INTERACTIVE = 'interactive',
  PAUSED = 'paused',
  COMPLETED = 'completed'
}
 
class SessionStateMachine {
  private state = SessionState.BACKGROUND;
  private stateHandlers: Map<SessionState, StateHandler>;
 
  transition(event: string, data?: any) {
    const handler = this.stateHandlers.get(this.state);
    const nextState = handler?.handleEvent(event, data);
    
    if (nextState && nextState !== this.state) {
      console.log(`Transitioning: ${this.state} -> ${nextState}`);
      this.state = nextState;
      this.onStateChange(nextState);
    }
  }
 
  private onStateChange(newState: SessionState) {
    switch (newState) {
      case SessionState.INTERRUPTED:
        this.notifyUser();
        break;
      case SessionState.INTERACTIVE:
        this.launchInteractiveMode();
        break;
      case SessionState.BACKGROUND:
        this.resumeBackgroundMode();
        break;
    }
  }
}

Integration with External Tools

GitHub Actions Integration

# .github/workflows/claude-background-task.yml
name: Claude Background Task with Interruption
 
on:
  workflow_dispatch:
    inputs:
      task:
        description: 'Task for Claude to perform'
        required: true
 
jobs:
  claude-task:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Claude Code
        run: npm install -g @anthropic-ai/claude-code
      
      - name: Run Claude with Monitoring
        run: |
          node scripts/run-with-monitoring.js \
            --task "${{ github.event.inputs.task }}" \
            --notify-webhook "${{ secrets.SLACK_WEBHOOK }}" \
            --interrupt-on-error \
            --checkpoint-interval 300

VS Code Extension Integration

// Extension that monitors Claude Code sessions
import * as vscode from 'vscode';
 
export function activate(context: vscode.ExtensionContext) {
  const monitor = new ClaudeSessionMonitor();
  
  monitor.on('interrupted', async (event) => {
    const action = await vscode.window.showInformationMessage(
      `Claude session interrupted: ${event.reason}`,
      'Resume Interactive',
      'Resume Background',
      'View Details'
    );
    
    switch (action) {
      case 'Resume Interactive':
        vscode.commands.executeCommand('claude.resumeInteractive');
        break;
      case 'Resume Background':
        monitor.resume();
        break;
    }
  });
}

Best Practices

1. Interrupt Condition Design

  • Be Specific: Design conditions that match your workflow needs
  • Avoid Over-Interruption: Balance between safety and productivity
  • Context Preservation: Ensure sufficient context is saved for resumption

2. Notification Strategy

  • Multi-Channel: Use multiple notification channels for critical interruptions
  • Actionable: Provide clear actions in notifications
  • Context-Rich: Include enough information for decision-making

3. State Management

  • Atomic Operations: Ensure state transitions are atomic
  • Recovery Mechanisms: Plan for unexpected terminations
  • Audit Trail: Log all state transitions for debugging

4. Performance Considerations

  • Lightweight Monitoring: Minimize overhead of condition checking
  • Buffered Output: Use buffering to reduce I/O operations
  • Resource Limits: Set clear resource boundaries

Common Use Cases

1. Long-Running Refactoring

# Start refactoring with automatic interruption on test failures
npm run claude-monitor -- \
  --task "Refactor the authentication system" \
  --interrupt-on "test-failure" \
  --checkpoint-every "10-minutes"

2. Data Processing Pipeline

# Process large dataset with memory monitoring
npm run claude-monitor -- \
  --task "Process and analyze customer data" \
  --memory-limit "2GB" \
  --notify-on "milestone,error"

3. Continuous Integration Helper

# Fix CI failures with automatic handoff on complex issues
npm run claude-monitor -- \
  --task "Fix all failing CI tests" \
  --interrupt-on "complex-error" \
  --max-duration "30m"

Troubleshooting

Session Not Resuming

  1. Check if session was properly saved:

    claude --list-sessions
  2. Verify process suspension worked:

    ps aux | grep claude
  3. Check logs for errors:

    tail -f ~/.claude/logs/session.log

Notification Not Received

  1. Verify notification service configuration
  2. Check system notification permissions
  3. Test notification channels independently

State Synchronization Issues

  1. Ensure atomic state updates
  2. Implement state recovery mechanisms
  3. Use distributed locks for multi-instance scenarios

Future Enhancements

Planned Features

  1. AI-Powered Condition Detection: Use ML to detect when interruption is needed
  2. Collaborative Handoffs: Multiple users can take turns with a session
  3. Smart Resume Points: AI determines optimal resume points
  4. Workflow Templates: Pre-built patterns for common scenarios

Community Contributions

The claude-auto-resume project provides a foundation for automatic resumption when usage limits are lifted. Consider contributing to or extending this project for your specific needs.

  • Core Concepts: Understanding the core session management is crucial before configuring interruptions.
  • Advanced Patterns: This feature is an implementation of the Circuit Breaker pattern for AI collaboration.
  • Security: For security-focused interruptions, see the guide on Sensitive Data Handling.

Quick Navigation

← Back to Workflows | Session Management | Resilience Patterns