# Ddev Arch

> 【禁止自动加载 — 不可被「技能强制评估」自动匹配】仅限用户手动调用。初始化项目级长期架构规范文档，建立模块边界、依赖规则和变更门禁，约束后续代码修改范围。

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

---


# 项目架构规范初始化

## 定位

这是**项目级架构边界契约**，目标是让 AI（和人）在修改代码前知道：模块职责是什么、边界在哪里、哪些依赖允许、哪些改动会破坏架构。

- 每个模块独立成文，必须讲清楚：**模块负责什么、不能负责什么、允许依赖谁、对外暴露什么**
- `仓库目录映射` 服务于架构约束：帮助 AI 把改动限制在正确模块内
- 文档要能回答"这次代码改动是否越界"，而不是只回答"代码在哪里"

## 与实现架构的区别

- **本 skill**：初始化项目级长期架构规范，产出稳定的模块边界、依赖规则和变更门禁。它约束后续所有代码修改。
- **`ddev-spec`**：针对某一次代码改动，编写临时实现架构文档。它必须读取并遵守本 skill 产出的项目级架构规范。

## 触发条件

- 新项目启动，需要建立长期架构规范
- 现有项目缺少架构约束文档，需要补建
- 用户明确要求"写架构文档"且不是针对某次代码改动
- 用户希望约束 AI 后续改代码范围，避免破坏既有架构

## 探索要求

1. 先并行分发多个子代理，从目录结构、构建目标、入口调用链、公共接口和数据所有权等视角探索仓库，收集模块边界候选。
2. 再根据识别出的功能模块，并行分发多个子代理分别深入探索各模块，补齐职责、边界、对外接口、依赖方向、状态所有权和关键数据结构。
3. 汇总所有子代理结果后，再统一写架构总览、模块规范文档和 `AGENTS.md`，不要在探索完成前提前定稿。

## 基本流程

1. 按"探索要求"探索仓库，先判定是否为多独立代码单元仓库（见"模块边界识别"规则 0），再形成模块候选、职责候选和依赖候选
2. **多单元仓库**：先写顶层 `00_仓库集成架构.md`（按"仓库集成架构模板"），再为每个独立代码单元写各自的 `01_架构总览.md` 和模块文档。**单单元仓库**：直接写 `01_架构总览.md`（按"单单元架构总览模板"）。**技术栈字段必须填写实际检测到的语言**，后续步骤以此为分流依据
3. 为每个模块写独立规范文档，按"模块规范模板"编写；多单元仓库时模块文档放在对应单元的子目录下
4. 需要图示时，按 ddev-diagram 规范手写 ASCII 到 `.md`，图附近标注用途说明
5. **项目依赖与封装审计**：根据各单元 `01_架构总览.md` 中声明的技术栈，按 [lang-audit-matrix.md](references/lang-audit-matrix.md) 分流到对应的审计策略（详见下方"项目依赖与封装审计"章节）。多单元仓库时，每个单元独立产出审计文档（放在各自子目录下）
6. **构建变体与环境审计**：根据各单元 `01_架构总览.md` 中声明的技术栈，按 [lang-audit-matrix.md](references/lang-audit-matrix.md) 分流到对应的审计策略（详见下方"构建变体与环境审计"章节）
7. 按"AGENTS.md 规则注入"章节的写入策略，将架构规范读取和变更门禁规则写入仓库根目录的相应配置文件（`AGENTS.md` 或 `CLAUDE.md`）
8. 全部完成后做验收检查（见"验收标准"）

## 模块边界识别

按以下优先级判定模块边界：

0. **独立代码单元检测**（最高优先级）：先判断仓库是否包含多套独立编译、无源码交叉引用的代码单元——
   - **异构多核**：同一芯片的不同核心（如 ARM A7 + RISC-V E907），各自有独立 OS、独立构建系统和入口
   - **多服务/多应用**：同一仓库下多个独立服务或应用，各自有独立构建配置（`CMakeLists.txt`、`Makefile`、`go.mod`、`Cargo.toml` 等）且互不直接源码依赖
   - **多固件镜像**：同一产品线多个独立固件镜像（如 bootloader + RTOS + Linux kernel），各自独立构建
   检测方法：扫描仓库顶层目录，若存在多个不共享构建系统的独立子目录（各自包含独立入口和构建配置），且它们之间无源码级 `#include`/`import` 交叉引用，则判定为多个独立代码单元。**多单元场景下，每个单元独立产出架构文档（各自的结构总览+模块边界），顶层另出 `00_仓库集成架构.md` 描述单元间的交互、数据流和联合构建关系。单单元场景直接走后续 1-7 条规则检测模块边界。**
