Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,24 @@

## [未发版 / Unreleased]

## [v0.11.2] - 2026-07-28

### Codex Hook 调度回归:响亮停机 + 文档勘误

*(EN: fail loudly on the upstream Codex hook-dispatch regression; correct v0.11.1's overstatement and stop reinstall/restart loops.)*

- current-session live-probe 失败时明确硬停写入型 `md-swarm` / `md-iterate`,并链接 OpenAI 上游回归 [openai/codex#21639](https://github.com/openai/codex/issues/21639)。
- Codex 已显示 Active/Trusted 但真实动作仍落盘时,不再循环建议重装、Trust、重启;改为切换到已通过双 DENY 的宿主。
- `probe_live_hooks.py --selftest` 新增失败指引回归断言,防止未来重新引入“重启循环”。
- README、INSTALL、用户手册与 v0.11.1 发布说明同步澄清:v0.11.1 修复的是事件形状适配,不能修复宿主未调度 Hook 的上游故障。

## [v0.11.1] - 2026-07-28

### Codex Desktop 工具形状兼容 + Claude runner 加固

*(EN: recognize Codex Desktop's real apply_patch/shell_command events while preserving Claude Code's PowerShell hook layer through the shell-neutral runner.)*
*(EN: recognize Codex Desktop's apply_patch/shell_command payload shapes when the host dispatches hooks, while preserving Claude Code's PowerShell hook layer through the shell-neutral runner.)*

> **2026-07-28 勘误:** 本版本修复的是 Codex 事件形状/参数适配,不能修复 Codex Desktop 自身未调度 Hook 的上游回归。物理保护是否可用只认 current-session live-probe 的两个明确 DENY;详见 v0.11.2 与 [openai/codex#21639](https://github.com/openai/codex/issues/21639)。

- Codex policy 兼容 FREEFORM `apply_patch` 与 `shell_command`,并用真实事件形状补回归测试。
- Codex 安装 matcher 同步覆盖动态工具名;live-probe 与 preflight 改为跨 harness 提示。
Expand Down Expand Up @@ -65,6 +78,8 @@
- 锁定版 pandoc 工具链一键安装(pandoc 3.9.0.2 + pandoc-crossref 0.3.24a,版本配套、自动下载)。
- 附:中文用户完全手册、Apache-2.0 许可、NOTICE 第三方声明。

[未发版 / Unreleased]: https://github.com/pwya/md-paper/compare/v0.11...HEAD
[未发版 / Unreleased]: https://github.com/pwya/md-paper/compare/v0.11.2...HEAD
[v0.11.2]: https://github.com/pwya/md-paper/compare/v0.11.1...v0.11.2
[v0.11.1]: https://github.com/pwya/md-paper/compare/v0.11...v0.11.1
[v0.11]: https://github.com/pwya/md-paper/compare/v0.1...v0.11
[v0.1]: https://github.com/pwya/md-paper/releases/tag/v0.1
20 changes: 19 additions & 1 deletion INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ The installer deploys one shared policy core to `~/.md-paper/hooks/md_hook_polic
- **OpenCode**: installs `~/.config/opencode/plugins/md-paper.js`, using `tool.execute.before` to call the same policy core.
- **Hermes / other agents**: no adapter yet; use the rules below.

> **Known Codex upstream regression (current as of 2026-07-28):** recent
> Codex Desktop and some non-interactive CLI builds can discover a hook, show it
> as Active/Trusted, yet never dispatch the handler. See
> [openai/codex#21639](https://github.com/openai/codex/issues/21639). Registration,
> Trust, restart, and a passing policy `--selftest` are not session-level proof.
> For write-heavy `md-swarm` / `md-iterate`, only two explicit DENY results from
> the live probe count.

These hooks are **layer 2**. Layer 1 remains load-bearing: single-writer apply + citation/uniqueness/order gates. Codex's own documentation also describes current `PreToolUse` interception as a guardrail rather than a complete enforcement boundary, so keep [AGENTS.md](AGENTS.md) in every paper project:

1. The rules in [AGENTS.md](AGENTS.md) — Codex / OpenCode / Hermes read that file automatically as workspace instructions.
Expand Down Expand Up @@ -128,6 +136,16 @@ For the session-level proof, run `md-swarm/probe_live_hooks.py --prepare`, perfo
the two printed real tool calls, and require both to be explicitly **DENIED**.
The filesystem `--check` result alone is not sufficient.

If either real action lands:

1. Stop all write-heavy md-paper work in that harness.
2. If the adapter is missing or untrusted, install/review it once and open a
fresh session.
3. If `/hooks` already shows Active/Trusted, **do not loop reinstall, Trust, or
restart**. Treat it as the upstream dispatch regression, switch to a harness
that passes both DENY checks (currently Claude Code is recommended), and
retest Codex only after its runtime or hook configuration actually changes.

**OpenCode:** restart it (local plugins load at startup), then check the same core:

```powershell
Expand Down Expand Up @@ -161,7 +179,7 @@ Run Steps 1–5 above yourself in PowerShell, substituting the cloned repo path

- **Claude Code** — skills auto-load, plus the established protection hooks (layer 2).
- **OpenCode** — reads `~/.claude/skills` natively; the installed local plugin supplies a best-effort layer-2 guard.
- **Codex** — junction into `~/.codex/skills`; `hooks.json` supplies a best-effort layer-2 guard after `/hooks` trust review.
- **Codex** — junction into `~/.codex/skills`; `hooks.json` supplies a conditional best-effort layer-2 guard after `/hooks` trust review. Current Desktop builds may not dispatch trusted hooks at all ([upstream #21639](https://github.com/openai/codex/issues/21639)); require two live DENY results before write-heavy use.
- **Hermes Agent** — junction into `~/.hermes/skills` (Step 2). Compatible with the agentskills.io standard; supports `AGENTS.md` workspace instructions.
- **Any other agent** — the five `SKILL.md` files are plain Markdown runbooks and every pipeline step is an ordinary CLI script (`py md-swarm\apply_md_changeset.py …`, `powershell md-build\build.ps1 …`). Tell the agent to read the relevant `SKILL.md` and follow it.
- **Safety model everywhere**: the load-bearing protection is **layer 1, inside the scripts** — `apply_md_changeset.py` is the single writer of `manuscript.md`, with citation / uniqueness / order gates. Harness hooks/plugins are an additional best-effort layer 2; keep the [AGENTS.md](AGENTS.md) iron rules in front of every agent.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ flowchart LR
### 已知限制

- **仅支持 Windows + Microsoft Word** —— `md-unpack` 靠 Word COM,macOS 暂不支持。
- **Codex Desktop 的 Hook 调度存在上游回归** —— 当前部分 Codex Desktop / 非交互 CLI 版本会显示 Hook 已 Active/Trusted,却不真正执行处理器([openai/codex#21639](https://github.com/openai/codex/issues/21639))。在 Codex 中运行写入型 `md-swarm` / `md-iterate` 前,必须亲眼看到 current-session live-probe 两个动作都 DENY;否则切换到已通过验证的宿主,当前推荐 Claude Code。
- *其他细微限制(引用来源、页码定位、个别转义、浮动图、老 AxMath 公式)未在此列出,见[用户完全手册](md-技能套件·用户完全手册.md)。*

### 许可
Expand Down Expand Up @@ -282,6 +283,7 @@ flowchart LR
### Known Limitations

- **Windows + Microsoft Word only** — `md-unpack` drives Word via COM; macOS is not supported yet.
- **Codex Desktop has an upstream Hook-dispatch regression** — some current Codex Desktop / non-interactive CLI builds report Hooks as Active/Trusted without invoking the handler ([openai/codex#21639](https://github.com/openai/codex/issues/21639)). Before any write-capable `md-swarm` / `md-iterate` run in Codex, require both current-session live-probe actions to DENY; otherwise switch to a verified host, currently Claude Code.
- *Other minor limitations (citation providers, page locators, escaping edge cases, floating figures, legacy AxMath equations) are not listed here — see the [User Guide](md-技能套件·用户完全手册.md).*

### License
Expand Down
2 changes: 1 addition & 1 deletion md-swarm/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ allowed-tools: [Read, Write, Edit, PowerShell, Bash, Grep, Glob, Agent, AskUserQ
> ```
> 然后**按脚本打印的 ACTION 1/2 原样做**:Claude Code 用 Write/Edit + PowerShell/Bash;Codex 用 apply_patch + shell_command。先尝试写临时 `manuscript.md`,再尝试 apply 临时 `机改` changeset;必须亲眼看到两次都被 DENY,再跑脚本打印的 `--check` 和 `--cleanup`。
>
> ⛔ 弱模型适配铁律:**不许只读这个脚本、不许直接调用 hook `.ps1`、不许把 `--check` 的“没落盘”当成已通过**;`--check` 只能发现“真的落盘了”的失败,不能区分 DENY 和你偷懒没做。没看到两个 DENY → 停下:Claude Code 重跑 `verify_hooks.ps1` 并新开会话;Codex 重跑 `setup_all_hooks`、在 `/hooks` 复核 Trust 并重启 Codex;然后重跑 live-probe。
> ⛔ 弱模型适配铁律:**不许只读这个脚本、不许直接调用 hook `.ps1`、不许把 `--check` 的“没落盘”当成已通过**;`--check` 只能发现“真的落盘了”的失败,不能区分 DENY 和你偷懒没做。没看到两个 DENY → **硬停,不运行任何写入型 md-swarm/md-iterate**。Claude Code 重跑 `verify_hooks.ps1` 并开全新会话;Codex 只在缺安装/缺 Trust 时各补一次。若 `/hooks` 已显示 Active/Trusted 而真实动作仍落盘,**不得循环重装、Trust、重启**:这是 Codex 已知的上游 Hook 调度回归(<https://github.com/openai/codex/issues/21639>),切换到已亲眼通过双 DENY 的宿主(当前推荐 Claude Code),待宿主版本或配置真正变化后再复测。

## Phase 2 总流程(并行起草 + 确定性落盘)

Expand Down
9 changes: 6 additions & 3 deletions md-swarm/preflight.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,12 @@ def gate(mode='block', context='', allow_no_hooks=False, dry=False, no_heal=Fals
if res['ok']:
print(' => protection hooks registered.')
if not in_claude_code():
print(' (NOTE: this session is NOT Claude Code -- registered hooks never fire')
print(' here. Layer-1 guards (single-writer apply + citation gates) are the')
print(' active protection. Never write manuscript.md directly.)')
print(' (NOTE: this audit covers Claude registration only; it cannot prove')
print(' Codex/OpenCode adapter dispatch. Require both current-session live')
print(' probe actions to DENY before write-heavy md-swarm/md-iterate. If an')
print(' Active/Trusted Codex adapter still lets either action land, stop; do')
print(' not loop reinstall/Trust/restart. See openai/codex#21639.)')
print(' Layer-1 guards (single-writer apply + citation gates) remain mandatory.')
return 0
print(' (NOTE: REGISTRATION only -- not a proof THIS session fires them. A snapshot')
print(' taken before the last hook change can still be stale.)')
Expand Down
30 changes: 27 additions & 3 deletions md-swarm/probe_live_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
PROTECT_BAD = "PROTECT_HOOK_PROBE_WRITE_SHOULD_NOT_LAND\n"
GATE_BAD = "GATE_HOOK_PROBE_APPLY_SHOULD_NOT_LAND\n"
STATE_REL = Path("swarm") / "live_hook_probe_state.json"
CODEX_HOOK_REGRESSION_URL = "https://github.com/openai/codex/issues/21639"


def suite_root():
Expand Down Expand Up @@ -175,12 +176,25 @@ def check(root):

print("")
print("RESULT: FAIL -- current-session hook layer is not live.")
print(" Claude Code: run verify_hooks.ps1, then open a brand-new session.")
print(" Codex: rerun setup_all_hooks, review/trust it in /hooks, then restart Codex.")
print(" Rerun this live probe before md-swarm/md-iterate writes.")
for line in failure_guidance():
print(line)
return 1


def failure_guidance():
"""Return fail-loud remediation shared by runtime output and self-test."""
return [
" STOP: do not run md-swarm/md-iterate writes in this harness.",
" Claude Code: run verify_hooks.ps1, then open a brand-new session.",
" Codex: install/review Trust once if missing. If already Active/Trusted,",
" do NOT loop reinstall/Trust/restart; current Codex builds have",
" a known upstream hook-dispatch regression:",
" " + CODEX_HOOK_REGRESSION_URL,
" Switch to a harness where both live actions explicitly DENY.",
" Re-run only after the host/runtime or hook configuration actually changes.",
]


def cleanup(root):
root = Path(root).resolve()
if root.exists():
Expand All @@ -205,6 +219,16 @@ def selftest():
if check(root) == 0:
print("[FAIL] gate failure should be detected")
return 1
guidance = "\n".join(failure_guidance())
if CODEX_HOOK_REGRESSION_URL not in guidance:
print("[FAIL] Codex regression URL missing from failure guidance")
return 1
if "do NOT loop reinstall/Trust/restart" not in guidance:
print("[FAIL] failure guidance can regress into the reinstall/restart loop")
return 1
if "Switch to a harness where both live actions explicitly DENY" not in guidance:
print("[FAIL] failure guidance does not provide a safe host fallback")
return 1
print("=== selftest: ALL PASSED ===")
return 0
finally:
Expand Down
6 changes: 3 additions & 3 deletions md-技能套件·用户完全手册.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
> 本手册写给**作者(用户)**:不用懂代码,读完就能独立完成"原稿摄取 → AI 批量改稿 → 出带活 Zotero 域的 Word"全流程。
> 各技能的完整行为定义在其各自的 `SKILL.md`(随技能一起安装)。
>
> **建立**:2026-06-17 · **版本**:v0.11.1
> **建立**:2026-06-17 · **版本**:v0.11.2

---

> ⚠️ **内测用户须知(用之前先看这三条,能省掉绝大多数"怎么坏了"的麻烦)**
>
> 1. **只在 Windows + 装了 Microsoft Word 的电脑上用。** 摄取原稿要调 Word(Mac 暂不支持);路径含中文/空格时,让 AI 用 PowerShell 工具跑脚本,**别用 Bash**(会乱码失败)。
> 2. **第一次用,必须先确认两个"防护钩子"真生效了,再开始改稿。** 这俩钩子是防止 AI 改稿时把你的引用/正文改丢的命脉闸——没装上 = 没保护,而且**不报警**。装法见仓库根目录的 `INSTALL.md`,装完**新开一个 Claude 会话**再跑 `md-swarm\verify_hooks.ps1`,要看到 **6/6 green** 才算数;看不到 = 钩子没生效,**先别改稿**,照该节排查(junction 在不在 / settings.json 注册没 / 重启 Claude Code 没 / `.ps1` 是不是 UTF-8 带 BOM)。**⚠️ "重启 Claude Code" 这步特别容易做错**:在 VS Code 里要**新开一个 Claude 对话**,不是关掉面板再打开(重开若恢复了旧会话、钩子还是没加载);`/clear` 对钩子不可靠、别用它充重启。
> 2. **第一次用,必须先确认两个"防护钩子"真生效了,再开始改稿。** 这俩钩子是防止 AI 改稿时把你的引用/正文改丢的命脉闸。静态检查通过不等于当前会话真会拦截:Claude Code 先跑 `md-swarm\verify_hooks.ps1`,确认 **6/6 green**,再跑 current-session live-probe,且两个动作都必须明确 **DENY**。Codex 当前存在上游 Hook 调度回归([openai/codex#21639](https://github.com/openai/codex/issues/21639)):即使显示 Active/Trusted,处理器也可能根本没执行。若 Codex live-probe 没有两个 DENY,**立即停止写入型 `md-swarm` / `md-iterate`,不要循环重装、Trust 或重启**;切换到已通过 live-probe 的宿主,当前推荐 Claude Code。
> 3. **这几类稿子现在还处理不了,别拿它们来试,否则会出坏稿:**
> - **AxMath 编辑的公式**:会变成 `$$\text{[TODO 重输 LaTeX]}$$` 占位,需你手动补 LaTeX(Word 原生公式不受影响)。
> - **行内公式 / 同行排多个图**:可能在 Word 里显示成字面 `[EQ-2]`。
Expand Down Expand Up @@ -241,7 +241,7 @@ powershell -ExecutionPolicy Bypass -File "%USERPROFILE%\.claude\skills\md-build\

整套是五个标准 Agent Skill(`md-unpack`/`md-triage`/`md-swarm`/`md-iterate`/`md-build`,[agentskills.io](https://agentskills.io) 开放格式),自然语言驱动、可自由组合:大改走 triage + swarm、小修走 iterate、随时 build 出稿。没有 GUI、没有要背的菜单——你只管说要干什么。

为 **Claude Code** 深度打造("保护钩子"这层物理防线仅 Claude Code 有);同时兼容 **Codex / OpenCode / Hermes Agent** 等支持 Agent Skills 开放标准的工具——OpenCode 原生就会读 `~/.claude/skills`,Codex 用 `~/.codex/skills`,Hermes 用 `~/.hermes/skills`。非 Claude Code 环境没有钩子这层,防护由脚本内置闸门(单写者 apply + 引用不删)+ 仓库根 `AGENTS.md` 守则承担;`preflight.py` 会自动识别非 Claude Code 会话,提示而不拦路。装法见 `INSTALL.md` 第 2 步。
为 **Claude Code** 深度打造,同时兼容 **Codex / OpenCode / Hermes Agent** 等支持 Agent Skills 开放标准的工具——OpenCode 原生读取 `~/.claude/skills`,Codex 使用 `~/.codex/skills`,Hermes 使用 `~/.hermes/skills`。Codex / OpenCode 的原生适配器只是可选的第二层保护;是否真的生效,只认当前会话 live-probe 的结果。Codex 当前有上游 Hook 调度回归([openai/codex#21639](https://github.com/openai/codex/issues/21639)),Active/Trusted 不是执行证明。未获得两个 DENY 时,不得运行写入型 `md-swarm` / `md-iterate`;应切换到已通过验证的宿主。所有宿主仍必须遵守脚本内置闸门(单写者 apply + 引用不删)和仓库根 `AGENTS.md`。装法见 `INSTALL.md` 第 2 步。

---

Expand Down
Loading