> For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt.

# AI Agent 底座完整入门：从 API 到 Runtime

> **Scope boundary / Current legacy Task examples（2026-07-15）**：本文关于 API、SDK、CLI、MCP、Skills、approval、audit 和 runtime 的通用解释仍可参考；其中 `lead_outreach / lead_follow_up / retention`、旧 task lifecycle 与 Objective-first 例子不是 Target contract。Task domain 与 AI runtime 统一以 [Task System Design V3](/product-design/v3/tasks-feature/task-domain-lifecycle.md) 为准。
>
> 写给：正在判断“我们要不要做 API / SDK / CLI / MCP / Botmux / Codex / Agent Runtime”的产品与工程同学。
>
> 结论先说：**不要从零造一个 Codex 或 Claude Code。先把 retaintive 的业务能力做成可靠 API、状态机和可审计数据，再按需要包 SDK / CLI / MCP / Skills，最后接入 Botmux、Lark、dashboard 等工作流入口。**

***

## 0. 这篇文档怎么读

这是一篇 one-stop 文档，目标是把容易混在一起的概念放到同一张地图里：

- HTTP / API / REST / OpenAPI / Webhook 到底是什么？
- 有了 HTTP API，为什么还要 SDK / CLI？
- SDK 和 CLI 是上下级，还是 API 上面的并列包装？
- MCP、Function calling、Connector、Skill 有什么区别？
- Agent Runtime 是什么，和 Codex CLI / Botmux 有什么关系？
- retaintive 如果要做 AI follow-up、评价分析、客户召回，哪些层 MVP 必须做，哪些可以以后补？
- 哪些东西应该用现成工具，哪些必须自己做？

推荐阅读顺序：

```text
先看 1-2：建立全局地图
再看 3：用一个 retaintive 例子跑完整链路
再看 4-6：补齐基础层、操作面、运行层概念
再看 7-11：做产品和工程取舍
```

retaintive 当前的现实起点是：

```text
已有:
  Hono backend API
  -> frontend 通过 Hono RPC fetch client / AppType 调 API

还不是:
  OpenAPI-first public developer platform
  public SDK
  public CLI
  hosted MCP server
```

下一步如果要让 Codex / Botmux / CI / agent 稳定操作 retaintive，最现实路线是：

```text
选少数稳定核心 API
  -> 写出或生成 OpenAPI schema
  -> 生成 internal client
  -> 做 thin CLI
  -> 后续再产品化成 public SDK / public CLI / MCP / Skills
```

***

## 1. 核心结论

AI Agent 的“基座”不是一个模型，也不是一个聊天框。一个能进入真实业务流的 agent 至少需要：

```text
LLM
  + instructions / skills
  + context / memory
  + tools / APIs / CLI / MCP
  + loop
  + state
  + queue / scheduler
  + permissions / policy
  + human approval
  + logs / traces / evals
  + product surface
```

但这不代表我们要全部从零开发。正确取舍是：

```text
不要重复造:
  coding agent runtime
  repo editing agent
  Lark CLI runtime
  通用 MCP protocol

必须自己做:
  retaintive data model
  store / tenant isolation
  usage metering
  approval queue
  audit log
  LLM Gateway
  call / lead / review / follow-up 的业务状态机
```

一句话：

> **API 是地基，OpenAPI 是机器可读合同，SDK / CLI / MCP 是从合同长出来的操作面，Skill 是 SOP，Runtime 是执行现场，Policy 是刹车。retaintive 要赢，重点不是重复造工具，而是把健身房客户运营这套业务事实和审核闭环做扎实。**

***

## 2. 一张完整分层图

把 AI Agent 产品想成从“业务事实”一路包装到“人类可监督的自动化执行”：

```text
Domain / Data model / Source of Truth
  ↓
业务服务代码
  ↓
API contract: REST / GraphQL / Webhook / Event stream / OpenAPI schema
  ↓
Docs + Sandbox + Test data
  ↓
+---------------------------+------------------------------+-------------------------------+
| SDK                       | CLI / Dev tools              | Tool layer                    |
| 给代码 import 用          | 给 terminal / CI / agent 用  | Function calling / MCP /      |
|                           | Logs / Local tunnel          | Skills / Tool schema          |
+---------------------------+------------------------------+-------------------------------+
  ↓
Agent Runtime: loop / state / memory / queue / scheduler / sandbox
  ↓
Policy layer: auth / scopes / approvals / audit / risk controls
  ↓
Product surface: Web dashboard / Lark / Slack / IDE / Desktop app
```

核心判断：

**越靠下越像“产品事实”，越靠上越像“AI 怎么使用这些事实”。**

如果底层数据模型和状态机不稳定，上面接 MCP、Botmux、Codex 只会让不稳定更快暴露。

注意：这张图不是说必须先做 SDK 才能做 CLI。**SDK、CLI、MCP / Tool layer 是 API 上面的 sibling wrappers**，面向不同使用者：

| 包装                | 面向谁                      | 典型形式                                    |
| ----------------- | ------------------------ | --------------------------------------- |
| SDK               | 代码和 integration          | `client.followUps.createDraft(...)`     |
| CLI               | terminal、CI、Codex、Botmux | `retaintive follow-up draft create ...` |
| MCP / Tool schema | 外部 AI client             | `create_follow_up_draft`                |
| Skill             | agent 的 SOP              | “先 create draft，再 approval，不要直接 send”   |

2026 年的主流方向是：尽量让这些 wrapper 从同一份 `OpenAPI schema` 生成或半生成，再做少量手工包装和产品化治理。

***

## 3. 一个 retaintive 例子：Call-to-Follow-up

用一个具体、好理解的 retaintive 场景先跑一遍全链路。

目标：

```text
潜在客户给健身房打电话，问价格和课程，但没有预约。
Retaintive 从通话记录和转录里识别 follow-up 机会。
AI 生成 follow-up draft。
老板或销售审核后发送 SMS / Email。
发送结果和后续预约效果回流到 dashboard。
```

这个例子会贯穿后面的概念。

### 3.1 业务事实层

系统必须先知道哪些对象是真实存在的：

```text
stores
contacts / customers
calls
call_transcripts
leads
lead_status_changes
tasks
follow_up_candidates
follow_up_drafts
approval_items
message_sends
usage_events
audit_logs
```

这些是 Source of Truth。Agent 可以总结、推荐、生成草稿，但不能把聊天记录当数据库。

### 3.2 业务服务层

业务服务代码负责真正的规则：

```text
这通电话属于哪个 store？
这个 caller 是新 lead 还是已有 customer？
通话里有没有价格、trial、schedule、cancellation 等意图？
这个 lead 是否需要 follow-up？
follow-up 文案是否只能先生成 draft？
谁有权限 approve？
这次 LLM 调用和发送动作计入哪个 client / store？
```

无论入口是 dashboard、API、CLI、MCP 还是 Lark card，规则都应该落到同一套 service / API boundary，不要散落在 prompt 或脚本里。

### 3.3 API 层

把关键动作做成稳定 API：

```text
GET  /stores/{store_id}/follow-up-candidates
POST /follow-up-drafts
GET  /approval-items?status=pending
POST /approval-items/{id}/approve
POST /messages/send
POST /usage-events
```

API 使用者看到的是 endpoint、request、response、error。平台内部做的是 auth、store isolation、idempotency、audit、usage metering 和 business validation。

### 3.4 OpenAPI / SDK / CLI / MCP 层

同一个 `POST /follow-up-drafts` 能长出多种操作面：

```text
OpenAPI schema
  -> generated internal client
  -> thin CLI
  -> MCP tool schema
  -> docs / mock / contract tests
```

工程师或 agent 可以跑：

```bash
retaintive follow-up candidates --store-id store_123 --format json
retaintive follow-up draft create --lead-id lead_456 --tone friendly --format json
retaintive approval list --status pending --format json
```

外部 AI client 看到的可能是：

