<!-- title: Headless会话管理：非交互到断点续传 -->

# Claude Code Headless会话管理：非交互到断点续传实战

## 概述

Claude Code的Headless模式（`-p`标志）远不止"无界面运行"这么简单——它是一套完整的会话生命周期管理系统。本教程深入讲解Headless模式的核心机制、会话续传（`--continue`/`--resume`）、结构化输出控制（`--output-format`）、权限自动化配置，以及生产级错误恢复策略。学完你将掌握用Shell脚本构建可靠、可恢复、可审计的AI自动化工作流。

**适用人群**：已有Claude Code基础使用经验的开发者、DevOps工程师、需要将AI能力嵌入CI/CD或定时任务的技术负责人。

---

## 前置条件

| 项目 | 要求 |
|------|------|
| Claude Code | v1.0.18+（支持`--output-format json`） |
| Node.js | v18+ |
| 操作系统 | macOS / Linux（Windows需WSL2） |
| API Key | Anthropic API Key已配置 |
| 基础知识 | 熟悉Shell脚本、管道操作、JSON处理 |

安装验证：

```bash
claude --version
# 确保 >= 1.0.18
```

---

## 一、Headless模式核心机制

### 1.1 -p标志：非交互的基石

`-p`（`--print`）标志是所有Headless自动化的入口。它让Claude Code跳过交互式TUI界面，直接处理提示并输出结果到stdout：

```bash
# 最简形式：单次执行，输出到stdout
claude -p "列出src/目录下所有未使用TypeScript类型的文件"

# 管道输入：将内容通过stdin传入
git diff HEAD~5 | claude -p "为这些变更生成CHANGELOG条目"

# 组合使用：文件内容作为上下文
cat error.log | claude -p "分析错误日志，给出修复建议"
```

**核心行为规则**：
- 执行完毕自动退出，退出码`0`表示成功
- 工具调用（文件读写、Bash执行）照常运行
- 无需人类交互——默认使用`settings.json`中的权限配置

### 1.2 --bare：极速启动模式

在自动化场景中，启动速度至关重要。`--bare`标志跳过所有启动发现过程：

```bash
# 普通Headless：需要加载hooks、skills、MCP发现
claude -p "检查代码风格"  # 启动约2-5秒

# Bare模式：跳过hooks、skills自动发现、MCP初始化
claude -p --bare "检查代码风格"  # 启动约0.5-1秒
```

`--bare`跳过的内容：
- Hooks自动发现和注册
- Skills目录扫描
- MCP服务器连接初始化
- 部分环境检测

**何时用`--bare`**：纯代码分析、日志解读、文本生成等不依赖MCP或自定义工具的轻量任务。

**何时不用`--bare`**：需要调用特定MCP工具、依赖Hooks触发器、或使用自定义Skills的任务。

### 1.3 输出格式控制

Headless模式最强大的特性之一是结构化输出：

```bash
# 纯文本输出（默认）
claude -p "总结这个项目的架构" > summary.txt

# JSON输出：包含完整元数据
claude -p "分析package.json的依赖" \
  --output-format json \
  > analysis.json

# JSON输出 + Schema约束
claude -p "列出所有TODO注释" \
  --output-format json \
  --json-schema '{
    "type": "object",
    "properties": {
      "todos": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "file": {"type": "string"},
            "line": {"type": "integer"},
            "text": {"type": "string"},
            "priority": {"enum": ["high", "medium", "low"]}
          },
          "required": ["file", "line", "text"]
        }
      }
    }
  }'
```

JSON输出结构示例：

```json
{
  "result": "找到12个TODO注释...",
  "cost_usd": 0.0034,
  "duration_ms": 4521,
  "num_turns": 2,
  "session_id": "abc123def456",
  "is_error": false
}
```

**关键字段解读**：
- `session_id`：后续用`--resume`恢复此会话的关键标识
- `cost_usd`：本次执行的精确Token费用
- `num_turns`：Agent循环的迭代次数，用于成本分析
- `is_error`：是否因错误退出

### 1.4 流式输出（Streaming）

对于长时间运行的任务，流式输出提供实时反馈：

```bash
# 流式JSON输出
claude -p "重构整个auth模块" \
  --output-format stream-json

# 每行输出一个JSON对象
# {"type":"assistant","content":"正在分析..."}
# {"type":"tool_use","tool":"Read","input":{"file_path":"src/auth.ts"}}
# {"type":"assistant","content":"发现3个问题..."}
```

流式输出的JSON Lines格式可用于构建进度监控：