1. **公开接口边界**：头文件、导出类、路由、命令、服务接口、包入口等对外暴露面，优先作为模块边界依据
2. **目录即模块**：如果仓库已经按目录划分了子系统/组件，直接以目录为模块单位
3. **数据所有权**：谁拥有关键状态、配置、缓存、设备句柄、数据库表或领域对象，谁就是对应职责的主模块
4. **入口文件回溯**：找 `main()`、`app init`、注册函数等入口，反向追踪调用链来聚合文件
5. **独立构建目标**：如果某目录有独立的 `CMakeLists.txt`、`Makefile`、`Cargo.toml` 等，就是一个模块
6. **平铺文件兜底**：如果几十个文件平铺在一个目录里，按功能前缀分组（如 `uart_*.c`、`spi_*.c`、`auth_*.py`、`handler_*.go`），每组为一个模块
7. **嵌套处理**：模块内若有明显的子模块边界（如 `module/sub_a/`、`module/sub_b/`），子模块独立成文，编号用两级序号（如 `02-01_子模块名.md`）

不确定边界时，宁可先拆小并写明"边界待确认"，不要把多个职责合成一个大模块。

## 文档目录规划

所有模块统一单文件，只包含架构约束内容。

### 单代码单元（默认）

仓库只包含一套代码时，采用扁平结构：

```
docs/architecture/
├── 01_架构总览.md                # 项目简介、架构原则、依赖规则、变更门禁、模块列表
├── stdlib-wrappers.md             # [C/C++ 项目] 标准库函数替代封装 API 参考
├── dependency-audit.md            # [非 C 项目] 依赖审计报告
├── modules/
│   ├── 02_<模块名>.md             # 模块约束：职责+边界+接口+依赖+状态所有权+修改范围+检查清单
│   ├── 03_<模块名>.md
│   └── 03-01_<子模块名>.md       # 子模块
└── diagrams/                      # 架构图文件（手写 ASCII 到 .md）
    └── *.md
```

### 多独立代码单元

仓库包含多套独立编译、互不源码依赖的代码单元时（异构多核、多服务/多应用、多固件镜像等），每单元独立出架构文档，顶层放单元间集成架构：

```
docs/architecture/
├── 00_仓库集成架构.md              # 各单元间的交互关系、数据流、通信协议、联合构建与部署
├── <unit_a>/                       # 独立代码单元 A（以单元实际目录名或简称命名，如 linux-4.9、melis-v3.0）
│   ├── 01_架构总览.md
│   ├── stdlib-wrappers.md          # 或 dependency-audit.md（按各单元语言独立审计）
│   ├── modules/
│   │   └── 02_<模块名>.md
│   └── diagrams/
├── <unit_b>/                       # 独立代码单元 B
│   ├── 01_架构总览.md
│   ├── modules/
│   └── diagrams/
└── ...
```

> **判定标准**：独立代码单元 = 有独立的构建系统入口 + 不与其他单元的源码发生 `#include`/`import` 交叉引用。各单元的依赖审计（`stdlib-wrappers.md` 或 `dependency-audit.md`）在各自子目录下独立产出。

## 项目依赖与封装审计

在写架构文档之后，必须对工程的依赖和封装做审计。审计策略依赖 `01_架构总览.md` 中声明的技术栈。

### ⚠️ 硬门禁：审计前必须先读取 lang-audit-matrix.md

**进入分流决策前，必须用 `Read` 读取 `references/lang-audit-matrix.md`，根据技术栈确定审计策略。禁止凭记忆或猜测选择审计方案。**

### 分流决策

主 agent 读取 `01_架构总览.md` 的「技术栈」字段，判断项目语言：

- **C 项目** → 执行下方「C 语言标准库替代函数审计」（完整流程，2 轮 + stdlib-wrappers.md）
- **C++ 项目** → 执行 C 标准库审计子集 + STL 策略审计
- **Rust / Go / Python / TS / JS / Java** → 执行「非 C 语言依赖审计」（简化流程，单轮 + dependency-audit.md）
- **Generic** → 记录依赖清单文件路径，不做深度审计

### C 语言标准库替代函数审计

当项目语言为 C 时执行。目标：让后续所有编码和审查工作都知道"这个工程对每个标准库函数有没有自己的封装、有的话应该用哪个"。

**审计目标仅为发现工程封装，产出 API 参考文档，不调查裸调现状。**

#### 审计流程（反复审查直到无新发现）

##### 第一轮：全量扫描

主 agent 拉独立子代理，按以下搜索范围全量扫描工程：

**搜索范围（按函数类别）：**

| 类别 | 标准库函数 |
|------|-----------|
| 内存分配 | `malloc`, `calloc`, `realloc`, `free` |
| 字符串操作 | `strcpy`, `strncpy`, `strcat`, `strncat`, `strlen`, `strcmp`, `strncmp`, `strstr`, `strchr`, `strrchr`, `strdup` |
| 格式化 | `sprintf`, `snprintf`, `vsprintf`, `vsnprintf`, `sscanf` |
| 内存操作 | `memcpy`, `memmove`, `memset`, `memcmp`, `memchr` |
| 文件 I/O | `fopen`, `fclose`, `fread`, `fwrite`, `fprintf`, `fscanf`, `fgets`, `fputs`, `fseek`, `ftell`, `remove`, `rename` |
| 标准输出 | `printf`, `puts`, `putchar` |
| 通用工具 | `atoi`, `atol`, `strtol`, `strtoul`, `abs`, `rand`, `srand`, `qsort`, `bsearch` |
| 断言/终止 | `assert`, `abort`, `exit` |
| 时间 | `time`, `localtime`, `strftime`, `sleep`, `usleep` |