```text
tool name: create_follow_up_draft
input schema: { store_id, lead_id, tone }
output schema: { draft_id, status, message_preview }
```

Skill 则告诉 agent：

```text
When handling follow-up messages:
1. Read candidate context first.
2. Create follow_up_draft only.
3. Never send SMS directly from generated content.
4. Put every external message into approval queue.
5. Record usage_event and audit_log.
```

### 3.5 Runtime / surface 层

MVP 可以先不用复杂 multi-agent runtime。更准确地说，Retaintive 现在和近期都应该先用确定性 workflow 管理业务事实和 task lifecycle：

```text
RingCentral call ended / lead email received / transcript ready
  -> backend workflow ingests raw event
  -> processing worker writes calls / transcripts / leads / contacts
  -> task workflow creates or updates lead_outreach / lead_follow_up / retention tasks
  -> dashboard shows task and contact timeline
  -> staff or manager works the task
  -> completion / outcome / audit is written back
```

这里使用的是 live Tasks Schema 的 `typeCategory` 名称：`lead_outreach` 是新 lead 首次联系任务，`lead_follow_up` 是 lead 后续跟进任务，投诉或流失风险类处理落到 `retention`。UI 可以写成 complaint / retention 这种人类可读标签，但 API、prompt 和 tooling 不应创建 `complaint` 或 legacy `follow_up` category。

Agent 不应该绕过这套 workflow 自己决定 task lifecycle。更合适的角色是读取 workflow 产物、生成解释、草稿、摘要和建议，并把高风险动作交给人审批：

```text
lead_outreach task created / lead_follow_up task overdue / retention task created
  -> agent summarizes context
  -> agent drafts suggested reply or manager brief
  -> approval_item or review card is created
  -> human approves / edits / rejects
  -> backend workflow performs the real mutation and writes audit log
```

以后接 Lark / Botmux：

```text
Boss in Lark:
  "show overdue lead_follow_up tasks and retention tasks"

Botmux / command bridge:
  -> runs stable CLI or calls API
  -> returns task summary / approval card
  -> human approves / edits / rejects
  -> backend enforces policy and writes audit log
```

这个例子的关键不是“AI 写文案”，而是：

```text
事实来自 SoT
动作通过 API
工具从 OpenAPI / client / CLI / MCP 暴露
草稿进入 approval
发送有 audit
task lifecycle 仍由 workflow 管理
结果能回流
```

***

## 4. 基础层概念

这一层回答：系统到底承认什么事实，怎么把能力稳定开放出来。

### 4.1 Domain / Data model / Source of Truth

**Domain** 是业务世界里的对象和规则。对 retaintive 来说，是门店、会员、lead、call、review、task、campaign、approval。

**Data model** 是这些对象在系统里的结构。比如 `lead` 有 `store_id`、手机号、最近通话、状态、来源、follow-up 记录。

**Source of Truth (SoT)** 是系统承认的事实来源。比如某个 lead 是否需要跟进，不能靠 AI 聊天记录判断，应该靠数据库里的 call、transcript、lead status、task、message history 判断。

为什么重要：Agent 可以推理，但不能替代事实库。没有 SoT，AI 会把“听起来对”当成“系统事实”。

### 4.2 业务服务代码

业务服务代码是真正执行规则的后端：

```text
客户是否符合 follow-up 条件？
评价是不是负面？
这个门店是否允许发 SMS？
这个用户是否能批准发送？
这个请求是否跨 store？
```

API、SDK、CLI、MCP 最后都只是入口，真正的规则应该在业务服务里统一执行。不要把核心规则散落在 prompt、CLI 脚本、MCP server 或前端按钮里。

### 4.3 HTTP / HTTPS

**HTTP** 是两台机器在网络上说话的常见协议。你打开网页、调用 API，大多都在用 HTTP。

**HTTPS** 是 HTTP 加密版。生产环境 API 必须用 HTTPS。

一个 HTTP request 大概长这样：

```http
POST /follow-up-drafts HTTP/1.1
Host: api.retaintive.com
Authorization: Bearer <TOKEN>
Content-Type: application/json

{"store_id":"store_123","lead_id":"lead_456"}
```

成功 response 大概长这样：

```http
HTTP/1.1 201 Created
Content-Type: application/json
Request-Id: req_abc123

{
  "draft_id": "draft_789",
  "status": "pending_approval",
  "message": "Hi Jane, thanks for calling about our trial class..."
}
```

失败 response 也会用同一套 HTTP 结构表达错误：

```http
HTTP/1.1 403 Forbidden
Content-Type: application/json
Request-Id: req_def456

{
  "error": {
    "code": "missing_scope",
    "message": "Token does not have follow_up_drafts:write scope."
  }
}
```

HTTP response 里最关键的是三块：

| 部分               | 作用        | 例子                                                                                    |
| ---------------- | --------- | ------------------------------------------------------------------------------------- |
| Status code      | 这次调用整体结果  | `201 Created`, `400 Bad Request`, `401 Unauthorized`, `403 Forbidden`, `409 Conflict` |
| Response headers | 元信息       | `Content-Type`, `Request-Id`, rate limit headers                                      |
| Response body    | 业务结果或错误详情 | `draft_id`, `status`, `error.code`                                                    |

如果用 HTTPS，业务层看到的 method、path、headers、body 基本还是同一套 HTTP 内容。区别在外层传输：

```text
HTTP:
  client -> plain HTTP request -> server

HTTPS:
  client -> TLS encrypted connection -> HTTP request inside TLS -> server
```

所以文档里通常会画 HTTP request，而不是单独画一份 HTTPS request。真实调用时 URL 会写成：

```text
https://api.retaintive.com/follow-up-drafts
```

HTTP / HTTPS 只管“怎么传话”，不管你的业务是什么意思。`POST /follow-up-drafts` 的业务含义、`201 Created` 代表什么、`missing_scope` 怎么处理，都来自 API contract 和后端 route handler，不来自 HTTP 协议本身。

### 4.4 API

**API** 是系统对外开放的能力入口。它规定外部可以让系统做什么、怎么传参数、会返回什么。

比如：

```text
GET  /stores/{store_id}/follow-up-candidates
POST /follow-up-drafts
POST /approval-items/{id}/approve
POST /messages/send
```

API 有两种视角：

```text
API 使用者看到:
  POST /follow-up-drafts
  Authorization: Bearer <TOKEN>
  body: { store_id, lead_id }

API 作者内部实现:
  route handler
    -> auth / scope check
    -> store access validation
    -> idempotency check
    -> followUpService.createDraft(...)
    -> usage_event
    -> audit_log
    -> response JSON
```

API 是所有上层包装的地基。SDK、CLI、MCP、dashboard 最后都应该调用同一套 API 或同一套 service layer。

### 4.5 REST / GraphQL / gRPC

这些是 API 的不同设计风格：

| 风格      | 一句话                           | 适合什么           |
| ------- | ----------------------------- | -------------- |
| REST    | 用 URL 表示资源，用 HTTP method 表示动作 | SaaS 最常见，简单稳定  |
| GraphQL | 客户端声明自己要哪些字段                  | 前端复杂查询、多对象组合   |
| gRPC    | 强 schema、高性能 RPC              | 内部微服务、低延迟服务间调用 |

retaintive 这种 B2B SaaS，外部/内部业务 API 默认用 REST 最稳。复杂 dashboard 查询可以考虑 GraphQL，但不要为了潮流引入。

### 4.6 OpenAPI / API contract

**OpenAPI** 是机器可读的 API 合同，描述 endpoint、参数、返回、错误码、auth。

它的价值：

- 自动生成 API docs。
- 自动生成 SDK。
- 自动生成或半生成 CLI。
- 自动生成或半生成 MCP server / tool schema。
- 自动生成 mock / contract test。
- 让 AI / agent 更容易理解你的 API。

但这里要分清两件事：

```text
OpenAPI 是 source of truth。
Generator 是把 OpenAPI 变成 SDK / CLI / docs / MCP 的工具。
```