```bash
# 实时显示进度，同时保存完整日志
claude -p "运行测试并修复失败的用例" \
  --output-format stream-json \
  2>/dev/null | while IFS= read -r line; do
    type=$(echo "$line" | jq -r '.type // empty')
    case "$type" in
      "assistant") echo "🤖 $(echo "$line" | jq -r '.content[:80]')" ;;
      "tool_use") echo "🔧 调用工具: $(echo "$line" | jq -r '.tool')" ;;
      "tool_result") echo "✅ 工具结果: $(echo "$line" | jq -r '.content[:80]')" ;;
    esac
  done
```

---

## 二、会话管理：断点续传

### 2.1 会话生命周期

Claude Code的每个Headless执行都创建一个会话，会话具有完整的生命周期：

```mermaid
stateDiagram-v2
    [*] --> 创建: claude -p
    创建 --> 活跃: Agent循环执行
    活跃 --> 工具调用: 读取/编辑/执行
    工具调用 --> 活跃: 返回结果
    活跃 --> 挂起: 达到max-turns限制
    活跃 --> 完成: 任务结束
    挂起 --> 恢复: --resume session_id
    完成 --> 续传: --continue
    恢复 --> 活跃: 继续执行
    续传 --> 活跃: 基于上次会话
    完成 --> [*]
```

### 2.2 --continue：延续上一次会话

`--continue`（简写`-c`）加载最近一次会话的完整上下文：

```bash
# 第一步：初始分析
claude -p "分析src/api/目录的代码质量问题" \
  --output-format json > step1.json

# 第二步：基于上一次会话继续，要求修复
claude -p --continue "根据上面的分析，修复所有高优先级问题" \
  --output-format json > step2.json

# 第三步：验证修复
claude -p --continue "运行测试验证所有修复" \
  --output-format json > step3.json
```

**关键特性**：
- `--continue`只能恢复最近一次会话
- 会话上下文包含之前的所有对话和工具调用结果
- 即使中间发生了其他交互式会话，`-c`仍然指向最后一次Headless会话

### 2.3 --resume：精确恢复指定会话

`--resume`（简写`-r`）通过`session_id`恢复任意历史会话：

```bash
# 从JSON输出中提取session_id
SESSION_ID=$(claude -p "分析代码覆盖率" \
  --output-format json | jq -r '.session_id')

echo "会话ID: $SESSION_ID"

# ... 几小时后或几天后 ...

# 恢复该会话，继续工作
claude -p --resume "$SESSION_ID" \
  "基于之前的覆盖率分析，为未覆盖的函数生成测试用例"
```

**实际场景——长时间任务的分段执行**：

```bash
#!/bin/bash
# 文件: incremental-refactor.sh
# 用途：大型重构的分段执行，每段限制20轮

TASK_DESCRIPTION="将所有class组件迁移为函数组件"
SESSION_FILE=".claude-refactor-session"

# 第一次执行或恢复
if [ -f "$SESSION_FILE" ]; then
  SESSION_ID=$(cat "$SESSION_FILE")
  echo "恢复会话: $SESSION_ID"
  RESULT=$(claude -p --resume "$SESSION_ID" \
    "继续迁移工作。上一次你迁移了哪些文件？继续剩余的。" \
    --output-format json \
    --max-turns 20)
else
  echo "创建新会话"
  RESULT=$(claude -p "$TASK_DESCRIPTION" \
    --output-format json \
    --max-turns 20)
fi

# 提取并保存session_id
NEW_SESSION=$(echo "$RESULT" | jq -r '.session_id')
echo "$NEW_SESSION" > "$SESSION_FILE"

# 检查是否完成
IS_ERROR=$(echo "$RESULT" | jq -r '.is_error')
NUM_TURNS=$(echo "$RESULT" | jq -r '.num_turns')

echo "本轮执行: ${NUM_TURNS}轮, 费用: \$(echo "$RESULT" | jq -r '.cost_usd')"

if [ "$IS_ERROR" = "true" ]; then
  echo "执行出错，请检查日志"
  exit 1
fi

if [ "$NUM_TURNS" -lt 20 ]; then
  echo "任务已完成！清理会话文件。"
  rm "$SESSION_FILE"
else
  echo "达到轮次上限，运行此脚本继续下一阶段。"
fi
```

### 2.4 会话上下文的边界

理解会话上下文包含什么，不包含什么：

| 上下文内容 | 是否保留 | 说明 |
|-----------|---------|------|
| 对话历史 | 是 | 完整的提示和回复链 |
| 工具调用记录 | 是 | 读取的文件内容、执行的命令输出 |
| 文件系统变更 | 否 | 恢复的是对话记忆，不是文件快照 |
| 环境变量变更 | 否 | 每次执行都是新的Shell环境 |
| MCP连接状态 | 否 | 重新建立MCP连接 |
| 运行中进程 | 否 | 后台进程不会被恢复 |