**子代理搜索方法：**

1. 在工程头文件（`*.h`）和源文件（`*.c`）中，对每个标准库函数名做 `grep`，找到：
   - **替代封装**（wrapper）：记录封装函数名、签名、所在文件和行号
2. 对于找到的替代封装，再反向搜索其调用者分布（哪些模块在用这个封装）
3. 识别封装的特征：是否添加了边界检查、错误日志、平台适配、返回值校验等增强
4. **条件编译门控审计**：对每个找到的替代封装，检查其定义和声明是否受条件编译宏（`#if`/`#ifdef`/`#if defined()`）门控：
   - 记录门控宏的名称
   - 记录门控宏的定义位置（文件 + 行号）
   - 判断门控宏的默认开关状态（默认开启 / 默认关闭 / 依赖其他宏）
   - 记录开启和关闭时的行为差异（如：关闭时是否有 fallback 实现、是否降级为空操作、是否导致编译错误）
5. **第三方库检查**：搜索 `thirdparty/`、`third_party/`、`external/`、`lib/` 等目录，识别工程中引入的第三方库（如 FatFs、lwIP、mbedTLS、FreeRTOS 等），检查：
   - 是否有对应的工程适配文件（`*_port.c`、`*_conf.h`、`*_config.h`）注入了工程封装
   - 记录每个第三方库的适配状态：**已适配 / 未适配（需标注风险）**

**子代理输出格式：**

```
## 标准库替代封装审计 — 第 N 轮

### 已发现的替代封装
| 标准库函数 | 工程封装 | 签名 | 所在文件 | 增强特性 |
|-----------|---------|------|---------|---------|
| malloc | os_malloc | void *os_malloc(size_t size) | src/os/heap.c:42 | 内存池、失败日志 |
| free | os_free | void os_free(void *ptr) | src/os/heap.c:78 | 指针置 NULL |

### 本轮尚未覆盖的标准库函数
| 函数 | 原因（未搜索到 或 搜索结果不明确） |
|------|----------------------------------|
```

#### 第二轮及以后：主代理审查 + 补充搜索

1. **主代理审查子代理输出**：
   - 检查是否有遗漏的函数类别
   - 检查子代理的输出中"尚未覆盖"列表是否合理
   - 标注需要进一步确认的项目
2. **主代理补充搜索**：对子代理标注的不确定项，主代理亲自搜索确认
3. **主代理拉新子代理做第二轮**：
   - 针对第一轮遗漏或不确定的类别，做更精确的搜索
   - 搜索范围可以缩小到特定目录或文件
   - 新子代理的输出格式同上
4. **循环终止条件**：
   - 最近一轮子代理输出中"尚未覆盖的标准库函数"列表已验证且无遗漏
   - 主代理确认所有不确定项已解决
   - 至少完成 2 轮（第一轮全量 + 至少一轮补充）

### 产出文档：stdlib-wrappers.md

审计完成后，将所有发现合并写入 `docs/architecture/stdlib-wrappers.md`：

```markdown
# 标准库函数替代封装参考

> 最后审计时间：<日期>
> 审计轮次：<N> 轮
> 本文档由 ddev-arch 标准库审计流程生成，后续所有代码编写和审查必须以此为参考。

## 内存分配

| 标准库函数 | 工程封装 | 签名 | 所在文件 | 说明 |
|-----------|---------|------|---------|------|
| malloc | `os_malloc` | `void *os_malloc(size_t size)` | `src/os/heap.c:42` | 内存池分配，自动对齐 8 字节 |
| free | `os_free` | `void os_free(void *ptr)` | `src/os/heap.c:78` | 回收到内存池，自动置 NULL |
| calloc | `os_calloc` | `void *os_calloc(size_t n, size_t size)` | `src/os/heap.c:65` | 封装 calloc + 零初始化校验 |
| realloc | —（无封装，禁止使用） | — | — | 工程内存池不支持 realloc |

## 字符串操作

| 标准库函数 | 工程封装 | 签名 | 所在文件 | 说明 |
|-----------|---------|------|---------|------|
| ... | ... | ... | ... | ... |

## 格式化

...

## 文件 I/O

...

## 断言

| assert | `MOD_ASSERT` | `#define MOD_ASSERT(expr)` | `include/common/mod_assert.h:15` | 失败时写日志 + 复位 |

## 条件编译门控

> 以下列出所有替代封装依赖的条件编译宏。**使用封装前必须确认对应宏已开启**，否则封装可能降级为 fallback 实现、空操作或导致编译错误。

