# 独立工作单元设计规范

本文档描述的是一种通用设计思想，不特指 `filesearch`。`everything_file_search` 只是当前仓库里的一个实例。

## 目标

独立工作单元（work unit）应该满足以下目标：

- 可复用：不依赖某个单一入口，例如微信、桌面、terminal。
- 可自解释：单元本身能说明“我是什么、怎么调、会返回什么”。
- 可注册：能力由具体 runtime 在启动时注册，而不是默认全局散落。
- 可组合：上层可以先做意图识别，再决定调用哪个工作单元。
- 可替换：传输层、UI 层、平台适配层变化时，核心单元不需要重写。

## 核心原则

### 1. 单元先于入口

不要先写微信命令、桌面按钮或某个 handler，再把核心逻辑埋进去。正确顺序是：

1. 定义独立工作单元
2. 定义它的输入输出契约
3. 实现归一化与执行逻辑
4. 再由具体 runtime 把它注册成 slash command、按钮或 agent tool

### 2. 先识别，再调用，再传输

一个完整链路应拆成三个阶段：

1. 意图识别
   目标：判断用户是不是要用某个工作单元，并产出结构化输入。
2. 单元调用
   目标：由工作单元自己完成输入归一化、执行、输出结果。
3. 传输或副作用
   目标：把结果发到微信、写到会话、保存到文件，或触发其他动作。

这三层不要混在一起。尤其不要把平台协议、UI 文案、业务执行揉成一个函数。

### 3. 自解释优先于隐式约定

每个工作单元至少应显式提供：

- 稳定名称
- 用途说明
- 输入字段定义
- 输出字段定义
- 帮助文本或 usage 文本
- 至少一个标准输入示例
- 至少一个标准输出示例

这样 AI、开发者、测试代码、运行时注册器都可以围绕同一份契约工作。

### 4. shortcut 是注册层，不是核心层

像 `/find` 这样的 slash command 不应成为核心能力本身，而只是某个 runtime 对工作单元的快捷注册方式。

要求：

- shortcut 由实际拥有该能力的 runtime 在启动时注册
- 不要默认全局注册所有 shortcut
- `help` 应回到工作单元自身的 usage 文本
- shortcut 只做参数转发、权限约束、交互包装，不承载核心执行逻辑

## 标准结构

推荐每个工作单元至少具备以下结构：

### A. Identity

- `ToolName`
- `Definition()` 或等价结构

### B. Contract

- `Input` 结构
- `Result` 结构

### C. Normalization

- 把自然输入或宽松输入规整成稳定内部格式
- 去重、补默认值、统一别名、时间/路径/类型归一化

### D. Execution

- 真正调用系统能力、外部程序或内部算法
- 尽量只关注“执行任务”，不处理展示文案

### E. Help / Usage

- 给人看的帮助
- 给 AI/agent 用的 usage 文本

## 运行时接入方式

不同 runtime 只做适配：

- WeChat bridge：注册 `/find`、`/find help`，处理多轮选择和发送文件
- Desktop：可以提供按钮、菜单、设置页
- Terminal：可以提供命令行包装
- Agent：可以把工作单元暴露成 tool provider

运行时应该依赖工作单元，不应反过来让工作单元依赖某个 runtime。

## 中心登记

仓库需要有一个中心化登记位置，记录已有工作单元及其契约。当前仓库使用 `AGENTS.md` 的 `Registered Tool Units` 作为登记表。

新增工作单元时，至少要登记：

- 单元名称
- 包路径
- 用途
- 输入契约
- 输出契约
- 由哪个 runtime 注册 shortcut
- 当前链路中的“意图识别 / 单元执行 / 传输层”分别落在哪些模块

## 测试要求

至少覆盖以下几类测试：

- 输入归一化测试
- 标准执行测试
- 帮助文本可达性测试
- runtime 注册测试
- 跨层集成测试

如果某个工作单元带有 shortcut，还要测试：

- 正常调用
- `help`
- 参数缺失
- 取消/中止
- 非本 runtime 场景下不误注册

## 反模式

以下做法应避免：

- 在微信 handler 里直接实现完整业务核心
- 只有自然语言提示词，没有稳定输入输出结构
- shortcut 全局硬编码，runtime 不区分是否真正具备能力
- 一个函数同时做意图识别、执行、展示、发送
- 模块存在，但没有中心登记和帮助文本

## 当前仓库示例

当前的 `everything_file_search` 符合这套思路：

- 意图识别：`internal/ai` 与 `internal/app`
- 单元执行：`internal/filesearch`
- 运行时注册：`internal/weixin`
- 传输层：`internal/weixin/media.go`

后续新增类似能力时，应优先复用这套模式，而不是再写一条入口专用逻辑链。
