# v0.2 hwlab-agent-skills 服务规格

`hwlab-agent-skills` 是 v02 agent 技能包的部署可见服务，运行在 `hwlab-v02` namespace，内部端口 `7430`。它用于暴露预装 skills bundle 的构建/health 元数据，不应成为 `hwlab-cloud-api` 每次 Code Agent 对话的运行时必依赖。

Code Agent 第一版 skill 来源分为两类：预装 skill 读取镜像内只读目录 `/app/skills`；用户上传 skill 读取 `hwlab-cloud-api` 挂载的 PVC 目录 `/data/user-skills`。两类 skill 必须保持不同目录和不同来源标识，不做 checksum、sha256、content-addressed artifact、鉴权、校验、Postgres metadata、audit、GC、版本发布或 session 绑定。

## 在系统中的职责划分

- 证明当前 lane 中 skills bundle 随 source commit 发布，并为 live-build inventory 和 M4/M5 agent-loop 验收提供 health metadata。
- 与 `hwlab-cloud-api` 注入给 AgentRun v0.1 的 `kind="gitbundle"` skills subtree 和 skills commit/version readiness 对齐。
- 预装 skill 只由镜像内 `/app/skills` 提供，不保存用户数据，不保存 Secret，不执行用户代码。
- 用户上传 skill 由 `hwlab-cloud-api` 管理，普通文件直接落到 PVC `/data/user-skills`，本服务不承载上传、预览或用户数据持久化 API。

## 内部架构

- artifact runtime 以 health-only server 方式运行，暴露 `/health` 和 `/health/live`。
- 镜像包含 `skills/` 目录，构建身份来自 `HWLAB_COMMIT_ID`、`HWLAB_IMAGE`、`HWLAB_IMAGE_TAG`。
- `HWLAB_SKILLS_COMMIT_ID` 由 GitOps render 注入；`HWLAB_SKILLS_VERSION` 是 skills manifest readiness 需要的稳定字段。
- `hwlab-cloud-api` 的 Code Agent skill discovery 必须同时扫描预装目录和用户上传目录。Linux runtime 推荐配置为 `HWLAB_CODE_AGENT_SKILLS_DIRS=/app/skills:/data/user-skills`；跨平台测试可使用现有 resolver 支持的逗号或分号分隔。
- `hwlab-cloud-api` 启动或上传后必须幂等维护 Codex 工作区聚合目录 `/workspace/hwlab/.agents/skills`，用 symlink 暴露两类 skill：预装 skill 使用 `preinstalled-<name>`，用户上传 skill 使用 `uploaded-<id>`。
- 聚合目录只作为 Codex 原生 skills discovery 入口，不改变 source truth：预装 source truth 仍是 `/app/skills`，用户上传 source truth 仍是 PVC `/data/user-skills`。

## 用户上传 skill 第一版边界

- 用户上传 skill 存储目录固定为 PVC 挂载路径 `/data/user-skills`，可通过 `HWLAB_USER_SKILLS_DIR` 显式配置。
- 预装 skill 目录固定为 `/app/skills`，可通过 `HWLAB_PREINSTALLED_SKILLS_DIR` 显式配置；PVC 不得挂载到 `/app/skills`。
- 上传目录按生成 ID 写入 `/data/user-skills/<generated-id>/`，例如 `skill-<timestamp>-<short-random>`；metadata 只写普通 JSON 文件，放在 PVC 中。
- 第一版 metadata 只用于列表和预览，不写入 Postgres，不做 migration，不依赖数据库恢复。
- 同名 skill 不覆盖、不合并、不校验拦截；API 和 Web 必须按 `source` 与 `id` 区分展示。
- HWLAB 自有 `skills.discover` 不得只按 skill name 去重；同名不同来源的 skill 必须保留。实现上至少使用 `name + sourceRoot + relativePath` 或 `source + id` 作为唯一 key。
- `SKILL.md` 预览只读取文本内容；二进制文件不内联展示。
- 第一版不把上传 skill 绑定到某个 Code Agent session，上传后作为全局可发现 skill 暴露。

## Code Agent 发现路径