| 封装函数 | 门控宏 | 定义位置 | 默认状态 | 开启时行为 | 关闭时行为 |
|---------|--------|---------|---------|-----------|-----------|
| `os_malloc` | `USE_OS_HEAP` | `src/config.h:12` | ✅ 开启 | 内存池分配，自动对齐 | fallback 到标准 `malloc` |
| `os_free` | `USE_OS_HEAP` | `src/config.h:13` | ✅ 开启 | 回收到内存池，自动置 NULL | fallback 到标准 `free` |
| —（示例，按实际工程填写） | — | — | — | — | — |

### 门控宏速查表

| 门控宏 | 默认值 | 影响范围 | 定义文件 |
|--------|--------|---------|---------|
| `USE_OS_HEAP` | 开启 | 内存分配/释放全部封装 | `src/config.h:12` |
| —（示例，按实际工程填写） | — | — | — |

## 第三方库适配状态

| 第三方库 | 版本 | 源码目录 | 适配方式 | 适配状态 | 备注 |
|---------|------|---------|---------|---------|------|
| FatFs | R0.14b | `thirdparty/fatfs/` | `ffconf.h` 配置宏 → `os_malloc/os_free` | ✅ 已适配 | — |
| mbedTLS | 3.4.0 | `thirdparty/mbedtls/` | `mbedtls_config.h` → `os_calloc/os_free` | ✅ 已适配 | — |
| lwIP | 2.1.2 | — | — | ⚠️ 未使用 | — |

### 未适配第三方库风险

如果第三方库适配状态为"未适配"：
- 该库的内存分配/文件 I/O/断言可能绕过工程封装体系
- 必须在此标注风险等级和允许的例外范围
- 后续审查中如果发现该库裸调标准库，视为已知风险，不阻塞但必须追踪
```

### 强制约束

- 审计未完成前，不得进入下一步（机型宏扫描）
- 至少完成 2 轮搜索才能定稿
- 最终文档必须覆盖上表中列出的所有标准库函数类别
- 如果某个类别整个工程均未使用（如文件 I/O），也必须在文档中标注"本工程未使用此类函数"
- 所有替代封装必须审计条件编译门控宏，记录宏名、定义位置、默认状态和行为差异
- `stdlib-wrappers.md` 必须包含「条件编译门控」章节和门控宏速查表

### 非 C 语言依赖审计

当项目语言为 C++ / Rust / Go / Python / TS / JS / Java 时执行。目标：记录依赖清单、识别风险依赖、标注关键封装。

#### 审计流程（单轮）

1. **识别依赖清单文件**：定位包管理器配置文件（`Cargo.toml`、`go.mod`、`pyproject.toml`、`package.json`、`pom.xml` 等）
2. **提取依赖树**：解析配置文件，提取直接依赖和版本约束。如果依赖数量 > 50，只记录直接依赖
3. **扫描标准库替代封装**：在项目源码中搜索对标准库函数的封装——
   - C++：自定义 allocator、智能指针策略、异常/RTTI 策略
   - Rust：`unsafe` 封装、自定义 allocator、`no_std` 策略
   - Go：`unsafe`/`cgo` 使用、标准库替代封装
   - Python：C 扩展模块、标准库函数封装（如 `os.path` 封装）
   - TS/JS：polyfill 策略、Node.js API 版本依赖
   - Java：反射/JNI 使用、标准库替代封装
4. **标注风险依赖**：已废弃、有已知漏洞、版本过旧的依赖
5. **产出 `dependency-audit.md`**：包含依赖树 + 关键封装清单 + 风险依赖标注

#### 产出文档：dependency-audit.md

```markdown
# 项目依赖审计

> 最后审计时间：<日期>
> 项目语言：<语言>
> 本文档由 ddev-arch 依赖审计步骤生成。

## 依赖清单

| 包名 | 版本 | 类型 | 用途 | 风险 |
|------|------|------|------|------|
| ... | ... | direct/dev | ... | — / ⚠️ deprecated / 🔴 CVE-xxxx |

## 标准库替代封装

<!-- 列出项目中对标准库的封装函数，无则标注"本项目未使用标准库替代封装" -->
| 标准库函数/类 | 工程封装 | 所在文件 | 增强特性 |
|-------------|---------|---------|---------|

## 风险依赖

<!-- 列出已废弃、有已知漏洞、或版本过旧的依赖 -->
| 包名 | 当前版本 | 风险类型 | 建议操作 |
|------|---------|---------|---------|
```

#### 强制约束

- 非 C 语言审计为单轮，不要求 2 轮循环验证
- 依赖清单至少覆盖所有直接依赖
- 如项目无任何第三方依赖，标注"本项目无第三方依赖"即可
- 如果某个语言的标准库替代封装搜索返回空，标注"本项目未使用标准库替代封装"

### Generic 项目依赖记录

当项目语言为 Generic（无法匹配任何已知语言）时：

1. 记录能找到的所有包管理配置文件路径
2. 记录 vendor / lib / external 等第三方代码目录
3. 产出 `dependency-manifest.md`，仅包含文件路径清单
4. 不做深度审计

## 构建变体与环境审计

在写架构文档之后、注入 AGENTS.md 规则之前，必须审计项目的构建变体和环境配置。审计策略依赖 `01_架构总览.md` 中声明的技术栈，按 [lang-audit-matrix.md](references/lang-audit-matrix.md) 分流。

### 分流决策

主 agent 读取 `01_架构总览.md` 的「技术栈」字段，判断：

- **嵌入式 C/C++ 项目**（存在 `cfg.h`、`VERSION_MAJOR`、`#define MODELNAME` 等信号）→ 执行下方「机型宏扫描与注入」（完整流程）
- **非嵌入式项目（所有语言）**→ 执行「通用构建审计」（简化流程，记录构建命令 + 产物路径 + 环境变量）