一个好的 OpenAPI operation 不只是写 `POST /follow-up-drafts`，还应该写清：

```yaml
paths:
  /follow-up-drafts:
    post:
      operationId: createFollowUpDraft
      tags: [follow-up]
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [store_id, lead_id]
              properties:
                store_id:
                  type: string
                lead_id:
                  type: string
                tone:
                  type: string
      responses:
        "201":
          description: Follow-up draft created
        "403":
          description: Missing scope or store access
```

这些字段会影响：

- SDK 里方法叫什么：`client.followUps.createDraft(...)`。
- CLI 里命令叫什么：`retaintive follow-up draft create`。
- MCP tool 叫什么：`create_follow_up_draft`。
- 文档里怎么分组。
- agent 怎么理解这个工具的输入、输出和错误。

不是所有 generator 能力一样：

| 工具类型                                         | 通常能生成什么                                            | 备注                                         |
| -------------------------------------------- | -------------------------------------------------- | ------------------------------------------ |
| OpenAPI Generator 这类 OSS 工具                  | client SDK、server stub、documentation、schema/config | 很适合生成 typed client，但不等于自动生成产品级 CLI         |
| Speakeasy / Stainless / Fern 这类 API DevEx 平台 | SDK、docs、MCP server，有的也能生成 CLI                     | 更接近“API spec -> developer interface suite” |
| 自己写的轻量脚手架                                    | CLI command、tool schema、测试样例                       | 适合内部工具，但维护能力取决于我们自己                        |

所以更准确的说法是：

```text
OpenAPI 可以驱动 SDK / CLI / MCP / docs 的生成。
但生成质量取决于 API 设计、operationId、tags、schema、error model、auth model 和 generator 配置。
```

没有 OpenAPI，团队和外部集成方只能读自然语言文档，容易 drift。有 OpenAPI 但写得粗糙，也会生成出难用的 SDK / CLI / MCP。

#### Hono 里能不能自动生成 OpenAPI

可以半自动，但不是装一个包就能从任意 Hono handler 里完美猜出来。

如果代码只有这样：

```ts
app.post("/follow-up-drafts", async (c) => {
  const body = await c.req.json();
  const draft = await followUpService.createDraft(body);
  return c.json(draft, 201);
});
```

工具很难准确知道：

```text
body 里哪些字段 required？
tone 有哪些 enum？
response 长什么样？
403 / 409 / 429 error 怎么返回？
需要什么 auth scope？
operationId 应该叫什么？
```

所以现实做法是：给 route boundary 补 request / response schema，再由 Hono OpenAPI 工具生成 `openapi.json`。

常见选择：

```bash
npm install @hono/zod-openapi zod
```

或：

```bash
npm install hono-openapi @hono/standard-validator
# 再安装你选择的 schema library，比如 Zod / Valibot / ArkType / TypeBox
```

概念化代码：

```ts
import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi";

const CreateFollowUpDraftInput = z.object({
  store_id: z.string(),
  lead_id: z.string(),
  tone: z.enum(["friendly", "concise", "professional"]).optional(),
}).openapi("CreateFollowUpDraftInput");

const FollowUpDraft = z.object({
  draft_id: z.string(),
  status: z.literal("pending_approval"),
  message: z.string(),
}).openapi("FollowUpDraft");

const createFollowUpDraftRoute = createRoute({
  method: "post",
  path: "/follow-up-drafts",
  operationId: "createFollowUpDraft",
  tags: ["follow-up"],
  request: {
    body: {
      content: {
        "application/json": {
          schema: CreateFollowUpDraftInput,
        },
      },
    },
  },
  responses: {
    201: {
      description: "Follow-up draft created",
      content: {
        "application/json": {
          schema: FollowUpDraft,
        },
      },
    },
  },
});

const app = new OpenAPIHono();

app.openapi(createFollowUpDraftRoute, async (c) => {
  const body = c.req.valid("json");
  const draft = await followUpService.createDraft({
    storeId: body.store_id,
    leadId: body.lead_id,
    tone: body.tone,
  });

  return c.json({
    draft_id: draft.draftId,
    status: draft.status,
    message: draft.message,
  }, 201);
});

app.doc("/openapi.json", {
  openapi: "3.0.0",
  info: {
    title: "Retaintive API",
    version: "1.0.0",
  },
});
```

这时 `GET /openapi.json` 就能返回机器可读的 API schema。后面再用这份 schema 生成 internal client、CLI、SDK、MCP tool schema 或 docs。

选择上可以这样判断：

| 场景                               | 推荐方式                         |
| -------------------------------- | ---------------------------- |
| 新 endpoint，愿意按 OpenAPI route 风格写 | `@hono/zod-openapi`          |
| 已有 Hono app，想尽量少改 route          | `hono-openapi` middleware 方向 |
| 只想先验证 3-5 个核心 endpoint           | 手写 OpenAPI YAML / JSON 也可以   |

Retaintive 自己怎么选，集中看 [8.1 当前状态](#81-当前状态)。这里先记住一件事：`@hono/zod-openapi` 和 `hono-openapi` 都是生成 OpenAPI 的方式，不是业务架构本身；业务边界、auth、error model、scope、idempotency 仍然要自己设计。

关键点：**工具能帮你生成格式和重复代码，但不能替你决定 API 设计。** `store_id` 怎么传、错误结构怎么统一、scope 怎么命名、哪些 response 要写清楚，这些仍然需要我们设计。

### 4.7 Auth / Identity / Scope

**Auth** 管“谁在调用”。

**Identity** 管“代表谁调用”：用户、bot、service account、tenant。

**Scope** 管“能做什么”：只读、创建 draft、发送短信、审批、管理 billing。

对 AI Agent 来说这层特别重要，因为 agent 可能会代表人做事：

```text
代表老板批准 follow-up message
代表 system 每天生成 draft
代表 support 查看某个客户数据
代表 bot 写入 Lark Base
```

如果 identity 和 scope 不清楚，agent 就会变成一把没有边界的远程钥匙。

### 4.8 Webhook / Event stream

API 是“我主动问你”。Webhook / event stream 是“事情发生了你主动告诉我”。

例子：

```text
RingCentral call ended -> webhook 通知 retaintive -> call ingestion workflow
Call transcript generated -> event 触发 contact / lead analysis workflow
Lead email received -> lead-tracking workflow creates lead_outreach task
Complaint detected -> task workflow creates retention task (UI label: complaint / retention)
Task overdue -> event 或 scheduled scan 触发 reminder / summary workflow
每天早上 9 点 -> scheduler 扫描 missed calls / overdue lead tasks
每周一 8 点 -> scheduler 生成 weekly operator report
```

Webhook 也有两种视角：

```text
事件发送方看到:
  POST https://api.retaintive.com/webhooks/ringcentral
  headers: signature / timestamp
  body: call ended event

retaintive 接收方内部实现:
  verify signature
    -> deduplicate event_id
    -> write raw event
    -> enqueue call analysis job
    -> return 200 quickly
```

注意：event / scheduler 触发的不一定是“自由 agent”。在 Retaintive 这种业务系统里，第一层通常应该是确定性 workflow：写入 raw event、去重、更新 calls / leads / tasks、维护 task lifecycle。Agent 更适合接在 workflow 后面，处理解释、摘要、草稿、排序和人类审批入口。

```text
不推荐:
  call ended
    -> agent 自己决定是否创建 task / 改 lead status / 发送消息

推荐:
  call ended
    -> backend workflow 更新 calls / leads / tasks
    -> lead_outreach / lead_follow_up / retention task created or overdue
    -> agent 生成 context summary / suggested reply / manager brief
    -> human approval for external messages
    -> backend workflow writes final mutation and audit log
```

所以“Agent 产品不能只靠人来问”的意思不是所有 event 都直接交给 agent，而是系统应该能被 event / scheduler 主动推动；其中确定性状态变更交给 workflow，模糊判断和自然语言产物交给 agent，并把高风险动作交给人审批。

***

## 5. 操作面概念

这一层回答：同一个 API 能力，怎么包装给代码、人、CI、agent、外部 AI client 使用。

### 5.1 SDK

**SDK** 是给程序员在代码里调用 API 的库。

用户如果不用 SDK，就要自己写 HTTP：

```ts
await fetch("https://api.retaintive.com/follow-up-drafts", {
  method: "POST",
  headers: { Authorization: `Bearer ${token}` },
  body: JSON.stringify({
    store_id: "store_123",
    lead_id: "lead_456",
  }),
});
```

SDK 用户看到的是普通代码调用，不需要看见 HTTP 细节：

```ts
const client = new RetaintiveClient({
  apiKey: process.env.RETAINTIVE_API_KEY,
});

await client.followUps.createDraft({
  storeId: "store_123",
  leadId: "lead_456",
});
```

SDK 内部最终还是会发 HTTP request。下面是概念化示例，不代表一定要手写这一层：

```ts
class RetaintiveClient {
  constructor(private options: { apiKey: string }) {}

  followUps = {
    createDraft: async (input: { storeId: string; leadId: string }) => {
      return fetch("https://api.retaintive.com/follow-up-drafts", {
        method: "POST",
        headers: {
          Authorization: `Bearer ${this.options.apiKey}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          store_id: input.storeId,
          lead_id: input.leadId,
        }),
      });
    },
  };
}
```

2026 年更常见的做法不是从零手写所有 SDK method，而是：

```text
OpenAPI schema
  -> SDK generator
  -> generated typed client
  -> 少量配置 / wrapper / publishing workflow
