# Markdown Formal

面向数学和技术长文的 Markdown Preview 扩展与本地 CLI：源码里保留稳定 hash ID，工具负责渲染编号、引用、定义查询、符号表、依赖图、AI artifacts 和发布导出产物。

## Metadata

- HTML: https://glenzli.com/projects/markdown-formal/
- Markdown: https://glenzli.com/projects/markdown-formal.md
- Collection: Projects
- Language: zh-CN
- Published: 2026-07-03
- Status: active
- Tags: markdown, math-writing, vscode, references, cli

## Content

Markdown Formal（包名 `markdown-formal`）是一个兼容 VS Code Markdown Preview 的扩展和本地 CLI，用于长期维护数学或技术类 Markdown 书稿。它不要求作者手工维护“定理 2.3”“公式 (4.1)”这类读者编号，而是在源码里保存稳定的 hash ID，再由工具渲染面向读者的编号、引用、导航、定义查询、符号表、依赖图和发布产物。

它的设计重点是 AI 辅助写作。AI 写作时使用轻量的 `tmp-*` 占位，CLI 在 `finish` 阶段把临时 ID 固化为稳定 `h-*` hash；`verify` 再检查断裂引用、残留临时 ID、迁移遗留和生成 metadata 的一致性。

## 项目入口

  ![markdown-formal 将 Markdown 源码中的稳定引用编译为预览和发布产物](/images/projects/markdown-formal-banner.png)

## 它解决什么问题

    **稳定编号**
    章节、小节、命题类对象、公式、图和表在源码里使用 `#h-...`，读者看到的编号由工具根据结构生成。

    **可重排引用**
    正文引用使用 `@h-...`、`@h-....title` 或 `@h-....full`，章节插入、删除和重排后不需要人工改编号。

    **定义和符号查询**
    定义不进入编号系统；标准定义自动扫描，项目特有 LaTeX 记号由 `.markdown-formal/symbols.json` 管理。

    **结构校验和导出**
    `prepare` 生成 reference map、preview cache 和依赖图；`verify` 做严格检查；导出时先降级为普通 Markdown，再进入 PDF 或项目发布流程。

这个项目的边界也比较明确：它不是论文排版系统，也不替代证明检查器。它负责维护 Markdown 书稿里的编号、引用和结构 metadata，让人和 AI 都能在同一套稳定引用上工作。

## 界面预览

  ![markdown-formal 多卷章节导航、目录、符号表和定义搜索界面](/images/projects/markdown-formal-navigation.png)
  预览工具栏提供返回、章节导航、目录、当前页符号表和定义搜索；多卷结构会自然折叠成卷到章的导航层级。

  ![markdown-formal 引用 recall 预览](/images/projects/markdown-formal-recall-preview.png)
  正文里的 `@h-...` 引用会渲染为当前编号，并支持就地 recall 预览，同时保留 Markdown 和 LaTeX 的源码可读性。

## Source 到 Output

下面的片段来自项目自带的 `examples/book1` 和生成的 `.markdown-formal/` 报告。重点不是“怎么写得更花”，而是看源码如何保留稳定标识，工具又能从中生成哪些可审查的结构信息。

      **源码保留稳定 ID，读者编号由工具生成**
      作者写 hash 引用，预览和导出时再渲染为当前章节里的编号。

    Source: `examples/book1/02-core-theorems.md`

```markdown
## #h-67631f13c67a6098 主要结论

定理 #h-5815f80196c52eef（算子网络演化定理）：如果一个算子网络满足 @h-70c80dc9769686c0.title 中的所有条件，那么该网络的长时间演化状态必收敛于唯一的定态。

公式 #h-1f4b6c2d8e0a9b71：
$$
\rho(T_G) \leq \max_{\gamma} w(\gamma) < 1
$$

图 #h-5c9e1b7a3d2f0e64（反馈环示意）：每个闭合反馈环 $\gamma$ 的权重 $w(\gamma)$ 都贡献到 @h-1f4b6c2d8e0a9b71 的上界。
```

    Generated reference map