**关键洞察**：会话恢复不是"时光机"——它恢复的是对话上下文，不是系统状态。如果之前的会话修改了文件，那些修改已经在磁盘上了；如果之前的会话启动了服务器，你需要重新启动它。

---

## 三、权限自动化

### 3.1 Headless模式的权限挑战

交互模式下，Claude Code遇到需要权限的操作会弹出确认。Headless模式下没有人类来点击"允许"——你需要预先配置权限。

### 3.2 --allowedTools：工具白名单

精确控制Headless执行可以使用哪些工具：

```bash
# 只读分析：只允许读取和搜索
claude -p "审计src/目录的安全漏洞" \
  --allowedTools "Read,Glob,Grep"

# 允许读取和编辑，但不允许执行Shell命令
claude -p "修复所有lint错误" \
  --allowedTools "Read,Edit,Glob,Grep"

# 完全自动化：允许所有工具
claude -p "实现用户认证模块" \
  --allowedTools "Bash,Read,Edit,Write,Glob,Grep"
```

**工具名称完整列表**：
- `Read` — 读取文件
- `Edit` — 编辑现有文件
- `Write` — 创建新文件
- `Bash` — 执行Shell命令
- `Glob` — 文件搜索
- `Grep` — 内容搜索
- `Task` — 启动子Agent

### 3.3 settings.json权限配置

对于频繁执行的自动化任务，在项目级`.claude/settings.json`中预配置权限：

```json
{
  "permissions": {
    "allow": [
      "Read",
      "Glob",
      "Grep",
      "Edit(src/**)",
      "Bash(npm test*)",
      "Bash(npm run lint*)",
      "Bash(git diff*)",
      "Bash(git log*)"
    ],
    "deny": [
      "Bash(rm -rf*)",
      "Bash(git push*)",
      "Bash(git reset*)",
      "Write(.env*)",
      "Write(*credentials*)"
    ]
  }
}
```

**模式匹配规则**：
- `Edit(src/**)` — 允许编辑`src/`目录下的所有文件
- `Bash(npm test*)` — 允许所有以`npm test`开头的命令
- `Write(.env*)` — 拒绝写入任何以`.env`开头的文件

### 3.4 Permission Modes（权限模式）

Claude Code提供三种全局权限模式：

```bash
# Plan模式：只读取不修改，适合分析
claude -p --permission-mode plan "分析代码架构并给出重构建议"

# Auto-accept模式：自动批准所有操作（危险！）
claude -p --permission-mode auto-accept "重构整个项目"

# 默认模式：根据settings.json配置
claude -p "常规开发任务"
```

**生产环境推荐**：

```bash
# 安全的CI审计模式
claude -p "检查PR的代码质量" \
  --permission-mode plan \
  --output-format json \
  --max-turns 5

# 受限的修复模式
claude -p "修复测试失败" \
  --allowedTools "Read,Edit,Bash(npm*,npx*)" \
  --max-turns 10 \
  --output-format json
```

---

## 四、安全边界与成本控制

### 4.1 三重安全阀门

每个Headless执行都应该设置三道安全边界：

```bash
claude -p "你的任务描述" \
  --max-turns 15 \          # 阀门1：最大Agent循环轮次
  --max-tokens 50000 \      # 阀门2：最大Token消耗
  --timeout 300000          # 阀门3：最大执行时间(ms)
```

```mermaid
graph TD
    A[Headless执行启动] --> B{max-turns检查}
    B -->|未达上限| C{max-tokens检查}
    B -->|已达上限| Z[停止: 轮次耗尽]
    C -->|未达上限| D{timeout检查}
    C -->|已达上限| Z2[停止: Token耗尽]
    D -->|未超时| E[执行Agent循环]
    D -->|已超时| Z3[停止: 时间到]
    E --> F{任务完成?}
    F -->|是| G[输出结果 + 退出码0]
    F -->|否| B
```

### 4.2 --max-turns：轮次上限

这是最重要的安全参数。每次Agent循环（"思考→调用工具→获取结果→再思考"）算一轮：

```bash
# 轻量任务：1-3轮足够
claude -p "这个函数做了什么？" --max-turns 3

# 中等任务：5-15轮
claude -p "修复所有TypeScript类型错误" --max-turns 15

# 重量任务：15-30轮
claude -p "重构认证模块为OAuth2.0" --max-turns 30

# 禁止：不加限制的执行
# claude -p "重构整个项目"  # 危险！可能无限循环
```

**轮次规划公式**：