```

SDK 解决的是开发效率、类型、retry、auth、错误处理。它主要给工程师写代码时用。SDK / CLI 可以做客户端 retry 和友好错误，但 backend 仍然必须自己做 auth、scope、idempotency、audit、rate limit 和 business validation。

SDK 不是所有 SaaS 的第一优先级。如果前端、后端和 worker 都在同一个系统边界内，后端内部应该优先调用 service layer，而不是绕一圈 HTTP 再通过 SDK 调自己：

```text
推荐:
  backend route -> followUpService.createDraft(...)

不推荐:
  backend route -> SDK -> HTTP API -> 同一个 backend
```

SDK 真正有价值的场景是：外部开发者、partner integration、POS 系统、mobile app、多个内部服务，或已经有 OpenAPI schema、可以低成本生成 typed client。

### 5.2 Generated internal client

`generated internal client` 是**先不对外发布的 SDK**。它不是给客户安装的 npm package，而是给我们自己的 CLI、测试、worker 或 future MCP server 用的 typed API client。

```text
OpenAPI schema
  -> generator
  -> internal client
  -> our CLI / tests / internal jobs call this client
```

调用方看到的是：

```ts
await internalClient.followUps.createDraft({
  storeId: "store_123",
  leadId: "lead_456",
});
```

它内部负责：

```text
storeId -> store_id
leadId -> lead_id
Authorization header
baseUrl
timeout
retry
error mapping
typed response
```

对 retaintive 来说，如果暂时没有外部开发者，就可以先不发布官方 SDK；但可以先生成一个 internal client 给 CLI、测试和未来 MCP server 复用。

### 5.3 CLI / Thin CLI

**CLI** 是命令行工具。它让人、脚本、CI、agent 在 terminal 里操作系统。

CLI 用户看到的是 terminal 命令：

```bash
retaintive follow-up candidates --store-id store_123 --format json
retaintive approval list --status pending --format json
```

`thin CLI` 是一层很薄的 terminal wrapper。它自己不应该重新写一套业务逻辑，只做三件事：

```text
1. 解析 terminal flags
2. 调 generated internal client / SDK
3. 把结果用 JSON / table 输出，并设置 exit code
```

CLI command 内部应该像这样薄：

```ts
const result = await internalClient.followUps.createDraft({
  storeId: options.storeId,
  leadId: options.leadId,
});

console.log(JSON.stringify(result, null, 2));
```

完整链路是：

```text
OpenAPI schema
  -> generated internal client
  -> thin CLI
  -> POST /follow-up-drafts
  -> backend service
```

一句话：**SDK 给代码用，CLI 给 terminal 用。**

CLI 有三种实现方式：

```text
方式 A: CLI 直接调 API
  retaintive CLI
    -> fetch("POST /follow-up-drafts")
    -> backend

方式 B: CLI 复用 SDK / generated client
  retaintive CLI
    -> internalClient.followUps.createDraft(...)
    -> client 内部调 API
    -> backend

方式 C: OpenAPI 直接生成 CLI
  OpenAPI schema
    -> CLI generator
    -> generated CLI wraps generated SDK or generated client
    -> backend
```

方式 A 开发最快，适合 MVP、内部工具、只有少量命令时。但风险是：如果每个 CLI command 都自己写 `fetch`、auth header、error handling，以后再补 SDK 时会发现逻辑散落在很多文件里。

更稳的 MVP 写法是：

```text
cli/commands/follow-up-create.ts   # 只负责参数解析、输出格式、exit code
cli/internal-client/follow-ups.ts  # 负责 createDraft(...)
cli/internal-client/request.ts     # 负责 baseUrl、auth、timeout、error mapping
```

以后升级成正式 SDK 或 generated SDK 时，大致变成：

```text
packages/retaintive-sdk/src/follow-ups.ts
packages/retaintive-sdk/src/request.ts
cli/commands/follow-up-create.ts -> import SDK
```

方式 C 是 2026 年越来越常见的 API DevEx 路线。Speakeasy 的 CLI generator 会从 OpenAPI spec 生成 Go/Cobra CLI，并包装 generated Go SDK；Stainless 和 Fern 也公开支持从 OpenAPI spec 生成 CLI / SDK / docs / MCP 这类 developer interface。

这也解释了为什么“SDK 可以生成”和“CLI 复用 SDK”并不矛盾：很多 generated CLI 本来就是包装 generated SDK。我们不一定要手写 SDK，但最好让 CLI 复用同一个 generated client / generated SDK，而不是 CLI 自己散落 HTTP 调用。

生成 CLI 的优势是快、覆盖面广、和 API spec 同步；缺点是默认命令体验未必符合人和 agent 的真实工作流。比如 API operation 可能叫 `createFollowUpDraft`，但人类更想要：

```bash
retaintive follow-up draft create --store-id store_123 --lead-id lead_456 --format json
```

agent 更需要稳定的 JSON 输出、可预测的 exit code、清晰的 `--dry-run`、`--as user/bot`、`--confirm` 等风险控制。生成 CLI 后通常仍需要一层产品化整理。

### 5.4 Dev tools / Logs / Local tunnel / Sandbox

这几个经常被忽略，但是真正决定开发体验。

| 概念           | 作用                    | Stripe 类比                                   |
| ------------ | --------------------- | ------------------------------------------- |
| Dev tools    | 帮开发者测试和管理 integration | `stripe` CLI                                |
| Logs         | 看 API 请求、错误、延迟        | `stripe logs tail`                          |
| Local tunnel | 把远程 webhook 转发到本地     | `stripe listen --forward-to localhost:4242` |
| Sandbox      | 安全测试环境                | test mode / sandbox account                 |
| Test data    | 可重复测试样本               | test customer / test payment / test store   |

对 retaintive 来说，未来也应该有 test store、test customer、test call、test review，而不是拿真实客户数据试 agent。

### 5.5 Function calling / Tool calling

这是“你自己的产品内 AI assistant”最常用的工具调用方式。

比如老板在 retaintive dashboard 里点：

```text
帮我总结这家门店本周未跟进 lead，并生成 follow-up 草稿
```

你的后端可以把几个 function 暴露给模型：

```text
get_follow_up_candidates(store_id, date_range)
create_follow_up_draft(lead_id, tone)
create_approval_item(draft_id)
```

这不需要 MCP。因为 AI 在你的产品里，你的 backend 直接控制工具和权限。

Function calling 的两种视角：

```text
产品用户看到:
  “帮我总结这家门店本周未跟进 lead，并生成 follow-up 草稿”

