story-setup:网文写作工具集基础设施部署

SkillFiles & storage

Infrastructure deployment for the web novel writing toolkit. Provides built-in adapters for Claude Code / OpenCode / Codex / Google Antigravity / ZCode / OpenClaw / Reasonix; Web AI / general agents can use the skills + AGENTS.md file mode. Triggers: /story-setup, $story-setup, "准备写书", "帮我搭一下环境", "配

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the story-setup:网文写作工具集基础设施部署 skill

What this skill tells your AI

The instructions your AI receives, as published by zenstory-ai/oh-story-claudecode in skills/story-setup/SKILL.md and read by ahel’s review.

你是写作基础设施部署器。将网文写作工具集部署到用户项目目录:已适配的 CLI 走专用 hooks/agents/config;NarraFork、Web AI、自定义 Agent 等环境走通用文件模式。

执行铁律:不覆盖用户已有配置,合并而非替换。

选择模式

  • 参数为 check,或用户只要求检查部署、诊断环境、排查 agent 不可用时:完整读取 references/diagnostics.md,按其中流程仅检查并报告;不进入下面的部署流程。
  • 用户要求安装、更新或修复时:执行下面的部署流程。检查后已明确授权的修复沿用本文件的部署与合并规则。

Phase 1:检测项目状态

先自检参考目录:以正在执行的本 SKILL.md 所在目录为准,列出与它同级的 references/ 下的子目录,核对下面 9 个名字是否都在且都非空——agent-referencestemplatesopencodecodexantigravityzcodeopenclawreasonixgeneric;同级 scripts/merge-claude-settings.pyscripts/merge-codex-hooks.pyscripts/merge-antigravity-hooks.pyscripts/generate-antigravity-agents.mjsscripts/deploy-antigravity-skills.pyscripts/copy-path-safety.py 也必须存在(Claude/Codex/Antigravity hooks 合并、Antigravity Skills 物化与 agent 生成、递归复制安全检查依赖它们)。有缺即 skill 包没装全,立即停止,不写任何部署文件,报告里区分「缺目录」「目录为空」和「缺脚本」,并给修复指令:「story-setup 参考资料包不完整,缺 {路径}。按你的安装方式重装 oh-story-claudecode(命令行装的重跑 npx skills add zenstory-ai/oh-story-claudecode -y -g,marketplace / Plugin Management 装的在面板里重装),再执行 /story-setup。」

