# 怎么读这份源码

> AGENTS.md 分层、设计文档与生成清单、无注释区、导入边界、实验开关、TS 设定与几条阅读捷径。

- 作者：David（道雾轩）
- 专栏：Kimi Code 源码解读（https://daiw.org/manual/kimi-code.md）
- 最后更新：2026-09-19
- 原文：https://daiw.org/manual/kimi-code/reading-the-source
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

## 先读 AGENTS.md，不是 README

这个仓库把架构说明写在 **`AGENTS.md`** 里——给 AI 编码助手看的指令文件，因为天天被使用，往往是最新的架构文档。根目录的 `CLAUDE.md` 只有一行 `AGENTS.md`，指回同一份文件。

分层放置：

```text
AGENTS.md                              仓库级：项目地图、硬约束、工作流
apps/kimi-code/AGENTS.md               CLI/TUI 的入口链与模块职责
apps/kimi-inspect/AGENTS.md
packages/klient/AGENTS.md              门面 / 契约 / 传输三层规则
packages/minidb/AGENTS.md
packages/pi-tui/AGENTS.md              与上游 pi-mono 的本地差异清单
packages/agent-core-v2/src/human/llm/AGENTS.md   目录级
docs/AGENTS.md
```

规则明确写着往哪写：

> Hard rules that affect almost every task: update the root `AGENTS.md`.
> Rules that only affect a specific directory: update the nearest sub-directory `AGENTS.md`.

但仓库同时声明**代码才是唯一真相**：

> Treat code, not documentation, as the source of truth.

这句话要当真。v0.43.0 的根 `AGENTS.md` 说 `agent-core-v2` 有四级 `LifecycleScope`，调用方经 `IWorkspaceLifecycleService.handlerFor` 组合会话生命周期；代码里的枚举只有三级，这个服务在引擎里也找不到，只剩 SDK 的注释还提到它。文档可以当索引，结论要回到代码。

## 第二读：设计文档与生成的清单

v2 引擎没有模块 README，取而代之的是 `packages/agent-core-v2/docs/`：

- `zh/llm.md`（及英文版）——`human/llm` 请求库的设计指南，九条设计原则写得很透；`src/human/llm/AGENTS.md` 要求改这个目录前先读它。
- `wire-manifest.d.ts`、`state-manifest.d.ts`、`config-manifest.toml`——由包内 `scripts/gen-*-manifest.mts` 生成，分别列出 wire 记录、App / Workspace / Session / Agent 各层状态与全部配置段。想一眼看全引擎的「数据面」，先翻这三份。

## 无注释区

`agent-core-v2`、`kap-server`、`transcript` 是 comment-free zones：不许有任何注释，连导出符号的 JSDoc 也不行，只保留必要的 lint 抑制指令。`scripts/check-no-comments.mjs` 扫这三个包的 `src/`、`test/`、`scripts/`，作为 `pnpm lint` 的一部分执行。

所以读引擎没有注释可依靠，只能靠类型、命名与测试；命名也因此普遍很长、很具体，比如 `llmRequesterMediaStrippedTurnsKey`。反倒是 node-sdk 的 `sdk-rpc-client-v2.ts` 注释极多，逐方法写明与 v1 行为的对齐和差异，是理解换代的好材料。

## 目录约定

```text
apps/            可运行的应用（CLI/TUI、VS Code 插件、可视化调试器、检查器）
packages/        库
plugins/official 官方插件（kimi-datasource、kimi-webbridge）
docs/            用户文档（中英双语）
scripts/         构建与检查脚本
.agents/skills/  仓库自带的 agent skills（write-tui、tdd、gen-changesets…）
.changeset/      变更集（发版用）
```

`packages/agent-core-v2/src/` 内部：

```text
_base/        DI 容器、事件、生命周期、贡献点等底座
human/        纯内核：agent / turn / tool 状态机、单次 LLM 请求库
llm-adapter/  引擎侧的 LLM 兼容边界（模型、provider、协议路由）
app/          App 级服务：配置、认证、插件、会话索引、flag……
workspace/    工作区：目录、git、信任、MCP 配置……
session/      Session 级：元数据、子代理、会话级工具策略……
agent/        Agent 级：loop、上下文、压缩、权限、工具执行、内置工具
features/     以 Feature 接入的功能：goal、plan、skill、swarm、cron……
tool/         工具契约与资源访问模型
wire/         wire 记录、日志与版本迁移
persistence/  存储接口与后端（node-fs / minidb / memory）
os/           宿主文件系统与进程
```

## 导入边界

`packages/agent-core-v2/scripts/check-import-boundaries.mjs`（`pnpm --filter @moonshot-ai/agent-core-v2 lint:imports`）把分层写成了可执行的规则：

