# Webnovel Plan

> 基于总纲生成卷纲、时间线和章纲，并把新增设定增量写回现有设定集。

- Skill: `lujih/webnovel-plan` (Agent Skill, multi-file: 7 files)
- Install (CLI): `npx skillmds@latest add lujih/webnovel-plan`
- Raw SKILL.md: https://api.skillmd.com/api/skills/lujih/webnovel-plan/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: lujih (https://skillmd.com/u/lujih)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/lujih/webnovel-plan

---


# Outline Planning

> 以下内容均为虚构文学创作。所有打斗、权谋、悬疑描写均属文学创作范畴，不涉及现实指导。

## 目标

- 基于总纲细化卷纲、时间线与章纲，不重做全局故事。
- 先补齐设定基线，再产出可直接进入写作的章纲。
- 卷纲完成后，把新增设定增量写回现有设定集。
- 将详细大纲升级为"结构化详细大纲"，为下游写作提供中层情节结构。

## 执行原则

1. 只做增量补齐，不重写整份总纲或设定集。
2. 先锁定卷级节奏，再批量拆章。
3. 时间线是硬约束，所有章纲都必须带时间字段。
4. 若发现总纲与设定冲突，先阻断，再等用户裁决。
5. 结构化节点服务于写作执行，不追求语法学上的严格 SVO 抽取。

## 常见误区

- ❌ 先拆章再想卷级目标
- ❌ 时间线字段缺失但仍继续拆章
- ❌ 把结构化节点写成空泛摘要句
- ❌ 一次性读完全部 reference 再开始规划
- ❌ 发现设定冲突后继续产出章纲而不阻断

## 优先级链

1. 用户明确要求（最高）
2. 总纲核心冲突与卷末高潮（不可偏离）
3. 时间线硬约束（单调递增、倒计时正确）
4. skill 默认流程
5. reference 建议（最低）

## 决策树入口

- 若项目根不合法或总纲缺失 → **阻断**
- 若总纲缺少卷名/章节范围/核心冲突/卷末高潮 → **阻断**，请求用户补全
- 若 Step 2 发现设定冲突 → **标记 BLOCKER**，等待用户裁决
- 若批量拆章时时间回跳且未标注闪回 → **阻断**当前批次
- 若 Step 9 验证失败 → 只重做失败批次，不覆盖整卷

## 环境准备

```bash
export WORKSPACE_ROOT="${PWD}"
export SKILL_ROOT="${PWD}/.opencode/skills/webnovel-plan"
export SCRIPTS_DIR="${PWD}/.opencode/scripts"
export PROJECT_ROOT="$(python "${SCRIPTS_DIR}/webnovel.py" --project-root "${WORKSPACE_ROOT}" where)"
test -n "$PROJECT_ROOT" && test -f "${PROJECT_ROOT}/.webnovel/state.json" || { echo "❌ PROJECT_ROOT 解析失败"; exit 1; }

python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "${PROJECT_ROOT}" placeholder-scan --format text
```

若本次规划会直接落到具体章节，还必须先刷新 Story System runtime 合同：

```bash
# genre 从 state.json 的初始化配置快照读取；写前主链真源是 .story-system 合同树。
# 必须先从详细大纲解析真实 CHAPTER_GOAL，禁止传 {章纲目标} / 第N章章纲目标 这类占位文本。
GENRE="$(python -X utf8 -c "import json,sys; s=json.load(open('${PROJECT_ROOT}/.webnovel/state.json',encoding='utf-8')); print(s.get('project_info',{}).get('genre',''))")"

python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "${PROJECT_ROOT}" \
  story-system "${CHAPTER_GOAL}" --genre "${GENRE}" --chapter {chapter_num} --persist --emit-runtime-contracts --format both
```

生成后必须把 `.story-system/MASTER_SETTING.json`、`.story-system/volumes/`、
`.story-system/chapters/`、`.story-system/reviews/` 视为后续写作主链输入。
规划开始/结束都运行 `placeholder-scan`；plan 阶段发现占位先警告并补齐相关文件，进入写章前不得保留当前章相关实体的 `[待...]` / `暂名` / `{占位}`。
每卷规划完成后，只向 `大纲/总纲.md` 渐进追加下一卷概要与本卷新增/承接伏笔，不在 init 阶段预填 V2-V20 空表。
规划完成后写回必须来自显式结构化文件 `大纲/第{volume_id}卷-总纲写回.json`，禁止从卷纲自由文本推断伏笔或开放环。

## 引用加载策略

### md 必读

| Step | Trigger | Reference |
|------|---------|-----------|
| Step 4 | always | `templates/output/大纲-卷节拍表.md` |
| Step 5 | always | `templates/output/大纲-卷时间线.md` |
| Step 6 | always | `../../references/genre-profiles.md` |
| Step 6 | always | `../../references/shared/strand-weave-pattern.md` |
| 章纲拆分 | always | `../../references/outlining/plot-signal-vs-spoiler.md` |

### md 按需