```
预估轮次 = 文件数量 × 每文件操作数 × 安全系数(1.5)

示例：修复20个文件的lint错误
预估轮次 = 20 × 2(读取+编辑) × 1.5 = 60
设置 --max-turns 60
```

### 4.3 成本监控与预算控制

```bash
#!/bin/bash
# 文件: budget-guard.sh
# 用途：带预算控制的Headless执行

MAX_COST=0.50  # 单次执行最大费用（美元）

RESULT=$(claude -p "$1" \
  --output-format json \
  --max-turns 20)

# 提取费用
ACTUAL_COST=$(echo "$RESULT" | jq -r '.cost_usd')
SESSION_ID=$(echo "$RESULT" | jq -r '.session_id')
TURNS=$(echo "$RESULT" | jq -r '.num_turns')

echo "=== 执行报告 ==="
echo "会话ID: $SESSION_ID"
echo "轮次: $TURNS"
echo "费用: \$$ACTUAL_COST"

# 预算检查
if (( $(echo "$ACTUAL_COST > $MAX_COST" | bc -l) )); then
  echo "⚠️ 费用超预算！上限: \$$MAX_COST, 实际: \$$ACTUAL_COST"
  exit 2
fi

# 提取实际回答内容
echo "$RESULT" | jq -r '.result'
```

### 4.4 退出码语义

Headless执行的退出码承载重要信息：

| 退出码 | 含义 | 处理策略 |
|-------|------|---------|
| 0 | 成功完成 | 继续下一步 |
| 1 | 一般性错误 | 检查提示和权限 |
| 2 | 被安全限制终止 | 增加`--max-turns`或`--timeout` |

```bash
# 根据退出码做条件处理
claude -p "运行测试" --max-turns 10 --output-format json > result.json
EXIT_CODE=$?

case $EXIT_CODE in
  0) echo "成功"; cat result.json | jq -r '.result' ;;
  1) echo "执行出错"; cat result.json | jq -r '.result' ;;
  2) echo "被限制终止，考虑增加限制或分段执行" ;;
esac
```

---

## 五、实战案例：生产级Headless任务运行器

### 5.1 架构设计

我们将构建一个完整的Headless任务运行器，具备以下能力：

- 任务队列管理（串行/并行）
- 会话断点续传
- 成本追踪
- 错误恢复
- 结构化报告输出

```mermaid
graph LR
    A[任务队列 JSON] --> B[任务调度器]
    B --> C{会话存在?}
    C -->|是| D[resume恢复]
    C -->|否| E[新建会话]
    D --> F[Claude -p 执行]
    E --> F
    F --> G{执行结果}
    G -->|成功| H[保存结果 + 清理会话]
    G -->|轮次耗尽| I[保存session_id + 排入重试队列]
    G -->|错误| J[记录错误 + 人工通知]
    H --> K[生成报告]
    I --> B
    J --> K
```

### 5.2 任务定义文件

```json
// 文件: tasks/queue.json
[
  {
    "id": "task-001",
    "name": "安全审计",
    "prompt": "扫描src/目录，检查SQL注入、XSS和其他OWASP Top 10漏洞。对每个漏洞给出文件名、行号、严重程度和修复建议。",
    "allowedTools": ["Read", "Glob", "Grep"],
    "maxTurns": 10,
    "maxCost": 0.30,
    "outputFormat": "json"
  },
  {
    "id": "task-002",
    "name": "生成API文档",
    "prompt": "基于src/routes/目录的路由定义，生成OpenAPI 3.0规范的YAML文档。包含所有端点、请求/响应schema和示例。",
    "allowedTools": ["Read", "Glob", "Grep", "Write"],
    "maxTurns": 15,
    "maxCost": 0.50,
    "outputFormat": "json"
  },
  {
    "id": "task-003",
    "name": "测试覆盖率提升",
    "prompt": "分析当前测试覆盖率报告，为覆盖率低于80%的模块生成新的测试用例。使用项目现有的测试框架。",
    "allowedTools": ["Read", "Edit", "Write", "Bash", "Glob", "Grep"],
    "maxTurns": 25,
    "maxCost": 1.00,
    "outputFormat": "json"
  }
]
```

### 5.3 任务运行器核心代码