判据是「有没有 SKILL.md」:只看正在执行的 SKILL.md 同级的 references/。项目内 .claude/skills/story-setup/.codex/skills/story-setup/ 和 OpenCode 的 skills/story-setup/ 只有 references/agent-references/、不含 SKILL.md,不会是执行目录,也不要拿它们核对。Antigravity / ZCode / OpenClaw / Reasonix / generic 的项目副本是整份 skill 拷贝、自带 SKILL.md,9 个子目录本就齐全,照常核对即可。

  1. 检查当前目录是否已部署过(存在 .story-deployed
    • agents_version 缺失、非整数或小于 30 → 标记为待更新,继续执行当前部署
    • agents_version: 30 → 使用 AskUserQuestion 确认是否重新部署;提示里写明重新部署只用当前本地 skill 包刷新项目文件,要拿 skill 本身的新版本得先更新 oh-story-claudecode(npx skills add 或 marketplace),再回来重跑
    • agents_version 大于 30 → 当前 story-setup 比项目部署旧;停止以避免降级覆盖,提示先更新 oh-story-claudecode,不写任何部署文件
    • 同时读 target_cli 字段。已部署项目以 sentinel 里的值为准:非空时(逗号分隔的多端组合原样保留)跳过下面第 5-12 步的环境探测与选择,直接按这些端重新部署。只有字段缺失或为空,才回落到探测。用户明确要求增删目标端时,用 AskUserQuestion 在现有值基础上改,改完的值写回 sentinel。
  2. 检查是否有书名目录(包含 追踪/ 子目录的目录,或用户自定义结构)
    • 有 → 识别为长篇项目,显示当前项目信息
    • 无 → 识别为新项目或短篇项目
  3. 检查 .claude/settings.local.json 是否存在
    • 存在 → 读取现有配置,后续合并
    • 不存在 → 后续创建新文件
  4. 检查 .active-book 文件是否存在
    • 存在 → 显示当前活跃书目
    • 不存在 → 跳过
  5. 检查 opencode.json.opencode/ 是否存在
    • 存在 → 识别为 opencode 项目,target_cli = opencode
    • 不存在 → 跳过
  6. 检查 .codex/.codex/config.toml.codex/agents/.codex/hooks.jsonAGENTS.md 中的 Codex 段
    • 存在 → 识别为 Codex 项目,target_cli = codex
    • 不存在 → 跳过
  7. 检查 .agents/hooks.json.agents/agents/,或 .agents/rules/oh-story.md 中的 Antigravity 标记
    • 存在 → 识别为 Google Antigravity 项目,target_cli = antigravity
    • 不存在 → 跳过
  8. 检查 .zcode/.zcode/config.jsonzcode.json.zcode/skills/.zcode/commands/AGENTS.md 中的 ZCode 段
    • 存在 → 识别为 ZCode 项目,target_cli = zcode
    • 不存在 → 跳过
  9. 检查 openclaw.json.openclaw/,或 AGENTS.md 中的 OpenClaw 段(标题行含 网文写作工具集(OpenClaw)
    • 存在 → 识别为 OpenClaw 项目,target_cli = openclaw
    • 不存在 → 跳过
  10. 检查 .reasonix/reasonix-plugin.jsonREASONIX.md,或 AGENTS.md 中的 Reasonix 段(标题行含 网文写作工具集(Reasonix)
  • 存在 → 识别为 Reasonix 项目,target_cli = reasonix
  • 不存在 → 跳过
  1. 检查 AGENTS.md 中的通用段(标题行含 网文写作工具集(通用 Agent / Web AI)
  • 存在 → 识别为通用 Web AI 项目,target_cli = generic
  • 不存在 → 跳过

第 9-11 步只认各端互斥的标记。skills/*/SKILL.mdmetadata.openclaw 不作 OpenClaw 信号:13 个 skill 全都带这个字段,而 OpenClaw / Reasonix / generic 三条 skills-only 路径部署出的 skills/ 长得一样,用它判定会把后两者一律误认成 OpenClaw。.agents/skills/ 由 Antigravity、Codex 与 Reasonix 共用,也不单独作准;Antigravity 必须由 hooks/agents/rule 专属标记识别。后三端真正的分辨点是各自 AGENTS.md 模板的标题行。

  1. .claude/CLAUDE.md、OpenCode、Codex、Antigravity、ZCode、OpenClaw、Reasonix、generic 标记同时存在 → 使用 AskUserQuestion 让用户选择目标环境(选项:Claude Code / OpenCode / Codex / Google Antigravity / ZCode / OpenClaw / Reasonix / 通用 Web AI 或其他 Agent / 任意组合)
  2. 如八类标记都不存在(全新项目)→ 使用 AskUserQuestion 让用户选择目标环境
  • 用户选择 opencode → target_cli = opencode,部署时创建 opencode.json.opencode/
  • 用户选择 claude-code → 按现有逻辑处理
  • 用户选择 codex → target_cli = codex,部署时创建 .codex/
  • 用户选择 antigravity → target_cli = antigravity,部署时创建 .agents/skills.agents/agents.agents/rules.agents/hooks 并合并 .agents/hooks.json
  • 用户选择 zcode → target_cli = zcode,部署时创建 .zcode/、合并根 AGENTS.md,不创建项目 custom agents
  • 用户选择 openclaw → target_cli = openclaw,部署时复制 OpenClaw 兼容 skills 到项目 skills/
  • 用户选择 reasonix → target_cli = reasonix,部署时复制 skills 到项目 skills/、写入 Reasonix 版 AGENTS.md,不创建项目 custom agents/hooks
  • 用户选择通用 Web AI / 其他 Agent → target_cli = generic,部署通用 AGENTS.md 与项目本地 skills/;不写平台专属 hooks/agents
  • 用户选择多端 → target_cli = claude-code,opencode,codex,antigravity,zcode,openclaw,reasonix,generic 的子集(仅包含用户选择的端)

Phase 2:部署基础设施

使用 AskUserQuestion 确认部署位置后,依次执行。

整个 Phase 2 幂等:目录复制、文件写入和下表各合并算法重复执行结果一致。因环境原因(工具不可用、权限被拒、网络失败)中途失败时,直接从头重跑本 Phase,不需要先清理半成品;create only if absent 的用户状态文件(见下表 Owner class)不会被二次覆盖。

两列基准目录不同Source path 相对正在执行的这份 skill 包,Target path 相对用户项目根。执行每一行(以及下面各端部署算法里的每个递归复制步骤)之前,先把通配符具体化为单个源/目标,再用本 SKILL.md 同级的 scripts/copy-path-safety.py 检查。该脚本按 Path.resolve / realpath 语义跟随已有 symlink,并在两侧都存在时用 samefile 核对文件系统对象;只转绝对路径或比较字符串不算检查完成。读取其 JSON:status: same 时 no-op,禁止复制;仅 copy_allowed: true 时可以复制;source_missingunsafe_target_within_sourcefilesystem_identity_error 必须停止该步骤并报告。无法运行脚本时只能用当前环境的文件系统 API 做完全相同的 canonical realpath、same-object 与 target-descendant 检查;无法确认就停止,不得尝试复制。OpenClaw / Reasonix / generic 的项目副本是整份 skill 拷贝,重跑时执行的就是项目里那份;Reasonix / Codex 还可能经 .agents/skills → ../skills symlink 加载,路径文本不同也可能指向同一目录,照字面复制会把目录嵌进自身并撑满磁盘。

部署前清理自嵌套残留{.claude,.codex,.zcode}/skills/story-setup/references/agent-references/ 与项目根 skills/story-setup/references/agent-references/ 里若多出 agent-references/ 层(可能嵌了多层),以及 skills/story-setup/skills/,整段删掉再部署,并在安装报告里列出删掉的路径。

Step 1:部署清单(机械可检查)

Source pathTarget pathOwner classMerge modeValidation check
skills/story-setup/references/templates/CLAUDE.md.tmplCLAUDE.mduser+managedmarker/section mergecontains story skill routing sections
skills/story-setup/references/templates/hooks/.claude/hooks/story-setup managedrecursive replacesession-*.sh, detect-story-gaps.sh, validate-story-commit.sh, guard-outline-before-prose.sh, check-prose-after-write.sh, story_hook_core.js, story_hook_cli.js, lib/common.sh, lib/sentinel.sh exist;story_hook_core.js 与 OpenCode/ZCode 副本字节一致
skills/story-setup/references/templates/rules/*.md.claude/rules/*.mdstory-setup managedreplaceevery rule contains paths frontmatter
skills/story-setup/references/templates/agents/*.md.claude/agents/*.mdstory-setup managedreplace7 agent files exist
skills/story-setup/references/agent-references/*.md.claude/skills/story-setup/references/agent-references/*.mdstory-setup managedreplaceevery story-setup/references/agent-references/*.md reference resolves
skills/story-setup/references/templates/settings-hooks.json.claude/settings.local.jsonuser+managedreplace managed registrations by stable hook identityhook JSON valid;旧 matcher 注册已迁移、当前模板命令各一份、用户 hook 保留
skills/story-setup/scripts/merge-claude-settings.py部署时执行,不复制到项目story-setup helperexecute替换已知 story hook 注册、保留用户 hooks/顶层字段,v24→v25 迁移与重复执行幂等
skills/story-setup/scripts/copy-path-safety.py每个递归复制步骤前执行,不复制到项目专用目录story-setup helperexecuteJSON 仅 copy_allowed: true 时允许复制;symlink 同对象 no-op;target 位于 source 内时停止
generated sentinel.story-deployedstory-setup managedreplacecontains agents_version, setup_skill_version, target_cli, resolver_strategy, references_dir
skills/story-setup/references/opencode/AGENTS.md.tmplAGENTS.mduser+managedmarker/section mergecontains story skill routing sections
skills/story-setup/references/opencode/agents/.opencode/agents/story-setup managedreplace7 agent files exist(replace 前按「配置 OpenCode Agent 模型」中的「保留已有模型配置」缓存现有 model:,避免覆盖用户已配模型)
skills/story-setup/references/opencode/plugin.ts.opencode/plugins/story-hooks.tsstory-setup managedreplaceTypeScript plugin file exists
skills/story-setup/references/opencode/story_hook_core.js.opencode/plugins/lib/story_hook_core.jsstory-setup managedreplaceNode syntax valid;与 ZCode 副本字节一致;被 story-hooks.ts import
skills/story-setup/references/opencode/commands/.opencode/commands/story-setup managedreplace13 command files exist
skills/story-setup/references/opencode/opencode.json.patchmerge into opencode.jsonuser+managedmerge by plugin/permission keyplugin entry registered
repository skills/story-setup/references/agent-references/skills/story-setup/references/agent-references/story-setup managedreplaceevery reference resolves
skills/story-setup/references/opencode/pre-commit.sh.git/hooks/pre-commituser+managedappend or createfile exists and is executable;含 marker 块则替换块内容,不含则检测 exit 0 位置智能插入
skills/story-setup/references/codex/AGENTS.md.tmplAGENTS.mduser+managedmarker/section mergecontains Codex story skill routing sections
skills/story-setup/references/codex/agents/.codex/agents/story-setup managedreplace7 TOML agent files parse and contain name/description/developer_instructions
skills/story-setup/references/codex/hooks/hooks.json.codex/hooks.jsonuser+managedreplace managed registrations by stable hook identityhook JSON valid; all stale direct/launcher registrations removed, current 6 registrations present exactly once
skills/story-setup/references/codex/hooks/{story_codex_hook.py,run-story-hook.sh,run-story-hook.cmd}.codex/hooks/ 同名文件story-setup managedreplacePython/shell/cmd launcher 文件齐全
skills/story-setup/scripts/merge-codex-hooks.py部署时执行,不复制到项目story-setup helperexecute替换已知管理注册、保留用户 hooks 与未知顶层字段,结果幂等
skills/story-setup/references/agent-references/.codex/skills/story-setup/references/agent-references/story-setup managedreplaceevery reference resolves
current package skill root + scripts/deploy-antigravity-skills.py.agents/skills/{browser-cdp,story*}/story-setup managed for 13 known skill namesatomically replace known dirs; preserve unknown skills; never write through symlink13 real skill directories with valid SKILL.md exist
skills/story-setup/scripts/generate-antigravity-agents.mjs + Claude agent sources.agents/agents/agent-name/agent.mdagent-name 为实际名称)story-setup managed for 7 known agent definitionsgenerate then atomically replace known definitions; preserve unknown user agents7 Markdown agents parse; exact Antigravity tool names; mainAgent: false, subagent: true
skills/story-setup/references/antigravity/rules/oh-story.md.agents/rules/oh-story.mdstory-setup managedreplacetrigger: always_on; under 12,000 characters
skills/story-setup/references/antigravity/hooks/hooks.json.agents/hooks.jsonuser+managedreplace only top-level oh-story groupvalid Antigravity named-group schema; user groups preserved; idempotent
skills/story-setup/references/antigravity/hooks/{story_antigravity_hook.js,story_hook_core.js}.agents/hooks/ same namesstory-setup managedreplaceNode syntax valid; core byte-identical to shared source; hook contract tests pass
skills/story-setup/scripts/merge-antigravity-hooks.pydeployment helper onlystory-setup helperexecuteatomically replaces only oh-story, preserves user groups, idempotent
skills/story-setup/references/zcode/AGENTS.md.tmplAGENTS.mduser+managedmarker/section mergecontains ZCode $story-* routing and solo fallback
repository skills/{browser-cdp,story*}/.zcode/skills/{browser-cdp,story*}/story-setup managed for known skill namesreplace known skill dirs only13 SKILL.md files exist and satisfy ZCode frontmatter limits
skills/story-setup/references/zcode/commands/.zcode/commands/story-setup managed for known command namesreplace known command files only13 commands have valid names/frontmatter
skills/story-setup/references/zcode/hooks/story_zcode_hook.js.zcode/hooks/story_zcode_hook.jsstory-setup managedreplaceNode syntax valid; hook contract tests pass
skills/story-setup/references/zcode/hooks/story_hook_core.js.zcode/hooks/story_hook_core.jsstory-setup managedreplaceNode syntax valid; hook contract tests pass
skills/story-setup/references/zcode/config.json.patchmerge into .zcode/config.jsonuser+managedmerge by event+matcher+process argsJSON valid; 按「ZCode 部署算法」第 4 步 hooks 互斥分支校验——未装 oh-story 插件时 hooks.enabled=true、only supported events;已装插件时校验 .zcode/config.json 不含(或已移除)这批 oh-story hooks 注册
skills/story-setup/references/openclaw/AGENTS.md.tmplAGENTS.mduser+managedmarker/section mergecontains OpenClaw story skill routing sections
skills/story-setup/references/generic/AGENTS.md.tmplAGENTS.mduser+managedmarker/section mergecontains generic story skill routing sections
skills/story-setup/references/reasonix/AGENTS.md.tmplAGENTS.mduser+managedmarker/section mergecontains Reasonix story skill routing sections and solo/direct fallback
repository skills/{browser-cdp,story*}/skills/{browser-cdp,story*}/story-setup managed for known skill namesreplace known skill dirs only13 SKILL.md files exist; OpenClaw-compatible frontmatter
repository skills/story-setup/references/agent-references/随上一行整份 skill 拷贝落地,本行 no-opstory-setup managed不单独复制every reference resolves

opencode.json 合并算法

部署 opencode.json.patch 时按以下规则合并:

  1. 读取现有 opencode.json(如存在),解析 JSON
  2. 合并 plugin 数组:将 ./.opencode/plugins/story-hooks.ts 加入数组,去重
  3. 保留用户已有的其他配置字段(permissionmodelprovider 等),不覆盖
  4. 写入合并后的 opencode.json

Step 2:部署 CLAUDE.md

  • 读取 skills/story-setup/references/templates/CLAUDE.md.tmpl
  • 替换占位符(见下方「模板占位符」段)
  • 写入项目根目录 CLAUDE.md(如已存在,按「CLAUDE.md 合并策略」处理)

Step 3:部署 Hooks

  • 递归复制完整目录树:将 skills/story-setup/references/templates/hooks/ 复制到用户项目 .claude/hooks/
  • 必须保留子目录 lib/,其中:
    • lib/common.sh 提供 project_rootdiscover_active_bookdiscover_all_books
    • lib/sentinel.sh 提供 .story-deployed 字段读取
  • 只需对 .claude/hooks/*.sh 设置执行权限(chmod +x);lib/*.sh 由 hook source,不要求可执行位

Step 4:部署 Rules

  • 读取 skills/story-setup/references/templates/rules/ 下所有 .md 文件
  • 复制到用户项目的 .claude/rules/ 目录

Step 5:部署 Agents

  • 读取 skills/story-setup/references/templates/agents/ 下所有 .md 文件
  • 复制到用户项目的 .claude/agents/ 目录
  • Agent 文件属于 story-setup 管理文件,可安全覆盖;版本升级时按 UPGRADING.md 的版本检测结果重新部署
  • target_cli 含 opencode 时,覆盖 .opencode/agents/ 之前先执行下面「配置 OpenCode Agent 模型」的 Step 1 缓存现有 model:。那一步写在本节后面,但必须先跑——照顺序读到哪做到哪会先覆盖再缓存,用户已配的模型就没了。
  • 部署后必须新开会话:agent 只在会话启动时注册;原因与必须输出的报告文案见「验证安装」中的「输出安装报告」。
Agent 兼容性处理
  • Agent 正文以 Claude Code Markdown 为真源;OpenCode 的 .opencode/agents/*.md 与 Codex 的 .codex/agents/*.tomlreferences/opencode/agents/references/codex/agents/ 下的预生成产物直接复制。Antigravity 的 .agents/agents/agent-name/agent.mdagent-name 为实际名称)则在部署时调用随 story-setup 下发的 scripts/generate-antigravity-agents.mjs,把 Claude 工具名、模型档、reference 根和调用术语确定性转换为 Antigravity 2.0 契约;不得把 Claude frontmatter 原样复制过去。
  • ZCode 3.3.4 不部署项目 agents:其自定义子智能体只支持用户级 ~/.zcode/agents/,plugin manifest 中的 agents 当前不执行。不要创建 .zcode/agents/ 或修改用户 home;相关 Skill 必须直接 solo/direct 并报告 fallback。
  • OpenClaw Phase 1 不部署 agents:OpenClaw 只部署 skills,agent 协作相关 skill 必须按既有 fallback 规则降级 solo/direct,不要把 Claude/OpenCode agent frontmatter 直接复制成 OpenClaw agent。
  • 部署到项目后,agent 内引用的参考资料必须走 story-setup/references/agent-references/*.md 这一本 skill 内复制路径;不要跨 skill 引用其他 skill 的 references。各 adapter 只使用当前规范前缀:Claude Code 为 .claude/skills/,Antigravity 为 .agents/skills/,OpenCode / OpenClaw / Reasonix / generic 为 skills/,Codex 为 .codex/skills/,ZCode 为 .zcode/skills/;不在运行时遍历历史备选路径。
部署 Agent References
  • skills/story-setup/references/agent-references/ 下所有 .md 复制到项目内 .claude/skills/story-setup/references/agent-references/
  • 校验:凡 agent 或 reference 中出现 story-setup/references/agent-references/<file>.md,源包与目标包都必须存在 <file>.md
部署 Codex Agents(target_cli 含 codex 时)
  • 读取 skills/story-setup/references/codex/agents/ 下所有 .toml 文件,复制到用户项目 .codex/agents/
  • Agent 文件属于 story-setup 管理文件,可安全覆盖;references/codex/agents/ 里的 TOML 由仓库根的 scripts/generate-codex-agents.py 从 Claude agent 模板确定性生成后提交入库,部署只做复制
  • 校验每个 TOML 都能解析,且包含 Codex 必需字段:namedescriptiondeveloper_instructions
  • 只读职责 agent(chapter-extractorconsistency-checkerstory-explorer)必须保留 sandbox_mode = "read-only"
  • 部署后必须 trust + 新开 Codex 会话(报告文案与 fallback 规则见「验证 Codex 部署」);若运行时返回 unknown agent_type,调用方必须降级 solo/direct 并报告 fallback。
  • skills/story-setup/references/agent-references/ 同步复制到 .codex/skills/story-setup/references/agent-references/,作为 Codex agent 的项目内参考资料主路径
部署 Antigravity Agents(target_cli 含 antigravity 时)
  • 先确认 node 在 PATH;Antigravity agent 生成与项目 hooks 都依赖 Node。缺失时停止 Antigravity 这一目标的部署,不留下半成品,并提示安装 Node 后重跑。
  • 执行 node "{story-setup skill目录}/scripts/generate-antigravity-agents.mjs" --source "{story-setup skill目录}/references/templates/agents" --dest "{项目}/.agents/agents"。生成器先渲染全部 7 个 agent,再原子替换这 7 个已知 .agents/agents/agent-name/agent.md 定义(agent-name 为实际名称),并清理旧版同名扁平 .md;保留其他用户 agent,任一源 frontmatter 异常时不得留下半更新目录,也不得沿 managed agent symlink 写出项目外。
  • 校验 7 个 .mdname 与文件名一致;mainAgent: falsesubagent: true;模型只使用 flash / pro;工具只来自 Antigravity 官方名称 view_filefind_by_namegrep_searchwrite_to_filereplace_file_contentmulti_replace_file_contentrun_command;不得残留 Claude 的 Read/Glob/Grep/Write/Edit/Bash 工具名或 .claude/skills/ reference 前缀。
  • 只读 agent(chapter-extractorconsistency-checkerstory-explorer)不得包含写文件或命令工具;其他 agent 按 Claude 真源的能力边界映射。
  • Antigravity 通过 invoke_subagentTypeName 调用这些 agent。部署后新开 Antigravity conversation,再用 story-review 验证 full/lean;运行时无法解析某个 custom agent 时按 skill 的 solo/direct fallback 执行。
配置 OpenCode Agent 模型

仅当 target_cliopencode 时执行。OpenCode 子代理不指定模型时继承主模型,导致低成本 Agent 也消耗主模型额度。此步骤自动检测用户模型并写入 model: 字段。

Step 1:保留已有模型配置(必须在 .opencode/agents/ 的 replace 之前执行)

OpenCode agents 部署是 replace,会覆盖上次写入的 model:。所以在执行该 replace 之前先扫描现有 .opencode/agents/*.md,缓存每个 agent 的 model:(agent 名 → 模型 ID)。后续检测失败/超时、或用户跳过某一级时,用缓存值回填,避免把用户上次配好的低成本模型抹成主模型。若 replace 已先发生、缓存为空,则按全新部署处理,并在安装报告中提示"未能保留上次模型配置"。

Step 2:获取模型列表

优先执行 opencode models --verbose,它输出含 cost(input/output/cache 单价)、context、capabilities 的 metadata;不可用或解析失败时回退到 opencode models 纯文本(每行 provider/model)。两者都用 60000ms(60 秒)超时,因为首次运行需加载 models.dev 缓存。

  • 成功 → 进入「模型分级」
  • 超时 → 重试一次(缓存可能未预热);仍然超时则按「保留已有模型配置」缓存回填已有 model:、跳过自动配置,在安装报告中输出手动配置指南
  • 失败(命令不存在、输出为空等)→ 同上:回填「保留已有模型配置」缓存、跳过自动配置、输出手动配置指南
Step 3:模型分级

优先按成本分级(有 --verbose 时):按每模型实际 cost 从低到高分档——低端取最便宜/免费档、中端取中价档、高端取最贵或上下文/能力最强档。免费模型按真实 cost=0 归低端,不按名字里的营销词(如 nemotron-3-ultra-free 名含 ultra 但 cost=0,应归低端)。无 cost 数据的模型也据此进入候选,不被丢弃。

回退按关键词分级(无 --verbose 或无 cost 时):按模型 ID 中最后一个 / 之后的模型名按 -._ 分割为段,逐段精确匹配关键词(不区分大小写)。例如 minimax-m3 拆为 [minimax, m3],不匹配 mini 也不匹配 maxclaude-haiku-4.5 拆为 [claude, haiku, 4, 5],匹配 haiku。关键词分级是启发式,安装报告中标注 分级依据:关键词(heuristic)

等级匹配关键词对应 Agent
低端haiku, flash, mini, nano, litechapter-extractor, consistency-checker, story-explorer
中端sonnet, plusstory-researcher, narrative-writer, character-designer
高端opus, pro, ultra, maxstory-architect
  • 一个模型可能匹配多个等级的关键词,取最高等级
  • 关键词回退下未匹配任何关键词的模型仍列入候选附加建议(按成本分级则一律纳入),并在安装报告列出,提示"可通过自定义输入使用"
  • 同一等级内,如果包含多个模型供应商,优先列出知名供应商(anthropic、openai、google、deepseek)的模型
Step 4:逐级交互选择

按 低端 → 中端 → 高端 顺序,每级用 AskUserQuestion 让用户选择。

低端选项结构:

问题:"为低成本 Agent(chapter-extractor, consistency-checker, story-explorer)选择模型:"
选项:
  - provider/model-id
  - provider/model-id
  - 自定义输入(手动输入完整模型 ID,ID 拼写错误要到运行时才会暴露)
  - 跳过,使用主模型(成本可能较高)

中端选项结构:

问题:"为写作质量关键 Agent(narrative-writer, character-designer, story-researcher)选择模型:"
选项:
  - provider/model-id
  - provider/model-id
  - 自定义输入(请勿使用低端模型,会影响正文质量;ID 拼写错误要到运行时才会暴露)
  - 跳过,使用主模型(主模型质量通常足够)

高端选项结构:

问题:"为总指挥 Agent(story-architect)选择模型:"
选项:
  - provider/model-id
  - provider/model-id
  - 自定义输入(手动输入完整模型 ID,ID 拼写错误要到运行时才会暴露)
  - 跳过,使用主模型(成本可能较高)

规则:

  • 候选最多显示 5 个,超过则截断并提示"更多模型请使用自定义输入"。每一级无论候选数是否为 0 都用 AskUserQuestion 弹出,选项至少含:候选模型(如有)、自定义输入保留现有模型(「保留已有模型配置」缓存到该 agent 的 model,无则不显示此项)、跳过,用主模型。候选为 0 时仍弹窗,并在问题说明里给出对应警告 + 列出未分级/未入档模型供参考——不再静默跳过交互(否则用户够不到自定义输入)。
  • 自定义输入:用户输入 provider/model-id 完整 ID;写入前校验为单行、无控制字符、匹配 ^[A-Za-z0-9._-]+/[A-Za-z0-9._:+-]+$,不符则提示重输或改选跳过。
  • 保留现有模型:写回「保留已有模型配置」缓存的该 agent model(重新部署时保住用户上次配置),不算"跳过"。
  • 跳过,用主模型:显式清除——不写该 agent 的 model:,agent 继承主模型。想保留上次配置请选 保留现有模型
  • 各级候选为 0 时在问题说明里给出提示:
    • 低端:"未检测到低成本模型,这 3 个 agent 将使用主模型,成本可能较高"
    • 中端:"未检测到匹配的中端模型。narrative-writer、character-designer、story-researcher 将使用主模型。如主模型质量足够此配置合理;如需降本,请用自定义输入指定不低于主模型质量的中端模型,或从下方未分级模型里选。"
    • 高端:"未检测到高端模型,story-architect 将使用主模型"
Step 5:写入 model 字段

对应用户选择的 agent 文件(.opencode/agents/*.md,由部署清单中 OpenCode agents 部署步骤在此步骤之前已部署),在 frontmatter 末尾、closing --- 之前,以零缩进的顶层字段插入 model:(不要插进 permission: 等多行 map 的缩进块内部)。值含 YAML 特殊字符时加引号,确保不破坏 frontmatter:

---
description: ...
mode: subagent
permission:
  read: allow
  edit: deny
steps: 12
model: provider/model-id
---
  • 如果 agent 文件已有 model: 字段(重新部署场景),替换该顶层 model: 的值,不新增重复键
  • 保留现有模型:写回「保留已有模型配置」缓存的该 agent model
  • 跳过,用主模型:不写入 model: 字段
  • 检测失败/超时、没走到本步骤的等级:用「保留已有模型配置」缓存回填 model:,避免 replace 抹掉用户上次配置

Step 6:合并 Hooks 注册到 settings.local.json

  1. 按现有跨平台规则探测 Python:for PYBIN in python3 python py; do "$PYBIN" -c "" 2>/dev/null && break; done;无可用解释器时停止,不手写或简化合并。
  2. 调用 "$PYBIN" "{story-setup skill目录}/scripts/merge-claude-settings.py" --existing "{项目}/.claude/settings.local.json" --template "{story-setup skill目录}/references/templates/settings-hooks.json" --output "{项目}/.claude/settings.local.json"
  3. helper 会移除所有已知 story-setup hook 的历史注册,再追加当前模板;因此 matcher/timeout/if 能随版本升级,同时混在旧 block 中的用户 hook 与未知顶层字段原样保留。写后解析 JSON,验证模板命令各一份、用户配置仍在,再复跑 helper 比较文件字节确认幂等。

Codex hooks.json 合并算法(target_cli 含 codex 时)

Codex 项目 hooks 部署到 .codex/hooks.json;运行脚本部署到 .codex/hooks/story_codex_hook.pyrun-story-hook.shrun-story-hook.cmd。JSON 只负责定位项目根与传递 event,解释器探测由平台 launcher 统一处理。

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
7k
Forks
977
Last commit
Sep 2026

ahel review

  • K6low
    bundled executables the agent is told to run

Automated review, not a security audit. Ruleset v1+k2.

Others that do the same job

Advanced
Catalog kind
skill
Gateway key
story-setup-zenstory-ai
Source
github.com/zenstory-ai/oh-story-claudecode