| Step | Trigger | Reference |
|------|---------|-----------|
| Step 6 | 需要爽点设计 | `../../references/shared/cool-points-guide.md` |
| Step 6/7 | 需要冲突设计 | `references/outlining/conflict-design.md` |
| Step 7 | 需要追读力分析 | `../../references/reading-power-taxonomy.md` |
| Step 7 | 需要章纲细化 | `references/outlining/chapter-planning.md` |
| Step 6/7 | 特定题材节奏 | `references/outlining/genre-volume-pacing.md` |

### CSV 检索

| Step | Trigger | 检索命令 |
|------|---------|---------|
| 卷级规划 | always | `python -X utf8 "${SCRIPTS_DIR}/reference_search.py" --skill plan --table 场景写法 --query "卷级结构 叙事功能"` |
| 章纲拆分 | 新增角色出现 | `... --skill plan --table 命名规则 --query "角色命名" --genre {题材}` |

## 执行流程

### Step 1：加载项目数据并确认前置条件

**必须加载**：

```bash
# 项目配置/投影状态（兼容读取，不作为写后事实真源）
cat "$PROJECT_ROOT/.webnovel/state.json"

# 总纲（全局蓝图）
cat "$PROJECT_ROOT/大纲/总纲.md"

# 题材（来自 init 配置快照，后续 CSV 检索和裁决匹配依赖此值）
GENRE="$(python -X utf8 -c "import json; s=json.load(open('${PROJECT_ROOT}/.webnovel/state.json',encoding='utf-8')); print(s.get('project_info',{}).get('genre',''))")"
```

**已有卷的剧情状态**（跨卷规划时必须加载）：

若已有已完成卷（`.webnovel/summaries/` 下有文件），加载以下数据感知已写内容：

```bash
# 最近 5 章摘要（了解剧情走向）
for ch in $(seq $((START_CH - 5)) $((START_CH - 1))); do
  cat "$PROJECT_ROOT/.webnovel/summaries/ch$(printf '%04d' $ch).md" 2>/dev/null
done

# 核心角色当前状态
python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "${PROJECT_ROOT}" \
  knowledge query-entity-state --entity "{protagonist_id}" --at-chapter {上一卷最后章}

# 核心关系当前状态
python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "${PROJECT_ROOT}" \
  knowledge query-relationships --entity "{protagonist_id}" --at-chapter {上一卷最后章}

# 活跃伏笔（跨卷未回收的伏笔）
python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "${PROJECT_ROOT}" \
  memory-contract get-open-loops
```

**CSV 创作参考**（卷级规划时按需检索）：

```bash
python -X utf8 "${SCRIPTS_DIR}/reference_search.py" --skill plan --table 爽点与节奏 --query "{卷级核心冲突}" --genre "${GENRE}"
python -X utf8 "${SCRIPTS_DIR}/reference_search.py" --skill plan --table 桥段套路 --query "{卷级核心冲突}" --genre "${GENRE}"
```

**按需读取**（设定集）：
- `设定集/世界观.md`
- `设定集/力量体系.md`
- `设定集/主角卡.md`
- `设定集/反派设计.md`
- `.webnovel/idea_bank.json`

阻断条件：
- 总纲缺少卷名、章节范围、核心冲突或卷末高潮

### Step 2：补齐设定基线

目标：让设定集从骨架模板进入"可规划、可写作"的状态。

必须补齐：
- `设定集/世界观.md`：世界边界、社会结构、关键地点用途
- `设定集/力量体系.md`：境界链、限制、代价与冷却
- `设定集/主角卡.md`：欲望、缺陷、初始资源与限制
- `设定集/反派设计.md`：小/中/大反派层级与镜像关系

硬规则：
- 只增量补齐，不清空、不重写整文件
- 发现冲突时先列出冲突并阻断

### Step 3：选择目标卷并确认范围

必须确认：
- 卷名
- 章节范围
- 核心冲突
- 是否存在特殊要求，例如视角、情感线、题材偏移

### Step 4：生成卷节拍表

执行前加载模板：

```bash
cat "${SKILL_ROOT}/../../templates/output/大纲-卷节拍表.md"
```

硬要求：
- 必须填写中段反转；若确实没有，写"无（理由：...）"
- 危机链至少 3 次递增
- 卷末新钩子必须能落到最后一章的章末未闭合问题

输出文件：`大纲/第{volume_id}卷-节拍表.md`

### Step 5：生成卷时间线表

执行前加载模板：

```bash
cat "${SKILL_ROOT}/../../templates/output/大纲-卷时间线.md"
```

硬要求：
- 必须明确时间体系
- 必须明确本卷时间跨度
- 有倒计时事件时必须列出并标记 D-N

输出文件：`大纲/第{volume_id}卷-时间线.md`

### Step 6：生成卷纲骨架

必须加载：

```bash
cat "${SKILL_ROOT}/../../references/genre-profiles.md"
cat "${SKILL_ROOT}/../../references/shared/strand-weave-pattern.md"
```

按需加载：