backend 内部实现:
  LLM chooses tool: get_follow_up_candidates(...)
    -> backend validates store access
    -> service reads leads
    -> LLM drafts follow-up
    -> backend writes approval_item
    -> UI shows editable draft
```

### 5.6 MCP

**MCP (Model Context Protocol)** 是 AI client 和外部工具之间的标准协议。

它适合这个问题：

```text
客户想在自己的 Claude / ChatGPT / Cursor 里连接 retaintive，
让外部 AI 安全读取门店数据、创建 draft、查询指标。
```

MCP server 暴露工具 schema，AI client 通过 `tools/list` 和 `tools/call` 使用它。

MCP 的两种视角：

```text
AI client 看到:
  tool name: create_follow_up_draft
  input schema: { store_id, lead_id, tone }
  output schema: { draft_id, status }

MCP server 作者内部实现:
  receive tools/call
    -> validate OAuth token / tenant
    -> check tool allowlist and scope
    -> call retaintive REST API or service layer
    -> return structuredContent
```

重要判断：

```text
客户在我们的 dashboard 里用 AI -> Function calling 更直接
客户在自己的 AI client 里接我们 -> MCP 更合适
内部 agent 在 terminal 里操作 -> CLI + Skill 往往更快
```

### 5.7 Connector

Connector 是已经封装好的外部系统连接器。比如 GitHub connector、Lark connector、Stripe connector、Sentry connector。

它和 MCP / CLI 的关系取决于实现：

```text
有的 connector 背后是 MCP
有的 connector 背后是平台私有 API
有的 connector 背后是 OAuth + REST API
```

产品判断上不用纠结名字，重点看：

- 它能不能读写你需要的对象？
- Auth 和 scope 能不能控？
- 有没有 audit？
- 有没有 rate limit 和错误处理？

### 5.8 Skill

Skill 是给 agent 的可复用操作指南。它通常是 Markdown，告诉 agent：

```text
什么时候使用这个工具
命令怎么跑
哪些动作需要人类确认
遇到权限错误怎么处理
输出应该怎么组织
```

Skill 不直接执行外部操作。它教 agent 用 CLI / MCP / API。

Skill 的两种视角：

```text
agent 看到:
  “遇到 follow-up message 需求时，先 create draft，再进 approval queue，不要直接 send”

Skill 作者写的是:
  SKILL.md
    - trigger conditions
    - allowed commands/tools
    - safety rules
    - output format
    - troubleshooting steps
```

对比：

| 维度          | CLI           | MCP                       | Skill                |
| ----------- | ------------- | ------------------------- | -------------------- |
| 是什么         | 命令行工具         | AI tool protocol          | Markdown/SOP/工作流指南   |
| 能不能直接操作外部系统 | 能             | 能                         | 不能                   |
| 谁用它         | 人、脚本、CI、agent | AI client / agent runtime | AI agent 读           |
| 解决什么问题      | 稳定执行命令        | 标准化暴露工具                   | 教 agent 何时、如何、安全地用工具 |

Lark CLI 的方向很典型：它既有大量 CLI commands，又有 AI Agent Skills。也就是说，**CLI 提供手，Skill 教怎么用手。**

***

## 6. Agent 运行层概念

这一层回答：agent 活在哪里，怎么持续跑，怎么被人监督。

### 6.1 Agent Runtime

Agent Runtime 是 agent 的运行现场。它管理：

```text
loop
state
memory
queue
scheduler
tool calls
sandbox
approval
retry
trace
```

一个最小 loop 可以理解成：

```text
observe context
  -> plan
  -> choose tool
  -> run tool
  -> inspect result
  -> ask human if risky
  -> write state / produce artifact
  -> continue or stop
```

Runtime 解决的是“agent 活在哪里”：

- 任务从哪里来：event、cron、Lark message、dashboard button。
- 任务状态存哪里：database、queue、Beads、workflow table。
- 工具怎么调用：API、CLI、MCP、SDK。
- 失败怎么重试：retry、dead letter、human escalation。
- 高风险动作怎么拦：approval、policy、scope。
- 结果怎么给人看：dashboard、Lark card、PR、email draft。

不要把 runtime 和模型混在一起。模型负责推理，runtime 负责让推理过程在真实系统里可恢复、可审计、可控制。

#### Workflow 和 Agent 的边界

Retaintive 现在很多核心能力本质上是 workflow，不应该为了“更 AI”就改成自由 agent：

```text
RingCentral event ingestion
lead email polling
transcript processing
contact / lead analysis pipeline
task creation / update / close
dashboard aggregation
message send logging
```

这些 workflow 的特点是：

```text
输入清楚
状态机清楚
幂等和重试重要
错误要可恢复
结果要可审计
不能让模型随意修改事实
```

所以当前正确路线不是“把 workflow 替换成 agent”，而是：

```text
Workflow owns state and lifecycle.
Agent assists with reasoning, language, prioritization, and human interface.
```

例子：

```text
lead_outreach task created
  -> workflow 写入 task
  -> agent 解释为什么这是 high priority
  -> agent 起草 manager brief 或 follow-up draft
  -> human approves if message will be sent
  -> workflow 执行发送和 audit

retention task created (UI label: complaint / retention)
  -> workflow 写入 retention task
  -> agent 总结 complaint history 和建议处理话术
  -> manager 审核
  -> workflow 记录 outcome / complaint_resolved / audit

daily schedule
  -> scheduler 扫描 overdue tasks / missed calls / stale leads
  -> agent 生成 morning summary
  -> manager 在 dashboard / Lark 里处理
```

未来可以升级成 agentic workflow，但边界仍然应该保留：

```text
确定性状态变更:
  workflow / service layer

模糊判断、语言产物、排序、解释:
  agent

外部触达、删除、审批、生产影响:
  human approval + policy + audit
```

### 6.2 State / Memory / Queue / Scheduler

这些是让 agent 从“一问一答”变成“能持续工作”的关键。

| 概念        | 作用       | 例子                            |
| --------- | -------- | ----------------------------- |
| State     | 当前任务进行到哪 | `approval.status = pending`   |
| Memory    | 可复用背景信息  | 门店话术、老板偏好                     |
| Queue     | 待处理任务队列  | 100 个待分析 call / review        |
| Scheduler | 定时触发     | 每天 9 点扫描 follow-up candidates |

不要把 memory 和 SoT 混为一谈。Memory 可以帮助表达，SoT 决定事实。

### 6.3 Policy / Approval / Audit

Policy 是刹车系统。

```text
read-only 可以自动
create draft 可以自动
send SMS 必须 human approval
delete customer 禁止 agent 执行
跨 store 数据默认拒绝
```

Audit 是事后可解释：

```text
谁触发了任务
agent 读了哪些数据
生成了什么 draft
谁批准了
什么时候发出
发给了谁
```

没有 policy 和 audit，AI Agent 很难进入真实商业工作流。

### 6.4 Observability / Traces / Evals

Observability 告诉你系统发生了什么。

Trace 告诉你 agent 每一步怎么做的。

Eval 告诉你模型输出有没有变好或变坏。

对 AI 功能来说，只看“有没有报错”不够，还要看：

```text
follow-up 文案是否符合品牌 tone
是否误把低意向 lead 当成高意向 lead
是否重复触达同一客户
是否漏掉关键 objections
是否违反审批规则
```

长期稳定性靠 eval 和 trace，不靠“我感觉这次回答还行”。

### 6.5 Product surface

Product surface 是人类使用和监督 agent 的地方：

```text
Web dashboard
Lark card
Slack thread
Email draft
IDE panel
Desktop app
```

surface 的核心不是“展示 AI 很聪明”，而是让人类可以：

- 看懂 AI 做了什么。
- 编辑 AI 草稿。
- 批准或驳回。
- 追踪结果。
- 发现错误并纠正系统。

Product surface 的两种视角：

```text
老板看到:
  待审核 follow-up 草稿
  编辑 / 批准 / 驳回按钮
  发送结果和效果回流

