← All guides

Background Tasks in Claude Code: The Complete Playbook

How to run background tasks in Claude Code — async operations, parallel agents, headless CLI execution, and patterns for long-running work that doesn't.

Background Tasks in Claude Code: The Complete Playbook

Claude Code runs background tasks through three mechanisms: the --print flag for headless CLI execution, the Agent SDK's run_in_background parameter for non-blocking agent calls, and worktree isolation for parallel Claude instances working simultaneously. Understanding when to use each pattern eliminates the most common productivity bottleneck: waiting for one task to finish before starting the next.


The Problem: Sequential Work in an Async World

By default, Claude Code is interactive — you ask, it responds, you ask again. This works well for focused single-task sessions but creates a bottleneck when you need multiple independent things done:

# Sequential (slow)
1. Claude Code writes the API endpoint (5 min)
2. Wait for completion
3. Claude Code writes the tests (3 min)
4. Wait for completion
5. Claude Code writes the documentation (2 min)
Total: 10 min

# Parallel (fast)
1. Claude Code instance A writes API endpoint
   Claude Code instance B writes tests        } simultaneously
   Claude Code instance C writes docs
Total: ~5 min

Method 1: Headless CLI with --print

The simplest background task pattern: run Claude Code non-interactively with --print and & to background the process.

# Run in background, capture output to file
claude --print --project /path/to/project \
  "Write comprehensive tests for the UserService class. Save to tests/user-service.test.ts" \
  > /tmp/task-output.txt 2>&1 &

echo "Task running in background, PID: $!"

Parallel tasks with headless CLI

#!/bin/bash
# Run 3 independent tasks in parallel

# Task 1: Write API endpoint
claude --print "Write a REST API endpoint for user profile updates with validation" \
  > /tmp/task1.txt 2>&1 &
PID1=$!

# Task 2: Write tests
claude --print "Write unit tests for the payment processing service" \
  > /tmp/task2.txt 2>&1 &
PID2=$!

# Task 3: Write documentation
claude --print "Update the README with the new authentication flow" \
  > /tmp/task3.txt 2>&1 &
PID3=$!

echo "All 3 tasks running in parallel..."
echo "PIDs: $PID1, $PID2, $PID3"

# Wait for all to complete
wait $PID1 && echo "Task 1 done" || echo "Task 1 failed"
wait $PID2 && echo "Task 2 done" || echo "Task 2 failed"
wait $PID3 && echo "Task 3 done" || echo "Task 3 failed"

echo "All tasks complete"

Checking progress

# Watch output file in real-time
tail -f /tmp/task-output.txt

# Check if process is still running
ps aux | grep claude

# Kill a runaway task
kill $PID1

Method 2: Agent SDK run_in_background

When using the Agent SDK in code, the run_in_background parameter dispatches an agent call without blocking execution.

Python

import anthropic
import asyncio

client = anthropic.Anthropic()


async def run_background_analysis(codebase_content: str) -> str:
    """Run a code quality analysis in the background."""
    # This returns immediately — analysis runs asynchronously
    response = await asyncio.to_thread(
        client.messages.create,
        model="claude-sonnet-4-5",
        max_tokens=2048,
        system="You are a code quality analyzer. Identify issues and suggest improvements.",
        messages=[
            {"role": "user", "content": f"Analyze this code:\n{codebase_content}"}
        ]
    )
    return response.content[0].text


async def main():
    # Start background analysis immediately
    analysis_task = asyncio.create_task(
        run_background_analysis("def add(a, b): return a+b")
    )

    # Do other work while analysis runs
    print("Analysis running in background...")
    print("Continuing with other work...")

    # Wait for analysis when needed
    result = await analysis_task
    print(f"Analysis complete: {result[:100]}...")


asyncio.run(main())

Parallel agent calls

import anthropic
import asyncio

client = anthropic.Anthropic()


async def call_claude(task: str, content: str) -> tuple[str, str]:
    """Call Claude for a single task."""
    response = await asyncio.to_thread(
        client.messages.create,
        model="claude-haiku-4-5",  # Haiku for cost efficiency on parallel tasks
        max_tokens=1024,
        messages=[{"role": "user", "content": f"{task}\n\n{content}"}]
    )
    return task, response.content[0].text


async def parallel_review(code: str):
    """Run multiple review passes in parallel."""
    tasks = [
        call_claude("Find security vulnerabilities:", code),
        call_claude("Find performance issues:", code),
        call_claude("Find code quality issues:", code),
        call_claude("Suggest test cases:", code),
    ]

    # All 4 run simultaneously
    results = await asyncio.gather(*tasks)

    for task_name, result in results:
        print(f"\n=== {task_name} ===")
        print(result[:200])


asyncio.run(parallel_review("""
def get_user(user_id):
    query = f"SELECT * FROM users WHERE id = {user_id}"
    return db.execute(query)
"""))

Method 3: Worktree Isolation for Parallel Claude Code Sessions

For the most complex scenario — multiple Claude Code sessions working on different branches simultaneously — git worktrees provide isolation.

# Create isolated worktrees for parallel work
git worktree add /tmp/feature-auth feature/auth
git worktree add /tmp/feature-payments feature/payments
git worktree add /tmp/feature-dashboard feature/dashboard

