LifeOS LocalIntelligence DailyBrief 工作流完全指南:一键聚合家乡八类本地信息的每日简报机制
【免费下载链接】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
导读
DailyBrief 是 LifeOS 中 LocalIntelligence 技能 的主控工作流:它负责把"家乡城市"的八类本地信息——建设许可、犯罪、商业、官员、立法、选举、逮捕、新闻——一次性全部抓取,写入统一的 JSON 摘要文件(latest.json),并在对话中按类别汇总播报。读完本文,你将掌握 DailyBrief 的完整执行链路:家乡地址如何解析、Refresh.ts编排器如何并发调用八个 fetcher、--fillAI 补缺模式如何工作、意图关键词如何映射为命令行标志,以及最终摘要文件的落盘结构与 Pulse 仪表盘的消费方式。
DailyBrief 在 LocalIntelligence 中的定位
LocalIntelligence 是一个"对任意美国城市通用的政务情报聚合器",围绕{city, state}(必要时含county)运行,不针对单一城市做硬编码。它由以下部分组成:
- 9 个 Workflow:
DailyBrief.md是编排入口,其余 8 个(News、Crime、Arrests、Elections、Legislation、Officials、Business、Construction)各自负责单类目查询; - 13 个 Tools:包括家乡解析器
Hometown.ts、编排器Refresh.ts、AI 补缺器ClaudeFill.ts、用户自定义源UserSources.ts、8 个 fetcher 以及历史回填工具Backfill.ts; - 1 个 References 文档:DataSources.md 收录了所有通用数据源的 URL 模式与可用性说明。
DailyBrief 的工作流文档对其使命的概括是:"Run the master daily civic digest for the principal's hometown. Calls every fetcher, writeslatest.json, summarizes the top items in chat."(为委托人家乡运行每日政务摘要:调用全部 fetcher,写入latest.json,并在对话中汇总前几条要闻。)
前置条件:Hometown 解析与委托人身份文件
DailyBrief 的第一步是解析家乡地址,这是唯一的城市信息来源。整个技能没有任何硬编码城市字符串——所有 workflow 和 fetcher 都通过 Tools/Hometown.ts 的readHometown()在运行时解析。
解析规则如下(源码HOMETOWN_RE正则):
- 从
~/.claude/LIFEOS/USER/PRINCIPAL/PRINCIPAL_IDENTITY.md(仓库内的模板见 PRINCIPAL_IDENTITY.md)中读取Quick Reference区的**Hometown:**行; - 期望的行格式为:
- **Hometown:** <City>, <ST> (ZIP <zip>, <County> County)例如:
- **Hometown:** Austin, TX (ZIP 78701, Travis County)<ST>可以是两位 USPS 州代码,也可以是完整州名(源码内置了 50 州 + 华盛顿特区的STATE_NAME_TO_CODE映射表);(ZIP <zip>, <County> County)为可选但推荐:zip支持5 位与9 位 ZIP+4格式,county用于拼接更精确的地点描述;- 解析结果同时生成
citySlug/stateSlug(kebab-case 化),供模板化 URL 使用,例如 Patch RSS 的https://patch.com/<state-slug>/<city-slug>/feed(见 FetchNews.ts 的fetchNews实现)。
身份文件路径可通过环境变量LIFEOS_PRINCIPAL_IDENTITY覆盖,默认值为上述路径。如果文件中没有**Hometown:**行,readHometown()会抛出NoHometownError(附带写入示例行的提示信息),DailyBrief 随即展示 setup-help 消息并退出(进程退出码为 2),绝不凭空捏造城市。
执行流程(Procedure)逐步拆解
DailyBrief 文档给出的标准流程共 5 步,下面结合源码逐一展开。
第 1 步:解析家乡
通过Tools/Hometown.ts解析家乡。若缺失则输出配置帮助消息并退出——这正是NoHometownError的语义。
第 2 步:运行 Refresh.ts 编排器
核心命令为:
bun run ~/.claude/skills/LocalIntelligence/Tools/Refresh.ts [--force] [--summary] [--json]Tools/Refresh.ts 是整个技能的编排中枢,它完成三件事:
(a)八路并发抓取:将 8 个 fetcher 注册进fetchers映射表(construction / crime / business / officials / legislation / elections / arrests / news),并通过Promise.allSettled并发执行——一个数据源挂掉不会拖垮整个摘要。每个 fetcher 的失败由runOne()捕获并转换为{ items: [], source_status: "unavailable", errors: [...] }的结果对象,而不是抛异常。
(b)结果归并:汇总sources_used(返回ok的源)、sources_failed(返回unavailable的源)以及带源标签的errors列表,组装成Digest对象。Digest的结构定义在 Tools/Types.ts:
interface Digest { meta: { city: string; state: string; county?: string; zip?: string generated_at: string sources_used: string[]; sources_failed: string[]; errors: string[] backfilled?: boolean } construction: FetchResult; crime: FetchResult; business: FetchResult officials: FetchResult; legislation: FetchResult; elections: FetchResult arrests: FetchResult; news: FetchResult }(c)落盘:persist()写入按日命名的时间戳文件(详见下文"输出产物"一节)。值得注意的加载顺序(源码注释明确说明):内置 fetcher → 用户配置源(UserSources.ts)→ AI 补缺(ClaudeFill.ts,仅当使用--fill时)——确定性数据永远优先于模型研究结果。
第 3 步:读取 latest.json
摘要落盘后,DailyBrief 读取~/.claude/LIFEOS/MEMORY/DATA/LocalIntelligence/latest.json,这是 Pulse 仪表盘 LOCAL 标签页消费的主路径。
第 4 步:汇总播报
在对话中按类别总结每类前 3 条,每条包含日期与来源链接。例如 News 类会展示标题、Patch来源、发布日期与原文 URL(这些字段正是Item接口的title / source / url / date / summary)。
第 5 步:暴露错误
如果meta.errors中有内容,必须点名失败的数据源,不得隐藏。这是"一个死源永不抹空白摘要"契约的另一半:数据可以缺,但失败必须可观测(源码中每个错误都带[section]前缀标签)。
意图到命令参数的映射(Intent-to-Flag Mapping)
DailyBrief 文档定义了一张"用户说什么 → 用什么标志"的意图映射表,用于 Agent 将自然语言请求路由到对应执行模式:
| 用户说 | 标志 | 效果 |
|---|---|---|
| "refresh"、"now"、"latest" | --force | 即使今日摘要已存在也重新执行 |
| "summary only" | --summary | 跳过编排器,直接读取现有 latest.json |
| "json only" | --json | 输出原始 JSON,不做对话汇总 |
结合源码需要说明一个关键实现细节:当前Refresh.ts的 CLI 入口(import.meta.main分支)将process.argv.slice(2)解析为Set,实际识别的是--fill(AI 补缺模式),并把--force / --summary / --json留作工作流层面的语义约定——即由 Agent 根据意图决定是重新跑编排器、直接读已有文件还是原样输出 JSON。因此这张映射表应当理解为"Agent 编排层的路由契约",而底层二进制当前真正承诺的开关是--fill:
bun run ~/.claude/skills/LocalIntelligence/Tools/Refresh.ts --fill--fill模式在确定性 fetcher 跑完后,由 Tools/ClaudeFill.ts 派生一个启用了WebSearch, WebFetch的claude --print子进程,对仍然为空的类别做一次性网络调研。所有模型输出必须通过validateSection()的确定性校验(必填字段、URL 形态^https?://...、每节上限 10 条)才能进入摘要;非法或疑似虚构条目会被丢弃并计入dropped计数,写入meta.errors。模型填充永远只能"补",不能覆盖已有确定性数据。Pulse 的每日 cron 与仪表盘"Refresh"按钮均使用--fill,裸调用保持纯确定性。
输出产物与数据落盘
DailyBrief 文档规定了三类输出:
- 文件:
~/.claude/LIFEOS/MEMORY/DATA/LocalIntelligence/<YYYY-MM-DD>_<city>_<state>_digest.json - 软链:
~/.claude/LIFEOS/MEMORY/DATA/LocalIntelligence/latest.json - 对话:每节前 3 条 + 如有则列出
meta.errors
结合 Refresh.ts 的persist()实现,这里有三点比文档更细化的实现事实:
双份 latest.json 而非单一软链:当前实现用
writeFile在两个位置各写入一份物理副本——USER/CUSTOMIZATIONS/SKILLS/LocalIntelligence/latest.json(Pulse 模块的优先读取路径)与MEMORY/DATA/LocalIntelligence/latest.json(历史兼容回退路径)。源码注释记载了一次事故:2026-05-03 至 2026-07-16 期间只写了旧路径,导致仪表盘静默展示了两个半月的过期摘要。因此"两份都要写、永不删除其一"是负载关键逻辑。No-clobber 保护:
totalItems(digest) === 0的全空运行(fetcher 宕机 + fill 失败)只写按日命名的历史文件,绝不覆盖已有内容的 latest.json。否则某天清晨 6 点的坏运行就会把仪表盘刷成空白。按日文件构成历史序列:Week/Month/Year 视图聚合这些按日文件;Tools/Backfill.ts 还可以用
--days 365深窗回填,把用户源自带历史记录按真实日期分布到过往的摘要文件中(回填日标记meta.backfilled: true)。
persist()的返回值还提供了一份机器可读的执行摘要(含sources_used、sources_failed、user_sources_merged、claude_filled、total_items与latest_skipped_no_clobber),便于 Agent 在对话中报告执行结果。
一个典型的latest.json内容结构(字段源自Digest/Item类型):
{ "meta": { "city": "Austin", "state": "TX", "county": "Travis", "zip": "78701", "generated_at": "2026-09-15T10:00:00.000Z", "sources_used": ["news", "officials", "business"], "sources_failed": ["construction"], "errors": ["construction: Patch returned 404 for https://patch.com/tx/austin/feed"] }, "news": { "items": [ { "title": "Austin council to vote on density bonus ordinance", "source": "Patch", "url": "https://patch.com/texas/austin/...", "date": "2026-09-14T00:00:00.000Z", "summary": "The ordinance would allow taller buildings near transit corridors." } ], "source_status": "ok" } }运行环境、通知与前置依赖
- 运行时:脚本为
#!/usr/bin/env bun,需在安装 bun。 - 语音通知:DailyBrief 启动时通过
localhost:31337的 LifeOS 通知端点播报:
curl -s -X POST http://localhost:31337/notify \ -H "Content-Type: application/json" \ -d '{"message": "Running DailyBrief in LocalIntelligence"}' \ > /dev/null 2>&1 &并在对话中输出一行Running **DailyBrief** in **LocalIntelligence**...。
- Pulse 集成:技能写 JSON、Pulse 读 JSON。Pulse 模块(
~/.claude/LIFEOS/PULSE/modules/local-intelligence.ts)只读latest.json,对外提供GET /api/local-intelligence与POST /api/local-intelligence/refresh;仪表盘 LOCAL 标签页(Observability/src/app/local/page.tsx)按九个区块渲染各类目。每日刷新由PULSE.toml中的[[job]]在0 6 * * *触发Refresh.ts。
边界情况与常见坑
以下要点提炼自 SKILL.md 的 Gotchas 清单,与 DailyBrief 直接相关:
- 没有 Hometown 行 = 不抓取:所有 workflow 输出配置帮助消息并以退出码 0 结束,不虚构城市;
empty≠unavailable:empty表示源返回 200 但没有匹配条目(小城镇常见),unavailable表示 4xx/5xx 或 DNS 失败——两者在仪表盘上渲染不同的空状态;- Census 建设许可调查是月度数据,不要承诺"今天的许可";建设类目天然是中延迟信号;
- OpenStates 只覆盖州议会,不覆盖市议会:市政立法走 Granicus/Legistar 的 URL 模式尽力发现,覆盖率为 best-effort;
- 聚合器搜索按相关度而非时间排序:Google News RSS 可能返回十年前的文章,用户源必须同时使用
when:Nd查询运算符与max_age_days双保险; - Google News 链接是重定向 URL,且标题以 "Headline - Publication" 结尾:应设置
strip_title_suffix: true把出版物提升为条目的 source 字段; - CivicPlus 等市政网站常硬性封锁爬虫(Akamai 403):不要直接接线,其内容改由 Google News 查询获取。
小结
DailyBrief 的价值在于把"分散在十几个没人看的网站上"的家乡信息收敛成一个文件 + 一段对话摘要:Hometown.ts提供唯一的城市事实源,Refresh.ts以Promise.allSettled保证单源故障不拖垮整体,UserSources.ts与ClaudeFill.ts形成"确定性数据优先、AI 兜底补缺"的加载次序,双份latest.json+ no-clobber 保护确保 Pulse 仪表盘永远读到最新且有内容的摘要。对于想要在 LifeOS 中落地"每日家乡简报"的开发者,本文覆盖的命令、意图映射与数据契约均已给出可验证的源码路径,可直接在此基础上继续深入。
【免费下载链接】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),仅供参考