```bash
#!/bin/bash
# 文件: headless-runner.sh
# 用途：生产级Headless任务运行器

set -euo pipefail

# ==================== 配置 ====================
TASKS_FILE="${1:-tasks/queue.json}"
STATE_DIR=".headless-state"
REPORT_DIR="reports"
MAX_RETRIES=3

mkdir -p "$STATE_DIR" "$REPORT_DIR"

# ==================== 工具函数 ====================

# 获取任务状态文件路径
state_file() { echo "$STATE_DIR/$1.state.json"; }

# 检查任务是否完成
is_completed() {
  local sf=$(state_file "$1")
  [ -f "$sf" ] && [ "$(jq -r '.status' "$sf")" = "completed" ]
}

# 检查任务是否需要重试
needs_retry() {
  local sf=$(state_file "$1")
  [ -f "$sf" ] && [ "$(jq -r '.status' "$sf")" = "retry" ] && \
    [ "$(jq -r '.retries' "$sf")" -lt "$MAX_RETRIES" ]
}

# 获取会话ID（用于续传）
get_session_id() {
  local sf=$(state_file "$1")
  if [ -f "$sf" ]; then
    jq -r '.session_id // empty' "$sf"
  fi
}

# ==================== 单任务执行 ====================

run_task() {
  local task_json="$1"
  local task_id=$(echo "$task_json" | jq -r '.id')
  local task_name=$(echo "$task_json" | jq -r '.name')
  local prompt=$(echo "$task_json" | jq -r '.prompt')
  local max_turns=$(echo "$task_json" | jq -r '.maxTurns // 15')
  local max_cost=$(echo "$task_json" | jq -r '.maxCost // 0.50')
  local output_format=$(echo "$task_json" | jq -r '.outputFormat // "json"')
  local tools=$(echo "$task_json" | jq -r '.allowedTools // [] | join(",")')

  local sf=$(state_file "$task_id")
  local session_id=""
  local retries=0

  # 恢复已有状态
  if [ -f "$sf" ]; then
    retries=$(jq -r '.retries // 0' "$sf")
    session_id=$(jq -r '.session_id // empty' "$sf")
  fi

  echo "▶ 执行任务: $task_name (ID: $task_id, 重试: $retries)"

  # 构建Claude命令
  local cmd="claude -p"

  # 会话续传或初始提示
  if [ -n "$session_id" ]; then
    echo "  ↻ 恢复会话: $session_id"
    cmd="$cmd --resume $session_id"
    cmd="$cmd \"继续之前的任务。\""
  else
    # 转义prompt中的引号
    local escaped_prompt=$(echo "$prompt" | sed 's/"/\\"/g')
    cmd="$cmd \"$escaped_prompt\""
  fi

  # 工具限制
  if [ -n "$tools" ]; then
    cmd="$cmd --allowedTools \"$tools\""
  fi

  # 安全限制
  cmd="$cmd --max-turns $max_turns"
  cmd="$cmd --output-format $output_format"

  # 执行并捕获结果
  local result
  set +e
  result=$(eval "$cmd" 2>&1)
  local exit_code=$?
  set -e

  # 解析结果
  local actual_cost="0"
  local actual_turns="0"
  local new_session_id=""
  local is_error="true"

  if [ "$output_format" = "json" ]; then
    actual_cost=$(echo "$result" | jq -r '.cost_usd // 0' 2>/dev/null || echo "0")
    actual_turns=$(echo "$result" | jq -r '.num_turns // 0' 2>/dev/null || echo "0")
    new_session_id=$(echo "$result" | jq -r '.session_id // empty' 2>/dev/null || echo "")
    is_error=$(echo "$result" | jq -r '.is_error // true' 2>/dev/null || echo "true")
  fi

  # 成本检查
  local cost_status="ok"
  if (( $(echo "$actual_cost > $max_cost" | bc -l 2>/dev/null || echo "0") )); then
    cost_status="over_budget"
  fi

  # 确定任务状态
  local task_status="completed"
  if [ "$exit_code" -ne 0 ]; then
    task_status="retry"
  elif [ "$is_error" = "true" ]; then
    task_status="retry"
  elif [ "$cost_status" = "over_budget" ]; then
    task_status="retry"
  fi

  # 保存状态
  cat > "$sf" <<EOF
{
  "task_id": "$task_id",
  "task_name": "$task_name",
  "status": "$task_status",
  "session_id": "$new_session_id",
  "retries": $((retries + 1)),
  "exit_code": $exit_code,
  "cost_usd": $actual_cost,
  "turns": $actual_turns,
  "timestamp": "$(date -Iseconds)"
}
EOF

  # 保存完整结果
  echo "$result" > "$REPORT_DIR/${task_id}-result.json"

  # 状态报告
  case "$task_status" in
    completed)
      echo "  ✅ 完成 | 轮次: $actual_turns | 费用: \$$actual_cost"
      ;;
    retry)
      echo "  ⚠️ 需要重试 | 退出码: $exit_code | 重试: $((retries + 1))/$MAX_RETRIES"
      ;;
  esac

  return 0
}

# ==================== 主循环 ====================

echo "======================================"
echo "  Claude Code Headless 任务运行器"
echo "  任务文件: $TASKS_FILE"
echo "======================================"

TOTAL_TASKS=$(jq 'length' "$TASKS_FILE")
COMPLETED=0
FAILED=0
TOTAL_COST=0

# 遍历所有任务
for i in $(seq 0 $((TOTAL_TASKS - 1))); do
  task_json=$(jq ".[$i]" "$TASKS_FILE")
  task_id=$(echo "$task_json" | jq -r '.id')

  # 跳过已完成的任务
  if is_completed "$task_id"; then
    echo "⏭ 跳过已完成任务: $task_id"
    COMPLETED=$((COMPLETED + 1))
    continue
  fi

  # 检查重试次数
  if [ -f "$(state_file "$task_id")" ]; then
    retries=$(jq -r '.retries // 0' "$(state_file "$task_id")")
    if [ "$retries" -ge "$MAX_RETRIES" ]; then
      echo "❌ 任务 $task_id 已达最大重试次数，跳过"
      FAILED=$((FAILED + 1))
      continue
    fi
  fi

  # 执行任务
  run_task "$task_json"

  # 统计
  sf=$(state_file "$task_id")
  if [ "$(jq -r '.status' "$sf")" = "completed" ]; then
    COMPLETED=$((COMPLETED + 1))
  fi
  TOTAL_COST=$(echo "$TOTAL_COST + $(jq -r '.cost_usd // 0' "$sf")" | bc)
done

# ==================== 生成报告 ====================

echo ""
echo "======================================"
echo "  执行报告"
echo "======================================"
echo "总任务数: $TOTAL_TASKS"
echo "已完成:   $COMPLETED"
echo "失败:     $FAILED"
echo "总费用:   \$$TOTAL_COST"
echo ""

# 生成JSON报告
jq -n \
  --arg total "$TOTAL_TASKS" \
  --arg completed "$COMPLETED" \
  --arg failed "$FAILED" \
  --arg cost "$TOTAL_COST" \
  --arg timestamp "$(date -Iseconds)" \
  '{
    total_tasks: ($total | tonumber),
    completed: ($completed | tonumber),
    failed: ($failed | tonumber),
    total_cost_usd: ($cost | tonumber),
    timestamp: $timestamp
  }' > "$REPORT_DIR/summary.json"

echo "报告已保存到: $REPORT_DIR/"
```