### 机型宏扫描与注入（嵌入式 C/C++ 项目）

### 扫描步骤

1. **搜索所有 cfg.h**：`grep -rl "VERSION_MAJOR\|FIRMWARE_VERSION" --include="*_cfg.h"`，列出所有配置头文件
2. **提取每个 cfg.h 中的机型宏**：识别所有 `#define MODELNAME` / `//#define MODELNAME` 对，或 `#define PRINTER_MODEL (N)` 枚举值，或 `#if defined(MODEL)` 分支
3. **提取每个机型的编译指令和产物**：搜索构建系统（Makefile、SConscript、.bat、.mk）中的 `project=`、`model=`、`-DMODEL=` 等变量，以及输出产物路径（`out/`、`build/`、`firmware_*.bin`）
4. **判断仓库类型**：

| 特征 | 类型 | 注入位置 |
|------|------|----------|
| 每个机型有自己的子目录（如 `project/pos/i9/`），目录下已有或可以创建 `CLAUDE.md` | 多机型分目录 | 每个机型子目录的 `CLAUDE.md` |
| 单个 Makefile/构建脚本，通过不同宏切换机型（如 `PRINTER_MODEL` 值） | 单构建多机型 | 仓库根目录的 `CLAUDE.md` 或 `AGENTS.md` |
| 单一机型，无分支 | 单机型 | 仓库根目录的 `CLAUDE.md` 或 `AGENTS.md` |

### 注入模板

#### 多机型分目录 — 写入 `<机型子目录>/CLAUDE.md`

如果子目录下已有 `CLAUDE.md` 或 `AGENTS.md`，在合适位置追加机型信息；否则新建 `CLAUDE.md`：

```markdown
## <机型名>

- **机型宏**：`<MODEL_MACRO>`（定义在 `<路径>/<文件>:<行号>`）
- **编译指令**：`<构建命令>`
- **编译产物**：`<产物路径>`
- **说明**：<机型用途或特性的一句话说明>

### 代码阅读前置条件

**本目录下的所有代码均以 `<MODEL_MACRO>` 宏启用为前提。** 阅读代码时：
1. 先确认机型宏 `#define <MODEL_MACRO>` 处于活跃状态
2. 所有 `#if defined(<MODEL_MACRO>)` 分支生效，其余 `#elif`/`#else` 分支忽略
3. 机型宏变更后，必须同步更新本文件中的机型宏和编译指令
```

#### 单构建多机型 — 写入根目录 `CLAUDE.md`

在架构规范段落之后追加：

```markdown
## 机型说明

本仓库通过 <选择机制> 切换机型，当前活跃机型为 `<MODEL_MACRO>`。

| 机型宏 | 说明 | 编译指令 | 编译产物 |
|--------|------|----------|----------|
| `<MACRO_A>` | <说明> | `<命令>` | `<路径>` |
| `<MACRO_B>` | <说明> | `<命令>` | `<路径>` |

### 代码阅读前置条件

1. 阅读代码前，必须先确认当前使用的机型宏
2. 所有代码理解以该机型宏 `#define` 为前提，只阅读该机型宏对应的 `#if`/`#elif` 分支
3. 机型宏通过 `<方式>` 切换（如修改 cfg.h 中的 `#define`、修改 Makefile 变量等）
4. **机型宏变更后，必须同步更新本文件中的"当前活跃机型"和相关编译指令**
```

#### 单机型 — 写入根目录 `CLAUDE.md`

```markdown
## 机型说明

- **机型宏**：`<MODEL_MACRO>`
- **编译指令**：`<构建命令>`
- **编译产物**：`<产物路径>`
```

### 强制规则

机型宏信息注入 `CLAUDE.md` 后，以下规则同时写入，成为 AI 的行为约束：

- **AI 在阅读任何代码之前，必须先确认当前文件/目录对应的机型宏，并基于该机型宏去理解 `#if`/`#elif` 分支。**
- **机型宏发生变更时（无论人工修改还是代码生成），必须同步更新对应 `CLAUDE.md` 中的机型说明、编译指令和产物路径。**
- **如果 AI 不确定当前机型宏，必须先查找并确认后再继续。**

### 通用构建审计（非嵌入式项目）

当项目为非嵌入式 C/C++ 或其他语言时执行。目标：记录构建命令、产物路径和环境配置。

#### 审计步骤