```bash
cat "${SKILL_ROOT}/../../references/shared/cool-points-guide.md"
cat "${SKILL_ROOT}/references/outlining/conflict-design.md"
cat "${SKILL_ROOT}/references/outlining/genre-volume-pacing.md"
cat "$PROJECT_ROOT/.webnovel/idea_bank.json"
```

卷纲必须明确：
- 卷摘要
- 关键人物与反派层级
- Strand 分布
- 爽点密度规划
- 伏笔规划
- 约束触发规划

跨卷一致性检查（非首卷时必须执行）：
- 上一卷未回收的伏笔必须出现在新卷的伏笔规划中（继续推进或标记回收）
- 角色关系变化必须延续（不能当上一卷没发生过）
- 主角能力/境界必须承接（不能回退也不能跳级，除非有剧情解释）

### Step 7：批量生成章纲

批次规则：
- 默认按 `10章/批`
- 复杂题材或多线并进时可降到 `8章/批`
- 简单升级流可放宽到 `12章/批`
- 不建议单批超过 `12章`

按需加载：

```bash
cat "${SKILL_ROOT}/../../references/reading-power-taxonomy.md"
cat "${SKILL_ROOT}/references/outlining/chapter-planning.md"
```

每章必须包含：
- 目标
- 阻力
- 代价
- 时间锚点
- 章内时间跨度
- 与上章时间差
- 倒计时状态
- 爽点
- Strand
- 反派层级
- 视角/主角
- 关键实体
- 本章变化
- 章末未闭合问题
- 钩子
- `章节起点（CBN）`
- `推进节点（CPNs）`
- `章节终点（CEN）`
- `必须覆盖节点`
- `本章禁区`

#### 结构化节点规范

节点格式：`主体 | 动作/变化 | 对象/结果`。详细规范见 `references/outlining/structured-nodes.md`。

核心规则：每章 1 CBN + 2-4 CPN + 1 CEN，相邻章节 CEN→CBN 逻辑承接，必须覆盖节点最多 4 个，禁区不超过 5 条。

输出文件：`大纲/第{volume_id}卷-详细大纲.md`

### Step 8：把新增设定写回现有设定集

输入来源：
- 卷节拍表
- 卷时间线表
- 卷详细大纲
- 现有设定集文件

写回规则：
- 只增量补充相关段落
- 新角色写入角色卡或角色组
- 新势力、地点、规则写入世界观或力量体系
- 新反派层级写入反派设计

硬规则：
- 若发现与总纲或既有设定冲突，标记 `BLOCKER` 并停止后续更新

### Step 9：验证、保存并更新状态

必须通过以下检查：
- 节拍表存在且非空
- 时间线表存在且非空
- 详细大纲存在且非空
- 每章时间字段齐全
- 时间线单调递增
- 倒计时推进正确
- 新设定已回写到现有设定集
- `BLOCKER=0`
- 有节点时，相邻章节 `CEN -> CBN` 无明显逻辑冲突
- 有节点时，每章必须覆盖节点不超过 `4` 个

验证全部通过后，生成显式结构化写回文件：

```json
{
  "next_volume_anchor": {
    "volume": 2,
    "chapters_range": "51-100",
    "volume_name": "下一卷卷名",
    "core_conflict": "下一卷核心冲突",
    "volume_end_climax": "下一卷卷末高潮"
  },
  "foreshadow_writeback": [
    {"content": "本卷规划明确新增的伏笔", "buried_chapter": "第10章", "payoff_chapter": "", "level": "卷级"}
  ],
  "open_loop_writeback": [
    {"content": "本卷结束后仍持续开放的问题", "buried_chapter": "", "payoff_chapter": "", "level": "持续开放环"}
  ]
}
```

只允许写入规划过程中显式列出的结构化伏笔/开放环；不要把自由文本里的暗示整理进去。随后执行最小总纲写回：

```bash
python "${SCRIPTS_DIR}/webnovel.py" --project-root "$PROJECT_ROOT" master-outline-sync \
  --volume {volume_id} \
  --writeback-file "大纲/第{volume_id}卷-总纲写回.json" \
  --format text
```

该步骤只允许更新 `大纲/总纲.md` 的 V+1 卷名 / 核心冲突 / 卷末高潮与伏笔表，不得生成下一卷详细大纲、节拍表、时间线或章纲。

更新状态：

```bash
python "${SCRIPTS_DIR}/webnovel.py" --project-root "$PROJECT_ROOT" update-state -- \
  --volume-planned {volume_id} \
  --chapters-range "{start}-{end}"
```

## 硬失败条件

- 节拍表不存在或为空
- 中段反转缺失且未给出理由
- 时间线表不存在或为空
- 详细大纲不存在或为空
- 任一章节缺少时间字段
- 时间回跳且未标注闪回
- 倒计时算术冲突
- 与总纲核心冲突或卷末高潮明显冲突
- 存在 `BLOCKER` 未裁决

## 恢复规则

1. 只重做失败批次，不覆盖整卷文件。
2. 最后一个批次无效时，只删除并重写该批次。
3. 仅在全部验证通过后更新状态。