```markdown
| Display | ID | Title | Location |
| --- | --- | --- | --- |
| § 2.2 | `h-67631f13c67a6098` | 主要结论 | `examples/book1/02-core-theorems.md:13` |
| 定理 2.2 | `h-5815f80196c52eef` | 算子网络演化定理 | `examples/book1/02-core-theorems.md:17` |
| 公式 (2.1) | `h-1f4b6c2d8e0a9b71` |  | `examples/book1/02-core-theorems.md:23` |
| 图 2.1 | `h-5c9e1b7a3d2f0e64` | 反馈环示意 | `examples/book1/02-core-theorems.md:30` |
```

源码里的 hash 不关心“这是第几章第几个定理”。章节结构变化以后，reference map 重新计算显示编号，正文引用仍然指向同一个对象。

      **AI 写作先用 tmp，工具负责固化**
      新增对象不让 AI 手工编 hash，避免生成一个看起来像 ID、实际不可追踪的字符串。

    Draft

```markdown
# #tmp-1 测度论基础

## #tmp-2 弱收敛

定义（紧族）：一族概率测度称为紧族，如果 ...

定理 #tmp-3（Prokhorov 判据）：设 \(\mathcal{P}\) 为一族概率测度。

证明：...

该结论由 @tmp-3 得到。
```

    After `finish`

```markdown
# #h-0c9a8d1f67e42a30 测度论基础

## #h-8a7f22b9c1d0e366 弱收敛

定义（紧族）：一族概率测度称为紧族，如果 ...

定理 #h-3f7a1c9d5b0e72aa（Prokhorov 判据）：设 \(\mathcal{P}\) 为一族概率测度。

证明：...

该结论由 @h-3f7a1c9d5b0e72aa 得到。
```

`#h-...` 和 `#tmp-*` 是声明语法，只出现在编号对象的位置；正文里使用 `@h-...` 引用。这个区别让迁移和校验可以非常直接。

      **依赖图来自显式引用**
      工具不会猜数学含义，只把命题、引理、定理、推论之间的显式 `@h-...` 关系写成图。

    Graph commands

```bash
npm run formal -- graph summary
npm run formal -- graph focus <h-id> --depth 2
npm run formal -- graph impact <h-id>
npm run formal -- graph upstream <h-id>
npm run formal -- graph matrix chapter
```

    Generated graph report

```markdown
# Dependency Graph Report

Nodes: 34
Explicit edges: 29
Statement edges: 26
Proof edges: 3
Cross-chapter edges: 17
Cross-volume edges: 6
Cycles: 1

High Incoming Dependencies:
- 引理 2.1 网络边界算子引理
- 定理 2.2 紧生成下降定理
- 定理 3.2 模空间粘合定理
```

这不是自动证明。它更像结构审计：当你要改一个关键引理时，可以先看 downstream impact，知道哪些章节和结论会被牵动。

      **定义、符号和预览缓存分开维护**
      标准定义自动扫描，非标准边界、别名和项目记号再进入显式 metadata。

    Definition and symbol metadata

```json
[
  {
    "term": "有界算子",
    "aliases": ["bounded operator"],
    "source": "book/01-foundations.md:42",
    "content": "有界算子是满足 \\(\\|Tx\\|\\le C\\|x\\|\\) 的线性映射。"
  }
]
```

```json
[
  {
    "pattern": "\\operatorname{Spec}(${operator})",
    "meaning": "匹配到的算子的谱。",
    "scope": "book"
  }
]
```

    Generated files

```text
.markdown-formal/reference-map.md
.markdown-formal/preview-cache.json
.markdown-formal/dependency-graph.json
.markdown-formal/dependency-report.md
.markdown-formal/report.md
.markdown-formal/audit.md
.markdown-formal/definitions.json
.markdown-formal/symbols.json
```

