> For the complete documentation index, see [llms.txt](https://docs.toughradius.net/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.toughradius.net/overview-1/agent-guide.md).

# Agent 开发指南

> English version: [Agent Development Guide](/overview/agent-guide.md)

本章是一份**面向贡献者**的摘要，介绍 ToughRADIUS 如何借助 AI 编码 agent 进行 开发，归纳工作规则、质量门禁与自动委托循环，使该工作流可从手册统一发现。

**权威**规则位于仓库根目录的 [`AGENT.md`](https://github.com/talkincode/toughradius/blob/main/AGENT.md)；该文件 保持权威地位，并被 agent 工具链直接引用。本章不替代它——如有歧义，以 `AGENT.md` 为准。

## 产品范围基线

开发始终锚定功能清单，绝不漂移到无关的产品方向。

* 权威范围基线为 [`docs/feature-checklist.md`](https://github.com/talkincode/toughradius/blob/main/docs/feature-checklist.md) （英文版见 [`docs/feature-checklist.en.md`](https://github.com/talkincode/toughradius/blob/main/docs/feature-checklist.en.md)）。
* 每个任务、issue、PR、测试与评审记录都映射到形如 `TR-F004` 的功能编号。
* 若某需求无法映射到现有编号，先更新功能清单（范围、状态、验收边界、理由）， 再改动代码。
* 非目标 `TR-N001`–`TR-N005`（支付、CRM、通用监控栈、多租户、整体重写）除非先 显式修订清单，否则一律不在范围内。

## 路线图与技能库

agent 驱动开发围绕三份产物组织：

* [`docs/roadmap.zh.md`](https://github.com/talkincode/toughradius/blob/main/docs/roadmap.zh.md) —— 长期路线图与里程碑，每项映射到 `TR-F` 编号，是 agent 工作的任务来源。
* [`.agents/skills/`](https://github.com/talkincode/toughradius/tree/main/.agents/skills/README.md) —— 可复用的技能 SOP，每个技能一个目录（`.agents/skills/<name>/SKILL.md`）。
* [`.agents/README.md`](https://github.com/talkincode/toughradius/blob/main/.agents/README.md) —— 委托参考与共享护栏。

一个**总调度层**驱动循环，执行 SOP 负责领域内的具体工作：

| 角色   | 技能                    | 职责                                         |
| ---- | --------------------- | ------------------------------------------ |
| 总调度  | `orchestrate-roadmap` | “自动委托开发”入口：选取下一个未勾选子任务、匹配 SOP、执行门禁、开 PR    |
| 门禁   | `review-pr`           | 以 CI 为锚的独立审查；通过标签/评论打回，仅在审过**且** CI 绿时自动合并 |
| 自我迭代 | `groom-roadmap`       | 每次合并后勾选已交付子任务并重新梳理路线图                      |

执行 SOP 包括：新增厂商 VSA（`add-radius-vendor`）、新增 EAP 方法 （`add-eap-method`）、新增 Admin API（`add-adminapi-endpoint`）、新增 React Admin 资源（`add-react-admin-resource`）、新增配置项（`add-config-schema`）、新增验收 测试（`add-acceptance-test`）、同步上游 radius（`sync-upstream-radius`）、引用 RFC （`reference-rfc`）、对齐清单（`align-feature-checklist`）、编写 Go 测试 （`write-go-tests`）、编写 Go API 文档（`document-go-apis`）。开始某类任务前先选用 匹配的技能。

agent **在你自己的主机**上用你自己的 agent/CLI 运行，而非通过 CI 工作流执行， 因此密钥不会进入 CI，执行环境完全自控。

## 工作准则

### 动手前先理解现有代码

绝不盲目改代码。先用检索定位现有实现、相关测试与文档，再模仿项目的命名、错误 处理与数据流。修 bug 前先追踪完整执行路径，重构前先梳理依赖与副作用。

### 持续验证

不要等到最后才跑测试。每个逻辑改动后都跑一次测试，使回归立即暴露，而不是堆到 大批量改动的末尾。

### 代码是最好的文档

* **所有导出 API 均带完整 godoc 注释**——用途、带约束的参数、返回值与错误条件 （复杂 API 附使用示例）。标准库风格的约定见 `document-go-apis` 技能。
* **复杂逻辑带行内注释**，解释*为什么*而非*做什么*。
* **厂商相关代码引用协议规范**（RFC 编号、VSA 文档）。
* **不产出冗余的独立总结文档**——信息应留在代码注释与 Git 历史中。

## 核心开发原则

### 测试驱动开发（TDD）

先写测试再写代码：用失败的测试定义预期行为（红），写最少代码使其通过（绿）， 随后在测试保持通过的前提下重构。若改动 `internal/radiusd/auth.go`，测试位于 `internal/radiusd/auth_test.go`。统一约定见 `write-go-tests` 技能。

### GitHub 工作流

* **仅走 Pull Request**——禁止直接推 `main`；受保护分支会拒绝直接推送。
* **约定式提交**——`<type>(<scope>): <subject>`，类型如 `feat`、`fix`、`test`、 `docs`、`refactor`、`perf`、`chore`。
* **小而原子的改动**优于巨型 PR。

### 仓库 issue/PR 自动化

仓库通过若干 GitHub Actions 做轻量分流，帮助维护者扫描队列；它们不替代阅读 原始 issue、PR diff 与 CI 输出。

| Workflow      | 触发与结果                                                                                                                                    | 维护者注意事项                                                                                                                                                                          |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Stale         | `.github/workflows/stale.yml` 每天 `04:24 UTC` 自动运行，也可手动触发。60 天无活动后添加 `stale`，再过 14 天仍无活动则关闭。                                              | 评论、推送提交或移除 `stale` 可保活。带 `pinned`、`security`、`help wanted`、`agent-roadmap`、`needs-human` 的 issue 豁免；带 `pinned`、`security`、`agent-roadmap`、`needs-human` 的 PR 豁免；所有 milestone 豁免。 |
| Labeler       | `.github/workflows/labeler.yml` 在 `pull_request_target` 上运行，并按 `.github/labeler.yml` 的路径规则打标签。                                           | 自动标签包括 `go`、`javascript`、`github_actions`、`dependencies`、`doc`。该 action 只读取变更文件列表和基础分支配置，不 checkout 或执行 PR 代码。                                                                   |
| Workflow Lint | `.github/workflows/workflow-lint.yml` 在修改 `.github/workflows/**` 或 `.github/actionlint.y*ml` 的 PR、触及这些路径的 `main` push，以及手动 dispatch 时运行。 | 它运行 `actionlint -shellcheck=`，因此门禁范围限定为 GitHub Actions YAML、表达式与 action 输入验证，不把既有 shell 风格告警混入本门禁。这只是静态验证，不执行 release tag、Docker 发布、Pages 部署，也不读取 secrets。                       |
| Greetings     | `.github/workflows/greetings.yml` 在贡献者首次打开 issue 或 PR 时运行，并发送入门提示评论。                                                                     | 评论仅用于引导，不改变评审要求或 issue 优先级。                                                                                                                                                      |

### Release tag 与 Docker 发布自动化

推送 `v*` tag 会触发两条发布 workflow；发版前需要同时理解二者的输出与凭据边界。

| Workflow        | 触发与输出                                                                                                                                                                    | 发版前置条件                                                                                                                                                                                                                             |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Release publish | `.github/workflows/release-publish.yml` 在 `v*` tag push 时运行，构建多平台二进制、生成 checksums，并创建 GitHub Release。                                                                    | tag 必须指向已验证的 `origin/main` 目标 SHA；release notes 由 workflow 基于 tag 和 closed issues 生成。                                                                                                                                              |
| Docker publish  | `.github/workflows/docker-publish.yml` 在 `v*` tag push 时运行，发布 `talkincode/toughradius:latest` 与版本 tag 到 Docker Hub，并独立尝试发布 `ghcr.io/<owner>/toughradius:latest` 与版本 tag。 | Docker Hub 需要 `DOCKERHUB_USERNAME` / `DOCKERHUB_TOKEN`。GHCR 需要 package repository access / inherited access 允许本仓库 `GITHUB_TOKEN` 写入，或配置具备 `write:packages` 的 `PKG_GITHUB_TOKEN`；若 token 所属账号不同于 tag 触发者，可选配 `PKG_GITHUB_USERNAME`。 |

Docker Hub 发布是必选门禁。GHCR 发布由于依赖 GitHub Packages 的外部 package access 设置，workflow 会把 GHCR push 独立成单独步骤，并先执行一次非破坏性的 写权限预检：若凭据不具备 package 写权限（即 `permission_denied: write_package` 签名），会直接跳过 GHCR 构建而不是在 push 中途失败，run summary 会给出 warning 与恢复提示，不再让维护者误判 Docker Hub 是否已发布。

发版前检查：

* 确认 tag 前的 `origin/main` CI 已绿，且 tag 版本号未被占用。
* 确认 Docker Hub secrets 存在且仍可写。
* 确认 GHCR package `talkincode/toughradius` 继承本仓库权限，或配置了 `PKG_GITHUB_TOKEN`（可选 `PKG_GITHUB_USERNAME`）；文档只记录 secret 名称和权限要求， 不记录真实值。
* tag 后检查 GitHub Release、Docker Hub `latest` / 版本 tag、GHCR `latest` / 版本 tag，以及两条 workflow 的最终结论。

失败恢复：

* 若 GitHub Release 成功、Docker Hub 成功、GHCR 失败，先修复 GHCR package access 或 token 权限，再重跑对应 tag workflow；不要为了同一源码重复创建错误版本 tag。
* 若 Docker Hub 发布失败，视为发布未完成，修复 secret 或 registry 问题后重跑 workflow。
* 若需要用新 patch tag 验证，先按 `release-version` SOP 重新审查未发布变更，避免跳过 版本判断。

### 周报 PR 自动化

每周报告 workflow 会通过短期自动化分支上的签名提交发布生成报告。workflow 在进入 报告 PR 步骤前都会先上传生成 artifact，因此即使 PR 创建被跳过或阻塞，维护者仍可 从本次运行的 artifact 检查报告内容。

| Workflow                     | 触发与发布文件                                                                                                                                                                 | PR 前置条件与 fallback                                                                                                                                                                                                                                                                                                                                                              |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| EAP acceptance weekly        | `.github/workflows/eap-acceptance-weekly.yml` 每周一 `09:17 UTC` 定时运行，也可手动触发。发布 `docs/reports/eap/<date>.md`、`docs/reports/eap/latest.md` 与 EAP 报告索引页。                     | 当外部 EAP 验收步骤成功且报告文件有变化时，PR 步骤需要 repository secret `EAP_REPORT_SIGNING_KEY`，以及 repository variables `EAP_REPORT_SIGNING_EMAIL` 和可选的 `EAP_REPORT_SIGNING_NAME`。缺少签名 key 或 email 会阻塞 PR 步骤，因为受保护的 `main` 要求 verified signed commit；此时可从已上传的 `eap-acceptance-<run_id>` artifact 读取生成报告。                                                                                            |
| Performance benchmark weekly | `.github/workflows/performance-benchmark-weekly.yml` 每周一 `10:37 UTC` 定时运行，也可手动触发。发布 `docs/reports/performance/<date>.md`、`docs/reports/performance/latest.md` 与性能报告索引页。 | 当 benchmark 完成且报告文件有变化时，PR 步骤使用 `PERFORMANCE_REPORT_SIGNING_KEY`、`PERFORMANCE_REPORT_SIGNING_EMAIL` 和可选的 `PERFORMANCE_REPORT_SIGNING_NAME`。若这些未配置，则复用 `EAP_REPORT_SIGNING_KEY`、`EAP_REPORT_SIGNING_EMAIL` 和可选的 `EAP_REPORT_SIGNING_NAME`。若没有任何签名 key/email 组合，workflow 会把生成报告保留在 `performance-benchmark-<run_id>` artifact 中，在 workflow step summary 说明已跳过 PR 创建，并让 PR 步骤成功退出。 |

这里和 issue/PR 评论中都不记录签名 key 的真实值。只记录 secret / variable 名称、 用途，以及是否已配置。

检查生成报告运行时：

* 先查看 workflow summary，确认是否存在跳过 PR 或凭据配置提示。
* 若没有打开报告 PR，从本次 run 的 artifact 下载生成报告。
* 若已生成报告 PR，合并前确认 head commit 在 GitHub 上显示为 verified。
* 对照 PR 正文中的发布文件列表与 workflow 预期的报告路径。
* 报告 PR 的 CI job 状态与 `mergeStateStatus=UNSTABLE` 行为属于 issue #494 继续跟踪的实现边界，本说明不改变该决策。

### 最小可行产品（MVP）

每次改动以最小、可独立使用、可回滚且不破坏既有行为的单元交付。大型工作拆成 MVP 增量（例如：厂商属性解析 → 认证集成 → 计费 → 管理界面），而非一次性塞进 一个超大 PR。

## 质量门禁

每个 agent 改动在合并前必须通过以下门禁：

* `go build ./...` —— 无编译错误。
* `go test ./...` —— 全部单元测试通过。
* `golangci-lint run` —— 干净（钉 **v2.12.2**，与 CI 一致）。
* `cd web && npm run build` —— 任何前端改动。
* `Workflow Lint` —— 修改 `.github/workflows/**` 或 `.github/actionlint.y*ml` 时必须通过；该门禁运行 `actionlint -shellcheck=`， 用于验证 GitHub Actions YAML、表达式与 action 输入。
* **协议 / 端到端改动**在 [`test/integration/`](https://github.com/talkincode/toughradius/tree/main/test/integration/README.md) 下附 CI 可执行的验收测试，并引用 [`docs/rfcs/`](https://github.com/talkincode/toughradius/tree/main/docs/rfcs/README.md) 下对应的规范。
* 产出一律走打了 `agent-roadmap` 标签的 PR，由 `review-pr` 门禁把关，仅在 `agent-approved` 且 CI 全绿时合并。

## 技术约束

* **禁用 CGO**——项目以 `CGO_ENABLED=0` 构建以便跨平台部署。仅使用纯 Go 驱动 （例如用 `github.com/glebarez/sqlite` 而非 `github.com/mattn/go-sqlite3`）。
* **数据库双兼容**——每次 schema 变更都必须同时兼容 PostgreSQL（默认）与 SQLite。
* **上游依赖**——核心库 `layeh.com/radius` 经 `go.mod` `replace` 指向组织 fork `github.com/talkincode/radius`；上游重要修复通过 `sync-upstream-radius` 技能评估。

## 常见反模式（禁止）

* 导出 API 不写文档。
* 不写测试就提交实现。
* 混杂多个关注点的巨型 PR。
* 先实现后补测试。
* 直接推 `main` 或跳过评审。
* 产出冗余的独立总结/报告文档。
* 引入 CGO 依赖。

## 下一步

* [`AGENT.md`](https://github.com/talkincode/toughradius/blob/main/AGENT.md) —— 完整、权威的 agent 开发指南。
* [文档地图](/overview-1/documentation-map.md) —— 找到 README、安全策略、功能清单、路线图 与 RFC 索引。
* [协议与 RFC 索引](/overview-1/rfc-index.md) —— 协议标准与代码、里程碑的对应关系。