# Open separate terminals and run Claude Code in each
# Terminal 1:
cd /tmp/feature-auth && claude

# Terminal 2:
cd /tmp/feature-payments && claude

# Terminal 3:
cd /tmp/feature-dashboard && claude

Each Claude Code instance has:

Clean up when done:

git worktree remove /tmp/feature-auth
git worktree remove /tmp/feature-payments
git worktree remove /tmp/feature-dashboard

Real Patterns: When to Use Each Method

Pattern: Background build validation

While you work on feature A, validate that a previous change didn't break the build:

# Start build check in background
claude --print "Run bun run build and bun run typecheck. Report errors only, skip warnings." \
  > /tmp/build-check.txt 2>&1 &

# Continue working on feature A
echo "Build check running, you can keep working..."

Pattern: Parallel content generation

Generate multiple documentation pages simultaneously:

for page in api-reference quickstart deployment troubleshooting; do
  claude --print "Write the $page documentation for our API. 
    Use the schema in lib/db/schema.ts as reference.
    Save to docs/${page}.md" \
    > /tmp/docs-${page}.log 2>&1 &
done

wait
echo "All documentation pages generated"

Pattern: Background test generation while you code

# As you write a new service, generate tests in the background
claude --print "Generate comprehensive unit tests for the EmailService class in lib/email.ts.
  Include happy path, error cases, and edge cases.
  Mock external dependencies.
  Save to tests/email.test.ts" \
  > /tmp/test-gen.log 2>&1 &

# You keep coding; tests are ready when you're done

Pattern: Async code review before PR

# Queue a code review while you do other things
git diff main..HEAD > /tmp/current-diff.txt

claude --print "Review this git diff for issues:
$(cat /tmp/current-diff.txt)

Focus on: security issues, missing error handling, performance problems.
Be specific with line references." \
  > /tmp/code-review.txt 2>&1 &

# Read the review when ready
cat /tmp/code-review.txt

Monitoring and Managing Background Tasks

Track running tasks

# List all Claude Code background processes
ps aux | grep "claude --print" | grep -v grep

# Get count
ps aux | grep "claude --print" | grep -v grep | wc -l

Set timeouts

Prevent runaway tasks:

# Kill task if it runs longer than 5 minutes
timeout 300 claude --print "Run the full test suite and report results" \
  > /tmp/test-results.txt 2>&1 &

Rate limiting parallel tasks

Don't run too many concurrent Claude API calls — you'll hit rate limits:

# Process in batches of 3
files=($(ls src/components/*.tsx))
batch_size=3

for ((i=0; i<${#files[@]}; i+=batch_size)); do
  batch=("${files[@]:i:batch_size}")
  
  for file in "${batch[@]}"; do
    claude --print "Add TypeScript strict types to $file. Save in-place." \
      > /tmp/types-$(basename $file).log 2>&1 &
  done
  
  wait  # Wait for batch to complete before starting next
  echo "Batch $((i/batch_size + 1)) complete"
done

Cost Management for Background Tasks

Background tasks consume API tokens. With parallel execution, costs can multiply quickly.

Cost-aware routing:

# Use Haiku for simple tasks (80% cheaper than Sonnet)
claude --print --model claude-haiku-4-5 \
  "Format all files in src/ according to our coding style" \
  > /tmp/format.log 2>&1 &

# Use Sonnet for complex analysis (needs full capability)
claude --print \
  "Analyze the authentication flow for security vulnerabilities and suggest fixes" \
  > /tmp/security.log 2>&1 &

Estimated parallel task costs:

Task type Model Tokens (est.) Cost
Simple formatting Haiku 2,000 $0.002
Test generation Sonnet 4,000 $0.012
Complex analysis Sonnet 8,000 $0.024
10 parallel Haiku tasks Haiku 20,000 $0.020

Running 10 parallel background tasks typically costs under $0.25 total.


Frequently Asked Questions

Can Claude Code run background tasks without keeping a terminal open? Yes. Use nohup to keep the task running after terminal close: nohup claude --print "your task" > /tmp/output.txt 2>&1 &. The process continues even if you close the terminal session.

How many parallel Claude Code tasks can I run? Anthropic's rate limits depend on your account tier. Default limits allow several parallel requests. Running more than 5-10 concurrent tasks risks hitting rate limits. Use batch processing with wait to stay within limits.

Do background tasks share the same context window? No. Each claude --print invocation starts a fresh session with its own context. For tasks that need the same project context, pass the relevant information in the prompt or use the --project flag to load CLAUDE.md.

What happens if a background task fails? Check the exit code: echo $? after wait $PID. A non-zero exit code means the task failed. Check the output file for error details. Re-run with more specific instructions if needed.

Is there a way to get notifications when background tasks complete? On macOS: claude --print "your task" > /tmp/output.txt && osascript -e 'display notification "Task complete" with title "Claude Code"'. On Linux: use notify-send similarly.


Related Guides


Go Deeper

Agent SDK Cookbook — $49 — 40 production automation patterns including parallel agent orchestration, background processing pipelines, and cost-optimized multi-task workflows. Python + TypeScript.

→ Get the Agent SDK Cookbook — $49

30-day money-back guarantee. Instant download.

AI Disclosure: Written with Claude Code; patterns tested in real multi-agent pipelines.

Tools and references