- `human/` 不许 import 内核以外的任何东西——它是纯 LLM / agent 内核，不认识 `llm-adapter` 与 v2 的各个领域；
- v2 代码里只有 `llm-adapter/`、`agent/loop/machine/`、`session/agentLifecycle/` 三处能 import `human` 的实现，其余只能用一小组「词汇」模块（消息、用量、能力等类型）；
- 协议基座内部的 format / lower / patterns 只许基座自己和测试 import；
- 不许再 import kosong。

知道这三个适配层，就知道内核与外壳在哪里接缝。

## 实验开关

未公开的功能一律挂在开关后面，env 驱动、默认关闭：

| 环境变量 | 作用 |
| --- | --- |
| `KIMI_CODE_EXPERIMENTAL_<NAME>` | 打开单个开关 |
| `KIMI_CODE_EXPERIMENTAL_FLAG` | 打开全部 |

优先级是：单个 env > 配置里的 `[experimental]` > 总开关 env > 条目的 `default`；发布某功能就是把 `default` 翻成 `true`。v2 没有中央注册表，各领域在 import 时自己调 `registerFlagDefinition`（`app/flag/flagRegistry.ts`），用 `IFlagService.enabled(id)` 判断。例如 `features/tower/flag.ts`（有删减）：

```ts
export const towerFlag: FlagDefinitionInput = {
  id: TOWER_FLAG_ID,
  title: 'Tower mode',
  env: TOWER_FLAG_ENV,
  default: false,
  surface: 'both',
  isExposed: (flags) => isTowerFeatureAssembled(flags),
};
```

想知道默认配置下哪些路径根本不会执行，`rg registerFlagDefinition` 扫一遍即可。

## TypeScript 设定

- 根 `tsconfig.json` 开了 `strict`、`noUncheckedIndexedAccess`、`noImplicitOverride`、`noPropertyAccessFromIndexSignature`、`verbatimModuleSyntax` 与 `experimentalDecorators`。最后一个给 DI 用：服务在构造函数参数上用 `@IAgentLoopService private readonly loop` 这样的装饰器声明依赖。
- 没有开 `exactOptionalPropertyTypes`。AGENTS.md 明确可选属性不必再写 `| undefined`（写 `user?: User` 即可）；传值直接给 `{ user }`，**不用**条件展开。
- 路径别名：`agent-core-v2` 的 `package.json` 里 `#/*` 指 `./src/*.ts`、`#human/*` 指 `./src/human/*.ts`；`src/human/` 还有自己的 `package.json`，其中的 `#/*` 只指向 human 内部——内核在包里又划了一道包界。
- `exports` 用 `./*` 暴露深路径，所以常见 `@moonshot-ai/agent-core-v2/agent/loop/turnOps` 这样的子路径导入。
- 除包的 `index.ts` 外，其余 `index.ts` 一律 `export * from './module'`。

## 几条阅读捷径

**想弄清一个功能怎么实现**，按这个顺序找：

1. `docs/zh/` 或 `docs/en/` 找该功能的用户文档，拿到准确名词。
2. `rg` 搜那个名词（仓库工作流明确要求用 `rg`）。
3. 落到 `packages/agent-core-v2/src/<层>/<领域>/`：先看接口文件（如 `agent/loop/loop.ts` 定义 `IAgentLoopService`），再看 `*Service.ts` 实现，最后看文件末尾的 `registerScopedService(...)`——它告诉你服务挂在哪一级 Scope、何时激活。

**想弄清一次调用的完整链路**，从 klient 契约切入：`packages/klient/src/contract/` 按 global / session / agent 列出每个线上方法的 zod 输入输出，`src/core/facade/` 把它们映射到引擎的服务名与方法（如 `agentPromptService.submit`）——这就是「前端能让引擎做什么」的清单。反方向（审批、提问）看 SDK 的 `src/v2/session-wiring.ts`。

**想知道某处行为的边界**，看测试。v2 的 `test/` 与 `src/` 同构，比如 `test/agent/loop/` 下的 `loop.test.ts`、`turnOps.test.ts`、`machineTools.test.ts`；klient 另有一套对每种传输原样重跑的一致性测试（`test/helpers/conformance.ts`）。

## 本专栏的引用约定

- 路径一律相对仓库根：`packages/agent-core-v2/src/agent/loop/loopService.ts`。
- 引用行号时以[基准](https://daiw.org/manual/kimi-code) tag `@moonshot-ai/kimi-code@0.43.0`（commit `ffa94fa`）为准。这个仓库变化很快——从 v0.29.1 到 v0.43.0 只隔七周，引擎就换了代——行号与结构都可能漂移，读时请以当前 HEAD 为准。
- 代码片段会做删减（省略无关分支、错误处理），保留结构；需要精确细节请回原文件。

下一篇：[一条消息的生命周期](https://daiw.org/manual/kimi-code/message-lifecycle)——把所有层串起来走一遍。