1. **识别构建系统**：定位构建配置文件——
   - C/C++：`CMakeLists.txt`、`Makefile`、`meson.build`、`BUILD`
   - Rust：`Cargo.toml`（`[profile]` 段）
   - Go：`go.mod` + `Makefile`（如有）
   - Python：`pyproject.toml`（`[project.scripts]` 段）、`setup.py`、`Makefile`
   - TS/JS：`package.json`（`scripts` 段）、`webpack.config.js`、`vite.config.ts`
   - Java：`pom.xml`、`build.gradle`
2. **提取构建命令**：从构建系统推断标准构建命令（如 `cmake --build build`、`cargo build --release`、`go build ./...`）
3. **记录产物路径**：识别输出目录（`build/`、`dist/`、`target/`、`out/`）
4. **记录环境配置**：如果存在 `.env`、`.env.example`、`config/`、`environments/` 等，记录关键环境变量和配置切换方式
5. **写入 `CLAUDE.md`**：在根目录 `CLAUDE.md` 中追加简化版构建说明

#### 注入模板（根目录 CLAUDE.md）

```markdown
## 构建说明

- **构建系统**：<CMake / Cargo / Go / ...>
- **构建命令**：`<标准构建命令>`
- **编译产物**：`<产物路径>`
- **环境变量**：
  | 变量名 | 说明 | 默认值 |
  |--------|------|--------|
  | ... | ... | ... |
```

如果项目无多环境/多变体，简化为：

```markdown
## 构建说明

- **构建命令**：`<命令>`
- **编译产物**：`<路径>`
```

## AGENTS.md 规则注入

所有架构文档生成后，按以下策略写入架构规范读取和变更门禁规则（按实际模块名和路径调整）：

- 仓库根目录已有 `AGENTS.md` -> 更新 `AGENTS.md`
- 仓库根目录已有 `CLAUDE.md` -> 更新 `CLAUDE.md`
- 两者都不存在 -> 创建 `CLAUDE.md`（不创建 `AGENTS.md`）
- 两者同时存在 -> 只更新已有的文件，不新增

以下为写入内容模板：

```markdown
<!-- 由 ddev-arch 自动生成 -->

## 项目架构规范

本仓库已建立项目级架构规范，位于 `docs/architecture/`。
<!-- 多单元仓库时追加：仓库包含 <N> 个独立代码单元，先读 00_仓库集成架构.md 了解整体关系。 -->

### 修改代码前

<!-- 多单元仓库时：先确认代码所属的代码单元，再读该单元的架构文档 -->
<!-- 单单元仓库时直接引用 01_架构总览.md -->
- 先读架构总览文档的"依赖规则"和"架构变更门禁"
- 读对应模块的约束文件（按实际路径：`modules/0X_<模块名>.md` 或 `<单元>/modules/0X_<模块名>.md`）
- 修改必须优先落在模块约束标注的"允许修改范围"内，不要因为路径相近就跨模块改代码
- 如果实现需要突破模块边界、增加反向依赖、移动文件、改变公共接口或迁移状态所有权，必须先更新架构文档，再改代码

### 架构变更门禁

以下变化视为架构变更，不能只改代码：

- 新增、删除、合并或拆分模块
- 改变模块职责或数据所有权
- 新增跨模块依赖，尤其是反向依赖、循环依赖或下层依赖上层
- 修改公共接口、协议、持久化格式、构建产物或外部可见行为
- 将原本私有的状态、函数或文件提升为跨模块共享

<!-- 项目语言为嵌入式 C/C++ 时，追加机型说明段（由"构建变体与环境审计"步骤写入） -->
<!-- 其他语言时，追加构建说明段（由"构建变体与环境审计"步骤写入） -->
```

对于需要写入根目录 CLAUDE.md 的机型说明（单构建多机型或单机型），在上述模板之后追加"机型宏扫描与注入"章节中对应类型的模板。

如果目标文件（`AGENTS.md` 或 `CLAUDE.md`）已存在，检查是否已有架构规范相关段落，有则更新内容，无则追加在合适位置。同样检查是否已有机型说明段落，有则更新，无则追加。

## 架构总览模板

`01_架构总览.md` 按以下结构编写：

```markdown
# 项目架构总览

## 项目简介
- 项目名称：<名称>
- 技术栈：<语言/框架/平台>
- 一句话定位：<这个项目是干什么的>

## 架构原则
<!-- 写 3-7 条会真实约束改代码的原则，不写空泛口号 -->
- <原则1：例如 UI 层不得直接访问持久化层>
- <原则2：例如 设备状态只归 Driver Context 持有>

## 模块全景图
<!-- 展示最终 ASCII 图；图前标注用途 -->

## 模块列表

| 序号 | 模块名 | 约束文件 | 职责 | 允许依赖 |
|------|--------|---------|------|----------|
| 02   | <模块A> | [02_<模块A>.md](modules/02_<模块A>.md) | <职责> | <模块B> |
| 03   | <模块B> | [03_<模块B>.md](modules/03_<模块B>.md) | <职责> | — |

## 依赖规则
<!-- 写清允许方向、禁止方向、是否允许跨层调用、公共接口归属 -->
- 允许：`<模块A>` → `<模块B>`
- 禁止：`<模块B>` → `<模块A>`
- 公共接口必须定义在：`<路径>`

## 架构变更门禁
- 新增跨模块调用前，必须更新对应模块约束文件
- 改变核心状态所有权前，必须更新对应模块约束文件

## 仓库顶层目录结构

- `src/` - 主源码，包含模块 <A>、<B>
- `include/` - 公共头文件
- `tests/` - 测试代码
```