### 5.4 使用方式

```bash
# 赋予执行权限
chmod +x headless-runner.sh

# 执行所有任务
./headless-runner.sh tasks/queue.json

# 查看某个任务的结果
cat reports/task-001-result.json | jq -r '.result'

# 查看执行摘要
cat reports/summary.json | jq .

# 重新运行未完成的任务（已完成的会自动跳过）
./headless-runner.sh tasks/queue.json
```

---

## 六、高级模式

### 6.1 多任务并行执行

利用Shell的后台任务实现并行：

```bash
#!/bin/bash
# 文件: parallel-runner.sh
# 用途：并行执行多个独立任务

MAX_PARALLEL=3  # 最大并行数
RUNNING=0

run_with_limit() {
  while [ "$(jobs -r | wc -l)" -ge "$MAX_PARALLEL" ]; do
    sleep 5
  done
  eval "$1" &
}

# 定义并行任务
TASKS=(
  'claude -p "扫描src/的安全漏洞" --allowedTools "Read,Glob,Grep" --max-turns 10 --output-format json > reports/security.json'
  'claude -p "分析代码复杂度" --allowedTools "Read,Glob,Grep" --max-turns 8 --output-format json > reports/complexity.json'
  'claude -p "检查依赖版本过期" --allowedTools "Read,Bash(npm*)" --max-turns 5 --output-format json > reports/deps.json'
  'claude -p "生成API文档" --allowedTools "Read,Glob,Grep,Write" --max-turns 15 --output-format json > reports/api-docs.json'
)

for task in "${TASKS[@]}"; do
  run_with_limit "$task"
done

# 等待所有任务完成
wait

echo "所有并行任务完成"
```

### 6.2 定时任务集成

将Headless执行嵌入cron实现定期自动化：

```bash
# 编辑crontab
crontab -e

# 每天凌晨2点执行代码审查
0 2 * * * cd /path/to/project && claude -p "审查最近24小时的代码提交，检查潜在问题" --allowedTools "Read,Glob,Grep,Bash(git*)" --max-turns 15 --output-format json > /var/log/claude-review-$(date +\%Y\%m\%d).json

# 每周一生成架构文档
0 3 * * 1 cd /path/to/project && claude -p "更新项目架构文档，反映最新代码结构" --allowedTools "Read,Glob,Grep,Write" --max-turns 20 --output-format json > /var/log/claude-arch-$(date +\%Y\%m\%d).json
```

