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 300VS 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
-
Check if session was properly saved:
claude --list-sessions -
Verify process suspension worked:
ps aux | grep claude -
Check logs for errors:
tail -f ~/.claude/logs/session.log
Notification Not Received
- Verify notification service configuration
- Check system notification permissions
- Test notification channels independently
State Synchronization Issues
- Ensure atomic state updates
- Implement state recovery mechanisms
- Use distributed locks for multi-instance scenarios
Future Enhancements
Planned Features
- AI-Powered Condition Detection: Use ML to detect when interruption is needed
- Collaborative Handoffs: Multiple users can take turns with a session
- Smart Resume Points: AI determines optimal resume points
- 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.
Related Resources
- Error Recovery Patterns
- Long Running Sessions
- Claude Code Commands Reference
- Task Orchestration Experiments
- claude-auto-resume on GitHub
Related Concepts
- 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