LifeOS 用户定制层完全指南:CUSTOMIZATIONS 目录的契约、结构与覆盖机制
【免费下载链接】LifeOS⛰️ The Life Operating System — an intent engineering platform that moves you from your current state to your ideal state, in life and work.项目地址: https://gitcode.com/GitHub_Trending/pe/LifeOS
导读
LifeOS 是一个「意图工程平台」(intent engineering platform),它的框架层内置了大量通用的 Skills、Agents、动作执行器与流水线执行器,但每一个真实用户的生命系统应当是独一无二的。CUSTOMIZATIONS/目录就是 LifeOS 为此设计的用户专属扩展层:所有需要“针对当前使用者而非所有 LifeOS 用户”生效的个性化内容都存放在这里,由系统组件在运行时动态叠加。读完本文,你将掌握 CUSTOMIZATIONS 目录的契约规则、SKILLS 与 ARBOL 两棵子树的组织方式、个人覆盖优先于系统默认的解析顺序,以及“何时该放、何时绝不该放”的边界判断标准。
CUSTOMIZATIONS 是什么:从「通用框架」到「你的 LifeOS」
打开仓库中的 CUSTOMIZATIONS/README.md,开篇即给出定义:LifeOS 框架自带通用的 skills、agents、action runners 和 pipeline executors,而CUSTOMIZATIONS/目录存放的是这些通用组件在运行时叠加(layer over)的用户内容——正是这些东西,让你的 LifeOS 与每一台其他安装的 LifeOS 都不同。
关键句值得反复咀嚼:
This directory holds the per-user content that those generic components layer over at runtime — the things that makeyourLifeOS different from every other LifeOS install.
也就是说,框架负责「公共的、可发布的、面向所有人的」行为,定制层负责「私人的、只属于这一个 principal 的」行为。二者不是两套系统,而是同一套系统在运行时的两层叠加:skill body 保持通用,用户文件在运行时覆盖其上。
这一点与仓库中的系统级文档完全一致。SystemUserBoundary.md 用四个 Zone(SYSTEM / USER / INTERFACE / RUNTIME-STATE)描述了整棵树的边界结构,其中USER区域明确包含 identity、TELOS、projects、integrations、contacts、finances、health、business 以及customizations;而 LifeosSystemArchitecture.md 则从架构层面说明为什么必须存在这一层用户内容挂载点。
契约(Contract):系统组件必须在这里找用户内容
原文档将最重要的规则定义为一条契约:
Anything running a system component MUST look here for user content that applies tothis principal but not every LifeOS user.
即:任何运行系统组件的代码,必须到 CUSTOMIZATIONS 查找“只适用于当前 principal、而不适用于所有 LifeOS 用户”的内容。该契约具体展开为两条:
- Skills读取
CUSTOMIZATIONS/SKILLS/<SkillName>/,用于存放用户偏好、来源清单(source lists)、声音档案(voice profiles)、项目名称以及其他公共 skill 主体无法包含的上下文。skill body 始终保持通用,用户文件在运行时叠加。 - Arbol读取
CUSTOMIZATIONS/ARBOL/,用于存放用户的 actions、pipelines、flows 与 worker 代码。解析顺序永远是个人优先(personal-first):CUSTOMIZATIONS/ARBOL/ACTIONS/<name>覆盖LIFEOS/ARBOL/Actions/<name>,PIPELINES/与FLOWS/同理。用户副本胜出(The user copy wins)。
这条“个人优先覆盖”的解析顺序是整个定制层最核心的机制:你不需要 fork 任何系统组件,只需要在正确的位置放下同名的覆盖文件,运行时就会自动采用你的版本。
目录结构:SKILLS 与 ARBOL 两棵子树
原文档给出了完整的目录骨架:
CUSTOMIZATIONS/ ├── SKILLS/ ← per-skill override files (one subdir per customized skill) └── ARBOL/ ← user actions, pipelines, flows, and Arbol worker code ├── ACTIONS/ ├── PIPELINES/ ├── FLOWS/ └── (worker code: Workers/, cli/, scripts/, etc.)在仓库的 CUSTOMIZATIONS 目录下,可以看到这一模板的实物形态:
SKILLS/README.md— 技能定制说明;ARBOL/ACTIONS/README.md— 动作模块说明;ARBOL/PIPELINES/README.md— 流水线注册说明;ARBOL/FLOWS/README.md— 流程编排说明。
新装状态下,这些子目录“Empty / Just this README”——即只有说明文档,真正的用户内容会在你实际使用 LifeOS 的过程中逐渐生长出来。这是一种刻意设计:定制内容由用户主动显式写入,而不是由框架预置。
SKILLS/:不改 skill,只覆盖行为
SKILLS/README.md 将 SKILLS 目录的目的概括为:
Per-skill overrides — the place to change a default skill behavior without forking the skill itself.
要点如下:
- 每个被定制的 skill 一个子目录,目录名与 skill 名一致,例如
CUSTOMIZATIONS/SKILLS/<SkillName>/; - 每个支持定制的 skill 会自行文档化它从覆盖目录读取哪些文件——通常是配置、模板或 prompt 片段,skill 在运行时将其与默认值合并(merges over its defaults);
- 填充方式是由用户显式进行的:只有当你确实想覆盖某个 skill 的默认行为时才创建子目录,否则保持为空,skill 以出厂默认行为运行。
仓库中大量 skill 文档都在实践这一约定。例如 LocalIntelligence/SKILL.md 及其 UserSources.ts 工具、Fabric/SKILL.md、SuggestSkills/SKILL.md 等文档中均提及在CUSTOMIZATIONS/SKILLS/下存放用户专属来源或偏好。这套约定的核心收益是:skill 是公共资产,可以在发布、升级、共享时保持纯净;你的品味、你的来源、你的项目、你的声音,全部安全地留在私有定制层。
ARBOL/:Actions、Pipelines、Flows 三原语
ACTIONS/README.md 说明 Actions 是可复用的动作模块——LifeOS 流水线与流程组合成更大工作流的原子工作单元。每个 action 是一个自包含子目录(典型命名A_<NAME>/,或按extract/、format/、transform/等类别目录分组),内含:
action.json— 清单:名称、描述、输入/输出 schema、requires(能力声明);action.ts— 实现:execute(input, ctx) → output。
Actions 的关键约束是:输入 → 单一操作 → 输出,无旁路通道、无共享状态。保持小而可组合是全部要点。你之所以要构建 action,是因为某段逻辑将被两个以上的 flows 或 pipelines 复用,或者你希望用经过良好测试的独立单元代替散落在多个 skill 中的内联代码。
PIPELINES/README.md 说明 Pipelines 是顺序处理链——把 actions 组合成线性工作流,前一个 action 的输出直接作为下一个 action 的输入。目录中存放一个pipeline-index.json注册表,外加每个 pipeline 一个 yaml 文件。Pipeline 刻意比 Flow 更简单:无分支、无条件、无并行扇出。如果工作就是“先 A,后 B,再 C”,pipeline 就是正确形态。新增方式:把 yaml 文件丢进目录,并在pipeline-index.json中登记。
FLOWS/README.md 说明 Flows 是分支式工作流定义——把 actions 组合成带条件路由、并行执行与错误处理的处理图(processing graph)。目录中存放一个flow-index.json注册表,外加每个 flow 一个 yaml 文件。Flow 描述的是 action 之间的有向图、路由条件、并行分支的扇出与汇合、以及失败如何传播。当工作流需要决策、重试或并发步骤时用 Flow;纯线性工作用 Pipeline。
三种原语的层级关系与命名规范
更完整的机制定义可以参考仓库中的 ArbolSystem.md(注意:该文档同时明确声明 Arbol 云端实现是维护者的私有基础设施,不随 OSS 发布随附,本文档作为架构蓝图与参考规范存在;LIFEOS/ARBOL/本地执行树在公共发布中被 rsync 排除)。其核心层级为:
Action ---> Pipeline ---> Flow (unit) (chain) (scheduled system)| 原语 | 前缀 | 做什么 | 组合方式 |
|---|---|---|---|
| Action | A_ | 单一工作单元(LLM 调用、API 调用、shell 命令) | 不组合 |
| Pipeline | P_ | 以管道模型按顺序链接 actions | 组合 Actions |
| Flow | F_ | 按计划把 source → pipeline → destination 连起来 | 组合 Pipelines |
命名约定上:action 采用UPPER_SNAKE_CASE、动词开头(WRITE、EXTRACT、LABEL、SEND)、2–4 个词,例如A_LABEL_AND_RATE、A_EXTRACT_TRANSCRIPT;pipeline 采用P_前缀,如P_MY_PIPELINE;flow 采用F_前缀与F_SOURCE_PIPELINE模式。
一个可参考的 action 清单示例(来自 ArbolSystem.md 的 Action 表):
| Action | 输入 | 输出 |
|---|---|---|
A_LABEL_AND_RATE | { content, title }(须为文章正文,不接受裸 URL,最少 200 字符,拒绝 LLM 拒绝模式) | { labels, rating, quality_score } |
A_EXTRACT_TRANSCRIPT | { url } | { content, video_id, title } |
A_TRANSCRIBE_AUDIO | { url } | { content, source: "whisper", audio_bytes, truncated } |
A_SEND_EMAIL | { to, subject, body } | { success, message_id } |
管道模型(Pipe Model)与 passthrough 模式
Pipeline 采用 Unix 风格的管道模型:第 N 个 action 的输出成为第 N+1 个 action 的输入。为了不让上下文在每一跳被丢弃,actions 使用passthrough 模式(...upstream)保留前序 actions 的元数据,同时附加自己的输出:
// Action receives upstream data, adds its own, passes everything forward const { content, ...upstream } = input; return { ...upstream, // preserve all prior action output myField: result, // add this action's contribution };这意味着 pipeline 中最后一个 action 可以访问前面每一个action 产出的字段,而不仅仅是紧邻上一个。这也是CUSTOMIZATIONS/ARBOL/下自定义 actions 的最佳实践之一。
一个新 action 的落地流程
结合 ArbolSystem.md 中“Creating a New Action”一节与定制层契约,在CUSTOMIZATIONS/ARBOL/ACTIONS/下新建一个动作的完整路径为:
- 创建目录:
CUSTOMIZATIONS/ARBOL/ACTIONS/A_YOUR_ACTION/; - 编写清单
action.json:声明 name、description、input/output schema、requires(例如["llm", "readFile"]); - 实现逻辑
action.ts:使用execute(input, ctx)模式,并遵循 passthrough 模式; - 本地测试:
bun lib/runner.v2.ts run A_YOUR_ACTION --input '{"content": "test"}'; - 若需部署到云端(可选):在
CUSTOMIZATIONS/ARBOL/Workers/a-your-action/下添加 Worker,再执行部署脚本。
一个完整的action.json示例:
{ "name": "A_LABEL_AND_RATE", "description": "Label and rate content using Fabric's label_and_rate pattern.", "input": { "content": { "type": "string", "required": true }, "title": { "type": "string" } }, "output": { "one_sentence_summary": { "type": "string" }, "labels": { "type": "array" }, "rating": { "type": "string" }, "quality_score": { "type": "integer" } }, "requires": ["llm", "readFile"] }Action 最佳实践清单:单一职责(一件事,做两件事就拆开)、始终 passthrough、显式声明requires、快速失败(立即校验输入并抛出清晰错误)、尽量幂等(LLM action 用 temperature 0)。
为什么定制层要放在 USER 之下
原文档用一个段落回答了“Why This Lives Under USER”:
LIFEOS/USER/holds everything specific to one principal.CUSTOMIZATIONS/is the part of USER that other system components read on every invocation — not standalone reference data (CONTACTS.md,OPINIONS.md) but live overlays that change how LifeOS behaves for this user.
翻译过来有两层含义:
LIFEOS/USER/存放一切属于单一 principal 的内容;CUSTOMIZATIONS/是 USER 中被其他系统组件在每次调用时读取的那一部分——它不是CONTACTS.md、OPINIONS.md那样的独立参考数据,而是改变 LifeOS 对该用户行为的实时覆盖层(live overlays)。
这一定位与 SystemUserBoundary.md 的边界设计互为表里:USER 区域的字节永远不进入公共发布管线,因此可以在其中放心存放任何个性化内容;而 SYSTEM 代码访问 USER 数据必须通过四个被允许的访问模式之一(LifeosConfig.load()类型化加载器、由 LifeosConfig 计算出的路径、启动时的 @-import、Pulse 的 HTTP/IPC),直接硬编码LIFEOS/USER/...字符串读取则构成边界违规。从源码结构看,SystemFileGuard.hook.ts 与 DeployRegistrationGate.hook.ts 等钩子正是这一边界在运行时的执行者。
何时应该把内容放进 CUSTOMIZATIONS
原文档给出了三条明确的准入标准:
- skill 需要你的偏好:一个 skill 需要你的品味、你的来源清单、你的项目或你的声音 → 写入
SKILLS/<SkillName>/PREFERENCES.md(或该 skill 文档声明的任何读取文件)。 - 你要覆盖系统组件:想用你自己的版本覆盖某个系统 action 或 pipeline → 把覆盖文件放到
ARBOL/ACTIONS/<name>或ARBOL/PIPELINES/<name>.yaml,runner 会优先采用你的版本。 - 你要新建私有组件:想创建一个只对你有意义的新 action 或 pipeline → 同样放进
ARBOL/。不存在 “personal vs. user” 的区分:只要是你的,就放这里。
判断的底层逻辑一句话概括:定制是关于“行为”(behavior)的,而不是关于“事实”(facts)的。
何时绝不该把内容放进 CUSTOMIZATIONS
同样地,原文档给出了两条排除标准:
- 纯参考数据:用户只是“读取”的参考数据(identity、projects、contacts、opinions、TELOS)——这些是
CUSTOMIZATIONS/的同级目录,而不是它的子级。定制层管行为,不管事实。仓库中可以看到这些参考数据确实以同级身份存在于 USER 目录 下:PRINCIPAL/、CONTACTS.md、OPINIONS.md、TELOS/、WORK/等。 - 一次性实验:临时尝试应使用
MEMORY/WORK/{slug}/,只有当它“证明了自己的价值(earns its keep)”时才提升(promote)到CUSTOMIZATIONS/。
这防止了两类常见的腐化:把事实数据混进行为层导致系统每次调用都加载无关内容;以及用一次性实验污染需要长期维护的覆盖空间。
一个端到端的最小心智模型
把上面所有规则压缩成一个可操作的工作流:
- 改 skill 行为但不 fork skill→
CUSTOMIZATIONS/SKILLS/<SkillName>/PREFERENCES.md(或该 skill 文档化的文件); - 复用一段逻辑到多处→ 在
CUSTOMIZATIONS/ARBOL/ACTIONS/A_<NAME>/下写action.json+action.ts; - 把多个 action 串成线性处理→ 在
CUSTOMIZATIONS/ARBOL/PIPELINES/下写 yaml 并登记到pipeline-index.json; - 需要分支、重试、并发→ 在
CUSTOMIZATIONS/ARBOL/FLOWS/下写 yaml 并登记到flow-index.json; - 凡是别人不该看到或不该共享的→ 一律留在 USER 区域,由边界机制保证不进入公共发布。
这套机制的最终效果,正如 SystemUserBoundary.md 所概括的:“LifeOS 这个操作系统是普适且公开的,而它所运行的人生是单一且私密的”——同一个仓库可以是所有人的 Life OS,却永远不会包含任何一个人的生活。CUSTOMIZATIONS/正是这条哲学在用户侧落地的执行枢纽。
【免费下载链接】LifeOS⛰️ The Life Operating System — an intent engineering platform that moves you from your current state to your ideal state, in life and work.项目地址: https://gitcode.com/GitHub_Trending/pe/LifeOS
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考