首页
/ LobeHub 仓库开发指南解读:面向 AI 编码 Agent 的架构约定、命令工作流与 Skill 体系

LobeHub 仓库开发指南解读:面向 AI 编码 Agent 的架构约定、命令工作流与 Skill 体系

2026-09-07 19:00:45作者:廉彬冶Miranda

导读

LobeHub 是一个将 AI 团队编排为 7×24 小时自动化运营的 Agent 平台,其开源仓库规模庞大(src/features/ 下数千个文件、apps/packages/ 承载桌面端、CLI、服务端与共享包)。为了让人类开发者与 AI 编码 Agent 在同一套约束下高效协作,仓库根目录的 AGENTS.md 定义了一套仓库级的开发宪章:它规定了技术栈、目录分层、SPA 路由拆分方式、开发命令、Git 工作流、质量检查与 i18n 流程。阅读本文后,你将掌握 LobeHub 仓库的分层架构心智模型、可复现的本地开发与质量验证命令,以及"仓库级规则 + Skill 级细节"的 Agent 协作范式。

AGENTS.md 在仓库中的定位:规则单一事实源

在 LobeHub 中,AGENTS.md 并不是一份摆设,它是"为在本开源仓库中工作的 AI 编码 Agent 准备的开发准则"(文档自述 Guidelines for using AI coding agents in this opensource LobeHub repository)。它与根目录的 CLAUDE.md 一类文档共同构成了 Agent 的上下文入口,但分工明确:

AGENTS.md 拥有仓库级(repository-wide)的架构与工作流定义;详细的实现规则下沉到 skills 中,让每个规则只有一处事实来源。

也就是说,AGENTS.md 只回答"仓库长什么样、规则是什么、命令怎么跑",而"怎么写一个符合规范的 React 组件、怎么拆分重领域页面"这类具体实现细节,被收敛到 .agents/skills/ 目录下独立的 skill 文件中。仓库中实际维护着 60+ 个 skill(如 reactcompose-atomsspa-routesdeep-reviewzustandtrpc-router 等),每个 skill 都自带 front-matter(name / description),description 明确描述了该 skill 的适用触发场景,方便 Agent 按需检索加载。这种"顶层少而稳、细节多而专"的分层,正是该仓库 Agent 协作体系的核心设计。

技术栈一览:一份可验证的选型清单

AGENTS.md 开篇即给出技术栈速览,而这些声明都能在仓库中逐一印证:

关注点 选型 仓库佐证
框架与语言 Next.js + React + TypeScript package.json 根依赖
前端形态 Next.js 内部承载 SPA,路由由 react-router-dom 负责 src/spa/router
UI 实现 @lobehub/ui、antd、antd-style react skill 中组件选型优先级
国际化 react-i18next packages/locales/src/default 下的 namespace 文件
状态管理 zustand src/store
数据请求 / 类型安全后端 SWR + TRPC src/services
ORM / 测试 Drizzle ORM + PostgreSQL;Vitest packages/database、各包 vitest.config.mts

这套选型的核心意图是类型安全贯穿前后端:TRPC 提供端到端类型安全的 RPC 边界,Drizzle ORM 让数据库 schema 与代码保持同构,Vitest 则支撑起从单测到回归测试的统一验证。

Agent Skills 体系:何时必须"先读再改"

AGENTS.md 明确要求,在改动特定类型代码前必须先读取对应 skill,避免 Agent 凭泛化经验行事:

  • React 与 TSX:在编辑组件、组件状态、渲染边界或做 memoization 优化之前,必须先读 .agents/skills/react/SKILL.md。该 skill 拥有组件选型、样式、状态局部化与渲染性能规则的"所有权"。
  • 重领域功能:当需要把一个臃肿的 Viewer/Page 拆成可复用的片段(page、portal、share、micro-app 等宿主)时,先读 .agents/skills/compose-atoms/SKILL.md。它的拆分原则是"按可挂载能力拆分,而不是按视觉区块拆分",并且不得用 readOnly / mode 标志去隐藏未使用的工作——因为被隐藏的模块仍然会随宿主被导入并打包。

以 react skill 为例,其 组件优先级 是:src/components 项目内组件 → @lobehub/ui/base-ui 无头原语(若有同名根导出,禁止绕道 import 根导出)→ @lobehub/ui 根导出 → antd → 自定义实现(最后手段)。它还特别提醒一个常见坑:import { Select } from '@lobehub/ui' 表面正常,实际拿到的是 antd 背书的 Select,应改用 base-ui。