系统内部实现:
  approval_item.status = pending
    -> user edits draft
    -> approve action checks permission
    -> send job enqueued
    -> message_sends row written
    -> audit log written
```

***

## 7. 怎么选择：API、SDK、CLI、MCP、Skill、UI

### 7.1 同一个能力可以有多种入口

底层能力是“创建 follow-up 草稿”。它可以同时被 API、SDK、CLI、MCP 和产品 UI 使用：

```text
Web dashboard button
  -> internal API / service layer

Backend worker / separate service
  -> SDK / generated internal client
  -> REST API / service layer

Engineer / CI / Codex / Claude Code
  -> CLI
  -> REST API / service layer

External AI client
  -> MCP tool
  -> REST API / service layer
```

关键原则：**入口可以很多，业务规则只能有一份。** 权限、计量、审核、幂等、审计都应该在 API 或 service layer 收口，不要复制到每个入口里。

### 7.2 选择表

| 问题                        | 优先选什么                            | 原因                                     |
| ------------------------- | -------------------------------- | -------------------------------------- |
| 产品内 AI assistant 要读写自己系统  | Function calling / service layer | backend 已经掌握 auth、tenant、policy        |
| 工程师、CI、Codex、Botmux 要稳定操作 | CLI / thin CLI                   | terminal、stdout、stderr、exit code 适合自动化 |
| 外部开发者写代码接入                | SDK                              | 类型、retry、auth、error mapping 更友好        |
| 外部 AI client 要接入          | MCP / tool schema                | 标准发现和调用工具                              |
| agent 容易误操作，需要 SOP        | Skill                            | 告诉 agent 何时用、怎么用、什么不能做                 |
| 人类要审批、编辑、追踪               | Product surface                  | AI 产物必须进入人的工作流                         |

### 7.3 MCP 和 CLI 不是替代关系

MCP 不是 API 的替代品，也不是 CLI 的替代品。它是 AI client 和工具之间的标准协议。

```text
AI client
  -> MCP tools/list
  -> MCP tools/call(create_follow_up_draft)
  -> MCP server
  -> retaintive REST API
```

MCP server 可以直接调 REST API，也可以调用 CLI，但要分场景：

| 场景                       | 推荐方式                        | 原因                               |
| ------------------------ | --------------------------- | -------------------------------- |
| 本地 dev tool / 内部 agent   | MCP 包 CLI 可以接受              | 复用现成命令，开发快                       |
| 生产 remote MCP / 多租户 SaaS | MCP 直接调 API 或 service layer | 更好做 auth、审计、超时、限流和错误处理           |
| 人类或 CI 调试                | 直接用 CLI                     | stdout、stderr、exit code 最好 debug |

Stripe 现在同时提供 CLI、MCP server、Agent Toolkit，说明这几层不是互斥的，而是面向不同使用者。

### 7.4 一个 API 要同时做 SDK 和 CLI，需要什么

| 层               | 需要什么                                                      | `create_follow_up_draft` 例子                        |
| --------------- | --------------------------------------------------------- | -------------------------------------------------- |
| API contract    | endpoint、method、request、response、error、auth               | `POST /follow-up-drafts`                           |
| OpenAPI quality | `operationId`、`tags`、schema、examples、security、error model | `operationId: createFollowUpDraft`                 |
| Types           | 输入输出类型                                                    | `CreateFollowUpDraftInput`, `FollowUpDraft`        |
| SDK method      | 程序员 import 后调用的方法                                         | `client.followUps.createDraft(input)`              |
| SDK runtime     | `baseUrl`、auth header、timeout、retry、error mapping         | `RETAINTIVE_API_KEY`                               |
| CLI command     | 命令名、参数、默认值、输出格式                                           | `retaintive follow-up draft create --store-id ...` |
| CLI output      | JSON/table、stderr、exit code                               | `--format json` 给 agent / CI 用                     |
| Tests           | API mock、SDK unit test、CLI smoke test                     | 创建 draft 成功、权限失败、重复请求                              |
| Docs            | HTTP 示例、SDK 示例、CLI 示例                                     | 三种入口都指向同一个业务能力                                     |

推荐投入顺序：

```text
MVP 内部使用:
  API -> OpenAPI schema -> generated internal client -> thin CLI

长期 developer experience:
  API + high-quality OpenAPI schema
    -> generated SDK
    -> generated or curated CLI wrapping the same client
    -> generated MCP / tool schema
    -> Skills / docs / tests
```

***

## 8. Retaintive 当前状态和投入顺序

### 8.1 当前状态

从现有架构文档看，retaintive 当前主要是：

```text
Hono backend API
  -> Hono RPC fetch client / AppType
  -> frontend web app
```

这对内部 web app 很好，因为前后端能共享类型。但它不是一套 public OpenAPI-first developer platform。也就是说，我们现在不应该假装已经有 Stripe 式 SDK / CLI / MCP 生态。

两者不是竞争关系：

| 维度              | Hono backend API             | OpenAPI-first developer platform |
| --------------- | ---------------------------- | -------------------------------- |
| 本质              | 后端实现                         | 对外 API 合同 + 开发者体验                |
| 主要用户            | 我们自己的 frontend/backend       | 外部开发者、partner、AI agent、CI        |
| Source of truth | TypeScript route / `AppType` | `OpenAPI schema`                 |
| 主要产物            | API route                    | docs、SDK、CLI、MCP、mock、tests      |
| 适合阶段            | 内部产品快速开发                     | 对外集成、agent 操作、长期平台化              |

更准确地说：

```text
Hono = API 怎么实现
OpenAPI = API 怎么被机器和外部系统理解、生成、测试、调用
```

`plain Hono + Hono RPC / AppType` 本身仍然是 API，只是它的 source of truth 是 TypeScript route 类型，而不是一份独立的 `openapi.json`：

| 问题                           | plain Hono + Hono RPC / AppType             | OpenAPI-first                   |
| ---------------------------- | ------------------------------------------- | ------------------------------- |
| 有没有 API                      | 有，仍然是 HTTP API                              | 有，通常也是 HTTP API                 |
| 谁最舒服                         | 同一个 TypeScript monorepo 里的 frontend/backend | 外部开发者、AI agent、CLI、MCP、跨语言 SDK  |
| 类型从哪里来                       | backend 的 TypeScript route type             | `openapi.json` / `openapi.yaml` |
| 能不能生成 public SDK / CLI / MCP | 不直接适合                                       | 适合                              |
| 改 API 时谁容易受影响                | 主要是同 repo TypeScript 调用方                    | 所有依赖 contract 的调用方              |

所以 `plain Hono + Hono RPC / AppType` 和 API 不是两层东西；它是**一种 API 实现 + 内部 typed client 方式**。OpenAPI-first 是在 API 之外再把合同标准化，方便更多机器和外部系统使用。

所以 Retaintive 不需要换掉 Hono。推荐路线是：

```text
保留 Hono backend
  -> 给核心 endpoint 补 Zod / OpenAPI schema
  -> 生成 openapi.json
  -> 生成 internal client
  -> 做 thin CLI
  -> 以后再生成 public SDK / MCP / docs / sandbox
```

更具体的阶段拆法：

```text
Phase 1:
  用 @hono/zod-openapi 做 /v3/agent 的 3-5 个核心 endpoint

Phase 2:
  openapi.json -> generated internal client

Phase 3:
  thin CLI 调 internal client

Phase 4:
  Botmux / Codex / CI 用 CLI 操作 Retaintive

Phase 5:
  如果以后真的开放给客户或 partner:
    Speakeasy / Fern / Stainless 生成 public SDK / docs / CLI / MCP
```

`@hono/zod-openapi` 的典型写法是：

```ts
import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi";

const CreateDraftInput = z.object({
  store_id: z.string(),
  lead_id: z.string(),
  tone: z.enum(["friendly", "concise", "professional"]).optional(),
}).openapi("CreateDraftInput");