定义不强行变成编号对象，符号表也只收项目特有记号；这样可以避免把每个变量、每个解释句都变成维护负担。

## 正常工作流

| 阶段 | 命令 | 作用 |
| --- | --- | --- |
| 安装开发依赖 | `npm install && npm run build` | 构建 VS Code 扩展、CLI 和 preview webview。 |
| 接入写作项目 | `node tools/markdown-formal/out/cli/formal-tools.js` | 目标项目 vendoring CLI，并维护自己的 `.markdown-formal/` metadata。 |
| npm CLI 安装 | `npm install -D markdown-formal` | 通过 npm 在项目脚本里使用 `markdown-formal` 命令。 |
| 写作前准备 | `npm run formal -- prepare` | 生成 reference map、agent guide、preview cache 和依赖图。 |
| 编辑后收束 | `npm run formal -- finish path/to/chapter-or-dir` | 固化 `tmp-*`，刷新报告并检查工作区。 |
| 提交前校验 | `npm run formal -- verify` | 检查断裂引用、残留临时 ID、迁移遗留和 metadata 一致性。 |
| 发布导出 | `export-md` / `export-md-split` / `export-pdf` | 先把 formal source 降级成普通 Markdown；PDF 导出支持封面、出版元数据页和前置声明页。 |

## AI artifacts 与文档产物

Markdown Formal 不提供自动安装的远端 skill，而是把可审阅的 AI 工作流 artifact 随 release bundle 或 npm 包一起发布。

| 入口 | 用法 |
| --- | --- |
| `skills/editor.md` | 详细 AI 写作规则，适合融合进目标项目的 `AGENTS.md`、写作 skill 或项目指南。 |
| `skills/integrator.md` | AI 组合指导 artifact，用于把 Markdown Formal 规则接入既有写作流程。 |
| `vasm-catalog/vasmc-catalog.yaml` | 给 VASMC 项目锁定消费的 catalog exports，让 consumer lockfile 固定 artifact hashes。 |
| `node_modules/markdown-formal/skills/` | npm 安装后可读取的 skills 路径。 |
| `node_modules/markdown-formal/vasm-catalog/` | npm 安装后可读取的 VASMC catalog 路径。 |

CLI 可以打印当前安装位置：

```bash
npm run formal -- paths
```

公开文档的维护源在 `docs-src/**/*.vasm.md`，目标项目 AI skill 的维护源在 `skills-src/**/*.vasm.md`。生成产物包括 `README.md`、`docs/*.md`、`skills/*.md` 和 `vasm-catalog/`。修改文档或 skill source 后运行：

```bash
npm run content:build -- --dry-run
npm run content:build
```

`--plan` 是 `--dry-run` 的别名，只查看计划，不写生成物、build-state 或默认 report。提交前再读取 `.vasmc/build-report.yaml`，完成 translate 或 review action。

## Release 包

```text
dist/
  markdown-formal-<version>.vsix
  extension/
  cli/
  skills/
  vasm-catalog/
  docs/
  README.md
  LICENSE
  INSTALL.md
  manifest.json
  checksums.txt
```

VSIX 用于编辑器安装，`cli/` 用于目标项目本地 vendoring，npm 包用于 `markdown-formal` CLI 安装，`skills/` 是需要审阅和融合的 AI artifact。发布前门禁是 `npm run release:check`；混合发布由 `npm run release` 编排 GitHub、GitLab 和 npm。

## 适合的场景

Markdown Formal 适合需要长期维护、经常重排、并且内部引用密集的文档：数学书稿、技术讲义、形式化程度较高的研究笔记、多卷技术手册，以及由 AI 参与编辑的长篇 Markdown 项目。

它不适合短文章或一次性说明文。短文直接用普通 Markdown 更省事；只有当“编号、引用、定义、符号、依赖和导出”已经开始互相牵制时，这套工具才会明显降低维护成本。