### 6.3 链式会话：多步骤工作流

通过会话续传实现复杂的多步骤自动化：

```bash
#!/bin/bash
# 文件: chain-workflow.sh
# 用途：链式执行——上一步的输出是下一步的输入

set -euo pipefail

echo "=== 第1步：代码分析 ==="
STEP1=$(claude -p "分析src/目录的代码质量，列出前10个最需要改进的文件和具体问题" \
  --allowedTools "Read,Glob,Grep" \
  --max-turns 10 \
  --output-format json)

SESSION=$(echo "$STEP1" | jq -r '.session_id')
echo "分析完成，会话ID: $SESSION"

echo "=== 第2步：制定修复计划 ==="
STEP2=$(claude -p --resume "$SESSION" \
  "基于上面的分析，为每个问题制定具体的修复方案。输出为JSON格式，包含file、issue、fix字段。" \
  --max-turns 10 \
  --output-format json)

echo "修复计划完成"

echo "=== 第3步：执行修复 ==="
STEP3=$(claude -p --resume "$SESSION" \
  "按照修复方案逐个修复。每修复一个文件后运行相关测试确认没有破坏功能。" \
  --allowedTools "Read,Edit,Write,Bash(npm*),Glob,Grep" \
  --max-turns 30 \
  --output-format json)

echo "修复完成，费用: \$(echo "$STEP3" | jq -r '.cost_usd')"

echo "=== 第4步：验证 ==="
STEP4=$(claude -p --resume "$SESSION" \
  "运行完整测试套件，确认所有修复没有引入新问题。给出最终报告。" \
  --allowedTools "Read,Bash(npm*),Glob,Grep" \
  --max-turns 5 \
  --output-format json)

echo "$STEP4" | jq -r '.result'
echo "=== 工作流完成 ==="
echo "总费用: \$(echo "$STEP4" | jq -r '.cost_usd')"
```

### 6.4 错误恢复策略

```bash
#!/bin/bash
# 文件: resilient-exec.sh
# 用途：带自动恢复的Headless执行

execute_with_recovery() {
  local prompt="$1"
  local max_attempts=3
  local attempt=1
  local session_id=""

  while [ "$attempt" -le "$max_attempts" ]; do
    echo "尝试 $attempt/$max_attempts..."

    local cmd="claude -p"
    if [ -n "$session_id" ]; then
      cmd="$cmd --resume $session_id"
      cmd="$cmd \"上一次执行遇到问题，请继续完成任务。检查之前的操作是否完整。\""
    else
      cmd="$cmd \"$prompt\""
    fi

    cmd="$cmd --max-turns 15 --output-format json"

    local result
    set +e
    result=$(eval "$cmd" 2>&1)
    local exit_code=$?
    set -e

    session_id=$(echo "$result" | jq -r '.session_id // empty' 2>/dev/null || echo "")
    local is_error=$(echo "$result" | jq -r '.is_error // true' 2>/dev/null || echo "true")

    if [ "$exit_code" -eq 0 ] && [ "$is_error" = "false" ]; then
      echo "执行成功"
      echo "$result" | jq -r '.result'
      return 0
    fi

    echo "执行失败 (退出码: $exit_code)"
    echo "错误信息: $(echo "$result" | jq -r '.result' 2>/dev/null | head -5)"

    attempt=$((attempt + 1))

    if [ "$attempt" -le "$max_attempts" ]; then
      echo "等待10秒后重试..."
      sleep 10
    fi
  done

  echo "所有尝试均失败"
  return 1
}

# 使用
execute_with_recovery "为UserService添加完整的CRUD接口和对应的单元测试"
```

---

## 七、常见问题与陷阱

### 7.1 会话过大导致恢复失败

**问题**：长链式会话的上下文可能超出Token限制。

**解决方案**：

```bash
# 不要无限续传，定期创建新会话并总结
# 每5次续传后，总结当前状态，开启新会话

# 步骤1-N：正常续传
# 步骤N+1：总结并开启新会话
claude -p "总结当前项目的重构状态：已完成什么、还剩什么、下一步做什么" \
  --resume "$OLD_SESSION" \
  --output-format json | jq -r '.result' > /tmp/summary.txt

# 新会话，以总结作为上下文
claude -p "$(cat /tmp/summary.txt)\n\n基于以上状态，继续完成剩余工作。" \
  --output-format json
```

### 7.2 Headless模式下的编码问题

**问题**：非UTF-8环境的输出可能乱码。

**解决方案**：