compose-atoms skill 则提出了"模块图拆分"(module-graph split)的判据:一个 atom 是"宿主被允许不挂载的最小单元"。判断粒度时自问"是否会有某个宿主想要其余部分却跳过这一块?"如果是,它就该是 atom;如果否,就留在父组件里。其状态下沉原则(sink state)强调:imports follow the hook——如果 useStore / handleAccept 还留在页面装配器上,那么该模块及其全部依赖仍会被每个挂载此页面的宿主打包带走。需要强调的是,若只是把单个组件切成更小的文件,不应使用该 skill,而应回归 react skill。

目录结构:四层清晰的职责划分

AGENTS.md 给出了仓库级目录地图(节选自其 Project Structure),可归纳为四个层次:

lobehub/
├── apps/                    # 可独立运行的端
│   ├── desktop/             # Electron 桌面应用
│   ├── cli/                 # LobeHub CLI
│   └── server/              # 后端服务(Hono 应用 + 服务端路由/服务)
├── packages/                # 共享包(@lobechat/*)
│   ├── database/            # 数据库 schema、模型、仓储
│   ├── agent-runtime/       # Agent 运行时
│   ├── locales/             # i18n 源:packages/locales/src/default/
│   ├── env/                 # env schema(@/envs/* 指向 packages/env/src/*)
│   └── ...
├── src/                     # Web 应用壳层
│   ├── app/                 # Next.js App Router(路由壳 + 鉴权)
│   ├── routes/              # SPA 页面段(薄层,委托给 features)
│   ├── spa/                 # SPA 入口与路由配置
│   ├── store/               # Zustand stores
│   ├── services/            # 客户端服务
│   ├── libs/                # 应用壳共享的客户端/服务端助手
│   └── ...
└── e2e/                     # E2E 测试(Cucumber + Playwright)

需要特别留意的是 src/app/src/ 的分工。前端业务并不全部走 Next.js 的页面路由,而是采用 Next.js 承载 SPA 的混合形态:src/app/(backend) 只放后端路由壳,src/app/spa/ 负责 SPA 的 HTML 模板服务,src/app/spa-auth/ 提供 SSR 的鉴权 HTML 壳。真正的 SPA 页面段在 src/routes/,业务逻辑在 src/features/

SPA 路由架构:roots vs features 的拆分纪律

这是 AGENTS.md 着墨最深、也是本次解读最值得展开的架构章节。LobeHub 明确采用 roots vs features 拆分:路由树只放页面段,业务逻辑与 UI 全部落在 features 中。要理解这一拆分,需先认识三个目录各自的"被允许内容":

src/spa/:SPA 入口与路由配置

src/spa 存放 SPA 入口文件(entry.web.tsxentry.mobile.tsxentry.desktop.tsxentry.popup.tsx,另有 entry.auth.tsx)以及 React Router 配置目录 src/spa/router。路由配置放在入口旁,正是为了避免与 src/routes/ 混淆。router 目录中除了各平台的 desktopRouter.config.*mobileRouter.config.tsxpopupRouter.config.tsx,还包含运行时支撑:routePreloadRegistry.ts(路由预加载注册表)、useRouteSkeleton.ts(路由骨架屏)与 tabRouter.tsx(Electron 多标签的内存路由)。

src/routes/:只允许薄页面段

src/routes/(roots)下仅允许三类文件:

  • _layout/index.tsxlayout.tsx:该段的布局(配合 <Outlet />);
  • index.tsxpage.tsx:该段页面入口;
  • [param]/index.tsx(如 [id][cronId]):动态段页面。