## 仓库集成架构模板

当仓库包含多个独立代码单元时，在顶层 `docs/architecture/` 下产出 `00_仓库集成架构.md`，按以下结构编写：

```markdown
# 仓库集成架构

## 仓库简介
- 仓库名称：<名称>
- 代码单元数量：<N> 个
- 仓库类型：<异构多核 / 多服务 / 多固件镜像 / 其他>

## 代码单元清单

| 单元名 | 架构文档路径 | 技术栈 | 构建系统 | 说明 |
|--------|-------------|--------|---------|------|
| <unit_a> | [<unit_a>/01_架构总览.md](<unit_a>/01_架构总览.md) | <C/Linux Kbuild> | `make` | <一句话说明该单元做什么> |
| <unit_b> | [<unit_b>/01_架构总览.md](<unit_b>/01_架构总览.md) | <C/Melis RTOS> | `make` | <一句话说明该单元做什么> |

## 单元间交互关系

<!-- ASCII 图展示各单元的交互关系，标注通信协议、数据流向 -->

### 通信方式

| 从（单元） | 到（单元） | 方式 | 协议/接口 | 说明 |
|-----------|-----------|------|----------|------|
| <unit_a> | <unit_b> | IPC / 网络 / 共享内存 / 文件 | <协议名> | <说明> |

### 数据流

<!-- 描述关键数据在各单元间的流动路径 -->

## 联合构建与部署

- 构建顺序：<先构建 A，再构建 B>
- 产物聚合方式：<打包脚本 / 烧录工具>
- 联合产物路径：`<路径>`

## 跨单元约束

<!-- 某单元的变更可能影响另一单元的场景 -->
- <unit_a> 的 <接口/协议> 变更会影响 <unit_b> 的 <功能>
```

## 模块规范模板

所有模块统一使用单文件模板，只包含架构约束内容。

```markdown
# <模块名>

## 模块职责
<一句话说清这个模块负责什么>

## 职责边界
- 负责：<本模块必须承担的职责>
- 不负责：<容易误放进本模块、但不属于本模块的职责>

## 对外接口
- 头文件/导出入口：`src/<路径>/xxx.h`
- 公开函数/类/命令：`<symbol>`
- 外部可见行为：<协议/文件/接口/构建产物>

## 仓库目录映射
- 主目录：`src/<实际路径>/`
- 核心文件：
  - `src/<路径>/xxx.c` - <文件职责>
  - `src/<路径>/xxx.h` - <头文件职责>
- 测试目录：`tests/<路径>/`

## 允许依赖
- 可依赖：`<模块B>`，原因：<为什么允许>
- 被依赖：`<模块C>` 会调用本模块的 `<接口>`
- 禁止依赖：`<模块D>`，原因：<会造成反向依赖>

## 状态与数据所有权
- 本模块拥有：<状态/结构体/配置/缓存/设备句柄>
- 本模块只读：<来自其他模块的数据>

## 允许修改范围
- 可以改：<模块内实现文件/私有函数/局部数据结构>
- 谨慎改：<公共接口/共享结构体/配置格式>
- 必须先更新架构文档再改：<职责迁移/依赖新增>

## 修改前检查清单
- 本次改动是否仍在"允许修改范围"内
- 是否新增了模块依赖或改变依赖方向
- 是否改变了公共接口、外部行为或状态所有权
```

## 子模块模板

若模块内有子模块边界，子模块独立成文，使用同上模板，编号用两级序号（如 `02-01_子模块名.md`）。

## 图怎么画

### ⚠️ 硬门禁：画图前必须先加载 ddev-diagram

**在任何 ASCII 图动笔之前，必须执行 `Skill("ddev-diagram")` 加载绘制规范。加载完成前禁止写任何 ASCII 图到 `.md`。**

加载后严格遵守：
- Unicode 制表符（┌─┐└┘│├┤┬┴┼），**禁止 ASCII 拼接**（+/-/|）
- 框内标签**英文**（CJK 字符宽度不可靠）
- 正交连线，**禁止斜线**
- 右边框对齐、上下等宽、无断线

优先画：

- 系统边界图（组件图）：看清系统与外部的关系
- 模块依赖图（组件图）：看清允许依赖方向和禁止方向
- 状态所有权图：看清关键状态属于哪个模块

## 验收标准

初始化完成后，逐项检查：

### 通用检查项（所有语言必须通过）