const DraftResponse = z.object({
  draft_id: z.string(),
  status: z.literal("pending_approval"),
  message: z.string(),
}).openapi("DraftResponse");

const createDraftRoute = createRoute({
  method: "post",
  path: "/follow-up-drafts",
  operationId: "createFollowUpDraft",
  tags: ["follow-up"],
  request: {
    body: {
      content: {
        "application/json": {
          schema: CreateDraftInput,
        },
      },
    },
  },
  responses: {
    201: {
      description: "Follow-up draft created",
      content: {
        "application/json": {
          schema: DraftResponse,
        },
      },
    },
  },
});

export const agentRoutes = new OpenAPIHono();

agentRoutes.openapi(createDraftRoute, async (c) => {
  const body = c.req.valid("json");
  const draft = await followUpService.createDraft(body);
  return c.json(draft, 201);
});

agentRoutes.doc("/openapi.json", {
  openapi: "3.0.0",
  info: {
    title: "Retaintive Agent API",
    version: "1.0.0",
  },
});
```

再把它 mount 到现有 Hono app：

```ts
app.route("/v3/agent", agentRoutes);
```

这说明 `OpenAPIHono` 适合新 route group，不要求把整个现有 app 一次性改写。

OpenAPI-first 不代表以后不能改 API。区别是：一旦它变成 contract，每次修改都要按兼容性处理：

| 改动类型                      | 是否安全                | 例子                                         |
| ------------------------- | ------------------- | ------------------------------------------ |
| 新增 optional request field | 通常安全                | 给 `CreateDraftInput` 增加可选 `tone`           |
| 新增 response field         | 通常安全                | response 增加 `created_at`                   |
| 新增 endpoint               | 安全                  | 增加 `GET /v3/agent/reports/morning-summary` |
| 删除字段 / 改字段类型              | breaking change     | `lead_id` 从 string 改成 number               |
| 改 endpoint path / method  | breaking change     | `POST /follow-up-drafts` 改成 `POST /drafts` |
| 改 auth / scope 语义         | 高风险 breaking change | 原本 read scope 变成 write scope               |

内部-only API 可以更快改；external / agent-facing API 要更稳。现实做法是版本化和扩展优先：

```text
/v3/agent/follow-up-drafts
  -> 新增字段优先 optional
  -> breaking change 新开 /v4 或新 operationId
  -> old endpoint 保留一段 deprecation window
```

已有 route 很多时，全量迁移成本高，不是因为 `OpenAPIHono` 本身难，而是因为迁移会牵动每个 endpoint 的边界合同：

```text
request schema
response schema
error schema
auth / scope
tenant / store access
operationId / tags
tests
frontend hc<AppType> 调用
```

如果只是为了“看起来 OpenAPI-first”重写所有 route，风险大于收益。更合理的是只把 agent、CLI、partner 真会用的能力先合同化。

前端如果仍是我们自己的 web app，`hono/client` + `AppType` 仍然适合：

```ts
import { hc } from "hono/client";
import type { AppType } from "./server";

const client = hc<AppType>("https://api.retaintive.com");
```

这里 frontend 只 import TypeScript type，不会把 server runtime bundle 进前端。它解决的是同一个 TypeScript monorepo 内部的 end-to-end type safety。

但它不等于 OpenAPI-first developer platform。CLI、MCP、外部 partner、跨语言 SDK、contract tests 更应该基于 `openapi.json`：

```text
openapi.json
  -> openapi-typescript + openapi-fetch
  -> generated internal client
  -> thin CLI
```

如果要生成 Vue Query / MSW mock，可以看 Orval；如果以后要做公开的 SDK / docs / CLI / MCP suite，再评估 Speakeasy / Fern / Stainless。

如果我们不把 SDK / CLI 暴露给 external people，只做内部 AI agent，也不一定一开始就需要 public SDK 或 public CLI。选择取决于 agent 跑在哪里：

| 内部 agent 运行位置                       | 推荐入口                                 | 原因                                                  |
| ----------------------------------- | ------------------------------------ | --------------------------------------------------- |
| 跑在同一个 backend / worker 里            | service layer / function calling     | 最直接，auth、tenant、policy 都在服务端                        |
| 跑在同一个 TypeScript monorepo 里         | Hono RPC / AppType 或 internal client | 类型安全，开发快                                            |
| 跑在 Botmux / Codex / CI / terminal 里 | thin CLI                             | terminal 环境天然会调用命令；JSON output、exit code、logs 适合自动化 |
| 跑在外部 AI client 或多租户 remote tool 里   | MCP 或 API                            | 更好做 auth、audit、rate limit、tenant isolation          |

因此，内部 agent 的 MVP 可以不做 public SDK；但如果 agent 不是直接运行在 backend 进程里，而是在 Botmux / Codex 这种 CLI runtime 里，`thin CLI + generated internal client` 会很有价值。

一句话判断：`plain Hono + Hono RPC / AppType` 是现在内部开发的快路；`@hono/zod-openapi` 是未来新 agent-facing API 的稳路；`hono-openapi` 是老 route 的迁移路。

类比：

```text
Hono backend API = 厨房里的做菜流程
OpenAPI-first developer platform = 对外菜单、点餐合同、配送规则和测试厨房
```

### 8.2 MVP 必须做

```text
1. Domain model / SoT
   store、contact、call、lead、follow_up_draft、approval、usage_event、audit_log

2. API
   创建 draft、列审核队列、批准发送、记录 usage、记录发送结果

3. OpenAPI schema
   至少覆盖核心 API 的 request、response、error、auth、operationId 和 examples

4. Generated internal client / thin CLI
   给工程师、CI、Codex、Botmux 一个稳定操作面，不需要一开始发布 public SDK

5. LLM Gateway
   所有 LLM 调用统一经过这里

6. Usage metering
   per-client / per-store 用量记录，支持套餐和超额

7. Human approval
   AI 只能出 draft，不能直接发 SMS / WhatsApp / Email

8. Basic product surface
   审核队列、编辑、批准、驳回、发送记录

9. Audit log
   谁生成、谁改、谁批准、发给谁、何时发送