- HWLAB 旧自有发现路径只作为历史线索；当前 AgentRun 装配以 `ResourceBundleRef.kind="gitbundle"` 和 `bundles[]` 为权威，详见 [agentrun-code-agent-dispatch.md](agentrun-code-agent-dispatch.md)。
- Codex 原生发现路径：Codex 会从工作区 `.agents/skills` 等标准位置加载 skill；因此 `hwlab-cloud-api` 必须准备 `/workspace/hwlab/.agents/skills` symlink 聚合目录，让 Codex 原生机制也能看到 `/app/skills` 与 `/data/user-skills` 中的 skill。
- 两条发现路径都必须保留来源信息；同名 skill 不能因为 HWLAB 侧去重而消失。
- AgentRun 装配发现路径：HWLAB v0.2 通过 AgentRun `ResourceBundleRef.kind="gitbundle"` 把 repo 内 `skills/` subtree 整体装配到 runner 工作区 `.agents/skills`。`GET /v1/skills` 必须额外返回 `agentRunAssembly` 摘要，包含 `bundles`、`promptRefs`、资源 bundle repo/branch/commit 和 `.agents/skills` 运行时装配目录；Cloud Web skills 面板必须展示该摘要，不能只展示 `/app/skills` 与 `/data/user-skills` 的静态列表。
- MiniMax-M3 runner 引导必须说明工具调用 JSON、BusyBox/GNU 工具差异和 GitHub CLI 读 issue/PR 的低噪声用法，降低无效 tool-call arguments 与命令兼容性摩擦。

## API 接口说明

| 接口 | 说明 |
| --- | --- |
| `GET /health`、`GET /health/live` | 返回 service identity、revision、image/build metadata 和 skills 相关 env。 |
| `GET /help` | 返回 health-only runtime 的可用 route。 |

## 测试规格

## T1

阅读 docs/reference/spec-v02-hwlab-agent-skills.md，然后用 cli 手动测试以下内容：访问 `hwlab-agent-skills:7430/health/live`，确认 `serviceId=hwlab-agent-skills`、revision 与 v02 source commit 对齐。

## T2

阅读 docs/reference/spec-v02-hwlab-agent-skills.md，然后用 cli 手动测试以下内容：检查 Deployment env，确认 `HWLAB_SKILLS_COMMIT_ID` 存在；若 `HWLAB_SKILLS_VERSION` 缺失，必须在验收结果中标记未完全实现。

## T3

阅读 docs/reference/spec-v02-hwlab-agent-skills.md，然后用 cli 手动测试以下内容：检查 `hwlab-cloud-api` Deployment env 和 volumeMount，确认 `HWLAB_CODE_AGENT_SKILLS_DIRS` 同时包含 `/app/skills` 与 `/data/user-skills`，用户上传 PVC 挂载到 `/data/user-skills`，且没有把 PVC 挂载到 `/app/skills`。

## T4

阅读 docs/reference/spec-v02-hwlab-agent-skills.md，然后上传一个与预装 skill 同名的测试 skill，确认上传目录落在 `/data/user-skills/<generated-id>/`，`/app/skills` 不变，Web 列表按来源和 ID 分开展示两个同名 skill。

## T5

阅读 docs/reference/spec-v02-hwlab-agent-skills.md，然后让 Code Agent 执行“列出你可用的 skills”，确认返回同时包含预装 skill 和用户上传 skill；同名不同来源的 skill 不被 `dedupeSkills()` 或等价逻辑吞掉。

## T6

阅读 docs/reference/spec-v02-hwlab-agent-skills.md，然后检查 `/workspace/hwlab/.agents/skills`，确认存在指向 `/app/skills` 下预装 skill 和 `/data/user-skills` 下用户上传 skill 的 symlink 聚合入口。

## 规格的实现情况

| 规格项 | 状态 | 说明 |
| --- | --- | --- |
| health-only 服务 | 已实现 | Deployment/Service 存在，端口 7430。 |
| skills bundle 随镜像发布 | 已实现 | Dockerfile 复制 `skills/` 到 `/app/skills`。 |
| `HWLAB_SKILLS_COMMIT_ID` | 已实现 | v02 render 已注入 source commit。 |
| `HWLAB_SKILLS_VERSION` | 未完全实现 | 当前 render 未稳定注入 version，manager/worker readiness 仍可能报告缺失。 |
| 作为 Code Agent 运行时依赖 | 不采用 | Code Agent 读取镜像内 skills，不应每轮依赖该服务。 |
| 用户上传 skill PVC 持久化 | 已实现 | `hwlab-cloud-api` 写入 `/data/user-skills`，metadata 保持为 PVC 内普通 JSON，不使用 Postgres。 |
| 预装/上传双目录发现 | 已实现 | `HWLAB_CODE_AGENT_SKILLS_DIRS` 同时覆盖 `/app/skills` 与 `/data/user-skills`；resolver 使用多目录发现并保留 source/sourceRoot。 |
| Codex `.agents/skills` 聚合入口 | 已实现 | `/workspace/hwlab/.agents/skills` 由 cloud-api 幂等维护来源前缀 symlink，预装为 `preinstalled-<name>`，上传为 `uploaded-<id>`。 |
| 同名 skill 不覆盖不合并 | 已实现 | 列表、预览、聚合和 prompt discovery 均按来源与路径/ID 区分；同名预装和上传 skill 可同时存在。 |