| 检查项 | 标准 |
|--------|------|
| 模块覆盖 | 所有可识别模块都有对应文档，无遗漏 |
| 职责边界 | 每个模块约束文件都写清"负责"和"不负责" |
| 依赖约束 | 总览和模块约束文件都写清允许依赖与禁止依赖 |
| 状态所有权 | 关键状态、配置、缓存、句柄都有明确归属 |
| 修改门禁 | 每个模块约束文件都有"允许修改范围"和"修改前检查清单" |
| 路径可定位 | 每个模块的"仓库目录映射"指向真实存在的目录/文件 |
| 图完整 | 架构总览有模块依赖图 |
| 交叉引用正确 | 模块间依赖关系在文档中有标注且路径正确 |
| 一致命名 | 模块名、文档名、图中标签三者一致 |
| 配置文件注入 | 仓库根 `AGENTS.md` 或 `CLAUDE.md`（按写入策略）含架构规范索引和变更门禁 |
| 语言声明 | 各单元 `01_架构总览.md`（单单元或多单元）的技术栈字段已填写实际检测到的语言 |
| 构建信息 | 构建命令、产物路径已写入对应 `CLAUDE.md`（按语言策略） |

### 多独立代码单元专属检查项

| 检查项 | 标准 |
|--------|------|
| 单元清单 | `00_仓库集成架构.md` 已列出全部独立代码单元，无遗漏 |
| 交互关系 | 仓库集成架构已描述单元间通信方式、数据流和联合构建部署 |
| 跨单元约束 | 仓库集成架构已标注跨单元变更影响的约束规则 |
| 单元间路径 | 所有交叉引用路径正确指向各单元子目录下的文档 |

### C/C++ 项目专属检查项

| 检查项 | 标准 |
|--------|------|
| **标准库审计** | `stdlib-wrappers.md` 已生成，至少 2 轮审计，覆盖全部函数类别，无遗漏 |
| **标准库审计质量** | 所有替代封装签名准确，所在文件路径和行号正确 |
| **条件编译门控** | 所有替代封装的条件编译门控宏已审计，`stdlib-wrappers.md` 含「条件编译门控」章节和门控宏速查表 |
| **第三方库适配** | 所有引入的第三方库均已在审计表中记录适配状态；未适配的已标注风险 |

### 嵌入式 C/C++ 项目专属检查项

| 检查项 | 标准 |
|--------|------|
| 机型宏注入 | 各机型子目录 `CLAUDE.md` 或根 `CLAUDE.md` 含机型宏、编译指令、产物路径和代码阅读前置条件 |
| 机型宏完整性 | 所有 cfg.h 中定义的机型宏均已被扫描和记录，无遗漏 |

### 非 C 项目专属检查项

| 检查项 | 标准 |
|--------|------|
| 依赖审计 | `dependency-audit.md` 已生成，依赖清单已解析，直接依赖无遗漏 |
| 依赖完整性 | 包管理器配置文件已解析，关键依赖和风险依赖已标注 |

## 文档维护

架构规范不是一次性的。以下情况必须更新：

- 新增/删除/合并/拆分模块时，更新对应单元的架构总览模块列表，新增/删除对应模块文档，同步更新 `AGENTS.md` 或 `CLAUDE.md`（按写入策略判断目标文件）
- **新增/删除独立代码单元时**，更新 `00_仓库集成架构.md` 的单元清单和交互关系，新增/删除对应单元子目录下的全套架构文档（仅多单元仓库）
- **独立代码单元间通信协议或交互关系变更时**，更新 `00_仓库集成架构.md` 的"单元间交互关系"和"跨单元约束"（仅多单元仓库）
- 模块文件迁移时，更新对应模块约束文件的"仓库目录映射"
- 模块职责发生变化时，更新约束文件的"模块职责"和"职责边界"
- 新增跨模块依赖时，更新总览的"依赖规则"和相关模块约束文件的"允许依赖"
- 状态、配置、缓存、句柄或关键数据结构所有权变化时，更新约束文件的"状态与数据所有权"
- 修改公共接口、协议、持久化格式或外部行为时，更新约束文件的"对外接口"和"允许修改范围"
- **新增/删除/变更标准库替代封装时，必须同步更新 `stdlib-wrappers.md` 的对应条目**（仅 C/C++ 项目）
- **机型宏变更时（切换机型、新增机型、修改机型宏名），必须同步更新对应 `CLAUDE.md` 中的机型说明、编译指令和产物路径**（仅嵌入式 C/C++ 项目）
- **新增机型时，在对应的 `CLAUDE.md` 中追加新机型的机型宏、编译指令和产物路径说明**（仅嵌入式 C/C++ 项目）
- **新增/删除/升级依赖时，必须同步更新 `dependency-audit.md` 的对应条目**（非 C 项目）
- **构建系统或环境配置变更时，必须同步更新 `CLAUDE.md` 中的构建说明**（所有项目）

## 完成后

架构规范初始化完成后，不必自动进入实现工作流。仅在用户后续发起具体代码改动时，才按需要触发 `ddev-spec`，并让该实现文档显式遵守 `docs/architecture/` 中的项目级约束。