```

### 8.3 MVP 可以先不做

```text
多语言官方 SDK
公开 CLI
公开 MCP server
复杂 multi-agent runtime
长期 memory
自动 schedule UI
多模型复杂动态路由
客户自带 ChatGPT/Claude 连接
```

注意：不是永远不做，而是不要在业务状态还没稳定前做。

### 8.4 长期稳定性必须补

```text
public SDK / public CLI
webhooks / event stream
sandbox / test mode
MCP server 或 hosted MCP integration
policy engine
evals / traces / regression suite
integration health check
rate limit / quota / billing reconciliation
```

### 8.5 推荐投入顺序

```text
Phase 1: data model + API + OpenAPI schema + approval + usage metering
Phase 2: generated internal client + thin CLI
Phase 3: stabilize task workflow, especially lead_outreach / lead_follow_up / retention task lifecycle
Phase 4: agent-assisted task summaries, morning summary, and review / complaint-handling drafts
Phase 5: recall / campaign Skill, 加 human approval + touch channel
Phase 6: RingCentral / POS / review platform events, 建闭环
Phase 7: LLM Gateway + audit log + basic evals 深化
Phase 8: Lark / Botmux control plane, 放进真实工作流
Phase 9: public SDK / generated CLI / MCP server, 面向客户或 partner
```

为什么先做 task workflow 和 agent-assisted summaries，再做主动召回：

- `lead_outreach` / `lead_follow_up` / `retention` task、overdue task 更接近现有 Retaintive workflow。
- Agent 可以先做摘要、解释、草稿和排序，不直接拥有 task lifecycle。
- 先做 draft 和 approval，比直接自动触达风险低。
- 主动召回会触达真实客户，必须先有 approval、audit、usage metering 和发送日志。
- 低风险场景能先验证 LLM Gateway、计量、UI、权限模型。

***

## 9. 什么自己做，什么不要重复造

### 9.1 不要重复造

| 需求                                             | 优先用现成的                  |
| ---------------------------------------------- | ----------------------- |
| coding agent / repo 修改                         | Codex CLI / Claude Code |
| Lark 里的 CLI session runtime                    | Botmux                  |
| Lark Docs / Base / Sheets / Task / Calendar 操作 | lark-cli / Lark MCP     |
| 标准连接外部 AI client                               | MCP                     |
| agent orchestration / tracing 起点               | OpenAI Agents SDK 等现成框架 |
| code review / PR 辅助                            | Codex / GitHub tools    |

### 9.2 必须自己做

| 领域                                              | 为什么不能外包给通用 agent                                  |
| ----------------------------------------------- | ------------------------------------------------- |
| retaintive data model                           | 只有我们知道 store、customer、call、lead、review、task 的业务含义 |
| tenant / store isolation                        | 这是产品安全边界，不是模型能力                                   |
| usage metering                                  | 收费按包月 + 使用量，必须精确可对账                               |
| approval queue                                  | AI 只能产草稿，人批准才触达客户                                 |
| audit log                                       | 商业化后必须能解释谁让系统做了什么                                 |
| LLM Gateway                                     | 模型路由、降级、缓存、成本和防注入需要统一出口                           |
| follow-up / review / recall Skills              | 这是产品差异化，不是通用工具                                    |
| POS / RingCentral / review platform integration | 集成质量决定产品闭环                                        |

***

## 10. Codex、Claude Code、Botmux、lark-cli 的关系

2026-06-15 本机验证快照：

```text
codex-cli 0.139.0
Claude Code 2.1.172
botmux 2.34.0
lark-cli 1.0.52
```

这些工具的关系：

| 工具          | 是什么                                          | 负责什么                                          | 不负责什么                  |
| ----------- | -------------------------------------------- | --------------------------------------------- | ---------------------- |
| Codex CLI   | OpenAI 的本地 coding agent CLI                  | 读 repo、改文件、跑命令、MCP、review、自动化 coding workflow | 不替你定义 retaintive 业务状态机 |
| Claude Code | Anthropic 的 coding agent CLI                 | 类似 Codex CLI，面向 repo 和 shell 的 agentic coding | 不替你做产品 SoT             |
| Botmux      | Lark/Feishu 到 AI coding CLI 的 runtime bridge | 把 Lark 私聊/群聊/话题映射到 CLI session，流式回传结果         | 不是 Lark 全能力 API 层      |
| lark-cli    | Lark/Feishu 工作系统 CLI                         | 操作 Docs、Base、Sheets、Tasks、Calendar、IM、Mail 等  | 不是长期 agent runtime     |

几个容易混的概念：

```text
Codex CLI = /opt/homebrew/bin/codex 这个可执行程序
Codex CLI session = 一次运行中的 Codex 对话/任务上下文
Botmux session = Lark chat/thread/topic 映射到一个 CLI session
openai/codex repo = Codex CLI 的开源源码，不等于每次使用都要 clone
```

所以 Botmux 使用 Codex 时，通常是启动本机已安装的 `codex` 命令，不是把 `openai/codex` repo 当作项目依赖 clone 进来。版本号只是当前机器快照，长期文档判断应以官方 docs、`command --version` 和实际部署配置为准。

***

## 11. 传统 API 公司怎么 AI-native 化

成熟 API 公司通常会从 API 往上补开发者体验，再补 AI-native 工具层：

```text
API
  -> OpenAPI schema
  -> generated docs / SDK / CLI / test fixtures
  -> sandbox / logs / webhook tooling
  -> MCP / Agent Toolkit / Skills
  -> runtime / workflow / approval / audit
```

几个参考模式：

| 公司/工具                        | 可借鉴点                                                                     |
| ---------------------------- | ------------------------------------------------------------------------ |
| Stripe                       | API + SDK + CLI + webhook local testing + MCP + Agent Toolkit 是完整开发者体验样板 |
| Lark CLI                     | 工作系统对象很多时，CLI + Skills 能让 agent 稳定操作 Docs / Base / Sheets / Tasks / IM   |
| Botmux                       | 不重写 Codex/Claude Code，而是把 Lark 变成 CLI runtime surface                    |
| Codex CLI                    | coding agent 不需要自己造，重点是配置、权限、上下文、任务边界                                    |
| RingCentral                  | 通信平台的关键是 events/webhooks/call logs，而不是只有一次性 API                          |
| Robinhood                    | 高风险交易类 API 的重点是 auth、risk、compliance、用户确认，不是让 agent 随便操作                 |
| Speakeasy / Stainless / Fern | API DevEx 工具链开始把 OpenAPI spec 直接变成 SDK、docs、CLI、MCP 等多种 interface        |

对传统 API 公司来说，AI-native 不是把 ChatGPT 接到客服入口就结束，而是：

```text
把业务能力变成机器可读合同
把合同生成稳定操作面
把操作面放进可审批、可审计、可观察的 runtime
```

***

## 12. 最终判断

你真正要学会的不是“怎么写一个 CLI”或“怎么接一个 MCP server”，而是这套 platform thinking：

> **先定义业务事实和权限边界，再把能力包成 API，并用 OpenAPI schema 固化合同；之后尽量生成 SDK / CLI / MCP / docs，再做少量产品化包装；需要 agent 持续执行时加 runtime；所有外部影响动作都必须经过 policy、approval、audit。**

对 retaintive 来说，最应该投入的不是重造 agent runtime，而是：

- 把 gym / studio 业务对象建成清晰 SoT。
- 把 AI 输出变成 draft + approval + audit 的状态机。
- 把所有 LLM 调用收进 LLM Gateway。
- 把 usage metering 从第一天做成一等公民。
- 把触达、回流、效果分析做成闭环。
- 用 OpenAPI + generator + Codex / Claude Code / Botmux / lark-cli / MCP 作为工具层，而不是从零造。

一句话版本：

**API 是地基，OpenAPI 是机器可读合同，SDK / CLI / MCP 是从合同长出来的操作面，Skill 是 SOP，Runtime 是执行现场，Policy 是刹车。retaintive 要赢，重点不在重复造工具，而在把健身房客户运营这套业务事实和审核闭环做扎实。**

***

## Sources

- [OpenAPI Documentation - OpenAPI Initiative](https://learn.openapis.org/)
- [Hono: Zod OpenAPI](https://hono.dev/examples/zod-openapi)
- [Hono: Hono OpenAPI](https://hono.dev/examples/hono-openapi)
- [OpenAPI Generator docs](https://openapi-generator.tech/docs/)
- [OpenAPI Generator generators list](https://openapi-generator.tech/docs/generators/)
- [Speakeasy: Generate SDKs from OpenAPI](https://www.speakeasy.com/docs/sdks/create-client-sdks)
- [Speakeasy: Generate a CLI from an OpenAPI document](https://www.speakeasy.com/docs/cli-generation/create-cli)
- [Stainless docs](https://www.stainless.com/docs/)
- [Fern: Docs, SDKs, and CLIs for your API](https://buildwithfern.com/)
- [Stripe CLI reference](https://docs.stripe.com/cli)
- [Stripe MCP](https://docs.stripe.com/mcp)
- [Stripe Agent Toolkit](https://docs.stripe.com/agents)
- [Lark CLI GitHub repo](https://github.com/larksuite/cli)
- [Botmux GitHub repo](https://github.com/deepcoldy/botmux)
- [OpenAI Codex CLI docs](https://developers.openai.com/codex/cli/)
- [OpenAI Agents SDK docs](https://developers.openai.com/api/docs/guides/agents)
- [Model Context Protocol docs](https://modelcontextprotocol.io/docs/getting-started/intro)
- [Robinhood Crypto API docs](https://docs.robinhood.com/crypto/trading/)
- [RingCentral Developers](https://developers.ringcentral.com/)
