开发插件
怎样在 PLUGIN.md 插件文档、远程插件和内置 TypeScript 插件之间做选择,需要克隆哪些仓库,以及从写第一个工具到上架插件市场的工作顺序。
插件(plugin)负责把 PKU harness 接到某一个校园服务上,或者给 App 增加一项功能。每个插件提供一组「工具」(tool),也就是带类型的小操作,比如「列出空闲教室」「查询校园卡余额」。AI 助手和用户在界面上的点击,调用的都是同一套工具。
所以写插件主要是三件事:弄清楚服务怎样响应请求,把这些请求包装成工具,再在合适的地方加一个小组件或页面。
阅读本章需要你能看懂 YAML 或 TypeScript,并会使用终端。你不需要了解 App 的内部实现。
选择插件类型
插件有三种。大多数情况下,你应该写第一种。
插件文档是一个包含 PLUGIN.md 文件的文件夹。它的工具用 YAML 步骤和安全的小型表达式写成,由 App 在手机上解释执行。你用 git push 发布,同学们通过链接安装和更新。大多数校园接入都适合写成插件文档:向校园网站或公开网站发请求,提取需要的数据,必要时带上用户的校园登录状态。建议先看快速上手,再读声明式插件。你也可以在 App 里让 AI 帮你写。
远程插件是你自己运行的服务器。它使用 MCP(Model Context Protocol,模型上下文协议)。MCP 是 AI 应用通过 HTTP 调用工具的一种标准协议,这里使用它的 Streamable HTTP 传输方式。远程插件可以用任何语言编写,部署服务器就等于发布更新,不需要 App 发版。它适合你自己的服务、计算量大的任务,或者需要通用代码的场景。从 templates/remote-plugin 开始。
内置插件是用 TypeScript、zod 和 React Native 编写的模块,打包在 App 里。它只能随 App 版本发布,所以动手之前请先开一个 issue。内置插件用于 App 自身的功能(看板、日程、定时任务、记忆、模型服务商等),以及插件语言暂时表达不了的接入。从 definePlugin 开始。
| 插件文档 | 远程插件 | 内置插件 | |
|---|---|---|---|
| 编写方式 | YAML 步骤和表达式 | 任意语言(MCP) | TypeScript |
| 运行位置 | 手机上,由 App 解释执行 | 你的服务器 | 手机上,App 内部 |
| 更新方式 | git push | 重新部署服务器 | 随 App 发版 |
官方的校园接入中,classrooms、campus-events、grades、canteen、shuttle 和 notices 已经是插件文档。其余官方接入目前仍是 TypeScript,我们正在逐个迁移。
开发流程
弄清协议
你需要知道服务用哪些地址、返回什么内容。如果 pkucli 已经对接过这个服务,就移植它的代码,并注明参考的文件。具体做法见从 pkucli 移植。
编写工具
一个操作写成一个工具。如实声明它的效果,给每个输入加上限制,描述要写给模型看。插件文档的写法见声明式插件,代码插件的写法见工具与 schema。
需要的仓库
从 pkuinfo/pku-harness-plugins 开始。这个仓库包含 SDK 和插件语言、作者命令行工具(bun run plugin)、官方插件文档和内置插件、插件市场的注册表,以及远程插件的模板和示例。
pkuinfo/pku-harness 是 App 本体,只有在手机或模拟器上运行内置插件时才需要。写插件文档时,在你想实际发出校园请求之前都用不到它。
pkuinfo/pkucli 是一组访问北大各项服务的 Rust 命令行工具,可以用来查阅各个服务的协议细节。
mkdir pku-info && cd pku-info
git clone https://github.com/pkuinfo/pku-harness-plugins.git # SDK、插件、注册表、模板
git clone --recurse-submodules https://github.com/pkuinfo/pku-harness.git # 只在 App 里运行内置插件时需要
cd pku-harness-plugins && bun install && bun test没有 npm 包
SDK 和插件都不发布到 npm,而是直接从 GitHub 仓库使用。请在 pku-harness-plugins 的本地副本里开发:它的 bun workspace 和 tsconfig.json 会把 @pku-harness/sdk 解析到 packages/sdk/src。App 也以 git 子模块 plugins/ 的形式引入同一个仓库。远程插件完全不需要 SDK。
基本规则(摘自 CONTRIBUTING.md)
- 工具就是 API。 每个工具要有清楚的中文
title,给用户看;还要有写给模型的description,说明什么时候用、怎么用。每个输入都要校验:插件文档用input字段,内置插件用 zod,远程插件用 JSON Schema。 - 如实声明效果。 只读工具设置
effect: read(插件文档和内置插件)或readOnlyHint: true(MCP)。会修改状态、花钱或公开发布内容的工具,必须声明出来。 - 绝不索要校园密码。 账号凭据只保存在用户的手机上。
- 返回数据,不要返回指令。 模型会把工具结果当作数据看待。
- 声明要访问的范围。 插件文档写
campus、network和abilities,requires由它们自动推导;代码插件写requires。不要依赖手机上的 shell 或文件系统。 - 校园协议从 pkucli 移植(如果它已经实现),并注明来源。
- 中英文都要写。 插件文档要有
i18n.en部分。内置插件要给清单里每个面向用户的字符串提供英文版本,页面和小组件里的文字放在src/strings.ts表里。