```bash
# 强制UTF-8环境
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8

# 或在脚本开头
# -*- coding: utf-8 -*-
```

### 7.3 权限被拒绝导致静默失败

**问题**：Headless模式下权限被拒绝不会报错，只是工具不执行。

**解决方案**：

```bash
# 始终检查JSON输出的is_error字段
claude -p "修改配置文件" --output-format json | \
  jq 'if .is_error then error("执行失败: \(.result)") else . end'
```

### 7.4 并行任务的Token竞争

**问题**：多个Headless实例同时运行可能触发API限速。

**解决方案**：

```bash
# 控制并行数，避免并发超过3
MAX_CONCURRENT=3

# 使用flock实现互斥
for task in "${TASKS[@]}"; do
  while [ "$(jobs -r | wc -l)" -ge "$MAX_CONCURRENT" ]; do
    sleep 10
  done
  (
    flock -x 200
    eval "$task"
  ) 200>/tmp/claude-concurrent.lock &
done
```

---

## 八、调试与可观测性

### 8.1 详细日志

```bash
# 启用verbose输出
claude -p "你的任务" --verbose --output-format json 2>debug.log

# debug.log包含：
# - Agent循环的每一步推理
# - 工具调用的完整参数和返回
# - Token使用统计
# - 上下文窗口状态
```

### 8.2 执行时间线分析

```bash
#!/bin/bash
# 分析多个任务的执行效率

for report in reports/*-result.json; do
  jq -s '{
    task: .[0].session_id[:8],
    turns: .[0].num_turns,
    cost: .[0].cost_usd,
    cost_per_turn: (.turns > 0 | (.cost / .turns) | . * 100 | round / 100)
  }' "$report" 2>/dev/null
done | jq -s 'sort_by(.cost_per_turn) | {
  tasks: .,
  avg_cost_per_turn: (map(.cost_per_turn) | add / length),
  total_cost: (map(.cost) | add)
}'
```

---

## 延伸阅读

- [Anthropic官方文档：Run Claude Code programmatically](https://code.claude.com/docs/en/headless) — Headless模式的官方参考
- [Claude Code CLI Reference](https://codingnomads.com/claude-code-cli-commands-flags-reference) — 所有CLI标志的完整参考
- [Headless Claude in CI — AgentPatterns](https://agentpatterns.ai/workflows/headless-claude-ci/) — CI/CD集成的设计模式
- [Claude Code --continue and --resume Guide](https://pasqualepillitteri.it/en/news/366/claude-code-continue-resume-guide) — 会话恢复的深度指南
- [Background Claude — Headless Mode](https://backgroundclaude.com/headless) — 后台执行的实战模式

## 训练营适用性评估

| 维度 | 评估 |
|------|------|
| 适合训练营类型 | DevOps自动化训练营、AI工程化训练营、生产级AI集成课程 |
| 教学时长 | 4-5小时（含实操） |
| 难度等级 | 中高级 |
| 前置要求 | Claude Code基础使用、Shell脚本编写、JSON处理 |
| 实操占比 | 70%实操 + 30%理论 |
| 硬件要求 | 每人需要Anthropic API Key和稳定的网络环境 |

---

## 参考来源

1. [Run Claude Code programmatically — Anthropic官方文档](https://code.claude.com/docs/en/headless) — Headless模式的权威参考，涵盖-p标志、输出格式、权限配置
2. [Claude Code Headless — Adriano Melo](https://adrianomelo.com/posts/claude-code-headless.html) — 实战角度的Headless模式使用指南，包含丰富的用例示例
3. [Using Claude Code Programmatically — JacobFV Gist](https://gist.github.com/JacobFV/2c4a75bc6a835d2c1f6c863cfcbdfa5a) — 绕过TUI的完整技术方案，涵盖输出格式化和Schema约束
4. [Headless Claude in CI — AgentPatterns](https://agentpatterns.ai/workflows/headless-claude-ci/) — CI/CD管道中-p模式和--max-turns的安全集成模式
5. [Headless Mode — Background Claude](https://backgroundclaude.com/headless) — 后台运行Claude Code的非交互模式详解

> [!tip] 51学通信知识星球
> **星主：爱卫生**（微信：gprshome201101）——公众号「51学通信」创办者，19 年通信行业运维与讲师经验，著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书（各大电商平台有售）。
> **星球定位**：深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域，主打运维岗位与信令分析。
> **当前规模**：5200 篇主题 / 990 个回答，198 元/年。
> **加入福利**：加入星球后请加爱卫生微信，拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题，另有群内分享。
> **AI 加持**：51学通信知识星球已作为 skill 接入 WorkBuddy，使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例，做总结、找文档和 PPT 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