这些文件必须保持薄:只能从 @/features/* import 并做组合,不允许携带业务逻辑或重型 UI。仓库实际分组与 AGENTS.md 描述一致:src/routes 下存在 (main)(mobile)(desktop)(popup) 以及 auth/onboarding/ 等特殊流目录。

src/features/:按领域的业务组件

业务组件按领域(domain)组织(如 PagesHomePageEditor),而非按路由路径组织。布局块(sidebar、header、body)、hooks、领域特有 UI 都放在这里,每个 feature 通过 index.ts(或 index.tsx)暴露清晰的公开导出。由于一个路由可使用多个 feature,一个 feature 也可被多个路由复用,因此不允许在 src/routes/ 内新建 features/ 文件夹

新增/变更 SPA 路由的标准流程

AGENTS.md 给出了四条操作步骤,结合 spa-routes skill 可以还原为完整动作:

  1. src/routes/ 中只添加委托给 features 的路由段文件(layout + page);
  2. src/features/<Domain>/ 下实现布局与页面内容并从该目录导出;
  3. 路由文件中用 import { X } from '@/features/<Domain>'(或 import Y from '@/features/<Domain>/...')引入;
  4. 共享的桌面内容路由只注册一次:公共 Web/Electron 路径、嵌套、metadata、懒加载器与 preloadId 值都放在 src/spa/router/desktopRouter.shared.tsx

在此基础上,薄的 desktopRouter.config.tsxdesktopRouter.config.desktop.tsx 只承载运行时差异:Web 直接挂载内容树,而 Electron 保留精简根桩,并通过 tabRouter.tsx 在每个标签页的内存 router 中挂载同一棵树。只有路由真正与平台相关时,才把代码放进平台适配器。由 desktopRouter.sync.test.tsx 守护这一共享行为与显式差异——修改路由时保持该测试通过。

从设计动机看,这套"薄 roots + 厚 features + 单一共享桌面路由"约束,本质上是为了让页面段只承担组合职责:任何新增页面都无需复制逻辑,也避免了同一段路由在 Web 与 Electron 两套配置中重复维护导致漂移。

启动开发环境:三套命令与 Debug Proxy 原理

AGENTS.md 给出了三种启动方式,按需选择:

# SPA dev 模式(纯前端,API 代理到 localhost:3010)
bun run dev:spa

# 全栈开发(Next.js + Vite SPA 并行)
bun run dev

# 独立 Hono 后端服务
pnpm --filter @lobechat/server dev
  • dev:spa 在根 package.json 中定义为 vite,即直接启动 Vite dev server 作为纯前端;同一脚本族还有 dev:spa:authdev:spa:mobile 等变体,通过环境变量切换形态。
  • dev 定义为 tsx scripts/devStartupSequence.mts,由 scripts/devStartupSequence.mts 编排 Next.js 与 Vite SPA 的并行启动。
  • 后端独立运行时走 pnpm workspace filter,指向 apps/server@lobechat/server),其运行时代码都位于 apps/server/src,通过 @/server/* 导入。

值得展开的是 Debug Proxy 机制。dev:spa 启动后,终端会打印一条形如下面的 URL:

Debug Proxy: https://app.lobehub.com/_dangerous_local_dev_proxy?debug-host=http%3A%2F%2Flocalhost%3A9876

这条 URL 对应仓库中的 public/_dangerous_local_dev_proxy.html:该页面从查询参数读取 debug-host(默认回退到 http://localhost:9876),并通过 sessionStorage 记住调试目标。打开此 URL 后,线上环境(app.lobehub.com)会把你的本地 Vite dev server 的 SPA 加载进在线页面,从而让你带着真实的服务器配置获得 HMR——即"用本地代码开发、用线上后端调试"。

后端架构约束:业务代码不进路由壳

AGENTS.md 对后端代码放置有三条硬约束:

  • 后端运行时代码位于 apps/server/src,通过 @/server/* 导入;
  • src/app/(backend) 只放 Next.js 路由壳,不得在其中添加后端业务逻辑;
  • Web 壳层的辅助代码属于 src/libs/* 或相应的 src/app 段,而不是 src/server

换言之,Next.js 在这里扮演的是"接线员"而非"业务宿主":路由壳只负责把 HTTP 请求转交给 apps/server 中真正的 Hono 服务与 server routers/services。理解这一点对 Agent 尤其重要——否则很容易把业务逻辑写进 App Router 的 route handler,破坏后续将 SPA 与后端分离部署的结构。

Git 工作流与包管理约定

仓库的协作节奏由分支模型与提交规范约束:

  • 分支策略canary 是开发分支(对应云端生产);main 是发布分支(定期从 canary cherry-pick)。
  • 新分支应从 canary 创建;PR 应指向 canary
  • git pull 使用 rebase。
  • 提交信息以 gitmoji 表情前缀开头。
  • 分支格式:<type>/<feature-name>

包管理方面采用双工具分工:pnpm 管依赖,bun 跑 npm scripts,bunx 跑可执行的 npm 包。这与根 package.json 的 scripts 实际定义一致(如 "check": "bun run .agents/scripts/check/cli.ts")。配套的 commitlint.config.mjsrenovate.json 分别约束提交规范与依赖自动化。

质量检查:bun run check 的纪律

AGENTS.md 规定了唯一的质量入口,并反复强调"别乱跑全量测试":

bun run check [changed-files...]

该命令对应根 package.json 中 "check": "bun run .agents/scripts/check/cli.ts",实际执行体是 .agents/scripts/check 下的一组脚本(cli.tslint.tscollect.tsexec.tsrouting.ts 等),其质量纪律包括:

  • 回归测试是硬要求:每个 bug 修复必须附带一个"修复前失败、修复后通过"的回归测试。唯一豁免是纯样式/CSS 修复(选择器、hover、遮罩、间距、颜色)——此时唯一可行的断言只能是对样式源码做字符串匹配,这种断言不算是值得交付的回归测试,可以跳过。
  • 单次单遍:无选择器时,lint + test 应在同一次 check 中完成,不要为每个选择器分别开一遍。--lint / --test / --type 用于收窄范围,且可在一次运行内自由组合。
  • 默认文件集合 = 工作区全部改动(staged + unstaged + untracked);显式传入路径会覆盖默认集合。
  • --lint 会自动修复给定文件并把修复内容以 diff 形式打印,方便审查改动。
  • --test 会为给定源文件自动发现相关测试,并在最近的所属 vitest 配置下运行(例如 packages/database),无需手动 cd 进包目录。
  • --type 运行全量类型检查。
  • 严禁直接 bun run test——全量套件需要约 10 分钟。需要手动跑单测(如单个文件或特殊 flag)时,先 cd 进所属包再执行,例如:cd packages/database && bunx vitest run --silent='passed-only' '[file-path]'

i18n 工作流:人机分工的翻译管线

LobeHub 的国际化采用"源文件 + 两个手写语言 + CI 兜底其余语言"的三段式:

  1. 加 key:在 packages/locales/src/default 下的 namespace 文件中添加(如 agent.tsauth.ts)。
  2. 手写 en-US 与 zh-CN:在同一个 PR 内完成——先在 packages/locales/src/default/*.ts 编写英文源,镜像到 locales/en-US/,再手工翻译 locales/zh-CN/
  3. 其余语言交给 CI:每日 CI 工作流 .github/workflows/auto-i18n.yml 会运行 bun run i18n 并自动开启翻译 PR。在翻译 PR 合并前,缺失的语言 key 会回退到英文。

只有当"立刻需要"翻译后的语言而非等待每日工作流时,才手动运行 bun run i18n(根 package.json 中定义为 npm run workflow:i18n && lobe-i18n && prettier -c --write "locales/**")。AGENTS.md 特别强调:该命令很慢且需要 OPENAI_API_KEY,且不要手工翻译生成的 locales——因为下一个 CI 周期会覆盖它们。

代码风格与代码审查:给 Agent 与人类的共同尺子

文件尺寸红线

AGENTS.md 建议:单个文件超过约 800 行时,考虑拆分为多个文件(抽取子组件、hooks、helpers 或 types)。理由并非玄学,而是"更小、更聚焦的文件对人类和 Agent 都更友好"——这与 compose-atomsreact 两个 skill 共同构成了对抗巨型文件的完整方案:react skill 负责把小组件拆小,compose-atoms 负责把重领域按可挂载能力切分。

deep-review skill 与设计价值观

审查 PR / diff / 分支改动之前,应先读 deep-review skill。普通审查请求使用其轻量模式(一名独立评审者对照各维度的快速检查清单);完整的多子 Agent 深度模式只在显式调用时启用。仓库中可见该 skill 的维度清单,包括逻辑、安全性、性能、可观测性、发布风险、复用架构、AI 编码坏习惯等(见 .agents/skills/deep-review/references/dimensions),且按 reviewer 场景区分 claude-code / codex。

同时,在设计或评审用户可见流程(空态/加载态/错误态、确认、异步反馈、按钮层级、大规模列表、选择器)时,应遵循 LobeHub 的设计价值观 Natural / Meaningful / Certainty / Growth(自然 / 意义感 / 确定性 / 成长),完整定义见 DESIGN.md 与配套的 DESIGN.dark.md。这套价值观不只是口号:仓库中 ux skill 对四个维度逐一展开,例如 Growth(生长性)被定位为更长周期的视角,在塑造一个功能如何演进的体验时用来权衡。DESIGN.md 本身则是一份主题化设计规范——主色与中性色均可由用户配置并解析为 CSS 变量(lobe-vars)。

总结:从 AGENTS.md 看 LobeHub 的工程化方法论

纵观全文,AGENTS.md 的价值不在于罗列规则,而在于其分层治理的思路:

  1. 规则有明确的归属层:仓库级架构/工作流留在 AGENTS.md,实现细节下沉到 60+ 个按需加载的 skill,避免上下文膨胀与规则互相打架;
  2. 架构分层服务于"可挂载能力":SPA 采用 Next.js 承载 + roots/features 拆分 + 单一共享桌面路由,使 Web、Electron、移动端、popup 等宿主各取所需;
  3. 验证链路刻意收窄:用 bun run check 单命令 + 自动发现相关测试替代"全量跑一遍",把 10 分钟的全量套件变成日常开发的禁区;
  4. i18n 采用人机分工:英文与中英双语由开发者手写保证质量,其余语种交给每日 CI 的自动翻译 PR 兜底。

对于要在本仓库中工作的开发者与 Agent 而言,AGENTS.md 就是第一份必读文档——它决定了你在哪个目录放代码、用哪条命令验证、以何种纪律提交。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391