LobeHub 仓库开发指南解读:面向 AI 编码 Agent 的架构约定、命令工作流与 Skill 体系
导读
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(如 react、compose-atoms、spa-routes、deep-review、zustand、trpc-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.tsx、entry.mobile.tsx、entry.desktop.tsx、entry.popup.tsx,另有 entry.auth.tsx)以及 React Router 配置目录 src/spa/router。路由配置放在入口旁,正是为了避免与 src/routes/ 混淆。router 目录中除了各平台的 desktopRouter.config.*、mobileRouter.config.tsx、popupRouter.config.tsx,还包含运行时支撑:routePreloadRegistry.ts(路由预加载注册表)、useRouteSkeleton.ts(路由骨架屏)与 tabRouter.tsx(Electron 多标签的内存路由)。
src/routes/:只允许薄页面段
src/routes/(roots)下仅允许三类文件:
_layout/index.tsx或layout.tsx:该段的布局(配合<Outlet />);index.tsx或page.tsx:该段页面入口;[param]/index.tsx(如[id]、[cronId]):动态段页面。
这些文件必须保持薄:只能从 @/features/* import 并做组合,不允许携带业务逻辑或重型 UI。仓库实际分组与 AGENTS.md 描述一致:src/routes 下存在 (main)、(mobile)、(desktop)、(popup) 以及 auth/、onboarding/ 等特殊流目录。
src/features/:按领域的业务组件
业务组件按领域(domain)组织(如 Pages、Home、PageEditor),而非按路由路径组织。布局块(sidebar、header、body)、hooks、领域特有 UI 都放在这里,每个 feature 通过 index.ts(或 index.tsx)暴露清晰的公开导出。由于一个路由可使用多个 feature,一个 feature 也可被多个路由复用,因此不允许在 src/routes/ 内新建 features/ 文件夹。
新增/变更 SPA 路由的标准流程
AGENTS.md 给出了四条操作步骤,结合 spa-routes skill 可以还原为完整动作:
- 在
src/routes/中只添加委托给 features 的路由段文件(layout + page); - 在
src/features/<Domain>/下实现布局与页面内容并从该目录导出; - 路由文件中用
import { X } from '@/features/<Domain>'(或import Y from '@/features/<Domain>/...')引入; - 共享的桌面内容路由只注册一次:公共 Web/Electron 路径、嵌套、metadata、懒加载器与
preloadId值都放在 src/spa/router/desktopRouter.shared.tsx。
在此基础上,薄的 desktopRouter.config.tsx 与 desktopRouter.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:auth、dev: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.mjs 与 renovate.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.ts、lint.ts、collect.ts、exec.ts、routing.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 兜底其余语言"的三段式:
- 加 key:在 packages/locales/src/default 下的 namespace 文件中添加(如
agent.ts、auth.ts)。 - 手写 en-US 与 zh-CN:在同一个 PR 内完成——先在
packages/locales/src/default/*.ts编写英文源,镜像到locales/en-US/,再手工翻译locales/zh-CN/。 - 其余语言交给 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-atoms 与 react 两个 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 的价值不在于罗列规则,而在于其分层治理的思路:
- 规则有明确的归属层:仓库级架构/工作流留在 AGENTS.md,实现细节下沉到 60+ 个按需加载的 skill,避免上下文膨胀与规则互相打架;
- 架构分层服务于"可挂载能力":SPA 采用 Next.js 承载 + roots/features 拆分 + 单一共享桌面路由,使 Web、Electron、移动端、popup 等宿主各取所需;
- 验证链路刻意收窄:用
bun run check单命令 + 自动发现相关测试替代"全量跑一遍",把 10 分钟的全量套件变成日常开发的禁区; - i18n 采用人机分工:英文与中英双语由开发者手写保证质量,其余语种交给每日 CI 的自动翻译 PR 兜底。
对于要在本仓库中工作的开发者与 Agent 而言,AGENTS.md 就是第一份必读文档——它决定了你在哪个目录放代码、用哪条命令验证、以何种纪律提交。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00