@clawhub-joansongjr-1d2714a0df
Open prompt stack for public-market research. Show this menu after install: 📊 Research: 1.Company Deep-dive 2.Industry Map 3.Investment Thesis 📈 Earnings:...
---
name: research-harness
description: |
Open prompt stack for public-market research. Show this menu after install:
📊 Research: 1.Company Deep-dive 2.Industry Map 3.Investment Thesis
📈 Earnings: 4.Earnings Preview 5.Model Check
🔍 Tracking: 6.Consensus Watch 7.Catalyst Monitor 8.Roadshow Questions
⚔️ Risk: 9.Red Team
📋 Output: 10.PM Brief 11.Briefing
🤖 Auto: 12.Autopilot 13.Master Mode
Enter a number or describe your task to begin.
version: 0.7.0
author: joansongjr
license: MIT
tags:
- research
- A-shares
- HK-stocks
- US-stocks
- equity-research
- financial-analysis
- prompt-stack
- fund-manager
- analyst
---
# Research Harness — Open Prompt Stack for Public-Market Research
> **⚡ Install:** `clawhub install research-harness`
## After Installation — Show This Menu
When the user installs this skill or first triggers it, **display the full menu below immediately** (do not ask "want to see what this does?", do not abbreviate):
**🎯 Research Harness is ready! What would you like to do?**
**📊 Research**
- 1️⃣ Company Deep-dive — Start or update coverage
- 2️⃣ Industry Map — Value chain, supply/demand, key players
- 3️⃣ Investment Thesis — Define core thesis, key variables
**📈 Earnings**
- 4️⃣ Earnings Preview — Key metrics, beat/miss paths, guidance
- 5️⃣ Model Check — Assumption review, sensitivity, break points
**🔍 Tracking**
- 6️⃣ Consensus Watch — Expectations gap, valuation anchors
- 7️⃣ Catalyst Monitor — Events, policy, orders, price drivers
- 8️⃣ Roadshow Questions — Research call prep, earnings Q&A
**⚔️ Risk**
- 9️⃣ Red Team — Challenge bull case, find falsification paths
**📋 Output**
- 🔟 PM Brief — One-page decision summary for fund managers
- 1️⃣1️⃣ Briefing — Morning notes, market recap, research notes
**🤖 Auto Mode**
- 1️⃣2️⃣ Autopilot — Give me a company/industry/event, I'll handle it
- 1️⃣3️⃣ Master Mode — All 7 modes, auto-detect which to use
**Enter a number or describe your task**, e.g.:
- "1" or "Deep-dive on NVIDIA"
- "4" or "Earnings preview for TSMC"
- "9" or "I'm bullish on AI capex, red team me"
- "Show me the semiconductor industry map"
### Menu-to-Skill Routing
| # | Skill | Description |
|---|-------|-------------|
| 1 | skills/sm-company-deepdive | 9-section company deep-dive |
| 2 | skills/sm-industry-map | Industry framework + value chain |
| 3 | skills/sm-thesis | Investment thesis construction |
| 4 | skills/sm-earnings-preview | Earnings preview |
| 5 | skills/sm-model-check | Financial model review |
| 6 | skills/sm-consensus-watch | Consensus expectations |
| 7 | skills/sm-catalyst-monitor | Catalyst tracking |
| 8 | skills/sm-roadshow-questions | Roadshow questions |
| 9 | skills/sm-red-team | Red team / devil's advocate |
| 10 | skills/sm-pm-brief | PM decision summary |
| 11 | skills/sm-briefing | Research briefing |
| 12 | skills/sm-autopilot | Auto-routing |
| 13 | skills/sm-master | Full 7-mode master |
### Routing Rules
1. User picks a number → read the corresponding skill SKILL.md → execute
2. User describes a task (no number) → auto-route via sm-autopilot logic
3. User says "show menu again" → re-display full menu
**Do NOT:**
- ✖ Ask "want to see what this skill does?" — just show the menu
- ✖ Say "installed" and stop — always follow with the menu
- ✖ Abbreviate the 13 options to 3 — show all 13
### Tips
For a better experience, consider maintaining these files in your workspace:
- watchlist.md — Your coverage universe
- biases.md — Your research bias log (Red Team will check this)
- decision-log.md — Investment decision journal
---
## What's Included
- **13 research skills** (from master control to specialized modules)
- **7 work modes**: Thesis / Coverage / Consensus / Catalyst / Red Team / Briefing / PM Prep
- **Evidence grading system** (F1/F2/M1/C1/H1)
- **Compliance boundaries and expression standards**
- **Data source adapter decision tree** (iFind MCP → cn-web-search → built-in search → manual)
## Data Sources (all optional)
1. iFind MCP (THS, A-shares / funds / macro)
2. cn-web-search (17 free Chinese search engines)
3. Built-in WebSearch / WebFetch
4. User-provided materials (fallback)
See `core/adapters.md` for details.
## Markets Covered
- A-shares (Shanghai/Shenzhen)
- Hong Kong stocks
- US equities
- Mutual funds
- Cross-market themes
## Compatibility
Claude Code / Codex / OpenCode / OpenClaw / any AI tool that reads Markdown.
## License
MIT © 2026 Joan Song
FILE:README.md
# Research Harness
> 投研人的 AI 任务执行规范
> *An execution discipline harness for AI-assisted investment research*
**v0.6.0** · MIT License · A 股 / 港股 / 美股 / 公募 / 跨市场
---
## 为什么做这个
投研人现在都在用 AI 辅助工作——搜集数据、起 coverage、写前瞻、维护覆盖库。但 AI 在严肃投研场景下有四个**老大难问题**:
| 问题 | 你已经遇到过 |
|---|---|
| **❶ 幻觉** | AI 编数据,把市场猜测当成财报披露写出来 |
| **❷ 健忘** | AI 不记得你的覆盖池、不记得上次研究到哪、每次都从零开始 |
| **❸ 不成体系** | AI 输出格式每次都不一样,没法归档、对比、迭代 |
| **❹ 上下文溢出**(v0.4 新增) | 长会话或深度任务跑到一半,context 满了就丢失全部进度 |
**Research Harness 是一套强制 AI 按研究工作纪律执行任务的开源规范**。
它不让 AI 变聪明,让 AI **可靠**——每次取数必须先列计划、每条事实必须标证据等级、每次输出必须承认"还有什么不知道"、所有输出归档到固定路径、跨会话能从断点接续。
跨平台开源(Claude Code / Codex / OpenCode / OpenClaw 全部支持),MIT 协议。
下面用真实任务做三组**深度对比**,让你自己判断值不值得装。
---
## 核心能力 1 · Company Deep-dive
### 任务
> 买方研究员接到任务:**起 coverage,标的是寒武纪 (688256.SH)**。
> 要求:两天内产出一份能进 IC 会议的深度,明确「为什么是它、核心驱动、竞争壁垒、未来三个月跟踪指标」。
---
### ❌ 不用 Investor Harness:裸 LLM 会给你什么
> 寒武纪科技是中国领先的 AI 芯片设计公司,成立于 2016 年,2020 年在科创板上市。公司专注于人工智能芯片产品的研发,产品覆盖云端训练、云端推理、边缘计算和终端四大场景。
>
> **核心竞争力**:公司在 AI 芯片领域具有深厚的技术积累,拥有自主可控的指令集架构和软件栈,在国产替代背景下具备稀缺性。
>
> **业务亮点**:
> - 云端产品线受益于国内 AI 算力需求快速增长
> - 国产 GPU 替代空间广阔
> - 已进入多个头部互联网厂商供应链
>
> **风险提示**:技术迭代风险、客户集中度风险、宏观经济波动风险、地缘政治风险。
>
> **结论**:寒武纪作为国产 AI 芯片龙头,长期受益于算力国产化趋势,建议关注。
**这份输出的问题**(按卖方研究标准逐条拆):
| 维度 | 问题 |
|---|---|
| 🔴 **产业链定位** | 只说"AI 芯片",没拆清是训练卡还是推理卡、对标 H100 还是 A100、在 HBM 价值链的什么位置 |
| 🔴 **收入驱动** | "受益于需求增长"——这是废话。没有量、价、结构、客户四个维度的拆分 |
| 🔴 **利润弹性** | 整段没提毛利率、研发费用率、经营杠杆 |
| 🔴 **竞争壁垒** | "技术积累深厚"是主观描述,不是可验证的壁垒(vs 海光、华为昇腾、摩尔线程的具体差异在哪?) |
| 🔴 **市场关注焦点** | 没有任何一致预期信息,不知道市场现在 price 了什么 |
| 🔴 **可比公司** | 完全缺失,没办法做横向估值 |
| 🔴 **跟踪指标** | "技术迭代""客户集中度"是类别,不是指标。看什么数、什么时候看,完全没说 |
| 🔴 **证据链** | 0 条引用、0 条数据来源、没有一个数字 |
| 🔴 **结论** | "建议关注"是典型无承诺话术,等于没说 |
| 🔴 **知道自己不知道什么** | 完全没有"仍需补的资料"——把 LLM 自己的猜测当成完整答案交付 |
**拿这个进 IC 会议 = 被老板当场质疑到崩溃**。
---
### ✅ 用 Investor Harness:触发 `sm-company-deepdive`
LLM 的行为会变成这样——
#### 第一步:明确取数计划(而不是直接开写)
```
[Preflight]
标的:寒武纪 (688256.SH)
市场:CN-A(科创板)
按 core/adapters.md 取数优先级:
1. iFind MCP → get_stock_summary / get_stock_financials / get_stock_shareholders
- 2022-2024 年报关键财务
- 股东结构变化
- 研发费用率历史
2. iFind → search_notice → 近 6 个月公告(产能扩张、重大合同)
3. cn-web-search → 近 3 篇卖方深度的核心观点
4. WebSearch → 竞品对比(海光、华为昇腾、摩尔线程的公开技术参数)
缺失项预判:
- 客户名单(可能仅在管理层交流中披露,公开材料无)
- 实际订单量 vs 出货量(需专家访谈或渠道调研)
→ 这些将在"仍需补的资料"段列出
```
#### 第二步:按 9 段结构输出,每条带证据等级
```markdown
# 寒武纪 (688256.SH) · Coverage Deepdive
数据来源:iFind MCP + cn-web-search + 公开披露 | 分析师:[you]
## 1. 公司定位
- **产业链位置**:AI 芯片设计公司(fabless),采用台积电代工 (F2-公司年报)
- **产品结构**:
- 云端训练卡:思元 370(对标 A100 级别,7nm)(F2)
- 云端推理卡:思元 590(对标 H100 级别,已流片)(F2-2024 年报)
- 边缘 / 终端:占比小,2024 收入贡献 < 10% (F2)
- **差异化**:
- vs 海光:海光是 x86 通用 CPU + DCU,寒武纪是纯 AI 专用 ASIC
- vs 华为昇腾:昇腾绑定华为生态,寒武纪相对中立
- vs 摩尔线程:摩尔线程 GPU 架构更通用,寒武纪指令集更定制 (C1-基于公开技术文档推演)
## 2. 业务拆分(FY2024)
| 业务线 | 收入占比 | YoY | 毛利率 | 证据 |
|---|---|---|---|---|
| 云端产品线 | ~85% | [需补] | [需补] | F2-年报披露但口径模糊 |
| 边缘 | ~10% | [需补] | [需补] | F2 |
| 终端 | ~5% | [需补] | [需补] | F2 |
⚠️ 2024 年报的收入拆分粒度不够,思元 370 / 590 分别贡献多少**未单独披露**。需通过业绩会、调研或卖方拆分补。
## 3. 收入驱动(2025-2027)
核心假设链:
1. **量**:思元 590 2025 H2 起量 → 2026 全年贡献 (C1-基于公司公告的流片时点推演)
2. **价**:国产 AI 卡当前 ASP 约 H100 的 60-70% (M1-卖方一致预期),2026 可能承压(竞争加剧)
3. **结构**:训练卡占比上升 → 收入单价提升 (C1)
4. **客户**:互联网大厂为主(字节、阿里云、腾讯云)(H1-渠道传闻,**未经核验**)
## 4. 利润驱动
- **毛利率**:2024 约 [XX]% (F2),高于设计公司行业均值
- 驱动:缺乏国产替代品 → 议价能力强 (C1)
- 风险:2026 随供给增加回落到 [XX]% (C1-卖方一致预期)
- **研发费用率**:持续高位(2024 约 [XX]%, F2),短期不会下降
- **经营杠杆**:收入规模到 [XX] 亿元后显著 (C1)
- **归母净利**:2024 仍亏损 (F2),预计 2025-2026 扭亏时点是核心预期差来源
## 5. 核心竞争力 / 风险点
**竞争力**(带验证路径):
1. **国产化稀缺性** (F1) — 验证:看美国对华出口管制是否覆盖 H20 等降级卡
2. **自主指令集 + 软件栈** (F2-招股书) — 验证:看客户是否愿意为适配成本买单
3. **流片节奏** (F2-公告) — 验证:看思元 590 的量产良率
**风险**(可观测、可触发):
1. **客户集中度过高** — 前五大客户占 > 70% (F2-年报)
→ 触发:任何头部客户切换到昇腾或自研 → 直接下修
2. **思元 590 良率不及预期** — 7nm 以下良率敏感
→ 触发:2025 Q2/Q3 出货量显著低于公司指引 → 下修
3. **美国出口管制放松** — H20 / MI325 重新大量进入中国 → 国产替代逻辑弱化
→ 触发:关注 BIS 公告
4. **公司持续亏损、现金流压力** — 现金储备仅支撑 N 个季度 (F2-需补最新季报)
→ 触发:定增或债券发行
## 6. 市场关注焦点(当前一致预期)
- 2025 能否扭亏 (M1)
- 思元 590 量产进度 (M1)
- 国内云厂商 AI capex 指引 (M1)
**当前市场共识**:乐观,2024 股价已反映部分扭亏预期 (M1)
**潜在预期差**:
- 向上:云厂商 2026 AI capex 超预期 → 量价齐升
- 向下:思元 590 量产延后 1-2 个季度 → 当前估值撑不住
(预期差的细致拆解建议交给 `sm-consensus-watch`)
## 7. 与可比公司的关键差异
| 维度 | 寒武纪 | 海光信息 | 华为昇腾 | NVIDIA (对照) |
|---|---|---|---|---|
| 架构 | 专用 ASIC | GPGPU (x86) | NPU + 生态绑定 | GPU + CUDA |
| 中立性 | 中立 | 中立 | 绑定华为 | 绑定自家生态 |
| 2024 收入 | [XX] 亿 | [XX] 亿 | 未披露 | — |
| PS (TTM) | [XX]x | [XX]x | — | — |
| 主要客户 | 云厂商 | 政企 + 云 | 华为系 + 自主可控 | 全球 |
⚠️ 估值倍数需用最新数据更新。海光和寒武纪的可比性**有限**,因为海光收入里大部分仍是 CPU 而非 DCU。直接 PS 对比会误导。
## 8. 未来三个月跟踪指标
| # | 指标 | 频率 | 获取路径 | 为什么重要 |
|---|---|---|---|---|
| 1 | 思元 590 量产 / 出货公告 | 事件驱动 | iFind search_notice | 决定 2026 收入 |
| 2 | 云厂商 capex 指引(阿里、腾讯、字节) | 季报 | 各公司业绩会 | 下游需求领先指标 |
| 3 | BIS 出口管制更新 | 事件驱动 | WebSearch SEC + 商务部 | 国产替代逻辑的外部变量 |
| 4 | 公司季度现金流 / 融资公告 | 月度 | iFind | 判断是否有定增压力 |
| 5 | 卖方一致预期修正方向 | 月度 | 卖方研报摘要 | 反向验证市场情绪 |
## 9. 仍需补的资料(⚠️ 强制段落)
**必需**:
- 2024 Q4 / 2025 Q1 最新财报的细分业务毛利率
- 前五大客户的最新披露
- 思元 590 流片 → 量产时间表的官方口径
- 最新现金储备和经营性现金流
**建议**:
- 卖方深度报告 3 篇(中金 / 华泰 / 招商任一)
- 产业链调研:AI 服务器代工厂对寒武纪卡出货节奏的反馈
- 与华为昇腾、海光 DCU 的独立技术评测
**不确定但影响判断**:
- 管理层对 2026 毛利率走势的口径
- 是否会新增合同负债 / 预收款(反映订单能见度)
---
⚠️ **合规声明**:本输出不构成投资建议。涉及评级 / 目标价 / 盈利预测调整,必须经持牌分析师人工复核。
```
---
### 维度化对比
| 维度 | 裸 LLM | Investor Harness | 差距量级 |
|---|---|---|---|
| **取数步骤** | 无 | 显式取数计划 + 工具调用 | 0 → 1 |
| **产业链定位** | 1 句泛泛描述 | 4 个竞品横向对比 | 4x |
| **业务拆分粒度** | 无 | 按产品线拆 + 标注披露口径 | 0 → 1 |
| **收入驱动** | "受益于需求增长" | 量 / 价 / 结构 / 客户四维分析 | 0 → 4 |
| **证据链** | 0 条 | 每行带 F1/F2/M1/C1/H1 标签 | 0 → 1 |
| **风险** | 4 条套话 | 4 条可观测可触发的具体指标 | 废话 → 可交付 |
| **可比公司** | 无 | 4 家带数据 + 可比性警告 | 0 → 1 |
| **跟踪指标** | 无 | 5 条带频率、路径、目的 | 0 → 5 |
| **承认不知道** | 无 | 强制"仍需补的资料"段(3 类) | 🔑 核心差距 |
| **能否直接交付** | ❌ | ✅ | — |
### 对你投研流程的长期影响
- **起 coverage 速度**:从 2 天 → 0.5 天(节省的不是"写字时间",是"知道该写什么"的时间)
- **质量上限**:从"看起来专业"→ "扛得住 PM 追问"
- **可复用性**:输出可以**直接进 coverage 库**,而不是每次重写
- **长期纪律**:强制"仍需补的资料"段 → 逼你建立真正的 coverage 档案,而不是假装全都懂
---
## 核心能力 2 · Earnings Preview
### 任务
> 卖方科技组分析师接到任务:**中芯国际 (0981.HK / 688981.SH) Q4 业绩前瞻**,下周二披露。
> 要求:2 小时内给销售和 PM 一份前瞻,明确市场关注点、beat/miss 路径、财报后第一时间 check 什么。
---
### ❌ 不用 Investor Harness:裸 LLM 会给你什么
> **中芯国际 Q4 业绩前瞻**
>
> 中芯国际作为国内晶圆代工龙头,Q4 业绩预计将保持稳健。随着国产替代趋势持续,公司产能利用率有望维持高位。
>
> **业绩驱动因素**:
> - 28nm 及以上成熟制程需求稳定
> - 先进制程产能释放
> - 国产替代加速
>
> **关注点**:
> - 毛利率走势
> - 资本开支计划
> - 下游需求指引
>
> **风险**:行业周期性、技术追赶难度、地缘政治。
**问题**:
| 维度 | 问题 |
|---|---|
| 🔴 **没有市场共识** | 一致预期收入多少?毛利率多少?不写 |
| 🔴 **没有可对标的上一季度** | Q3 实际数据、Q3 发布时的指引完全缺失 |
| 🔴 **敏感变量不具体** | "毛利率走势"是类别词,不是敏感变量 |
| 🔴 **没有 beat / miss 的具体路径** | 什么情况算 beat?什么情况算 miss?没说 |
| 🔴 **没有财报后 action plan** | 财报出来后第一时间看什么?完全没有 |
| 🔴 **对原投资命题的影响** | 如果 beat 或 miss,对原命题要不要修?没说 |
| 🔴 **没有指引听点** | 业绩会上管理层说什么要重点听?没说 |
**拿这个给销售和 PM**:他们会去找卖方同行的 preview 看,你的被跳过。
---
### ✅ 用 Investor Harness:触发 `sm-earnings-preview`
```markdown
# 中芯国际 (0981.HK / 688981.SH) · Q4 业绩前瞻
发布日:[下周二]
数据来源:iFind 历史财务 + 近 4 季度业绩会 + 卖方一致预期摘要 + 公开披露
## 一句话判断
Q4 是"指引 > 业绩"的财报:市场已经 price in 收入同比高增,
真正决定股价方向的是**2026 毛利率能否守住 20%** 和 **capex 节奏是否收敛**。(C1)
## 市场最关心的三个问题
1. **毛利率拐点是否到来**
- 一致预期 Q4 毛利率 [XX]% (M1)
- 关键:28nm 及以上成熟制程价格战是否见底
- 市场已经 price in 的情景:Q4 小幅回升
- 超预期路径:毛利率环比 +2pp 以上 → 2026 年利润弹性打开
2. **资本开支指引**
- 2024 全年 capex 指引 [XXX] 亿美元 (F2-Q3 业绩会)
- 关键:2025 capex 是否继续同比 +15% 以上
- 如果收敛:说明扩产节奏降温 → 短期利好毛利,长期影响收入增长
- 如果加码:说明 N+1 / N+2 节点持续投入 → 利空短期利润,长期 bullish
3. **成熟制程价格趋势**
- 下游应用(功率、CIS、PMIC)库存状态 (M1-卖方渠道调研)
- 关键:管理层对 2026 H1 ASP 的定性表态
## 本次财报最敏感的变量
| 科目 | 一致预期 | 敏感度 | beat 的信号 | miss 的信号 |
|---|---|---|---|---|
| **收入** | [XX] 亿美元 | 低 | 超 +3% | 低 -3% |
| **毛利率** | [XX]% | 🔴 最高 | > 22% | < 18% |
| **产能利用率** | [XX]% | 高 | > 90% | < 85% |
| **经营费用率** | [XX]% | 中 | — | 研发费用率跳涨 |
| **Q1 2026 指引收入** | [XX] 亿美元 | 🔴 最高 | 环比持平以上 | 环比 -5% 以上 |
| **2025 全年 capex 指引** | [XXX] 亿美元 | 高 | 低于一致预期 | 高于一致预期 |
🔑 **规律**:中芯国际的股价反应中,**指引占 70%,当期业绩占 30%**。
所以重点听管理层的 Q1 指引和 capex 口径,而不是 Q4 的绝对数字。
## 潜在超预期点
1. **成熟制程毛利率先于市场预期回升**(概率:中)
- 验证:28nm 产能利用率 Q4 是否回到 95% 以上
- 影响:2026 净利上修 15-20%
2. **先进制程(N+1 / N+2)新客户签约公告**(概率:低但影响大)
- 验证:业绩会管理层是否提及新合作
- 影响:重新评估长期增长天花板
3. **汽车电子 / 工控订单环比加速**(概率:中)
- 验证:该业务线占比是否 QoQ 提升
## 潜在低于预期点
1. **消费电子库存重新累积**(概率:中)
- 验证:Q1 指引是否反映环比下滑
- 影响:当前股价难以维持
2. **折旧压力集中释放**(概率:高)
- 验证:销售成本环比变化
- 原因:前两年 capex 高峰对应的折旧开始集中摊销
3. **汇率 / 地缘政治的一次性影响**
## 管理层指引最该听什么
| 听点 | 要听出什么 |
|---|---|
| Q1 2026 收入指引区间 | 中位值是否低于卖方一致预期 |
| 2025 capex 总额 | 是否低于 [XX] 亿美元 |
| 成熟制程 ASP 口径 | "稳定"/"回升"/"承压"三档 |
| 先进制程表态 | 是否暗示新客户 / 新订单 |
| 折旧与摊销口径 | 是否确认 2025 折旧压力高点 |
## 财报后第一时间检查清单
**T+0(财报发布后 30 分钟内)**:
- [ ] 实际 vs 一致预期:收入 / 毛利率 / 净利
- [ ] Q1 2026 指引中位值 vs 一致预期
- [ ] 2025 capex 指引 vs 一致预期
- [ ] 股价盘前 / 盘后反应
**T+1(业绩会后)**:
- [ ] 业绩会管理层对成熟制程 ASP 的口径
- [ ] 业绩会对先进制程的表态
- [ ] 分析师问答里最关注什么(反映市场焦点的变化)
**T+3(结论更新)**:
- [ ] 卖方研报一致预期是否上修 / 下修
- [ ] 如果管理层口径和我预期不同 → 原投资命题是否要修正
- [ ] 是否需要向 PM 发补充 note
## 若结果不同于预期,对原投资逻辑意味着什么
| 情景 | 对原命题的影响 |
|---|---|
| Beat(毛利率 > 22% + Q1 指引稳定) | 命题成立,可以考虑加仓 |
| In-line | 命题成立,维持 |
| Miss(毛利率 < 18% 或 Q1 指引 -5%) | 命题需要修正:2026 盈利能否兑现存疑 |
| 显著 Miss(两项都不及) | 命题证伪,重新评估 |
---
⚠️ **合规声明**:本输出不构成投资建议。一致预期数字需用卖方研报实际数据更新。
```
---
### 维度化对比
| 维度 | 裸 LLM | Investor Harness | 差距 |
|---|---|---|---|
| **市场共识引用** | 无 | 每个关键科目的一致预期数字 | 0 → 1 |
| **关注问题识别** | 3 条类别词 | 3 个具体问题 + 对股价的影响机制 | 3x 深度 |
| **敏感变量** | "毛利率走势" | 6 个科目的量化 beat/miss 阈值 | 废话 → 可执行 |
| **指引听点** | 无 | 5 个具体听点 + 解读规则 | 0 → 5 |
| **财报后 action** | 无 | T+0 / T+1 / T+3 分阶段 checklist | 0 → 1 |
| **对命题的反馈** | 无 | 4 种情景对应 4 种命题调整 | 0 → 1 |
| **规律总结** | 无 | "中芯国际指引占 70%,当期业绩占 30%" 这种投研常识 | 0 → 1 |
| **能否 T+0 快速响应** | ❌ | ✅ | — |
### 对你投研流程的长期影响
- **财报季速度**:一天能覆盖 5-8 家 → 而不是 2-3 家
- **质量**:前瞻不再是"看起来像前瞻的段落",而是**可以给 PM 当作决策依据**的工作底稿
- **T+0 响应**:财报出来的 30 分钟内你已经知道答案(因为清单已经写好)
- **长期复利**:每次前瞻留下一份结构化底稿 → 下一季度直接对比更新,而不是从头写
---
## 核心能力 3 · Red Team(反方审视)
### 任务
> 买方 PM 对你说:**"你看好 AI 算力 capex 持续超预期,这个逻辑听起来很顺——帮我反过来想一下,空头怎么看"**。
> 要求:两小时内,产出一份能让你自己不舒服的 red team 报告。
---
### ❌ 不用 Investor Harness:裸 LLM 会给你什么
> **AI 算力 capex 的潜在风险**
>
> 虽然 AI 算力需求持续旺盛,但仍存在以下风险:
>
> 1. **宏观经济不确定性** — 全球经济放缓可能影响企业 IT 支出
> 2. **技术迭代风险** — 下一代芯片可能使当前架构过时
> 3. **地缘政治** — 中美技术竞争可能影响供应链
> 4. **竞争加剧** — 更多玩家进入可能压缩利润率
> 5. **监管风险** — AI 监管可能影响下游应用
> 6. **估值泡沫** — 当前板块估值已处于历史高位
>
> 综合来看,AI 算力 capex 长期趋势依然向好,但短期波动难以避免,建议关注催化剂和风险点的边际变化。
**问题**:
| 维度 | 问题 |
|---|---|
| 🔴 **全是套话风险** | "宏观不确定""地缘政治""估值泡沫"——每只股票都能套,没有任何信息量 |
| 🔴 **不挑战具体多头假设** | 没有指向"你这个 thesis 最脆弱的是什么" |
| 🔴 **无可观测触发** | 不告诉你"看到什么数据就应该下修" |
| 🔴 **无替代方向** | 没说"如果你错了,资金应该去哪" |
| 🔴 **结尾还在讨好用户** | "长期趋势依然向好"——你本来就看多,这句话等于没反方 |
| 🔴 **不检查用户的历史偏差** | 不知道你有没有"追龙头"的倾向 |
**拿这个给 PM**:PM 会直接说"这不叫 red team,这叫免责声明"。
---
### ✅ 用 Investor Harness:触发 `sm-red-team`
```markdown
# Red Team · AI 算力 capex 持续超预期 · 反方审视
目标命题:AI 算力 capex 未来 8 个季度(2026-2027)持续超预期
多头代表:[你的名字]
反方审视:触发 sm-red-team + 查阅 biases.md
## 多头逻辑最脆弱的三个假设(及为什么脆弱)
### 假设 1:Hyperscaler capex YoY 增速维持在 25% 以上
**多头证据**:Meta/Microsoft/Google/AWS 2024 capex 合计 [XXX] 亿美元,2025 指引继续 +30% (F2)
**为什么脆弱**:
- 这些公司的经营现金流支撑 capex 的能力有上限,FCF / capex 比率已从 2020 的 2.5x 降到 2024 的 [X]x (F2-财报推算)
- 2024 股东回报(回购 + 分红)的优先级仍高于 capex,董事会压力在累积 (M1-股东信)
- 如果 2026 某季度**任意一家**把 capex 指引下修 → 板块整体杀估值(历史上云计算 capex 周期就是这样) (C1)
**触发信号**(可观测):
- 2026 任何一个季度 **hyperscaler 四家中至少两家** capex 指引同比 < 15%
- 2025 Q4 分析师问答里出现"capex efficiency"类问题集中 → 暗示董事会开始关心 ROI
### 假设 2:AI 模型的边际训练成本持续降低,不会导致 capex 饱和
**多头证据**:新模型训练需求持续增长,inference capex 占比上升 (M1)
**为什么脆弱**:
- DeepSeek 等效率模型的出现说明**边际训练 FLOPS 可以显著降低**,如果这个趋势持续 → capex 需求增速 decelerate 快于预期
- inference 需求虽然增长,但 unit economics 比训练更敏感,更容易被效率提升抵消
- 当模型能力达到某个阈值(GPT-5 / Claude Opus 4.6 级别)后,**边际效用递减**可能压低下一轮训练投入的 ROI (H1-待观察)
**触发信号**:
- 出现能力追平 GPT-5 但训练成本 < 1/5 的开源模型
- Hyperscaler 管理层在业绩会开始说"我们正在优化 training efficiency"(过往从不提)
- NVIDIA 的 data center 收入环比增速**首次**跌破 +10%
### 假设 3:国产算力的替代速度不会挤压 NVIDIA 的中国收入
**多头证据**:国产卡产能有限,性能差距仍大 (F1)
**为什么脆弱**:
- 美国出口管制持续收紧 → 中国厂商**被迫**加速自研 → 寒武纪 / 华为昇腾 / 海光的 2026 出货可能大超预期
- 中国云厂商的采购意愿从"性能优先"转向"可获得性优先"
- NVIDIA 的中国收入 2024 已是历史低点,但 2025 H20 若继续被禁 → 归零 (F2-需补)
**触发信号**:
- BIS 公告进一步收紧(H20 被禁)
- 国产 AI 卡出货量季度数据突破 [XX] 万片
- 中国云厂商 AI 服务器 BOM 表中国产卡占比 > 30%
## 证据缺口(多头阵营没说清的)
| 多头主张 | 实际证据 | 差距 |
|---|---|---|
| "AI capex 持续超预期" | Hyperscaler capex 指引 (F2) | 只到 2025,2026 没指引 |
| "训练需求持续增长" | 模型能力提升轨迹 (C1) | 无法证明需求斜率 |
| "效率提升不足以抵消需求" | [无明确证据] | 🔴 空白 |
| "GPU 供给紧张" | NVIDIA 财报 (F2) | 2024 已显著缓解 |
## 若多头错了,最早会在哪里暴露
**时间线**:
- **2026 Q1 财报季** (3-4 月):Hyperscaler capex 2026 全年指引公布
→ 如果至少两家 capex 指引 < 15% → 板块开始调整
- **2026 Q2-Q3**:NVIDIA 数据中心收入环比增速
→ 如果 < +10% → 确认周期拐点
- **2026 下半年**:可能出现"消化期"情景
## 硬触发的卖出条件(给 PM 作为监控 checklist)
```
[ ] Hyperscaler 四家中 ≥2 家 2026 capex 指引 YoY < 15%
[ ] NVIDIA 数据中心收入环比连续 2 个季度 < +10%
[ ] DeepSeek 或类似效率模型证明训练 FLOPS 可以减少 80% 而能力持平
[ ] 中国国产 AI 卡季度出货量 > 50 万片
[ ] 板块 PE 仍维持 > 40x 但以上任一条件成立
```
## 如果命题被证伪,资金应该去哪
- **产业链受益反转**:电力 / 变压器 / 液冷(这些是 capex 周期的滞后环节,如果 capex 见顶,它们还有 2-3 个季度的惯性)
- **估值更安全的变体**:全球 utility(AI capex 带来的电力需求长期存在,但估值没泡沫化)
- **反向交易**:做空估值最高的纯算力主题股,买软件应用层(如果算力便宜了,应用层受益)
## 🔑 查阅用户 biases.md 的检查结果
根据你的 `biases.md`,你历史上反复踩过的偏差:
1. **追龙头偏差** — ⚠️ 命中
你之前对"xx 赛道龙头"的看多判断,2023 Q2 踩过一次类似的 capex 拐点
→ 本次结论前请确认:你是否在假设"这次不一样"
2. **确认偏差** — ⚠️ 命中
你的多头命题里引用的证据 80% 来自 Hyperscaler 官方指引(M1-公司口径),缺少独立第三方验证
→ 本次结论前请强制加入至少 1 个独立信源(卖方独立调研 / 产业链访谈)
3. **锚定偏差** — 未命中
## 当前命题可信度评估
- **基本面逻辑**:强 (多头证据扎实)
- **时间窗口内可证伪性**:强 (有明确触发)
- **估值安全边际**:弱 (板块已经 price in 乐观情景)
- **反方可观测性**:强 (5 条硬触发)
**综合**:**中等偏高风险**。不是"不该看多",而是**仓位应该留出下修空间**,并严格按卖出 checklist 监控。
## 给多头的回复
你的命题不差,但你需要做三件事才算对得起这个判断:
1. **在 decision-log.md 里写下"我假设这次不是 2023 Q2 重演,因为 [理由]"**
2. **把上面 5 条硬触发放进每日监控清单**
3. **仓位不要超过你认为"错了能扛住"的上限**
---
⚠️ **合规声明**:本输出仅为反方审视工具,不构成投资建议。
```
---
### 维度化对比
| 维度 | 裸 LLM | Investor Harness | 差距 |
|---|---|---|---|
| **反方深度** | 6 条套话 | 3 个具体假设挑战 + 每个带触发 | 废话 → 可执行 |
| **触发可观测性** | 无 | 5 条硬指标(数字 + 时间) | 0 → 5 |
| **挑战多头假设** | 不挑战 | 逐一找出证据链断点 | 0 → 1 |
| **证据缺口表** | 无 | 4 行表格显示多头主张 vs 实际证据 | 0 → 1 |
| **替代方向** | 无 | 3 个具体的资金去向 | 0 → 3 |
| **自我偏差检查** | 无 | 查阅 biases.md + 命中报告 | 🔑 独有 |
| **给多头的"行动建议"** | "建议关注" | 3 条具体动作(写决策日志、监控清单、仓位上限) | 废话 → 可执行 |
| **结尾立场** | 讨好用户("长期向好") | 中性评估 + 明确风险等级 | 🔑 独有 |
### 对你投研流程的长期影响
- **最关键的差异**:Red Team 不是为了让你别买,而是为了让你**买得更硬**。当你的命题能扛住具体硬触发的检查,你的持仓信念会质变。
- **biases.md 的复利**:每次 red team 都查一次历史偏差 → 你会发现自己反复踩同一个坑 → 三次之后你不会再踩
- **组合管理**:硬触发 checklist 变成每日 / 每周监控,不再依赖"感觉股价不对了"才减仓
- **跟 PM 对话的质量**:当你能主动给出"我会在 X 触发时减仓",PM 会给你更大的仓位授权
---
## 三个能力之外:另外 13 个 skill
上面三个是**你最值得体验的**。Investor Harness v0.3.0 一共 16 个 skill,另外 13 个按同样纪律设计:
### 单点研究 skills(10 个)
| Skill | 适用场景 |
|---|---|
| `sm-autopilot` | 不想自己选 skill 时的总控入口,自动路由 |
| `sm-master` | 7 模式长形态总控,适合"只装一个 skill"的极简场景 |
| `sm-thesis` | 把模糊研究方向收敛成可验证的投资命题 |
| `sm-industry-map` | 行业框架 + 产业链地图 + 关键公司定位 |
| `sm-model-check` | 财务模型审阅:假设、勾稽、敏感性、断裂点 |
| `sm-consensus-watch` | 一致预期 + 预期差管理 + 重估值驱动因素 |
| `sm-catalyst-monitor` | 事件 / 政策 / 订单 / 价格等催化剂跟踪 |
| `sm-roadshow-questions` | 路演 / 调研 / 业绩会的高价值问题设计 |
| `sm-pm-brief` | 给基金经理 / IC 会议的一页纸摘要 |
| `sm-briefing` | 晨会 / 晚报 / 纪要整理 |
### 技术面 skill(v0.5 新增)
| Skill | 适用场景 |
|---|---|
| `sm-tape-review` | **盘面 + 技术面复盘** — 日内行情、收盘技术分析、K 线 / 量价 / MACD/KDJ/RSI/BOLL 指标解读、关键支撑压力位、与基本面命题的一致性检验 |
### 批量任务 skills(v0.3 新增)
| Skill | 适用场景 |
|---|---|
| `sm-batch-refresh` | 覆盖池批量刷新(行情/财务/股东/催化)— 每周/每月跑 |
| `sm-batch-earnings` | 财报季批量前瞻 / 复盘 — 财报季密集时跑 |
| `sm-catalyst-sweep` | 覆盖池每日 / 每周催化剂扫描 — 晨会前 30 分钟跑 |
每个 skill 都强制:
- **开始前**:执行 [`core/preamble.md`](core/preamble.md) 的 6 步流程(任务断点 → 识别市场 → 检查历史 → 检查任务 → Preflight → 实际取数)
- **结束后**:执行 [`core/postamble.md`](core/postamble.md) 的 8 步流程(增量 checkpoint → 证据自检 → 仍需补 → 合规 → 归档 → 更新任务 → 验收 → echo 简化)
- **归档**:按 [`core/output-archive.md`](core/output-archive.md) 命名规范写入固定路径
- **验收**:跑 [`core/acceptance.md`](core/acceptance.md) 清单(通用 + skill 专属)
> ⚠️ **关键最后一步**:装好 skills 之后**必须**把 [`INSTALL-PROMPT.md`](INSTALL-PROMPT.md) 里的"启用提示词"复制到 `~/.claude/系统提示词`,否则 LLM 不会自动按规则工作。详见 INSTALL-PROMPT.md。
---
## 设计哲学 · 为什么是 Prompt Stack 不是 Agent
Investor Harness 是**开放提示词栈**,不是 AI agent。它没有 runtime,依赖你的 AI 工具(Claude Code / Codex / OpenCode 等)作为 runtime 执行。
这是**刻意的设计选择**,不是缺失:
| 维度 | Agent 形式 | Prompt Stack(本项目) |
|---|---|---|
| 跨 AI 工具兼容 | ❌ 通常绑死一个 runtime | ✅ 任何支持 markdown 的工具 |
| 合规友好度 | ⚠️ "AI 替你做研究"引发监管疑虑 | ✅ 方法论是你的,AI 只是工具 |
| 可审计性 | ⚠️ Python 代码,分析师看不懂 | ✅ 纯 markdown,能看能改能审计 |
| 升级 / 修改门槛 | ⚠️ 需要懂代码 | ✅ 改文本就行 |
| 分析师价值保留 | ⚠️ 有被替代风险 | ✅ 强制分析师保持纪律 |
**一句话**:投研的核心价值是"分析师的纪律",不是"自动化"。Prompt Stack 让纪律被强制执行,而不是外包。
---
## 安装
### 路径 A · 最小安装(1 分钟)
把 `skills/sm-master/SKILL.md` 复制到任何 AI 工具的系统提示词里。1 个文件解决 80% 需求。
### 路径 B · 完整安装(5 分钟)
```bash
git clone https://github.com/joansongjr/investor-harness.git
cd investor-harness
clawhub install investor-harness # 或 codex.sh / opencode.sh / generic.sh
```
### 路径 C · 完整工作区(10 分钟,推荐机构和进阶用户)
```bash
clawhub install investor-harness
```
会生成一套分析师工作区模板:系统提示词 / memory.md / coverage.md / decision-log.md / biases.md / research-queue.md / **active-tasks.md** (v0.3 新增),填几个空就能开始用。
详见 [setup/README.md](setup/README.md)。
---
## 数据源
全部可选,按 `core/adapters.md` 的优先级自动降级:
1. **iFind MCP**(同花顺官方,A 股 / 基金 / 宏观 / 资讯)
2. **cn-web-search skill**(聚合 17 个中文搜索引擎)
3. **WebSearch / WebFetch**(所有 harness 内置)
4. **用户手动贴材料**(兜底)
未来接入 Wind / Bloomberg / FactSet / S&P CapIQ 等,只需在 `core/adapters.md` 增加优先级条目,**skill 文件不用改**。
---
## 适用 / 不适用
✅ 持牌卖方分析师 / 买方研究员 / 基金经理 / IC 成员 / 商学院金融方向学生
❌ 数字货币 / 一级市场 / 期权期货 / 散户量化 / 期望 AI 替你决策的人
---
## Changelog
### v0.6.0 — 交互式安装 + 更新向导
> 解决 v0.5 的最后一个门槛:**非技术用户装不了**。
> 手动跑 `git clone + clawhub install investor-harness + 复制粘贴 INSTALL-PROMPT` 步骤太多,容易卡。
> v0.6 提供**交互式向导**:一个命令全搞定。
**新增**:
- **`setup.sh`** — 交互式安装向导(交互式安装)
- 检测操作系统 / Shell / Git / 现有 harness
- 选择目标 harness(Claude Code / Codex / OpenClaw,可多选)
- 选择数据源(iFind / Alpha派 / 进门财经 / Wind / cn-web-search / WebSearch)
- 检测现有 .mcp.json 配置
- 安装 skills(默认 symlink 模式)
- 可选创建投研工作区(跑 bootstrap.sh)
- 验证安装
- **`update.sh`** — 交互式更新向导
- 检测本地 vs 远程版本
- 显示新 commit 列表
- 检测破坏性变更(major bump / skill 重命名 / core 文件变更)
- git pull(含 stash 保护)
- 检测 系统提示词 里启用提示词的版本,不一致时提示更新
- 备份机制完善
- **ClawHub** — clawhub install investor-harness
- clawhub install investor-harness
- 自动 git clone + 调用 setup.sh
- 适合首次安装场景
- 包含占位符(DATE / HARNESS_PATH / WORKSPACE_ROOT / DATA_SOURCES 等)
**四个数据源全部是 MCP**:
| 数据源 | 类型 | 默认优先级 |
|---|---|---|
| iFind MCP | MCP server | 1(A 股 / 公募最优)|
| Alpha派 MCP | MCP server | 2 |
| Wind MCP | MCP server | 3(全球覆盖)|
| 进门财经 MCP | MCP server | 4(路演/专家/研报)|
| cn-web-search | Skill | 5 |
| WebSearch | harness 内置 | 6(兜底)|
| 用户贴材料 | 手动 | 7(最后兜底)|
**安装路径对比**:
| 方式 | 命令 | 适合谁 |
|---|---|---|
| ClawHub | clawhub install investor-harness | All |
| 🟡 **clawhub install investor-harness` | 想看清楚每一步的人 |
| 🔴 **低级命令** | `clawhub install investor-harness`(原 v0.5)| 自动化脚本 |
**更新路径**:
```bash
cd ~/investor-harness
clawhub update investor-harness
```
自动处理:版本检查、破坏性变更警告、git pull、系统提示词 迁移。
### v0.5.1 — Dual Output Discipline 修正(云端用户友好)
> 修复 v0.4 over-optimization:原 Step 7 "对话只回 ~300 token 摘要"忽视了云端用户根本打不开本地文件。
**改动**:
- `core/postamble.md` Step 7 重写:从"Echo Discipline 只回摘要"改为"**Dual Output Discipline 双输出**"——对话里贴完整内容(云端用户能直接读)+ 同时写文件(归档 + 跨 skill 引用 + 长期 diff)
- 结尾追加 `📁 已归档:{path}` + 关键统计 + 下一步建议
- 例外:用户主动说"省 token 模式"才退回到 v0.4 纯摘要
- `_boot.md` Output discipline 段同步更新
- `setup/workspace/系统提示词.template` 同步更新
- `INSTALL-PROMPT.md` Step 7 描述同步更新
**Token 影响**:每任务对话成本 ~300 → ~5500 tokens。200k context 能跑的任务数从 ~50(理论但不可用)变为 ~25(真实可用)。
**为什么这个修正很重要**:
- 投研人很多在 Claude.ai web / Codex web / 远程 SSH 跑 Claude Code → 没有本地文件系统
- 即使是本地用户,"打开文件"也比"对话直读"麻烦
- 文件存档的核心价值是**跨 skill 引用 + 长期归档**,不是"对话不贴"
- 对话是 control plane + data plane 双重身份,文件是补充
### v0.5.0 — 技术面复盘 skill + 强制启用提示词
> 解决两个新发现的痛点:
> 1. 缺技术面 skill(基本面 13 个 skill 都覆盖了,技术面是空白)
> 2. markdown 规范没有强制力——非技术用户的 LLM 不会自动遵守
**新增**:
- **`sm-tape-review`** — 盘面 + 技术面复盘 skill(第 17 个)
- 7 段输出:行情摘要 / 资金面 / K 线形态 / 技术指标 / 关键位 / 一致性检验 / 明日观察
- 强制使用 iFind get_stock_performance 拉真实指标,禁止凭印象编造
- §6 必须引用同标的最新 sm-thesis / sm-company-deepdive 输出做基本面一致性检验
- 适用场景:日内复盘、收盘技术面、加减仓技术确认、stop loss 设定
- **`INSTALL-PROMPT.md`** — 启用提示词模板(关键文件)
- 解决"装好但 LLM 不遵守"的问题
- 用户复制粘贴到 `~/.claude/系统提示词` 之后,LLM 自动按 Investor Harness 流程工作
- 包含完整的 boot protocol / preamble / postamble / 自动路由规则
- 三种粘贴方式:全局 系统提示词 / 工作区 / 单次对话
- **`acceptance.md`** 新增 sm-tape-review 专属验收清单(10 条)
**更新**:
- 4 个 install 脚本(claude-code / codex / opencode / generic)安装完后**主动打印**INSTALL-PROMPT.md 路径和复制粘贴说明
- `core/_boot.md` 16 → 17 skills 速查
- README 添加技术面 skill 段落 + INSTALL-PROMPT.md 强调
#### 为什么要有 INSTALL-PROMPT.md
v0.4 之前的设计假设 LLM 会"看到 SKILL.md 就遵守",但现实是:
- 小白用户不知道说"用 sm-X",他们说"看一下 X"
- LLM 看到模糊请求会直接给百度百科段落,不会主动 invoke skill
- markdown 规则依赖 LLM 自觉遵守
INSTALL-PROMPT.md 是用户主动**给 LLM 灌输**"以后所有投研任务都按这套规则做"的指令。一次粘贴,永久生效。
### v0.4.0 — Context overflow 防御 + 三层加载优化
> 解决 v0.3 没解决的"上下文溢出 + 任务被打断后失忆"问题。
- **新增 `core/_boot.md`** — 启动文件,~1.2k tokens,每次新会话第一个读。包含 16 skill 一行说明、boot protocol、resume protocol、三层加载策略
- **新增 `core/task-pulse.md`** — `.task-pulse` 心跳信号文件规范(< 100 tokens 的 JSON),让 LLM 用极小代价知道工作区当前任务状态
- **新增 `core/checkpoint.md`** — `.checkpoint/{task-id}.md` 断点续跑机制,让任务被 compact / 重开会话后能从断点继续,不重复
- **preamble.md 新增 Step 0** — 任务断点检查(读 .task-pulse → 询问续跑或新建)
- **postamble.md 新增 Step 0** — 增量 checkpoint 写入(每完成一段就写,不是任务完才写)
- **postamble.md 新增 Step 7** — Context Echo Discipline:对话只回 ~300 token 的摘要,完整输出在文件里。**节省 ~90% 对话 token**
- **三层加载优化**:
- **Tier 0**(每次必读)_boot.md + .task-pulse + 系统提示词 ≈ 1.5k tokens
- **Tier 1**(skill 调用时)SKILL.md + preamble + postamble + adapters ≈ 6k tokens
- **Tier 2**(按需)evidence / compliance / output-archive / acceptance ≈ 5k tokens
- vs v0.3 每次任务 ~17k 静态成本,**节省 50-70%**
- **系统提示词.template** 升级为 v0.4 三层加载 + Context Overflow 保护
- **bootstrap.sh** 自动创建 `.task-pulse` 和 `.checkpoint/` 目录
#### v0.4 真实 token 测算
| 操作 | v0.3 token | v0.4 token | 节省 |
|---|---|---|---|
| 新会话启动 | ~10k | ~1.5k | 85% |
| 一次完整 skill 调用 | ~42k | ~15-20k | 50%+ |
| 200k context 能跑几个任务 | 4-5 个 | 8-10 个 | 100%+ |
| 任务被打断后续跑 | ❌ 丢失 | ✅ 完整恢复 | — |
### v0.3.0 — 兑现"治幻觉、健忘、杂乱"三大承诺
- **新增 `core/preamble.md`** — 强制开始前 5 步流程(治幻觉 + 治健忘)
- **新增 `core/postamble.md`** — 强制结束后 6 步流程(治幻觉 + 治不成体系)
- **新增 `core/output-archive.md`** — 输出归档命名规范,让所有 skill 输出可 diff、可 review、可引用
- **新增 `core/acceptance.md`** — 输出验收清单(通用 + 各 skill 专属),最后一道质量关卡
- **新增 `core/menu.md`** — 零配置入口菜单。用户首次使用 / 输入模糊时自动显示 16 个 skill 的编号菜单,直接按数字或描述选择任务。配套零配置工作区初始化(3 个问题搞定)
- **新增 `setup/workspace/active-tasks.md.template`** — 任务进度持久化机制,治"AI 忘记任务到哪了"
- **新增 3 个批量任务 skill**:
- `sm-batch-refresh` — 覆盖池批量刷新
- `sm-batch-earnings` — 财报季批量前瞻 / 复盘
- `sm-catalyst-sweep` — 每日催化剂扫描
- **重写所有 13 个旧 skill 的"开始前先取数"段** — 改为强制引用 preamble.md / postamble.md / output-archive.md / acceptance.md,每个 skill 加上独有的注意事项
- **更新 系统提示词.template** — 加入强制流程引用 + 主动报告进行中任务的规则
- **品牌定位升级** — 从"开放提示词栈" → "投研人的 AI 任务执行规范",三大痛点(幻觉/健忘/杂乱)显式列出
- **manifest.yaml 新增 `solves` 字段** — 机器可读的痛点声明
### v0.2.0
- 品牌正式命名为 **Investor Harness**
- 新建 `core/adapters.md` — 数据源优先级决策树
- 新建 `core/markets.md` — 市场识别与分市场差异
- 新增 `sm-master` skill — 7 模式长形态总控
- 新增 `setup/` — 投研工作区脚手架(系统提示词 / memory / 覆盖池 / 决策日志 / 偏差清单等模板)
- 新增 `setup/agents/` — 5 个多 agent 团队角色定义
- 所有 skill 的 frontmatter 补齐 `inputs / outputs / data_sources / markets`
- 增加顶层 `manifest.yaml`、`install/` 多 harness 安装脚本
### v0.1.0
- 12 个专业子 skill + autopilot
- Codex 安装脚本
---
## License
MIT © 2026 Joan Song
> ⚠️ **免责声明**:本工具不构成投资建议。所有 AI 生成内容仅供研究参考,使用者应自行核验关键数据、遵守所在机构合规要求。涉及投资决策必须进行人工复核。
---
**⭐ Star 让更多投研人看到** · [🐛 Issue](https://github.com/joansongjr/investor-harness/issues) · [🤝 PR](https://github.com/joansongjr/investor-harness/pulls)
FILE:_meta.json
{
"ownerId": "kn7bwe5zrs5ghyr5qzz2byttf980shq8",
"slug": "research-harness",
"version": "0.7.0",
"publishedAt": 1775662967075
}
FILE:core/_boot.md
# Investor Harness · Boot
> 🚀 每次新会话第一个读的文件。**< 1k tokens**。其他 core/* 按需懒加载。
## What this is
Investor Harness v0.4 — 投研人的 AI 任务执行规范。
治三大痛点:**幻觉 / 健忘 / 不成体系**。
## 17 skills (one-line each)
`sm-master`(7 模式总控) · `sm-autopilot`(自动路由) · `sm-thesis`(命题构建) · `sm-industry-map`(行业框架) · `sm-company-deepdive`(公司深度) · `sm-earnings-preview`(财报前瞻) · `sm-model-check`(模型审阅) · `sm-consensus-watch`(预期差) · `sm-catalyst-monitor`(事件跟踪) · `sm-roadshow-questions`(路演问题) · `sm-red-team`(反方审视) · `sm-pm-brief`(PM 一页纸) · `sm-briefing`(晨会晚报) · `sm-tape-review`(盘面 + 技术面复盘) · `sm-batch-refresh`(批量刷新) · `sm-batch-earnings`(财报季批量) · `sm-catalyst-sweep`(催化剂扫描)
## Boot protocol (新会话/compact 后)
1. 读 `.task-pulse`(如存在)
2. 读 `系统提示词`
3. 如 .task-pulse 有 in_progress 任务 → 主动告知用户 + 等选择,不要默认从头开始
4. 用户选了某 skill 才加载 SKILL.md
5. SKILL 内按需加载 core/preamble.md 等
## 三层加载(节省 token)
- **Tier 0** (always): _boot.md + .task-pulse + 系统提示词 ≈ 1.5k
- **Tier 1** (on skill invoke): SKILL.md + preamble + postamble + adapters ≈ 6k
- **Tier 2** (on demand): evidence / compliance / output-archive / acceptance ≈ 5k
⛔ 不要在不需要时加载 Tier 2。
## Resume protocol (断点续跑)
```
1. 读 .task-pulse → 找 in_progress 任务 id
2. 读 .checkpoint/{task-id}.md → 知道做到哪段
3. 加载对应 SKILL.md
4. 从断点继续,不重复
5. 完成后写最终输出到归档路径,更新 .task-pulse 标 done
```
## Output discipline (v0.5.1 双输出)
- 输出贴到对话即可。
- 对话里贴完整内容(人类读),文件里存完整内容(归档 + 跨 skill 引用)
- 结尾追加 `📁 已归档:{path}` 提示 + 关键统计 + 下一步建议
- **不要**只回摘要——很多人在云端跑,打不开本地文件
- 例外:用户明确说"省 token 模式"才退回到摘要
## Where to find more
| 需要时读 | 文件 |
|---|---|
| 完整 5 步开始前 | core/preamble.md |
| 完整 6 步结束后 | core/postamble.md |
| 数据源决策树 | core/adapters.md |
| 证据分级 F1-H1 | core/evidence.md |
| 合规边界 | core/compliance.md |
| 归档命名规范 | core/output-archive.md |
| 验收清单 | core/acceptance.md |
| 入口菜单 | core/menu.md |
| 市场识别 | core/markets.md |
| 任务持久化格式 | core/task-pulse.md |
| 断点续跑细节 | core/checkpoint.md |
FILE:core/acceptance.md
# Acceptance · 输出验收清单
> 每个 skill 输出完成后,必须按本清单逐条自检。任何一条没过 → 不算完成 → 必须补完再交付。
>
> 这是治"幻觉"和"不成体系"的最后一道关卡。
---
## 通用验收清单(所有 skill 都要过)
### A. Preamble 完成度(治健忘)
- [ ] **A1** 已识别市场(CN-A / CN-FUND / HK / US / GLOBAL)
- [ ] **A2** 已检查同标的的历史输出(即使结果是"无")
- [ ] **A3** 已检查 active-tasks.md(即使结果是"新任务")
- [ ] **A4** 已输出 `[Preflight]` 段,包含取数计划
- [ ] **A5** 已实际调用工具取数(不只是声称要取)
### B. 证据纪律(治幻觉)
- [ ] **B1** 每条事实陈述都带 F1/F2/M1/C1/H1 标签
- [ ] **B2** 关键结论由 F1 / F2 支撑(不是 M1 或 H1)
- [ ] **B3** 所有 C1 都附了推演链路说明
- [ ] **B4** 没有把 H1 当作结论的唯一依据
- [ ] **B5** 没有混淆"事实"和"推测"
### C. 输出结构(治不成体系)
- [ ] **C1** 输出按本 skill 规定的结构(不是自由发挥)
- [ ] **C2** "仍需补的资料"段非空且分了"必需 / 建议 / 不确定"三档
- [ ] **C3** 末尾有"合规声明"段
- [ ] **C4** 末尾有数据来源列表
- [ ] **C5** 末尾有时间戳和使用的 skill 名
### D. 归档与持久化(治不成体系 + 治健忘)
- [ ] **D1** 输出已写入 [output-archive.md](output-archive.md) 规定的路径
- [ ] **D2** 文件名符合命名规范(YYYY-MM-DD-skill-short.md)
- [ ] **D3** 如果是覆盖标的,已更新该 ticker 的 INDEX.md
- [ ] **D4** active-tasks.md 已更新(status / progress / output 字段)
### E. 合规(治幻觉的硬约束)
- [ ] **E1** 没有"确定会涨"、"已经确认"、"内部消息证实"等违禁表述
- [ ] **E2** 没有承诺收益
- [ ] **E3** 没有给具体目标价(除非已标注"需人工复核")
- [ ] **E4** 没有给评级(除非已标注"需人工复核")
- [ ] **E5** 没有伪造渠道反馈、专家纪要、订单数据
---
## 各 skill 专属验收清单
### sm-company-deepdive 专属
- [ ] 9 段结构齐全:公司定位 / 业务拆分 / 收入驱动 / 利润驱动 / 核心竞争力 / 市场关注 / 可比公司 / 跟踪指标 / 仍需补的资料
- [ ] 至少 3 家可比公司的横向对比
- [ ] 至少 3 个"未来三个月跟踪指标"
- [ ] 业务拆分有具体收入占比(即使是 H1)
### sm-thesis 专属
- [ ] 命题是**可证伪**的(不是"长期看好"这种)
- [ ] 列出至少 3 个"必要条件"
- [ ] 列出"最早暴露错误的地方"
- [ ] 列出"未来一个月最该跟踪的三项数据"
### sm-earnings-preview 专属
- [ ] 引用了一致预期数字(即使是 H1 待核验)
- [ ] 列出"市场最关心的三个问题"
- [ ] beat/miss 的具体阈值(数字,不是"超预期"这种词)
- [ ] 财报后第一时间检查清单(T+0 / T+1 / T+3 三档)
- [ ] "若结果不同于预期,对原投资逻辑的影响"段
### sm-red-team 专属
- [ ] 反方观点必须可观测、可触发(不是套话)
- [ ] 至少 3 个具体的硬触发条件
- [ ] 检查了 biases.md 并显式报告命中情况
- [ ] 给了"如果命题被证伪,资金应该去哪"
- [ ] 不能以"长期向好"等讨好用户的话结尾
### sm-consensus-watch 专属
- [ ] 明确分了"市场已 price in 的内容" vs "未充分反映的变量"
- [ ] 预期差成立的"具体条件"
- [ ] 对估值锚的影响
### sm-pm-brief 专属
- [ ] 一页纸长度(< 800 字)
- [ ] 没有大段背景复述
- [ ] 入场条件 / 卖出条件都是硬触发
- [ ] 任何评级 / 目标价都标了"需人工复核"
### sm-briefing 专属
- [ ] "今日最重要的三件事"恰好三件
- [ ] 每件事都说清"对覆盖池的影响"
- [ ] 一句话给基金经理的精简表述
### sm-industry-map 专属
- [ ] 产业链结构有上中下游
- [ ] 至少 5 家关键公司的分工标注
- [ ] 当前市场争议点(不是"前景广阔")
- [ ] 至少 3 个行业跟踪指标
### sm-model-check 专属
- [ ] 至少 3 条"敏感性最高的变量"
- [ ] 至少 1 条"最容易误导结论的地方"
- [ ] 假设链明确列出
### sm-roadshow-questions 专属
- [ ] 每个问题都附"背后要验证什么"
- [ ] "若回答偏强 / 中性 / 偏弱各自意味着什么"
- [ ] 没有"请介绍一下业务进展"这种泛问题
### sm-catalyst-monitor 专属
- [ ] 影响路径明确(事件 → 收入 / 利润 / 估值 / 情绪)
- [ ] 跟踪节奏明确(一周 / 一个月 / 一季度)
### sm-master 专属
- [ ] 已显式声明本次走的是 7 种模式中的哪一种
- [ ] 按对应模式的结构输出
### sm-autopilot 专属
- [ ] 已显式声明本次自动路由到了哪个 / 哪几个 skill
- [ ] 整合输出而不是堆砌每个 skill 的完整输出
### sm-batch-refresh 专属
- [ ] 列出了本次刷新的标的清单(数量 + 来源)
- [ ] 每个标的有"更新的字段"摘要
- [ ] 失败的标的明确列出原因
### sm-batch-earnings 专属
- [ ] 按财报日期排序
- [ ] 每家公司的 preview 都通过通用验收清单 + sm-earnings-preview 专属清单
### sm-catalyst-sweep 专属
- [ ] 时间窗明确(默认 24 小时)
- [ ] 命中事件按重要性分级
- [ ] 每条命中关联到具体的 ticker
### sm-tape-review 专属
- [ ] 7 段结构齐全:行情摘要 / 资金 / K 线形态 / 技术指标 / 关键位 / 一致性检验 / 明日观察
- [ ] §1 行情数据带具体数字(涨跌幅 / 成交量 / 量比 / 换手率,全部 F2)
- [ ] §3 K 线形态有明确判断(不只是描述)
- [ ] §4 技术指标**带实际数值**(禁止凭印象写"金叉")
- [ ] §5 至少 2 个支撑位 + 2 个压力位
- [ ] §6 一致性检验**必须**引用最新 sm-thesis 或 sm-company-deepdive 结论
- [ ] §7 明日观察点带"如果 X → 意味着 Y"的条件式判断
- [ ] 没有"必涨"、"突破在即"等武断表述
- [ ] 没有日内 / 小时级 / 分钟级建议
---
## 自检的执行方式
LLM 在输出末尾必须显式跑一遍验收,输出形如:
```markdown
---
## 📋 Acceptance Self-check
**通用清单**:
- A. Preamble: ✅ A1 ✅ A2 ✅ A3 ✅ A4 ✅ A5
- B. 证据: ✅ B1 ✅ B2 ✅ B3 ✅ B4 ✅ B5
- C. 结构: ✅ C1 ✅ C2 ✅ C3 ✅ C4 ✅ C5
- D. 归档: ✅ D1 ✅ D2 ✅ D3 ✅ D4
- E. 合规: ✅ E1 ✅ E2 ✅ E3 ✅ E4 ✅ E5
**sm-{skill} 专属**:
- ✅ {item 1}
- ✅ {item 2}
- ⚠️ {item 3 — 部分通过,原因}
**结论**:✅ 通过 / ⚠️ 部分通过(已标注) / ❌ 不通过(需重新输出)
```
如果有任何一项 ❌,**必须重新执行该步骤后再交付**,不允许跳过。
---
## 这套验收的设计原则
1. **可机读** — 每条都是 binary check,未来可以做 LLM judge 自动评测
2. **覆盖三大痛点** — A/D 治健忘、B/E 治幻觉、C/D 治不成体系
3. **强制性** — 没过 = 没做完,不允许灰色地带
4. **skill 专属补充** — 每个 skill 有自己的关键结构验证
---
## 给团队 lead / 机构客户的承诺
任何一份通过本清单的输出,都满足:
- 可追溯(每条事实有来源等级)
- 可审计(输出已归档到固定路径)
- 可 review(结构标准化,团队成员可对比)
- 可合规(违禁表述已自动排除)
- 可承认不知道(仍需补的资料段非空)
如果一份输出没通过本清单 → **不应该交付给 PM 或客户**。
FILE:core/adapters.md
# Data Adapters
所有 sm-* skills 在开始输出前,先按本文件的"数据获取协议"拿数据,再进入各自的分析流程。
这是**建议模式**的决策树:给出优先级和判断条件,但不强制写死调用参数,允许 LLM 根据当前任务灵活选择。
---
## 总原则
1. **先确认任务的市场归属**(A 股 / 港股 / 美股 / 跨市场),参见 [markets.md](markets.md)
2. **按优先级探测可用数据源**:MCP 工具 → skill 工具 → 通用搜索 → 兜底
3. **拿到什么数据就标什么证据等级**(见 [evidence.md](evidence.md))
4. **数据不足时不要编造**,先走兜底流程让用户补
---
## 数据源优先级(通用决策树)
```
Step 1 — 判断标的市场
│
├── A 股 / 公募 → 跳 §A
├── 港股 → 跳 §H
├── 美股 → 跳 §U
└── 跨市场 / 行业主题 → §A + §H + §U 并行
Step 2 — 按市场分支获取数据
Step 3 — 若全部失败 → 走"兜底协议"
```
---
## §A — A 股 / 公募基金
**优先级 1:iFind MCP(同花顺官方数据)**
检测方式:工具命名空间存在 `hexin-ifind-ds-*`
- 公司层:`get_stock_summary`, `get_stock_performance`, `get_stock_financials`, `get_stock_info`, `get_stock_shareholders`, `get_risk_indicators`, `get_stock_events`, `get_esg_data`
- 行业 / 选股:`search_stocks`
- 基金:`search_funds`, `get_fund_profile`, `get_fund_portfolio`, `get_fund_market_performance`, `get_fund_ownership`
- 宏观:`get_edb_data`, `search_edb`
- 资讯 / 公告:`search_notice`, `search_news`, `search_trending_news`
调用约定:
- 所有 `query` 参数使用**中文自然语言**,包含证券名称/代码 + 指标名 + 时间范围
- 财务指标用报告期:`2025-12-31`、`2025-06-30`
- 选股条件不要过于宽泛,资讯 size 上限 20
**优先级 2:cn-web-search skill**
检测方式:用户环境中存在 `cn-web-search` skill 或等效工具
典型查询:
- `{公司名} 年报 2024`
- `{公司名} 产业链地位`
- `{公司名} 一致预期`
- `{行业} 景气度 2025`
**优先级 3:WebSearch(通用兜底)**
所有主流 harness 都支持。典型查询:
- `{公司名} 财报 site:cninfo.com.cn`
- `{公司名} 公告 site:sse.com.cn OR site:szse.cn`
**优先级 4:让用户贴材料**(走"兜底协议")
---
## §H — 港股
**优先级 1:cn-web-search skill**(如果可用)
- `{公司名} 业绩 HKEX`
- `{公司名} 通告`
**优先级 2:WebFetch 直取 HKEX 官网**
- `https://www.hkexnews.hk/` 搜索公告
- `https://www.hkex.com.hk/` 公司页面
**优先级 3:WebSearch**
- `{stock name} annual report hkex`
- `{股票代码} 港股 公告`
**优先级 4:兜底协议**
---
## §U — 美股
**优先级 1:WebSearch + SEC EDGAR**
- `{ticker} 10-K site:sec.gov`
- `{ticker} 10-Q site:sec.gov`
- `{company name} earnings transcript`
**优先级 2:WebFetch SEC EDGAR 直取**
- `https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK={ticker}`
**优先级 3:其他公开财经源**(WSJ、Reuters、Bloomberg 摘要、公司 IR 页)
**优先级 4:兜底协议**
---
## 跨市场 / 行业主题
例如 "全球动力电池供给" 这类题目:
1. 先用 `sm-industry-map` skill 的框架搭产业链
2. 按"核心玩家清单"拆解到各自市场(§A/§H/§U)
3. 并行拉数据,最后在同一个证据表里汇总
---
## 兜底协议(所有市场通用)
当上述优先级全部不可用时:
1. **停下来**,不要开始分析
2. 按下面模板回复用户:
```
我当前无法直接获取 {公司/行业/主题} 的数据。要继续,需要你提供:
必需(至少选一项):
- 最新年报 / 季报(PDF 或关键财务指标文本)
- 近一个季度的公司公告或新闻
- 你对标的的现有观点、材料、或研究笔记
可选(提高分析质量):
- 可比公司清单
- 你关心的关键变量
- 时间窗口(近期事件 vs. 长期逻辑)
贴完后我会按 sm-{current-skill} 的标准流程输出。
```
3. 拿到材料后才开始正式流程,并在输出的"仍需补的资料"一栏列出仍缺的项。
---
## 对 LLM 的行为要求
- **不要**猜数据。缺数据就走兜底或降级到下一优先级
- **不要**混合真假数据。比如用一个工具拿到的数据和自己推演的数字放在一起而不标注
- **要**在输出开头一行注明本次分析的数据来源(例:`数据来源:iFind MCP + 用户提供资料`)
- **要**为每条关键事实打证据等级标签(F1/F2/M1/C1/H1)
- **要**在"仍需补的资料"一栏列出未能获取的关键项
---
## 新增数据源时怎么办
如果未来接入新的 MCP 或工具(例如 Wind MCP、Bloomberg API),只需要:
1. 在本文件对应 §A/§H/§U 段落里插入新的优先级条目
2. 不需要修改任何 skill 文件
3. 发布 patch 版本
这就是 adapter 层抽离的核心价值——**数据源变化不影响方法论**。
FILE:core/checkpoint.md
# Checkpoint · 任务断点续跑机制
> 让 skill 能在 context overflow / compaction / 重开会话之后**从断点继续**而不是从头开始。
> 这是 v0.4 解决"健忘"痛点的核心机制。
---
## 文件位置
```
{workspace_root}/.checkpoint/{task-id}.md
```
每个 in_progress 任务一个文件。
---
## 何时写 checkpoint
每个 sm-* skill 必须遵循以下规则:
### Rule 1:每完成一个 H2 段就写 checkpoint
不要等任务全部完成才写文件。每完成一段就更新 checkpoint。
例:sm-company-deepdive 9 段,每完成 §1、§2、§3... 都更新 checkpoint。
### Rule 2:每次取数后写 checkpoint
如果一次 iFind 调用返回了关键数据,立即写入 checkpoint,避免数据丢失。
### Rule 3:context budget 警告时强制写 checkpoint
LLM 估算到剩余 context < 30k tokens 时,必须立即:
1. 写完当前段的 checkpoint
2. 告知用户"已写入 checkpoint,建议开新会话续跑"
3. 不再继续新段
---
## Checkpoint 文件格式
```markdown
# Checkpoint · {task-id}
**task_id**: t-001
**skill**: sm-company-deepdive
**target**: 688256_寒武纪
**started**: 2026-04-07T14:00:00Z
**last_updated**: 2026-04-07T14:30:00Z
**step**: 6/9
**status**: in_progress
## Completed sections
### §1 公司定位 ✅
{完整内容,按最终输出格式}
### §2 业务拆分 ✅
{完整内容}
### §3 收入驱动 ✅
{完整内容}
### §4 利润驱动 ✅
{完整内容}
### §5 核心竞争力 / 风险点 ✅
{完整内容}
### §6 市场关注焦点 ✅
{完整内容}
## In progress
### §7 与可比公司的关键差异 (in_progress)
{已经写到的部分}
## Pending
- §7 (continue)
- §8 未来三个月跟踪指标
- §9 仍需补的资料
## Data fetched so far
| Source | Tool | Result |
|---|---|---|
| iFind | get_stock_summary | ✅ pulled |
| iFind | get_stock_financials | ✅ pulled |
| iFind | get_stock_shareholders | ✅ pulled |
| WebSearch | "寒武纪 海光 对比" | ⚠️ partial |
| - | 卖方一致预期 | ❌ pending |
## Resume instructions
下次会话用以下指令恢复:
```
继续 t-001
```
LLM 会自动:
1. 读本文件
2. 跳过已完成的 §1-§6
3. 继续 §7(从已写的部分接着)
4. 完成 §8、§9
5. 写最终输出到归档路径
6. 删除本 checkpoint
7. 更新 .task-pulse 标 done
```
---
## 如何续跑
### 用户视角
```
用户:继续 t-001
LLM: 检查 .task-pulse → 找到 t-001
LLM: 读 .checkpoint/t-001.md → 看到做到 §6
LLM: 读 sm-company-deepdive/SKILL.md
LLM: 加载 §1-§6 的内容(已完成的)
LLM: 从 §7 继续工作
LLM: 完成 §7-§9
LLM: 写最终输出到 coverage/688256_寒武纪/deepdive/2026-04-07-deepdive.md
LLM: 删除 .checkpoint/t-001.md
LLM: 更新 .task-pulse 移除 t-001
LLM: 输出摘要给用户
```
### 简化指令
用户可以用以下任一方式触发续跑:
- "继续 t-001"
- "continue t-001"
- "resume task 001"
- "接着上次的"(LLM 自动从 .task-pulse 找最近一个 in_progress 任务)
---
## Checkpoint 文件大小约束
- **典型大小**:3-10 KB(包含 6-8 段已完成内容)
- **最大**:50 KB(如果超过说明任务粒度太粗,应该拆分)
- **超过 50 KB 的应对**:
- 把已完成的段落归档到归档路径
- checkpoint 只保留"指针"和"剩余部分"
## 清理协议
| 状态 | 清理时机 |
|---|---|
| 任务完成 | 立即删除 checkpoint |
| 任务取消 | 立即删除 checkpoint |
| 任务超过 7 天没动 | 标记为 stale,提醒用户清理 |
| 任务超过 30 天没动 | 自动归档到 `.checkpoint/archive/`,从主目录移除 |
---
## 与 .task-pulse 的协作
```
用户开新会话
↓
LLM 读 .task-pulse(< 100 tokens)
↓
看到 t-001 in_progress, ckpt: .checkpoint/t-001.md
↓
用户:"继续 t-001"
↓
LLM 读 .checkpoint/t-001.md(~5 KB)
↓
LLM 加载 sm-company-deepdive
↓
从 §7 继续
```
总成本:~3k tokens 恢复完整任务状态,vs 从头跑 ~25k+ tokens。
**节省:90%+**。
---
## 边界场景
### Q: 用户在中途改了想法,想换一个 skill 怎么办?
- 提示用户:"t-001 还没做完,确定要切换吗?"
- 用户确认后,移动 checkpoint 到 `.checkpoint/abandoned/`,保留以便事后回看
### Q: 多个会话同时编辑同一个 task 怎么办?
- 用 ts 字段做"乐观锁"
- 写入前检查 ts,如果发现 ts 比自己读的新 → 拒绝写入,告知用户冲突
### Q: checkpoint 文件本身丢了怎么办?
- LLM 检测到 .task-pulse 有 task 但 ckpt 文件不存在 → 警告用户 → 提供"从头开始"或"标记 abandoned"选项
### Q: 任务没有明确 9 段结构(比如 sm-briefing)怎么 checkpoint?
- 用 logical sections("今日事件 1 - 已完成"、"事件 2 - 进行中")
- step 字段写 "2/3" 等
---
## 给 skill 设计者的硬约束
每个 sm-* skill 在设计时必须支持 checkpoint。必要条件:
1. **可分段**:能拆成 N 个顺序步骤,每步可独立写 checkpoint
2. **幂等**:从 checkpoint 续跑产出的最终输出和一次跑完的输出相同
3. **可追溯**:checkpoint 包含足够信息让 LLM 重建上下文
不满足这三条的 skill 设计应该重做。
FILE:core/compliance.md
# Compliance
这组 skills 仅用于研究辅助与效率提升,不替代持牌分析师判断、内部审批和合规审核。
## 必守边界
- 不承诺收益
- 不生成买卖指令
- 不伪造渠道反馈、专家纪要、订单数据
- 不把非公开信息包装为公开结论
- 涉及评级、目标价、盈利预测调整时,提醒人工复核
## 推荐表达
- “基于当前公开信息,市场可能低估了……”
- “若以下条件成立,则盈利弹性可能来自……”
- “该判断仍需通过后续财报 / 数据验证”
## 禁止表达
- “确定会涨”
- “已经确认订单翻倍”
- “内部消息证实”
- “这次一定超预期”
FILE:core/evidence.md
# Evidence
所有投研 skills 统一使用以下证据标签,避免把猜测写成事实。
- `F1`:公开事实,可直接验证
- `F2`:财报、公告、官方披露、权威数据库
- `M1`:市场观点或一致预期
- `C1`:基于事实的合理推演
- `H1`:待核验线索或假设
## 使用原则
- 关键结论优先由 `F1`、`F2` 支撑
- 可以使用 `M1` 描述市场共识,但不能把共识当事实
- `C1` 必须说明推演链路
- `H1` 不能成为最终结论的唯一依据
FILE:core/markets.md
# Markets
Investor Harness 覆盖的市场范围与识别规则。
## 支持的市场
| 标签 | 市场 | 识别特征 | 主要数据源 |
|---|---|---|---|
| `CN-A` | A 股(沪深) | 6 位数字代码(6xxxxx/0xxxxx/3xxxxx)、中文公司名、"股份有限公司" | iFind MCP → cn-web-search → WebSearch |
| `CN-FUND` | 公募基金 | 6 位代码以 0/1/5 开头、"基金"字样 | iFind Fund MCP → cn-web-search |
| `HK` | 港股 | 4-5 位数字代码、HKEX、港交所、中文/英文混合 | cn-web-search → WebFetch HKEX |
| `US` | 美股 | 字母 ticker(AAPL, NVDA)、NYSE/NASDAQ、SEC filings | WebSearch SEC → WebFetch EDGAR |
| `GLOBAL` | 跨市场主题 | 行业 / 宏观 / 主题类问题 | 并行多市场 |
## 市场识别规则
LLM 收到任务后,按以下顺序判断:
1. 用户明确指定市场 → 直接采用
2. 用户给出标的代码 → 按代码格式匹配(见上表)
3. 用户给出公司中文全名 → 默认 `CN-A`,若包含"港"/"HK"/"H 股"切 `HK`
4. 用户给出英文公司名或 ticker → 默认 `US`
5. 用户只说行业 / 主题 → `GLOBAL`,按 sm-industry-map 展开
## 合规分市场差异
- **CN-A / CN-FUND**:严格遵守 `compliance.md`,涉及评级、目标价、盈利预测调整必须提醒人工复核
- **HK**:注意公告延迟和信息披露差异
- **US**:SEC 文件为主要 primary source,分析师报告为 M1 级
- **GLOBAL**:跨市场对比必须注明不同会计准则、不同季度披露口径
## 不支持
以下市场暂不在 harness 覆盖范围内,遇到时明确告知用户:
- 数字货币 / 加密资产
- 未上市 / 一级市场 / PE/VC 标的
- 大宗商品期货(可通过 iFind EDB 查指标但不做交易分析)
- 衍生品(期权、CDS 等)
FILE:core/menu.md
# Menu · 零配置入口菜单
> 这是用户首次使用 Research Harness 时看到的"前台菜单"。
> 当 LLM 检测到用户输入符合下列任一触发条件,**必须直接显示这个菜单**,不要先解释 harness 是什么。
---
## 触发条件
LLM 看到以下任一情况,立即显示菜单:
- 用户说 "investor harness" / "harness" / "你能做什么" / "帮帮我"
- 用户说 "菜单" / "menu" / "选项" / "怎么用"
- 用户在新会话开始时只发了一个问候("你好" / "在吗" / "ready")
- 用户输入完全模糊(不到 5 个字且没有任何标的、行业、动作关键词)
- 用户明确说 "显示菜单" / "show menu"
- 用户问 "能帮我做什么" / "你会什么"
---
## 菜单内容(直接复制输出)
```
🎯 Research Harness 已就绪!请选择你想做什么:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📊 研究类
1️⃣ 公司深度研究 — 起 coverage 或更新跟踪
2️⃣ 行业图谱 — 产业链地图、供需格局、关键公司
3️⃣ 投资命题构建 — 定义核心矛盾、拆解研究问题
📈 财报类
4️⃣ 财报前瞻 — 关注点、beat/miss 路径、指引听点
5️⃣ 财务模型校验 — 假设审阅、敏感性分析、断裂点
🔍 跟踪类
6️⃣ 一致预期监控 — 预期差挖掘、估值锚变化
7️⃣ 催化剂跟踪 — 事件/政策/订单/价格驱动
8️⃣ 路演问题设计 — 调研提纲、业绩会高价值问题
⚔️ 风控类
9️⃣ 反方论证 (Red Team) — 挑战多头逻辑、找证伪点
📋 输出类
🔟 基金经理摘要 (PM Brief) — 一页纸决策摘要
1️⃣1️⃣ 投研简报 — 晨会纪要、收盘复盘、调研纪要
⚡ 批量类(v0.3 新增)
1️⃣2️⃣ 覆盖池批量刷新 — 行情/财务/股东/催化一次更
1️⃣3️⃣ 财报季批量前瞻 — 一周内多家财报排队前瞻
1️⃣4️⃣ 每日催化剂扫描 — 晨会前 30 分钟扫一遍覆盖池
🤖 自动模式
1️⃣5️⃣ Autopilot — 给我一个公司名/行业/事件,自动跑全流程
1️⃣6️⃣ Master 模式 — 7 种工作模式自动识别,一个 skill 搞定
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
输入编号或直接描述你的需求,例如:
• "1" 或 "帮我深度看一下宁德时代"
• "4" 或 "做中芯国际财报前瞻"
• "9" 或 "我看多 AI 算力,帮我反方论证一下"
• "帮我看一下光模块行业" → 自动进入行业图谱
───
💡 提示:你还可以设置个人投研工作区,让 Harness 更好用:
• coverage.md — 你的覆盖池(跟踪哪些股票)
• biases.md — 你的投研偏差记录(Red Team 会自动检查)
• decision-log.md — 投资决策日志(半年后回看用)
• active-tasks.md — 任务进度持久化(跨会话接续)
要现在初始化吗?输入 "初始化工作区" 即可,10 秒搞定。
```
---
## 编号到 skill 的映射
| 编号 | Skill | 说明 |
|---|---|---|
| 1 | sm-company-deepdive | 公司深度研究 |
| 2 | sm-industry-map | 行业图谱 |
| 3 | sm-thesis | 投资命题构建 |
| 4 | sm-earnings-preview | 财报前瞻 |
| 5 | sm-model-check | 财务模型校验 |
| 6 | sm-consensus-watch | 一致预期监控 |
| 7 | sm-catalyst-monitor | 催化剂跟踪 |
| 8 | sm-roadshow-questions | 路演问题设计 |
| 9 | sm-red-team | 反方论证 |
| 10 | sm-pm-brief | PM 一页纸 |
| 11 | sm-briefing | 投研简报 |
| 12 | sm-batch-refresh | 覆盖池批量刷新 |
| 13 | sm-batch-earnings | 财报季批量前瞻 |
| 14 | sm-catalyst-sweep | 每日催化剂扫描 |
| 15 | sm-autopilot | 自动路由 |
| 16 | sm-master | 全能 7 模式 |
---
## 用户输入解析规则
### Case 1:输入纯数字("1" / "4" / "11")
直接路由到对应 skill:
- 询问标的:"好的,要分析哪家公司?" 然后等用户回答
- 拿到标的后,**立即按对应 skill 的强制流程开跑**(preamble.md → skill 主体 → postamble.md)
### Case 2:输入自然语言描述
LLM 自动识别用户意图,匹配最合适的 skill:
- 出现公司名 + "深度 / 起 coverage / 看看" → sm-company-deepdive
- 出现行业名 + "看看 / 怎么看" → sm-industry-map
- 出现 "财报 / 业绩 / 前瞻" → sm-earnings-preview
- 出现 "反方 / 唱反调 / 空头 / 找问题" → sm-red-team
- 出现 "晨会 / 简报 / 整理" → sm-briefing
- 出现 "PM / 一页纸 / 给老板" → sm-pm-brief
- 出现 "调研 / 路演 / 业绩会问题" → sm-roadshow-questions
- 出现 "模型 / 估值 / DCF" → sm-model-check
- 出现 "一致预期 / 预期差" → sm-consensus-watch
- 出现 "催化 / 事件 / 政策" → sm-catalyst-monitor
- 出现 "刷新覆盖池 / 周度更新" → sm-batch-refresh
- 出现 "财报季 / 一周财报" → sm-batch-earnings
- 出现 "扫一遍 / 今日催化" → sm-catalyst-sweep
- 完全模糊 / 没线索 → sm-autopilot
### Case 3:输入 "初始化工作区"
走零配置初始化流程(见下节)。
### Case 4:用户输入完全跟投研无关
礼貌告知 Research Harness 的范围,再次显示菜单。
---
## 零配置初始化流程
当用户输入"初始化工作区"或类似指令时,LLM 必须按以下流程操作:
### Step 1:检查 bootstrap.sh 是否可执行
如果用户安装了完整 harness,运行:
```bash
clawhub install research-harness
```
如果模板文件不存在,手动创建(见下)。
### Step 2:交互填空(最少必填)
用户必须填的最少信息:
1. **你的角色** — 卖方分析师 / 买方研究员 / PM / 个人投资者 / 学习中
2. **覆盖范围** — 哪个市场 + 哪些行业(一句话)
3. **首批覆盖标的** — 至少 1 个(用来初始化 coverage.md)
```
让我帮你初始化工作区。回答 3 个问题就好:
1. 你是谁?(卖方分析师 / 买方研究员 / PM / 个人投资者 / 学习中)
2. 你覆盖什么?(一句话,例:A 股科技板块 / 美股半导体)
3. 你正在跟踪哪个标的?(至少给 1 个,可以是公司名或代码)
```
### Step 3:生成最小可用工作区
根据用户回答,**立即**生成:
- `系统提示词` — 填好用户角色和覆盖范围
- `memory.md` — 填好身份和触发约定
- `coverage.md` — 填好首批标的
- `active-tasks.md` — 空模板
`biases.md` / `decision-log.md` / `watchlist.md` / `research-queue.md` 暂时不创建,等用户实际用到时再问。
### Step 4:返回菜单 + 引导第一个任务
```
✅ 工作区初始化完成!
- 角色:{你填的}
- 覆盖:{你填的}
- 已添加首批标的到 coverage.md:{ticker}
要不要我现在帮你跑一次第一个任务?建议从这个开始:
🎯 用 sm-company-deepdive 起 coverage:{你填的标的}
要继续吗?(输入"继续"或选择菜单的其他选项)
```
---
## 不显示菜单的情况
LLM **不应该**显示菜单的情况:
- 用户已明确指定了 skill 和标的("用 sm-thesis 看一下宁德时代")
- 用户在 active-tasks.md 里有进行中任务,且新输入显然是接续原任务
- 用户在跟某个 skill 的中间步骤交互
- 用户问了一个具体问题,应该被路由而不是被菜单打断
---
## 在 系统提示词 中如何引用
任何工作区的 系统提示词 应在"默认行为"段加上一句:
> **Menu trigger**: 当用户输入符合 [`~/.claude/skills/research-harness/core/menu.md`](~/.claude/skills/research-harness/core/menu.md) 的触发条件时,必须显示该文件中的菜单内容。
这样无论是单 skill 模式(只装了 sm-master)还是完整套件模式,都能用到菜单。
FILE:core/output-archive.md
# Output Archive · 归档命名规范
> 所有 sm-* skill 的输出都要按本规范归档,不许散落在临时目录。
> 这是治"不成体系"的物理基础——没有归档协议,所有的"半年后回看"承诺都是空话。
---
## 为什么必须归档
1. **可 diff**:三个月后重跑同一个 skill,可以和上次输出做 diff
2. **可 review**:团队成员可以读到你的研究,PM 可以审计你的工作
3. **可引用**:其他 skill 可以读到同标的的历史输出(见 [preamble.md](preamble.md) Step 2)
4. **可追溯**:每次决策都能查到当时的研究底稿
5. **可批量更新**:周度刷新等批量任务依赖归档结构
---
## 默认目录结构
### 单股研究
```
{coverage_root}/
├── {ticker}_{name}/ ← 一家公司一个目录
│ ├── INDEX.md ← 公司元数据 + 当前命题摘要
│ │
│ ├── thesis/ ← sm-thesis 输出
│ │ ├── 2026-04-07-thesis.md
│ │ └── 2026-07-15-thesis-update.md
│ │
│ ├── deepdive/ ← sm-company-deepdive 输出
│ │ ├── 2026-04-07-deepdive.md
│ │ └── 2026-08-20-deepdive-update.md
│ │
│ ├── earnings/ ← sm-earnings-preview 输出
│ │ ├── 2026-Q1-preview.md
│ │ ├── 2026-Q1-postmortem.md
│ │ ├── 2026-Q2-preview.md
│ │ └── 2026-Q2-postmortem.md
│ │
│ ├── catalysts/ ← sm-catalyst-monitor 输出
│ │ └── 2026-04-07-event-{name}.md
│ │
│ ├── consensus/ ← sm-consensus-watch 输出
│ │ └── 2026-04-07-consensus.md
│ │
│ ├── red-team/ ← sm-red-team 输出
│ │ └── 2026-04-07-redteam.md
│ │
│ ├── model/ ← sm-model-check 输出 + 模型文件
│ │ └── 2026-04-07-modelcheck.md
│ │
│ ├── roadshow/ ← sm-roadshow-questions 输出
│ │ └── 2026-04-07-roadshow.md
│ │
│ ├── pm-brief/ ← sm-pm-brief 输出
│ │ └── 2026-04-07-pmbrief.md
│ │
│ ├── data/ ← 原始数据快照(财报、公告等)
│ │ ├── 2024-annual-report.pdf
│ │ └── 2025-Q3-financials.json
│ │
│ └── notes/ ← 路演纪要、调研、专家访谈
│ └── 2026-04-05-management-call.md
```
### 行业 / 主题研究
```
{workspace_root}/themes/
└── {theme-slug}/
├── INDEX.md
├── 2026-04-07-industry-map.md ← sm-industry-map 输出
├── 2026-04-07-thesis.md ← sm-thesis 输出
└── members/ ← 主题相关公司的索引(软链 / md 链接)
├── 寒武纪 → ../../coverage/688256_寒武纪/
└── 海光信息 → ../../coverage/688041_海光信息/
```
### 晨会 / 简报
```
{workspace_root}/briefings/
├── 2026-04-07-morning.md ← sm-briefing 输出
├── 2026-04-07-evening.md
└── weekly/
└── 2026-W14.md
```
---
## 命名规范
### 文件名格式
```
{YYYY-MM-DD}-{skill-short}[-{descriptor}].md
```
| 字段 | 说明 | 示例 |
|---|---|---|
| `YYYY-MM-DD` | 必填,输出当天日期 | `2026-04-07` |
| `skill-short` | skill 的简称 | `deepdive` / `thesis` / `preview` |
| `descriptor` | 可选,区分同日多次输出 | `update` / `postmortem` / `q4-special` |
### Skill 简称对照表
| Full skill name | Short name |
|---|---|
| `sm-master` | `master` |
| `sm-autopilot` | `autopilot` |
| `sm-thesis` | `thesis` |
| `sm-industry-map` | `industry` |
| `sm-company-deepdive` | `deepdive` |
| `sm-earnings-preview` | `earnings` |
| `sm-model-check` | `modelcheck` |
| `sm-consensus-watch` | `consensus` |
| `sm-catalyst-monitor` | `catalyst` |
| `sm-roadshow-questions` | `roadshow` |
| `sm-red-team` | `redteam` |
| `sm-pm-brief` | `pmbrief` |
| `sm-briefing` | `briefing` |
| `sm-batch-refresh` | `batch-refresh` |
| `sm-batch-earnings` | `batch-earnings` |
| `sm-catalyst-sweep` | `catalyst-sweep` |
### Ticker 目录命名
```
{ticker}_{name}/
```
- `ticker` 优先用交易所代码(A 股 6 位、港股 4-5 位、美股字母)
- `name` 用公司中文名(A 股、港股)或英文名(美股)
- 例:`688256_寒武纪/`、`0700_腾讯控股/`、`NVDA_NVIDIA/`
---
## 配置:coverage_root 在哪
每个工作区的 `系统提示词` 建议用户自行配置 coverage_root。
```yaml
# In 系统提示词
coverage_root: ../覆盖公司库
workspace_root: ./
```
如果用户没设置:
- 默认 `coverage_root: ./coverage`
- 默认 `workspace_root: ./`
skills 按用户指定的路径归档。
---
## INDEX.md 的作用
每个 ticker 目录下的 `INDEX.md` 是该公司的"元数据 + 命题摘要":
```markdown
# {Ticker} {Name}
**market**: CN-A
**sector**: 半导体
**started_coverage**: 2026-01-15
**last_updated**: 2026-04-07
**current_thesis**: "AI 算力国产替代龙头,2026 思元 590 量产是关键拐点"
**conviction**: medium
**latest_outputs**:
- thesis: thesis/2026-04-07-thesis.md
- deepdive: deepdive/2026-04-07-deepdive.md
- earnings: earnings/2026-Q1-preview.md
- red-team: red-team/2026-04-07-redteam.md
**next_catalysts**:
- 2026-05-XX 公司业绩会
- 2026-Q2 思元 590 量产指引
**watchlist_triggers**:
- 思元 590 量产延后 → 下修
- BIS 进一步收紧 → 上修
```
INDEX.md 是 LLM **每次** preamble Step 2 检查的首要文件。
---
## 历史输出的引用机制
当 preamble.md Step 2 发现历史输出时,LLM 应该:
1. 读取最近一份同 skill 的输出,diff 与本次的差异
2. 读取该公司的 INDEX.md 拿到 current_thesis
3. 读取相关其他 skill 的最近一份(如果做 deepdive,读 thesis;如果做 earnings preview,读 deepdive 和 consensus)
4. 在本次输出顶部声明:`本次为更新 — 上次 deepdive 2026-01-15,上次 thesis 2026-02-20`
---
## 团队场景(v0.4 预留)
未来团队版会增加:
- `coverage_root` 区分 `team-coverage/` vs `personal-coverage/`
- 输出归档时自动加 `author` 字段
- 团队 review 工作流
当前 v0.3 只支持单人工作区。
FILE:core/postamble.md
# Postamble · 强制结束后流程
> 所有 sm-* skill 在产生分析输出**之后**,必须按本文件依序完成 7 个步骤。
> 跳过任何一步视为未完成任务。
>
> 这是治"幻觉"和"不成体系"的核心机制。
>
> v0.4 改动:新增 Step 0(增量 checkpoint 写入)+ Step 7(context echo 简化),原 6 步保留。
---
## Step 0 · 增量 Checkpoint 写入(v0.4 新增 · 治健忘)
**每完成一段输出,立即更新 checkpoint,不要等任务全部完成**。
具体操作:
1. 写入 `.checkpoint/{task-id}.md` 的对应段落
2. 更新 `.task-pulse` 的 `step` 字段(如 "5/9" → "6/9")
3. 估算剩余 context budget:
- 剩余 > 30k → 继续下一段
- 剩余 < 30k → 写完当前段后**主动提醒**用户"context 紧张,建议本任务跑完后开新会话"
- 剩余 < 10k → **强制停止**,写 checkpoint,告知用户"已保存进度,请用'继续 {task-id}' 开新会话续跑"
详细机制见 [checkpoint.md](checkpoint.md)。
---
## Step 1 · 自检证据等级(治幻觉)
回看本次输出的每一段。每一条"事实陈述"必须有 F1/F2/M1/C1/H1 标签之一:
| 标签 | 含义 |
|---|---|
| **F1** | 公开事实,可直接验证 |
| **F2** | 财报 / 公告 / 权威披露 |
| **M1** | 市场观点 / 一致预期 |
| **C1** | 基于事实的合理推演(必须说明推演链路) |
| **H1** | 待核验线索或假设 |
**自检规则**:
- 没有标签的"事实"句子 → **必须**补标
- 关键结论必须有 F1 / F2 支撑
- M1 不能当事实
- C1 必须附推演链路
- H1 不能成为最终结论的唯一依据
详见 [evidence.md](evidence.md)。
---
## Step 2 · 输出"仍需补的资料"段(治幻觉的强制承认)
每份交付**必须**有这一段,按以下结构:
```markdown
## 仍需补的资料
**必需**(关键缺口,影响结论可靠性):
- {数据 1} — 应从 {来源} 获取
- {数据 2} — 应从 {来源} 获取
**建议**(提升分析质量):
- {数据 3}
- {数据 4}
**不确定但影响判断**:
- {假设性问题}
```
**这一段不能为空**。任何 skill 跑完都会有"我没拿到的数据",你必须老实列出来。
如果你觉得"什么都拿到了"——说明你没真的检视过自己的输出,回去再看一遍。
---
## Step 3 · 输出合规声明
每份交付末尾**必须**附以下段落(按场景调整):
```markdown
---
⚠️ **合规声明**:本输出不构成投资建议。
- 涉及评级 / 目标价 / 盈利预测调整 → 必须经持牌分析师人工复核
- 数据来源:{本次实际使用的数据源}
- 输出时间:{YYYY-MM-DD HH:MM}
- 使用的 skill:{sm-xxx}
```
详见 [compliance.md](compliance.md)。
---
## Step 4 · 归档输出(治不成体系)
按 [output-archive.md](output-archive.md) 的命名规范,把本次输出写入归档路径:
```
{coverage_root}/{ticker}/{skill}/{YYYY-MM-DD}-{skill}.md
```
或对于行业 / 主题任务:
```
{workspace_root}/themes/{theme}/{YYYY-MM-DD}-{skill}.md
```
**为什么必须归档**:
- 半年后回看可以 diff
- 团队成员可以 review
- 跨 skill 引用可以读到(preamble.md Step 2)
- 如果不归档,等于没做
如果用户没设置 coverage_root,归档到默认 `./output/{YYYY-MM-DD}-{skill}-{target}.md`。
---
## Step 5 · 更新任务进度(治健忘)
更新 `{workspace_root}/active-tasks.md`:
- 如果本次工作完成了某个 active task → 标记 `status: done` + 记录完成时间 + 输出归档路径
- 如果本次工作只完成了部分 → 更新 `progress` 字段,记录"做到哪一步"
- 如果本次工作产生了后续任务 → 在 `active-tasks.md` 添加新条目
---
## Step 6 · 验收清单
按 [acceptance.md](acceptance.md) 的清单逐条自检:
- [ ] Preamble 0-5 步全部完成
- [ ] 每条事实带证据等级
- [ ] "仍需补的资料"段非空
- [ ] 合规声明已附
- [ ] 输出已归档到正确路径
- [ ] .task-pulse + active-tasks.md 已更新
- [ ] .checkpoint 已删除(任务完成时)
**任何一条没过 → 不算完成 → 必须补完再交付**。
---
## Step 7 · Dual Output Discipline(v0.5.1 修正 · 双输出 + 文件备份)
> **v0.5.1 修正**:v0.4 原 Step 7 是"对话只回 ~300 token 摘要,完整输出在文件里"。
> 这个设计**忽视了云端用户**——很多人在 Claude.ai / Codex web / OpenCode hosted 上跑,**根本打不开本地文件**。
>
> **新原则**:完整输出**两份**——对话里贴一份(人类阅读),文件里存一份(归档 + 跨 skill 引用)。
---
### 核心规则
任务完成后**必须同时**:
1. **在对话里贴出完整输出** — 给用户直接读,包括 9 段全部内容、证据等级、仍需补的资料、合规声明
2. **写一份完整副本到归档路径** — 按 [output-archive.md](output-archive.md) 命名规范
3. **结尾追加一段简短的"📁 已归档"提示** — 告知用户文件位置 + 关键统计
---
### 标准结尾摘要(追加在完整输出末尾)
```
---
📁 **已归档**:{coverage_root}/{ticker}/{skill}/{YYYY-MM-DD}-{skill}.md
📊 文件大小:{N} KB · 段落数:{X/Y} · 证据:F1×{N} F2×{N} M1×{N} C1×{N} H1×{N}
🆔 Task ID:{task-id} · 状态:done
⚠️ 本输出不构成投资建议。涉及评级 / 目标价 / 盈利预测调整须经持牌分析师人工复核。
🔄 建议下一步:
- {推荐 1:基于本次输出的下一个 skill}
- {推荐 2:另一个相关 skill}
```
---
### 为什么是双输出而不是只贴对话或只写文件
| 场景 | 只贴对话(v0.3 老方式)| 只写文件(v0.4 错方式)| **双输出(v0.5.1 正确)** |
|---|---|---|---|
| 云端用户(Claude.ai / web) | ✅ 能看 | ❌ **打不开文件** | ✅ 直接读对话 |
| 本地用户 | ✅ 能看 | ⚠️ 要打开文件 | ✅ 对话直读 + 文件备份 |
| 跨 skill 引用 | ❌ 下次会话失效 | ✅ 文件可读 | ✅ 文件可读 |
| 长期归档 / diff | ❌ 没有 | ✅ 有 | ✅ 有 |
| context overflow | ✅ 输出还在文件 | ✅ 输出还在文件 | ✅ 输出还在文件 |
| 团队 review | ❌ 需要 ctrl+F | ✅ 可以 grep | ✅ 双方式 |
**结论**:双输出是唯一对所有用户都友好的方式。多花 5-10k tokens 换"全用户体验一致",值得。
---
### 上下文成本权衡
| 设计 | 每任务对话成本 | 200k context 能跑几个任务 |
|---|---|---|
| v0.3 旧方式(只贴对话) | ~5000 tokens | ~30 个 |
| v0.4 错方式(只回摘要) | ~300 tokens | ~50 个(理论但不可用) |
| **v0.5.1 双输出(推荐)** | **~5500 tokens** | **~25 个** |
25 个完整投研任务对一个会话来说足够了。**省 token 不能以牺牲可用性为代价**。
---
### 例外情况:用户主动要求"省 token 模式"
如果用户明确说**"只回摘要"** / **"省 token"** / **"我等会儿打开文件看"** → 可以退回到 v0.4 的纯摘要模式。
但**默认**必须双输出。
---
## 用户视角看到的最终输出(v0.5.1 双输出版)
```
[完整的 9 段 sm-company-deepdive 输出,按结构展开,每条带证据等级]
# 寒武纪 (688256.SH) · Coverage Deepdive
## 1. 公司定位
...
## 2. 业务拆分
...
[省略中间 7 段]
## 9. 仍需补的资料
...
---
📁 **已归档**:覆盖公司库/688256_寒武纪/deepdive/2026-04-07-deepdive.md
📊 文件大小:12.4 KB · 段落数:9/9 · 证据:F1×8 F2×15 M1×6 C1×9 H1×4
🆔 Task ID:t-001 · 状态:done
⚠️ 本输出不构成投资建议。涉及评级 / 目标价需人工复核。
🔄 建议下一步:
- sm-red-team 反方审视(推荐)
- sm-pm-brief 给 PM 一页纸
```
**总成本**:~5500 tokens 对话 + 12 KB 文件
**好处**:云端用户直接读,本地用户双备份,跨 skill 引用照常工作
FILE:core/preamble.md
# Preamble · 强制开始前流程
> 所有 sm-* skill 在产生任何分析输出**之前**,必须按本文件依序完成 6 个步骤。
> 这是治"幻觉"和"健忘"的核心机制——跳过任何一步视为未完成任务。
>
> v0.4 改动:新增 Step 0(任务断点检查),Steps 1-5 保留。
---
## Step 0 · 任务断点检查(v0.4 新增 · 治健忘)
在做任何其他事情之前:
1. **读 `.task-pulse`**(如果存在)
- 不存在 → 视为新工作区,跳过本 step
- 存在 → 解析 JSON,检查是否有进行中任务
2. **匹配本次请求**
- 如果用户输入是"继续 t-XXX"或类似 → 直接进入 [checkpoint.md](checkpoint.md) 的恢复流程
- 如果用户输入与 .task-pulse 中某个 in_progress 任务的 target 匹配 → 主动询问"你之前在做这个标的的 X 任务,要继续吗?"
- 如果不匹配 → 创建新 task 条目,分配 task-id
3. **创建 task 条目**
- 在 `.task-pulse` 添加新条目:`{id, skill, target, step:"0/N", ckpt:".checkpoint/{id}.md"}`
- 创建空的 `.checkpoint/{id}.md` 文件
4. **Context budget 估算**
- 如果当前会话已使用 > 150k tokens → 警告用户"建议本任务跑完后开新会话"
- 如果 > 180k → 强制只完成当前段,写 checkpoint,停止
---
## Step 1 · 识别市场
按 [markets.md](markets.md) 确定标的的市场归属:
- `CN-A` — A 股 / 沪深
- `CN-FUND` — 公募基金
- `HK` — 港股
- `US` — 美股
- `GLOBAL` — 跨市场主题 / 行业
输出标记:`市场:{CN-A | CN-FUND | HK | US | GLOBAL}`
---
## Step 2 · 检查历史输出(治健忘)
按 [output-archive.md](output-archive.md) 的归档路径检查:
```
{coverage_root}/{ticker}/research/
{coverage_root}/{ticker}/{skill}/
```
**如果存在同标的、同 skill 的历史输出**:
- 读取最近一次输出
- 在本次输出开头声明:`本次为更新(上次:YYYY-MM-DD)`
- 重点输出"自上次以来的变化",避免完全重写
**如果存在同标的、其他 skill 的历史输出**:
- 引用其结论作为本次工作的输入(标 M1 或 C1)
- 例:`命题来自 sm-thesis 输出 (2026-02-15)`
**如果完全无历史**:
- 在本次输出开头声明:`本次为首次研究`
- 进入下一步
---
## Step 3 · 检查任务进度(治健忘)
读取 `{workspace_root}/active-tasks.md`:
- 是否存在与本次任务相关的"进行中"任务?
- 如果是 → 读取 `progress` 字段,从断点继续
- 如果否 → 在本次工作开始时创建一条新的 active task
---
## Step 4 · 输出 [Preflight] 取数计划(治幻觉)
按 [adapters.md](adapters.md) 的数据源决策树,**强制**输出以下结构:
```
[Preflight]
标的:{公司/行业/主题}
市场:{Step 1 的结果}
历史状态:{Step 2 的结果,"首次研究" 或 "更新(上次 YYYY-MM-DD)"}
任务进度:{Step 3 的结果,"新任务" 或 "续 task-id"}
数据源优先级链:
1. {工具 A} → {预期拉取什么}
2. {工具 B} → {备用 / 补充}
3. {工具 C} → {兜底}
预期缺失项:
- {可能拿不到的关键数据 1}
- {可能拿不到的关键数据 2}
→ 这些将在末尾"仍需补的资料"段明确列出
```
**⛔ 严禁跳过 Preflight 直接开始分析输出。**
如果用户没给标的代码或者市场不明确:
- 先问一句歧义澄清问题(仅限同名标的、市场不明这两种情况)
- 拿到答案后再走完 Preflight
---
## Step 5 · 按优先级实际取数
按 Preflight 写的优先级链,**实际调用工具拿数据**:
- **不要**只在 Preflight 里"声称"要拿什么,要真去拿
- 拿到的每条数据**立即**标证据等级(F1/F2/M1/C1/H1,见 [evidence.md](evidence.md))
- 拿不到的数据**立即**记录到"缺失项实际清单",等会写进 postamble 的"仍需补的资料"段
---
## 完成 Preamble 之后
进入对应 skill 的具体分析流程。
分析输出的结尾必须按 [postamble.md](postamble.md) 走强制结束流程。
---
## 例外说明
**仅以下情况允许跳过 Preamble**:
- 用户明确说"不需要取数,我直接贴材料"——此时 Step 4 的优先级链直接写"用户提供材料"
- 用户明确说"快速看一下,不用深度"——此时仍需 Step 1/2/3,但 Step 4 可以简化
**任何其他情况跳过 Preamble 都视为违规。**
FILE:core/quick-prompts.md
# Quick Prompts
这份清单给“最低操作量”使用者。默认优先使用 `sm-autopilot`,尽量把输入压缩到一句话。
## 最常用一句话
- `请用 sm-autopilot 看一下宁德时代`
- `请用 sm-autopilot 看一下中际旭创,重点判断未来3个月预期差`
- `请用 sm-autopilot 看一下AI眼镜产业链`
- `请用 sm-autopilot 看一下英伟达发布会对A股算力链影响`
- `请用 sm-autopilot 做中芯国际财报前瞻`
- `请用 sm-autopilot 检查我上传的盈利预测模型`
- `请用 sm-autopilot 给我准备寒武纪业绩会提问`
## 更稳的一句话
如果愿意多给一点信息,推荐用下面格式:
```text
请用 sm-autopilot + 任务对象 + 关注点 + 时间窗
```
示例:
- `请用 sm-autopilot 看一下宁德时代,重点看储能和毛利率,时间窗未来3个月`
- `请用 sm-autopilot 做中芯国际财报前瞻,重点看成熟制程价格和下季指引`
- `请用 sm-autopilot 检查我上传的模型,重点看收入拆分、毛利率和capex`
## 团队内推荐统一口令
为了让团队输出更稳定,推荐统一使用这三种口令:
### 1. 看公司
```text
请用 sm-autopilot 看一下【公司名】,输出一句话结论、核心逻辑、预期差、风险和下一步行动。
```
### 2. 看财报
```text
请用 sm-autopilot 做【公司名】财报前瞻,输出市场最关心问题、潜在超预期点、潜在低于预期点和财报后检查清单。
```
### 3. 看模型
```text
请用 sm-autopilot 检查我上传的模型,输出最脆弱假设、最容易误导结论的地方和待核验项目。
```
## 不推荐的问法
- `分析一下XXX`
- `你怎么看`
- `简单说说`
这些问法不是不能用,而是容易让输出漂。最好至少补一个“关注点”。
FILE:core/task-pulse.md
# Task Pulse · 微型任务状态信号
> 一个 < 100 tokens 的 JSON 文件,让 LLM 在每次新会话用极小代价知道工作区当前状态。
> 类似 git 的 `.git/HEAD` —— 一个 pointer 文件维护整个工作区的"心跳"。
---
## 文件位置
```
{workspace_root}/.task-pulse
```
每个工作区一个。
---
## 文件格式(JSON)
```json
{
"v": "0.4",
"ts": "2026-04-07T14:30:00Z",
"tasks": [
{
"id": "t-001",
"skill": "deepdive",
"target": "688256_寒武纪",
"step": "6/9",
"ckpt": ".checkpoint/t-001.md"
},
{
"id": "t-002",
"skill": "earnings",
"target": "688981_中芯国际",
"step": "3/7",
"ckpt": ".checkpoint/t-002.md"
}
],
"compacted": false,
"warn": null
}
```
## 字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
| `v` | string | task-pulse 格式版本("0.4" 起) |
| `ts` | ISO 8601 | 最后一次更新时间 |
| `tasks` | array | 进行中的任务(最多 5 个) |
| `tasks[].id` | string | 任务唯一 id(短格式 t-NNN) |
| `tasks[].skill` | string | skill 简称(按 output-archive.md 简称表) |
| `tasks[].target` | string | 标的(ticker_name 或 theme-slug) |
| `tasks[].step` | string | 进度("6/9" 表示完成 6 段中的 9 段) |
| `tasks[].ckpt` | string | 该任务的 checkpoint 文件路径 |
| `compacted` | bool | 上次会话是否被 compact 过 |
| `warn` | string\|null | 上下文预警信息(context budget 剩余 < 30k 时设置) |
## 大小约束
- **目标**:< 500 字节
- **最大**:1 KB
- **超过 1 KB 触发清理**:archive 已完成任务,只保留 in_progress
## LLM 启动时的读取协议
1. 检查 `.task-pulse` 是否存在
- 不存在 → 视为新工作区,跳过任务恢复
2. 解析 JSON
- 解析失败 → 警告用户、跳过、不删除(避免数据丢失)
3. 如果 `compacted: true`
- 主动告知用户:"上次会话被 compact 过,已恢复任务状态"
4. 如果 `tasks` 非空
- 列出所有进行中任务给用户
- 等用户选择"继续 t-001"或"开始新任务"
5. 用户选择继续后
- 读对应 `ckpt` 文件
- 加载对应 skill
- 从 step 指示的位置继续
## LLM 完成 step 时的更新协议
每完成一段(不是每完成一个任务),更新 `.task-pulse` 的对应 task:
```
更新前: "step": "5/9"
更新后: "step": "6/9"
"ts": <当前时间>
```
并同时更新 `.checkpoint/{task-id}.md` 的内容。
## 任务完成时的清理协议
任务标 done 后:
- 从 `.task-pulse` 的 `tasks` 数组中移除该 task
- 把任务详情归档到 `active-tasks.md` 的"已完成"段
- 删除 `.checkpoint/{task-id}.md`
## 上下文预警协议
LLM 在每次输出后估算剩余 context budget。如果剩余 < 30k tokens:
1. 在 `.task-pulse` 设置 `warn: "context budget low: ~25k remaining"`
2. 在用户交互时主动告知:"上下文预算紧张,建议本任务跑完后开新会话"
3. 如果剩余 < 10k tokens
- **强制**写 checkpoint 后停止本任务
- 告知用户:"任务已保存到 .checkpoint/{id},请开新会话用 '继续 t-id' 接续"
## 与 active-tasks.md 的关系
| 文件 | 作用 | 大小 | 何时读 |
|---|---|---|---|
| `.task-pulse` | 心跳信号 | < 1 KB | **每次新会话**必读 |
| `active-tasks.md` | 完整任务历史 | 5-50 KB | **只在需要任务详情时**读 |
`.task-pulse` 是 active-tasks.md 的"索引"。LLM 默认只读 .task-pulse,**只在用户问详情时**才读 active-tasks.md。
这是 v0.4 节省 token 的核心设计。
FILE:core/templates.md
# Templates
## 默认整合输出
```text
一句话结论:
为什么现在值得看:
核心逻辑:
关键证据 / 预期差:
最关键催化:
最大风险与证伪点:
下一步行动:
本次默认假设:
```
## 一页纸摘要
```text
结论:
为什么现在看:
市场可能错在哪:
最关键催化:
最大风险:
建议下一步:
```
## 公司跟踪卡
```text
公司:
产业链位置:
收入驱动:
利润驱动:
市场关注点:
未来三个月关键指标:
仍需验证的问题:
```
## 晨会 / 晚报
```text
今日最重要的三件事:
1.
2.
3.
对覆盖池 / 组合的影响:
最值得跟踪的方向:
待回答问题:
一句话给基金经理:
```
## 财报前瞻
```text
公司:
财报日期:
一句话判断:
市场最关心的三个问题:
1.
2.
3.
本次财报最敏感的变量:
- 收入:
- 毛利率:
- 费用率:
- 现金流:
- 指引:
潜在超预期点:
潜在低于预期点:
财报后第一时间检查清单:
1.
2.
3.
```
## 模型检查
```text
模型目的:
核心假设:
-
-
-
收入驱动检查:
利润率 / 费用率检查:
现金流与资产负债表检查:
估值假设检查:
敏感性最高的三个变量:
1.
2.
3.
最容易误导结论的地方:
需要立刻回头核验的项目:
```
## 路演问题清单
```text
本次交流目的:
需要优先验证的三个假设:
1.
2.
3.
必问问题:
1.
2.
3.
每个问题背后验证什么:
若回答偏强 / 中性 / 偏弱,分别意味着什么:
交流后应如何更新观点或模型:
```
FILE:core/triggers.md
# Auto-Triggers · LLM 自动识别表
> 本文件解决 research-harness 的根本问题:**LLM 默认走捷径,不会主动调 skill**。
>
> 用户 / 系统提示词 / agent.md 只能"软提醒",无法硬拦截。唯一的防御是:LLM 在看到用户消息的那一刻,用本文件的关键词表做 **pattern matching**,命中即触发对应 skill。
>
> v0.4 新增。配合 系统提示词 的 预加载ed 硬约束一起使用。
---
## 使用方法
LLM 在每次收到用户消息后,**第一件事**是扫描消息文本,匹配下表中的触发词:
1. 如果命中任一触发词 **且** 消息里提到覆盖池中的 ticker / 公司名
2. **立即停止"自由回答"模式**,改为"skill 调用"模式
3. 在回答开头明确声明:"识别到触发词 `{word}`,按 research-harness 纪律执行 `sm-{skill}`"
4. 按 preamble.md 走 Step 0-5
5. 调对应 skill
6. 按 postamble.md 收尾
---
## 触发词表
### 估值类 → `sm-company-deepdive` + `sm-thesis`
| 中文触发词 | 英文触发词 |
|---|---|
| 估值怎么样 / 估值如何 | valuation / how is the valuation |
| 贵不贵 / 便宜不便宜 | expensive / cheap / overvalued / undervalued |
| P/E / PE 多少 | multiple / trading multiple |
| 值多少钱 / fair value | fair value / intrinsic value |
| 目标价 | target price / price target / TP |
| 合理估值 | justified multiple |
### 评级 / 买卖类 → `sm-thesis` + 必配 `sm-red-team`
| 中文 | 英文 |
|---|---|
| 值不值得买 | worth buying / should I buy |
| 看多看空 | bullish / bearish |
| 买入 / 卖出 / 持有建议 | buy / sell / hold recommendation |
| Rating / 评级 | rating / upgrade / downgrade |
| 多头逻辑 / 空头逻辑 | bull case / bear case |
### 业务 / 商业模式类 → `sm-company-deepdive`
| 中文 | 英文 |
|---|---|
| 做什么的 / 主营业务 | what does X do |
| 商业模式 | business model |
| 产业链位置 | value chain position |
| 收入来源 | revenue breakdown / segment |
| 客户结构 | customer concentration |
| 核心竞争力 | moat / competitive advantage |
### 财报类 → `sm-earnings-preview`
| 中文 | 英文 |
|---|---|
| 财报 / 业绩 | earnings / Q1 / Q2 / Q3 / Q4 results |
| 下季度 / 下次业绩 | next quarter |
| Beat / Miss | beat or miss |
| 预期 / 指引 | guidance / consensus |
### 比较类 → 两次 `sm-company-deepdive` + 合并
| 中文 | 英文 |
|---|---|
| A 和 B 对比 / 比较 | X vs Y / compare X and Y |
| 谁更好 | which is better |
| 相对估值 | relative valuation |
### 模型 / DCF 类 → `sm-model-check`
| 中文 | 英文 |
|---|---|
| 财务模型 | financial model |
| DCF 合理吗 | DCF reasonable |
| 假设怎么看 | assumptions check |
| WACC / 永续增长 | WACC / terminal growth |
### 催化剂 / 触发事件类 → `sm-catalyst-monitor`
| 中文 | 英文 |
|---|---|
| 催化剂 | catalyst |
| 下 3 个月关注什么 | next 3 months |
| 驱动因素 | driver |
### 一致预期类 → `sm-consensus-watch`
| 中文 | 英文 |
|---|---|
| 卖方最近怎么看 | sell-side view |
| 一致预期 | consensus estimate |
| 预期差 | expectation gap |
| 分析师评级变化 | analyst rating changes |
### 反方 / 红队类 → `sm-red-team`
| 中文 | 英文 |
|---|---|
| 反方 / 红队 | red team / devil's advocate |
| 多头逻辑有什么问题 | what could go wrong |
| 最大风险 | biggest risk |
### 路演 / 调研问题 → `sm-roadshow-questions`
| 中文 | 英文 |
|---|---|
| 见管理层问什么 | mgmt meeting questions |
| 路演问题 | roadshow questions |
| 调研清单 | diligence questions |
### PM 一页纸 → `sm-pm-brief`
| 中文 | 英文 |
|---|---|
| PM 视角 | PM view |
| 一页纸 | one-pager / brief |
| 投资要点 | investment summary |
### 简报类 → `sm-briefing`
| 中文 | 英文 |
|---|---|
| 今日动态 / 今天怎么样 | today's news |
| 本周要点 | weekly brief |
| 日报 / 周报 | daily briefing |
### 行业地图类 → `sm-industry-map`
| 中文 | 英文 |
|---|---|
| 产业链 / 行业全景 | industry map |
| 赛道玩家 | players in the space |
| 上下游 | value chain upstream/downstream |
---
## 防御规则
### 规则 1:宁可多触发,不可漏触发
触发了没必要的 skill → 代价是几秒钟额外 context read
漏触发 → 代价是违反纪律 + 用户被动发现 + 信任崩塌
**优先级:触发 > 效率**。
### 规则 2:模糊命中也要触发
用户说"NVDA 咋样"—— "咋样"不是精确触发词,但意图明显。**命中语义而非字面**。
### 规则 3:同一消息多词命中,取优先级最高
优先级:`sm-red-team > sm-thesis > sm-company-deepdive > 其他`
如果用户说"NVDA 值不值得买?要考虑反方"—— 同时触发 thesis + red-team,两个都要跑。
### 规则 4:用户明确说"快速看一下"时
仍然 MUST 执行最小集合:
1. `[Preflight]` 段(可以简化)
2. 关键事实带证据等级
3. 末尾合规声明
允许省略的:完整 9 段式 deepdive、历史输出检查、归档步骤
### 规则 5:**违规自我报告机制**
如果 LLM 发现自己**已经开始输出** 但意识到漏触发了,MUST 立即:
1. 停止当前输出
2. 说:"违规检测:我漏触发了 sm-{skill},现在回滚并按纪律重做"
3. 重启流程
---
## 反例集合(LLM 易犯错误)
### 反例 1:估值表格式输出
❌ **违规**:用户问"KEYS 和 MU 估值怎么样",LLM 直接拉 yfinance 数据出一张 fwd P/E 表格 + 多空观点。
✅ **正确**:识别"估值怎么样"+ "KEYS / MU 是覆盖池成员"→ 触发 `sm-company-deepdive`(两次)→ 完整 9 段式 → postamble 归档。
### 反例 2:闲聊式开场
❌ **违规**:用户说"最近 NVDA 跌了,怎么看",LLM 聊天式开始:"NVDA 最近回调主要因为..."
✅ **正确**:识别"怎么看"+ "NVDA"→ 触发 `sm-thesis`(命题构建)+ `sm-red-team`(反方)→ 按结构输出。
### 反例 3:只加合规声明不调 skill
❌ **违规**:LLM 写了一段自由分析,末尾加"以上仅供参考,不构成建议"—— 认为这样就合规。
✅ **正确**:合规声明**只是**交付的一部分,不是 skill 的替代。必须先调 skill 走流程,然后 postamble 才加合规声明。
### 反例 4:跳 Preflight
❌ **违规**:调了 skill 但直接开始 9 段式输出,没写 `[Preflight]`。
✅ **正确**:调 skill → 先写 `[Preflight]`(标的/市场/数据源链/缺失项)→ 再 9 段式。
---
## 落地建议
本文件需要配合以下两个机制之一才能发挥作用:
1. **系统提示词 预加载**(分析师工作区的 系统提示词 引用本文件,让 LLM 每次启动时都看到)
单独的 triggers.md 没有效果,必须有外部机制让 LLM 读到它。
---
## 版本
- v0.4.1(本版):首次引入 auto-trigger 概念,配合 系统提示词 硬约束
FILE:core/workflows.md
# Workflows
这组投研 skills 可以组合成类似 gstack 的研究流程。
## 最低操作量入口
- `sm-autopilot`
默认总控入口。适合不想自己挑 skill 的使用者。
## 推荐顺序
1. `sm-autopilot`
用于自动判断应该走哪条研究链路。
2. `sm-thesis`
用于定义问题和值不值得研究。
3. `sm-industry-map`
用于搭行业框架和产业链地图。
4. `sm-company-deepdive`
用于下沉到公司层面。
5. `sm-earnings-preview`
用于财报前瞻和财报后验证。
6. `sm-model-check`
用于检查盈利预测和估值模型。
7. `sm-consensus-watch`
用于判断市场预期差。
8. `sm-catalyst-monitor`
用于跟踪财报、政策和产业催化。
9. `sm-roadshow-questions`
用于准备路演和管理层交流问题。
10. `sm-red-team`
用于强制反方审视。
11. `sm-pm-brief` 或 `sm-briefing`
用于输出给基金经理、晨会或团队流转。
## 团队映射
- `sm-autopilot`:总控调度入口
- `sm-thesis`:基金经理 / 投资主理人
- `sm-industry-map`:行业研究员
- `sm-company-deepdive`:公司研究员
- `sm-earnings-preview`:财报季前瞻助理
- `sm-model-check`:模型审阅助理
- `sm-consensus-watch`:预期管理助理
- `sm-catalyst-monitor`:事件跟踪助理
- `sm-roadshow-questions`:调研提纲助理
- `sm-red-team`:反方风险官
- `sm-pm-brief`:面向投资决策层的输出官
- `sm-briefing`:晨会与材料整理助理
FILE:manifest.yaml
# Investor Harness 套件清单
# harness 开发者和 LLM 可读,用于发现、路由、依赖校验
name: research-harness
display_name: Research Harness
version: 0.6.0
description: 研究员的 AI 任务执行规范。17 个 sm-* skill 强制 LLM 在做研究工作时不出现幻觉、不丢失上下文、不输出杂乱。v0.5 新增技术面复盘 skill (sm-tape-review) + INSTALL-PROMPT.md 用户级强制提示词,让小白用户的 LLM 也能自动遵守规则。
license: MIT
author: Joan Song
homepage: https://github.com/joansongjr/investor-harness
compatible_harnesses:
- claude-code
- codex
- opencode
- openclaw
- generic # 任何支持"读取相对路径 markdown"的 harness
# 三大痛点定位 + v0.4 新增:上下文溢出保护
solves:
- hallucination: 强制取数协议 + 证据分级 + 仍需补的资料段
- task_forgetting: 持久化记忆系统 + .task-pulse + .checkpoint 断点续跑
- lack_of_structure: 16 个标准化 skill + 输出归档协议 + 验收清单
- context_overflow: 三层加载(Tier 0/1/2)+ 输出文件化 + Echo 简化 + 断点续跑
# 数据源:全部可选。skill 会按 adapters.md 的优先级逐级降级
data_sources:
optional:
- name: ifind-mcp
description: 同花顺 iFind MCP,覆盖 A 股、公募、宏观、资讯(用户需自备账号)
servers:
- hexin-ifind-ds-stock-mcp
- hexin-ifind-ds-fund-mcp
- hexin-ifind-ds-edb-mcp
- hexin-ifind-ds-news-mcp
- name: cn-web-search
description: 中文网页搜索 skill,聚合 17 个免费搜索引擎
- name: websearch
description: harness 内置的通用英文搜索(所有主流 harness 默认可用)
- name: webfetch
description: harness 内置的网页抓取(所有主流 harness 默认可用)
fallback: 用户手动贴材料(所有 skill 必须支持此模式)
markets:
- code: CN-A
name: A股(沪深)
- code: CN-FUND
name: 公募基金
- code: HK
name: 港股
- code: US
name: 美股
- code: GLOBAL
name: 跨市场主题
skills:
- id: sm-master
path: skills/sm-master
tier: entry
description: 单 skill 长形态总控,7 模式全量,适合"只装一个 skill"
- id: sm-autopilot
path: skills/sm-autopilot
tier: entry
description: 轻量路由入口,自动串联下游 skill
- id: sm-thesis
path: skills/sm-thesis
tier: framing
- id: sm-industry-map
path: skills/sm-industry-map
tier: framing
- id: sm-company-deepdive
path: skills/sm-company-deepdive
tier: research
- id: sm-earnings-preview
path: skills/sm-earnings-preview
tier: research
- id: sm-model-check
path: skills/sm-model-check
tier: research
- id: sm-consensus-watch
path: skills/sm-consensus-watch
tier: research
- id: sm-catalyst-monitor
path: skills/sm-catalyst-monitor
tier: monitoring
- id: sm-roadshow-questions
path: skills/sm-roadshow-questions
tier: monitoring
- id: sm-red-team
path: skills/sm-red-team
tier: challenge
- id: sm-pm-brief
path: skills/sm-pm-brief
tier: output
- id: sm-briefing
path: skills/sm-briefing
tier: output
# v0.5 新增技术面 skill
- id: sm-tape-review
path: skills/sm-tape-review
tier: technical
description: 盘面 + 技术面复盘(K 线 / 量价 / 指标 / 关键位 / 一致性检验)— v0.5 新增
# v0.3 新增 batch skills
- id: sm-batch-refresh
path: skills/sm-batch-refresh
tier: batch
description: 覆盖池批量刷新(行情/财务/股东/催化)— v0.3 新增
- id: sm-batch-earnings
path: skills/sm-batch-earnings
tier: batch
description: 财报季批量前瞻 / 复盘 — v0.3 新增
- id: sm-catalyst-sweep
path: skills/sm-catalyst-sweep
tier: batch
description: 覆盖池每日 / 每周催化剂扫描 — v0.3 新增
core:
- path: core/evidence.md
purpose: 证据分级 F1/F2/M1/C1/H1
- path: core/compliance.md
purpose: 合规边界与表达规范
- path: core/templates.md
purpose: 输出模板
- path: core/workflows.md
purpose: skill 协作顺序与团队映射
- path: core/adapters.md
purpose: 数据源优先级决策树
- path: core/markets.md
purpose: 市场识别与分市场差异
# v0.3 新增 core
- path: core/preamble.md
purpose: 强制开始前流程(识别市场→检查历史→检查任务→Preflight→实际取数)— v0.3 新增
- path: core/postamble.md
purpose: 强制结束后流程(证据自检→仍需补→合规声明→归档→更新任务→验收)— v0.3 新增
- path: core/output-archive.md
purpose: 输出归档命名规范 — v0.3 新增
- path: core/acceptance.md
purpose: 输出验收清单(通用 + 各 skill 专属)— v0.3 新增
- path: core/menu.md
purpose: 零配置入口菜单(首次使用 / 模糊输入时显示)— v0.3 新增
- path: core/_boot.md
purpose: 启动文件(每次新会话第一个读,~1.2k tokens)— v0.4 新增
- path: core/task-pulse.md
purpose: .task-pulse 心跳信号文件格式规范 — v0.4 新增
- path: core/checkpoint.md
purpose: .checkpoint/ 断点续跑机制规范 — v0.4 新增
user_install_prompt:
path: INSTALL-PROMPT.md
purpose: 用户复制粘贴到 ~/.claude/CLAUDE.md 的强制启用提示词,让 LLM 自动遵守 harness 规则 — v0.5 新增
critical: true
workspace_templates:
- path: setup/workspace/CLAUDE.md.template
purpose: 分析师 persona + 默认行为
- path: setup/workspace/memory.md.template
purpose: 记忆索引
- path: setup/workspace/coverage.md.template
purpose: 覆盖池清单
- path: setup/workspace/watchlist.md.template
purpose: 观察池
- path: setup/workspace/decision-log.md.template
purpose: 投资决策日志
- path: setup/workspace/biases.md.template
purpose: 已知偏差清单
- path: setup/workspace/research-queue.md.template
purpose: 待研究队列
- path: setup/workspace/active-tasks.md.template
purpose: 任务进度持久化 — v0.3 新增
recommended_workflows:
company_research:
- sm-company-deepdive
- sm-consensus-watch
- sm-red-team
- sm-pm-brief
industry_research:
- sm-thesis
- sm-industry-map
- sm-pm-brief
earnings_season:
- sm-earnings-preview
- sm-consensus-watch
- sm-model-check
- sm-pm-brief
event_driven:
- sm-catalyst-monitor
- sm-consensus-watch
- sm-pm-brief
daily_briefing:
- sm-briefing
# v0.3 新增批量工作流
weekly_coverage_refresh:
- sm-batch-refresh
- sm-catalyst-sweep
- sm-briefing
earnings_season_full:
- sm-batch-earnings
- sm-consensus-watch
- sm-pm-brief
daily_morning_routine:
- sm-catalyst-sweep
- sm-briefing
# v0.5 新增技术面工作流
daily_tape_review:
- sm-tape-review
add_position_decision:
- sm-thesis
- sm-red-team
- sm-tape-review
- sm-pm-brief
FILE:skills/sm-autopilot/SKILL.md
---
name: sm-autopilot
description: 二级市场投研总控入口 skill。面向最低操作量使用场景,自动识别用户是在看公司、行业、财报、模型、事件还是调研准备,并自动串联对应的投研 skills,优先直接产出可决策摘要而不是反复追问。
inputs:
- 公司名 / 股票代码 / 行业 / 主题 / 事件 / 文件
outputs:
- 整合型投研一页纸摘要
data_sources: 见 ../../core/adapters.md
markets: [CN-A, CN-FUND, HK, US, GLOBAL]
---
# SM Autopilot
这是整套投研 skill 组的"默认入口"。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Autopilot 特别注意:用户通常只给极少信息,preamble Step 4 的 [Preflight] 必须明确声明本次自动路由到了哪个 / 哪几个 sm-* 子 skill。
目标不是让使用者自己判断该用哪个 skill,而是让使用者只要给出最少的信息,比如:
- 一个公司名
- 一个行业 / 主题
- 一条新闻 / 一个事件
- 一个模型文件 / 财报 / PPT / 纪要
- 一句模糊需求
就能自动走到接近资深分析师工作流的输出。
## 最低输入要求
下面几种输入,任意一种都可以直接开工:
1. `公司 / 股票名` 例:`中际旭创怎么看`
2. `行业 / 主题` 例:`帮我看一下AI眼镜`
3. `事件` 例:`英伟达发布会对A股算力链影响`
4. `文件` 上传财报、模型、纪要、PPT,然后说 `帮我看重点`
5. `一个动作` 例:`帮我做财报前瞻`
如果用户只给了极少信息,不要立刻要求补一长串背景。优先基于默认规则推进,并在最后列出假设。
## 默认路由规则
收到任务后,先自动判断主任务类型,再决定调用哪些技能思路。不要把路由过程完整展示给用户,只展示整合后的最终结果。
### 1. 公司判断
**触发**:出现公司名、股票名、ticker;问"怎么看 / 值不值得看 / 给个判断"
**链路**:`sm-company-deepdive` → `sm-consensus-watch` → `sm-red-team`(轻量版)→ `sm-pm-brief`
**默认输出**:一页纸投资摘要
### 2. 行业 / 主题判断
**触发**:出现赛道、主题、产业链、行业
**链路**:`sm-thesis` → `sm-industry-map` → `sm-pm-brief`
**默认输出**:主线判断 + 产业链地图 + 核心跟踪指标
### 3. 财报前后任务
**触发**:出现财报、业绩、指引、预告、业绩会
**链路**:`sm-earnings-preview` → `sm-consensus-watch` → (如有模型)`sm-model-check` → `sm-pm-brief`
**默认输出**:财报前瞻摘要
### 4. 模型检查
**触发**:上传模型文件;提到盈利预测、估值、DCF、假设、勾稽
**链路**:`sm-model-check` → (如需)`sm-red-team` → `sm-pm-brief`
**默认输出**:模型风险摘要 + 待核验清单
### 5. 事件驱动 / 新闻影响
**触发**:出现政策、订单、价格、会议、发布会、出口限制、新产品、专家会
**链路**:`sm-catalyst-monitor` → `sm-consensus-watch` → `sm-pm-brief`
**默认输出**:事件影响判断 + 受益/受损方向 + 跟踪清单
### 6. 路演 / 调研 / 业绩会准备
**触发**:出现路演、调研、专家访谈、业绩会提问、管理层交流
**链路**:`sm-roadshow-questions` → (如需)`sm-thesis` 或 `sm-company-deepdive`
**默认输出**:可直接使用的问题清单
## 默认假设补全
如果用户没给完整背景,按下面规则自动补全,不要因为小缺口就停下来。
### 时间窗默认值
- 公司判断:未来 `3个月`
- 行业 / 主题:未来 `6个月`
- 财报任务:`当前季度` + `下季度指引`
- 模型检查:`未来12个月`,年度口径按 `未来2个财年`
- 事件驱动:`未来1周到1个季度`
### 输出默认值
如果用户没指定格式,默认输出:一句话结论 / 核心逻辑 / 关键证据 / 市场预期或预期差 / 催化剂或验证点 / 风险与证伪点 / 下一步行动
用户只说"简单看看"也不要只写两句话,仍要给一个可决策版本,只是压缩篇幅。
### 比较基准默认值
- A股:默认相对 `沪深300`
- 港股:默认相对 `恒生指数`
- 美股:默认相对 `标普500` 或 `纳指`
- 财报或模型:默认相对 `市场一致预期`
### 证据默认值
- 优先使用用户提供材料
- 无材料时,按 [../../core/adapters.md](../../core/adapters.md) 的兜底协议,基于公开信息框架输出,但必须明确哪些是待验证假设
## 追问规则
默认不要追问。只有下面三种情况允许追问一个问题:
- 同名公司 / 标的明显歧义
- 用户想要正式评级、目标价、盈利预测调整(合规边界)
- 上传了多个文件,但任务目标完全不明确
其他情况直接做,并在最后写 `本次默认假设`。
## 输出风格
优先输出最终整合稿,而不是把每个 skill 的中间过程都摊给用户看。
默认输出顺序:
1. `一句话结论`
2. `为什么现在值得看`
3. `核心逻辑`
4. `关键证据 / 预期差`(带证据等级 F1/F2/M1/C1/H1)
5. `最关键催化`
6. `最大风险与证伪点`
7. `下一步要做什么`
8. `本次默认假设`
## 极简使用法
以下输入都应能直接产出高质量结果:
- `请用 sm-autopilot 看一下宁德时代`
- `请用 sm-autopilot 看一下AI眼镜`
- `请用 sm-autopilot 做中芯国际财报前瞻`
- `请用 sm-autopilot 检查我上传的模型`
- `请用 sm-autopilot 给我准备寒武纪业绩会提问`
## 内部优先级
任务不明确时按以下优先级处理:
1. 先定义用户真正要解决的研究问题
2. 再选主 skill 路线
3. 再用其他 skill 作为辅助补强
4. 最后统一压缩成一个高密度输出
不要把用户变成调度员。这个 skill 的职责就是替用户做调度。
## 参考
- [../../core/workflows.md](../../core/workflows.md)
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/templates.md](../../core/templates.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/adapters.md](../../core/adapters.md)
- [../../core/markets.md](../../core/markets.md)
FILE:skills/sm-batch-earnings/SKILL.md
---
name: sm-batch-earnings
description: 财报季批量前瞻 / 复盘 skill。用于在一周或一个财报季内批量产出多家覆盖标的的财报前瞻或财报后复盘,按发布日期排序,统一输出格式,方便分析师团队在密集财报季高效响应。
inputs:
- 时间窗(如"下周"、"2026-Q1 财报季")
- 可选:标的范围(覆盖池子集 / 行业 / 全量)
- 可选:模式(preview 前瞻 / postmortem 复盘)
outputs:
- 按发布日期排序的批量财报报告
- 每家公司的标准前瞻或复盘
- 总体行业财报季节奏摘要
data_sources: 见 ../../core/adapters.md
markets: [CN-A, HK, US]
---
# SM Batch Earnings
这个 skill 用于**财报季的批量前瞻或复盘**——分析师团队在财报季最痛的时间窗。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Batch Earnings 特别注意:每家公司的子任务必须**完整调用 `sm-earnings-preview`** 的逻辑,不能简化。preamble Step 4 必须先列出本次时间窗内的全部财报日历。
## 适用场景
- **财报季前一周**:批量产出本周所有覆盖标的的前瞻
- **财报季中**:每天复盘前一日发布的多家结果
- **财报季后**:整合一个完整财报季的命题验证
## 工作流程
### 第一步:拉取财报日历
通过 iFind 或公司公告,拉出指定时间窗内的全部财报发布日:
```
[Earnings Calendar 2026-04-07 ~ 2026-04-14]
| 日期 | Ticker | 名称 | 类型 |
|---|---|---|---|
| 2026-04-08 | 688256 | 寒武纪 | Q1 财报 |
| 2026-04-10 | 0700 | 腾讯控股 | Q1 业绩会预告 |
| 2026-04-12 | NVDA | NVIDIA | FY26 Q1 |
```
### 第二步:按公司逐个跑完整 sm-earnings-preview
对每家公司:
- 调 `sm-earnings-preview` 完整流程
- 输出按 sm-earnings-preview 的结构
- 单家归档到 `{coverage_root}/{ticker}/earnings/{YYYY-QN}-preview.md`
### 第三步:生成总体节奏摘要
在每家完成后,汇总成一份"财报季节奏摘要":
```markdown
# Batch Earnings Preview · {Date Range}
## 本期覆盖
- N 家公司,按发布日期排序
## 行业层面观察
- AI 算力链:{X 家中 Y 家有上修指引可能}
- 半导体:{Z 家面临折旧压力高点}
- 新能源:{W 家受益储能放量}
## 高优先级关注
- 🔴 {ticker}:{为什么是高优先级}
- 🟡 {ticker}:{为什么}
## 各家详细前瞻链接
- [688256 寒武纪 Q1 Preview](coverage/688256_寒武纪/earnings/2026-Q1-preview.md)
- [688981 中芯国际 Q4 Preview](coverage/688981_中芯国际/earnings/2026-Q4-preview.md)
- ...
```
### 第四步(可选):复盘模式
如果是 postmortem 模式,对每家发布后的公司:
- 实际 vs 一致预期
- 实际 vs 你的 preview
- 对原 thesis 的影响
- 是否需要触发 sm-thesis update
## 输出验收(除通用清单外)
- [ ] 财报日历完整且按日期排序
- [ ] 每家公司的 preview / postmortem 都通过 sm-earnings-preview 的专属验收清单
- [ ] 行业层面观察非空
- [ ] 高优先级标的有显式标注
- [ ] 所有子输出已写入对应 ticker 目录
## 与其他 skill 的协作
- **每家 preview 内部**:触发 `sm-consensus-watch` 拿一致预期
- **postmortem 后**:如果实际显著偏离 preview → 触发 `sm-thesis update`
- **若高优先级**:自动建议跑 `sm-pm-brief` 给 PM 一页纸
- **批量收尾**:自动建议跑 `sm-briefing` 整合成晨会要点
## 性能与节流
- 大批量任务(>10 家)建议拆批执行
- 在 active-tasks.md 记录"批次进度",断点续做
- 单次会话不超过 20 家,超过分多个会话
## 参考
- [../../core/preamble.md](../../core/preamble.md)
- [../../core/postamble.md](../../core/postamble.md)
- [../../core/output-archive.md](../../core/output-archive.md)
- [../../core/acceptance.md](../../core/acceptance.md)
- [../sm-earnings-preview/SKILL.md](../sm-earnings-preview/SKILL.md)
FILE:skills/sm-batch-refresh/SKILL.md
---
name: sm-batch-refresh
description: 覆盖池批量刷新 skill。用于按周/月节奏批量更新覆盖公司的最新行情、财务、股东、催化剂等关键数据,并自动写入每家公司的归档目录。适合分析师团队维护几十到几百家覆盖标的。
inputs:
- 覆盖池清单(默认从 coverage_root/INDEX.md 读取)
- 可选:刷新范围(全量 / 子赛道 / 单家)
- 可选:刷新维度(全部 / 行情 / 财务 / 股东 / 催化剂)
outputs:
- 每家标的的批量更新摘要
- 失败标的清单 + 原因
- 总体覆盖池健康度报告
data_sources: 见 ../../core/adapters.md
markets: [CN-A, CN-FUND, HK, US]
---
# SM Batch Refresh
这个 skill 用于**批量维护覆盖公司池**——分析师团队最高频但最枯燥的工作。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Batch Refresh 特别注意:preamble Step 4 的 [Preflight] 必须列出本次刷新的标的清单 + 维度 + 预计的工具调用次数,确保用户知道这是大批量任务。
## 适用场景
- **每周一早晨**:刷新全部覆盖池的行情、本周公告、本周新闻
- **每月第一个工作日**:刷新所有公司的财务指标 + 股东结构
- **每季度财报季前**:批量预拉财报披露日历
- **临时全扫**:行业事件后批量看影响("美国限令更新,扫一遍 AI 算力链")
## 核心任务
1. **读取覆盖池清单**:从 `{coverage_root}/INDEX.md` 拉全部 ticker
2. **筛选范围**:按用户指定(全量 / 子赛道 / 个别)筛
3. **逐个执行**:对每个 ticker 调用对应的取数工具
4. **自动归档**:每家更新写入 `{coverage_root}/{ticker}_{name}/data/{YYYY-MM-DD}-refresh.md`
5. **生成总报告**:汇总成功 / 失败 / 显著变化
## 输出格式
### 总体摘要
```markdown
# Batch Refresh · {YYYY-MM-DD}
**范围**:{全量 82 家 / 光模块子赛道 22 家 / ...}
**维度**:{行情+公告+新闻 / 全部财务字段 / ...}
**用时**:{X 分钟}
## 摘要
- ✅ 成功更新:N 家
- ⚠️ 部分成功:M 家
- ❌ 失败:K 家
## 显著变化(关注点)
| Ticker | 名称 | 变化类型 | 详情 |
|---|---|---|---|
| 688256 | 寒武纪 | 重大公告 | 新增订单合同 (F2) |
| 688981 | 中芯国际 | 财务异常 | Q4 毛利率超预期 (F2) |
## 失败清单
| Ticker | 名称 | 失败原因 |
|---|---|---|
| {ticker} | {name} | iFind 超时 / 数据未披露 |
```
### 每家标的的更新明细(写入 data/ 目录)
```markdown
# {ticker} {name} · Refresh {YYYY-MM-DD}
## 行情快照
- 收盘价 / 周涨跌 / 月涨跌 / YTD (F2-iFind)
## 财务最新
- 最近一期 PE / PB / PS / ROE (F2-iFind)
- 营收 / 净利 / 毛利率 同比 (F2-iFind)
## 股东变化
- 十大股东最新一期 (F2-iFind)
- 与上一期对比 (C1)
## 本周公告 / 新闻
- {公告 1} (F2)
- {新闻 1} (M1)
## 自动告警
- ⚠️ 任何"显著变化"必须在这里标出(毛利率突变、股东大幅减持、重大公告等)
## 仍需补的资料
- {缺失项}
```
## 批量执行的最佳实践
### 节流
- 每个 ticker 之间至少 200ms 间隔,避免触发数据源 rate limit
- iFind MCP 单次会话最多 100 个 query,超过分批
### 失败重试
- 任何 ticker 失败立即记入失败清单,**不要中断整个批量任务**
- 全部跑完后统一汇报失败
### 增量更新
- 对比上次 refresh 的快照,**只输出有变化的字段**
- 避免每次都把全部数据重写一遍
### 任务持久化
- 长批量任务必须支持中断恢复
- 在 active-tasks.md 里记录"已完成 N/总 M",断点继续
## 与其他 skill 的协作
- **触发深度研究**:如果某只标的检测到"显著变化",**自动**触发 `sm-catalyst-monitor` 单点分析
- **触发反方审视**:如果某只标的本周涨幅超过 20%,**自动建议**走 `sm-red-team`
- **触发命题更新**:如果财务数据与上一份 thesis 假设矛盾,**主动提醒**用户跑 `sm-thesis` update
## 输出验收(除通用清单外)
- [ ] 已列出本次刷新的标的清单
- [ ] 每个标的有"更新的字段"摘要
- [ ] 失败的标的明确列出原因
- [ ] 显著变化已标注并触发后续 skill 建议
## 参考
- [../../core/preamble.md](../../core/preamble.md)
- [../../core/postamble.md](../../core/postamble.md)
- [../../core/output-archive.md](../../core/output-archive.md)
- [../../core/acceptance.md](../../core/acceptance.md)
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/compliance.md](../../core/compliance.md)
FILE:skills/sm-briefing/SKILL.md
---
name: sm-briefing
description: 晨会、晚报、调研纪要和路演提纲整理 skill。用于把零散信息整理成适合投研团队和基金经理阅读的结构化摘要,并明确最重要的事项、覆盖池影响和待跟踪问题。
inputs:
- 零散材料(新闻、纪要、公告、路演记录)
- 可选:覆盖池清单
outputs:
- 晨会/晚报结构化摘要
data_sources: 见 ../../core/adapters.md
markets: [CN-A, CN-FUND, HK, US, GLOBAL]
---
# SM Briefing
这个 skill 用于把材料整理成投研团队能直接使用的摘要。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Briefing 特别注意:通常需要拉近 24 小时内的资讯,preamble Step 4 的 [Preflight] 必须包含资讯类工具调用。
适用场景:
- 晨会要点
- 收盘复盘
- 调研纪要
- 路演摘要
- 问题清单
## 默认输出格式
- `今日最重要的三件事`
- `对覆盖池 / 组合的影响`
- `最值得跟踪的公司或方向`
- `待回答问题`
- `一句话给基金经理`
如果用户要调研提纲,改为输出:
- `调研目的`
- `必问问题`
- `不同回答分别意味着什么`
## 参考
- [../../core/templates.md](../../core/templates.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/adapters.md](../../core/adapters.md)
FILE:skills/sm-catalyst-monitor/SKILL.md
---
name: sm-catalyst-monitor
description: 事件催化与财报前瞻 skill。用于跟踪政策、财报、价格、订单、产品发布、产业数据等催化剂,判断其对收入、利润、估值或情绪的影响,并输出短中期跟踪清单。
inputs:
- 事件 / 新闻 / 政策 / 产业数据
- 可选:相关公司或板块清单
outputs:
- 事件影响判断 + 短中期跟踪清单
data_sources: 见 ../../core/adapters.md
markets: [CN-A, HK, US, GLOBAL]
---
# SM Catalyst Monitor
这个 skill 用于事件驱动研究和财报前瞻,不是简单新闻摘要。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Catalyst Monitor 特别注意:事件跟踪需要交叉多源(政策 + 公告 + 行业媒体),preamble Step 4 的 [Preflight] 必须列出至少 2 个独立信源。
## 核心任务
- 判断事件影响方向
- 区分一次性扰动和趋势性变化
- 判断影响收入、利润、估值还是风险偏好
- 给出跟踪节奏
## 输出格式
- `事件概述`
- `为什么重要`
- `影响路径`
- `最相关的公司 / 板块`
- `对盈利 / 估值 / 情绪的影响`
- `接下来一周到一个季度的跟踪清单`
## 典型适用任务
- 财报前瞻
- 政策点评
- 产业价格周跟踪
- 新品发布影响分析
- 订单 / 渠道 / 出货节奏变化跟踪
## 参考
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/templates.md](../../core/templates.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/adapters.md](../../core/adapters.md)
FILE:skills/sm-catalyst-sweep/SKILL.md
---
name: sm-catalyst-sweep
description: 覆盖池每日 / 每周催化剂扫描 skill。用于在固定时间窗内扫描全部覆盖标的的公告、新闻、政策、价格异动等催化剂信号,按重要性分级并关联到具体标的。适合做晨会前批量扫描和持仓异动监控。
inputs:
- 时间窗(默认 24 小时)
- 可选:标的范围(默认全覆盖池)
- 可选:催化剂类型筛选(公告 / 新闻 / 价格异动 / 政策)
outputs:
- 按重要性分级的催化剂清单
- 每条催化剂关联到具体 ticker 和影响判断
- 高优先级催化剂的后续 skill 调用建议
data_sources: 见 ../../core/adapters.md
markets: [CN-A, CN-FUND, HK, US, GLOBAL]
---
# SM Catalyst Sweep
这个 skill 用于**批量扫描覆盖池的所有催化剂信号**——分析师晨会前最该跑一次。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Catalyst Sweep 特别注意:preamble Step 4 必须明确时间窗(默认过去 24 小时),并按"覆盖池 → 子赛道 → 全市场"三层依次扫描。
## 适用场景
- **每日晨会前 30 分钟**:扫一遍覆盖池过去 24 小时的所有催化
- **重大事件后**:扫一遍受影响的子赛道("美国对华出口管制更新,扫一遍 AI 算力链")
- **每周一早晨**:扫上周末的政策、产业新闻、海外动态
- **持仓异动告警**:股价异常变动后追溯催化原因
## 工作流程
### 第一步:定义扫描范围
```
[Preflight - Sweep]
时间窗:{2026-04-06 09:00 ~ 2026-04-07 09:00}
标的范围:覆盖池 82 家
催化类型:公告 / 新闻 / 价格异动 / 政策
预计调用:iFind search_notice (82 次) + search_trending_news (按子赛道)
```
### 第二步:分类型扫描
**类型 A:公司层公告**
- 对每家覆盖标的调 `iFind.search_notice query="{name} 最近24小时公告"`
- 命中的写入候选清单
**类型 B:行业 / 政策新闻**
- 按子赛道调 `iFind.search_trending_news query="{sector} 今日热点"`
- 国家级政策调 `WebSearch site:gov.cn` 或新华社
**类型 C:价格异动**
- 调 `iFind.get_stock_performance` 拿覆盖池涨跌幅
- 标记 |变动| > 5% 的标的
### 第三步:按重要性分级
每条命中按以下标准打分:
| 级别 | 标准 | 处理 |
|---|---|---|
| 🔴 高 | 直接影响盈利预测的事件(重大合同、业绩预告、监管处罚) | 必须人工立即看 + 触发 sm-catalyst-monitor |
| 🟡 中 | 影响估值或叙事的事件(政策变化、行业数据) | 写入晨会要点 |
| 🟢 低 | 仅作为背景信息(一般新闻、例行公告) | 归档到 catalyst-log |
### 第四步:输出总扫描报告
```markdown
# Catalyst Sweep · {YYYY-MM-DD HH:MM}
**时间窗**:过去 24 小时
**覆盖范围**:82 家覆盖标的 + 5 个行业 + 政策面
**总命中**:N 条事件
## 🔴 高优先级(M 条)
### 1. {ticker} {name} - {事件标题}
- **类型**:业绩预告 / 重大合同 / 监管 / ...
- **影响方向**:⬆️ / ⬇️ / 中性
- **影响路径**:{一句话说明对哪个变量的影响}
- **建议下一步**:调 sm-catalyst-monitor 做深度分析
- **证据**:F2 - {链接}
### 2. ...
## 🟡 中优先级(K 条)
| Ticker | 名称 | 事件 | 影响方向 | 证据 |
|---|---|---|---|---|
| ... | ... | ... | ⬆️/⬇️ | F2 |
## 🟢 低优先级(J 条 - 仅归档)
[折叠列表]
## 行业级观察
- {子赛道 1}:{今日整体情绪/事件}
- {子赛道 2}:{今日整体情绪/事件}
## 政策面
- {国家级政策 1}
- {国家级政策 2}
## 价格异动 Top 5
| Ticker | 涨跌幅 | 原因(如已知) |
|---|---|---|
| ... | +X% | ... |
```
## 与其他 skill 的协作
- **🔴 高优先级标的** → **自动建议**调 `sm-catalyst-monitor` 做单事件深度
- **行业级共振** → **自动建议**调 `sm-industry-map update`
- **多个高优先级** → **自动建议**调 `sm-briefing` 整合成晨会要点
- **价格异动 Top 1-2** → **自动建议**调 `sm-red-team` 检查多空逻辑
## 输出验收(除通用清单外)
- [ ] 时间窗明确(具体到小时)
- [ ] 命中事件按 高/中/低 三级分类
- [ ] 每条命中关联具体 ticker(不能是"行业利好")
- [ ] 价格异动 Top 5 已附
- [ ] 高优先级事件都给出"建议下一步" skill
## 性能与节流
- 全量扫 82 家公告 + 行业新闻约需 5-8 分钟
- 节流:每个 query 之间 200ms
- 失败的标的记入失败清单,不中断扫描
- 进度写入 active-tasks.md
## 与 sm-batch-refresh 的区别
| 维度 | sm-catalyst-sweep | sm-batch-refresh |
|---|---|---|
| **频率** | 每日(24h 时间窗) | 每周/每月 |
| **重点** | 事件 / 催化 / 异动 | 财务 / 行情 / 股东 |
| **输出** | 行动导向(建议下一步) | 数据导向(更新数据) |
| **协作** | 触发 sm-catalyst-monitor | 触发 sm-thesis update |
两者互补,建议都跑。
## 参考
- [../../core/preamble.md](../../core/preamble.md)
- [../../core/postamble.md](../../core/postamble.md)
- [../../core/output-archive.md](../../core/output-archive.md)
- [../../core/acceptance.md](../../core/acceptance.md)
- [../sm-catalyst-monitor/SKILL.md](../sm-catalyst-monitor/SKILL.md)
- [../sm-briefing/SKILL.md](../sm-briefing/SKILL.md)
FILE:skills/sm-company-deepdive/SKILL.md
---
name: sm-company-deepdive
description: 二级市场公司深度研究 skill。用于拆解公司商业模式、收入利润驱动、产业链位置、竞争壁垒、关键客户、财务弹性和未来三个月跟踪指标。适合覆盖启动、公司更新和财报前准备。
inputs:
- 公司名 / 股票代码
- 可选:研究材料、年报、纪要、卖方摘要
outputs:
- 公司深度跟踪卡(9 段)
data_sources: 见 ../../core/adapters.md
markets: [CN-A, HK, US]
---
# SM Company Deepdive
这个 skill 用于公司层面的深度研究,不写空泛概述,要尽量回答"为什么是这家公司,而不是别人"。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Company Deepdive 是最吃数据的 skill,缺数据时**严禁**开始输出结论。如果 preamble 拿不到关键数据(最近一期财报、股东、可比公司),必须走兜底协议让用户贴材料。
适用场景:
- 覆盖启动
- 公司更新
- 财报前准备
- 可比公司比较
## 必答问题
- 公司在产业链里的位置是什么
- 收入增长靠什么驱动
- 利润弹性来自哪里
- 市场当前为什么关注它
- 与同行相比真正不同的地方是什么
- 下一个验证节点是什么
## 输出格式
- `公司定位`
- `业务拆分`
- `收入驱动`
- `利润驱动`
- `核心竞争力 / 风险点`
- `市场关注焦点`
- `与可比公司的关键差异`
- `未来三个月跟踪指标`
- `仍需补的资料`
## 约束
- 没有证据时,不要假设客户、订单或份额变化
- 避免把管理层表述直接当成事实
- 优先突出影响盈利和估值的变量
- 关键事实必须带证据等级(F1/F2/M1/C1/H1)
## 参考
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/templates.md](../../core/templates.md)
- [../../core/adapters.md](../../core/adapters.md)
- [../../core/markets.md](../../core/markets.md)
FILE:skills/sm-consensus-watch/SKILL.md
---
name: sm-consensus-watch
description: 一致预期与预期差管理 skill。用于判断市场已 price in 的内容、被低估或高估的变量、盈利与估值的偏差来源,以及哪些边际变化可能带来股价重估。适合财报季、估值切换和预期差挖掘。
inputs:
- 公司名 / 行业
- 可选:卖方一致预期、市场观点、公司指引
outputs:
- 预期差矩阵与验证节点
data_sources: 见 ../../core/adapters.md
markets: [CN-A, HK, US]
---
# SM Consensus Watch
这个 skill 用于研究"市场在想什么"以及"市场可能错在哪"。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Consensus Watch 特别注意:必须重点获取卖方一致预期(iFind `get_stock_performance` 或卖方研报摘要),缺这层数据时**禁止**输出预期差判断,必须明确告知用户"无法判断预期差"并走兜底。
## 核心任务
- 识别市场共识
- 判断哪些变量已被定价
- 找出边际变化
- 分析预期差对盈利、估值和仓位的影响
## 输出格式
- `市场共识`
- `已 price in 的内容`
- `可能未充分反映的变量`
- `预期差成立条件`
- `对盈利预测 / 估值锚 / 仓位讨论的影响`
- `最关键验证节点`
## 约束
- 不要把"我觉得"当作共识
- 不要脱离时间窗口谈预期差
- 尽量写清比较基准和估值语境
- 市场共识标 `M1`,被低估变量的支撑证据标 `F1`/`F2`
## 参考
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/templates.md](../../core/templates.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/adapters.md](../../core/adapters.md)
FILE:skills/sm-earnings-preview/SKILL.md
---
name: sm-earnings-preview
description: 证券分析师专用的财报前瞻与财报后验证 skill。用于围绕一致预期、模型假设、市场关注点和管理层指引,输出财报前需要验证的核心问题、潜在超预期或低于预期项,以及财报发布后的第一时间检查清单。
inputs:
- 公司名 + 财报日期
- 可选:历史财报、一致预期、卖方摘要、自建模型
outputs:
- 财报前瞻摘要 + 财报后第一时间检查清单
data_sources: 见 ../../core/adapters.md
markets: [CN-A, HK, US]
---
# SM Earnings Preview
这个 skill 用于财报季最常见的两类任务:
- 财报前瞻
- 财报后第一时间验证
目标不是重复一遍公司背景,而是回答"这次财报最该看什么,市场会对什么最敏感,什么结果会改变原来的投资命题"。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Earnings Preview 特别注意:preamble Step 4 的 [Preflight] 必须包含历史财务数据 + 一致预期 + 近期公告 + 行业同业数据 4 类。preamble Step 2 必须读取该公司最近一次 deepdive 和 thesis 输出作为基线。
## 适用场景
- "帮我做下周财报前瞻"
- "这次市场最关心哪三个问题"
- "财报后我要先核验什么"
- "哪些项目可能超预期 / 低于预期"
## 工作方式
默认按以下顺序输出:
1. 明确市场最关心的问题
2. 写清本次财报的关键变量
3. 区分收入、毛利、费用、现金流、指引五个层面的敏感项
4. 识别潜在超预期和低于预期来源
5. 给出财报后第一时间验证清单
## 输出格式
- `一句话判断`
- `市场最关心的三个问题`
- `本次财报最敏感的变量`
- `潜在超预期点`
- `潜在低于预期点`
- `管理层指引最该听什么`
- `财报后第一时间检查清单`
- `若结果不同于预期,对原投资逻辑意味着什么`
## 分析要求
- 一定要写清比较基准(同比、环比、相对一致预期)
- 一定要写清时间窗口(本季、下季指引、半年)
- 一定要区分"影响盈利"和"影响估值"的变量
- 如果用户给了模型、预期或卖方摘要,要优先基于这些材料展开
## 约束
- 不要凭空捏造一致预期数字
- 不要把管理层口径默认视为高可信度事实
- 没有足够信息时,应明确列出仍待验证项
## 参考
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/templates.md](../../core/templates.md)
- [../../core/adapters.md](../../core/adapters.md)
FILE:skills/sm-industry-map/SKILL.md
---
name: sm-industry-map
description: 二级市场行业框架与产业链拆解 skill。用于构建行业研究框架、供需逻辑、价格传导、竞争格局、关键公司地图和当前市场争议点。适合行业深度、主线梳理和赛道筛选。
inputs:
- 行业 / 主题名称
- 可选:已有研究材料、产业链初步认知
outputs:
- 行业框架图 + 关键公司地图 + 跟踪指标
data_sources: 见 ../../core/adapters.md
markets: [CN-A, HK, US, GLOBAL]
---
# SM Industry Map
这个 skill 用于行业和赛道层面的研究框架搭建。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Industry Map 特别注意:preamble Step 4 的 [Preflight] 必须包含产业链代表公司清单 + 行业指标 + 行业报告政策 3 类。归档路径在 `themes/{theme-slug}/`。
适用场景:
- 行业深度
- 赛道梳理
- 主题投资主线判断
- 周期与景气跟踪
## 输出重点
- 产业链地图
- 需求驱动因素
- 供给格局
- 价格与利润传导机制
- 关键公司定位
- 当前争议点和预期差来源
## 输出格式
- `行业一句话判断`
- `产业链结构`
- `需求侧驱动`
- `供给侧变化`
- `价格 / 利润传导`
- `重点公司与分工`
- `当前市场争议点`
- `最值得跟踪的行业指标`
## 约束
- 不要只列公司名单
- 不要把宏观背景写得过长
- 最终要落到"谁受益、谁受损、何时验证"
## 参考
- [../../core/workflows.md](../../core/workflows.md)
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/templates.md](../../core/templates.md)
- [../../core/adapters.md](../../core/adapters.md)
- [../../core/markets.md](../../core/markets.md)
FILE:skills/sm-master/SKILL.md
---
name: sm-master
description: 二级市场投研总控 skill(长形态)。7 种模式 Thesis/Coverage/Consensus/Catalyst/Red Team/Briefing/PM Prep 的全量说明,适合当作"单一 skill 入口"独立使用。若已安装完整 Investor Harness 套件,优先用 sm-autopilot 做路由,再进入各专门 skill。
inputs:
- 公司名 / 股票代码 / 行业 / 主题
- 可选:研究材料、财务模型、纪要、新闻链接
outputs:
- 按 7 模式之一产出结构化分析
data_sources:
- 见 ../../core/adapters.md
markets:
- CN-A
- CN-FUND
- HK
- US
- GLOBAL
license: MIT
---
# SM Master(二级市场投研总控)
这是 Investor Harness 的**长形态总控 skill**。如果你只想装一个 skill 就能跑全套流程,用这个。如果你装了完整套件(12 个专业子 skill),请优先使用 `sm-autopilot` 路由到具体子 skill。
## 适用对象
- 持牌证券分析师
- 买方研究员 / 基金经理 / 助理研究员
- 需要快速形成"观点、证据、催化、风险、跟踪清单"的投研团队
## 不适用场景
- 自动下单、交易执行、收益承诺
- 绕过研究合规、信息隔离墙或保密要求
- 将未经核验的传闻直接写成投资结论
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
SM Master 特别注意:作为长形态总控,必须在 [Preflight] 中**显式声明本次走的是 7 种模式中的哪一种**,并按对应模式的结构输出。
## 启动原则
收到投研类任务后,先判断当前任务属于哪一种模式,再按该模式输出,不要一上来就写长篇结论。
### 7 种模式
1. `Thesis`:形成投资主线、判断核心矛盾、拆解研究问题
2. `Coverage`:行业或公司深度跟踪
3. `Consensus`:一致预期、市场预期差、估值锚变化
4. `Catalyst`:事件驱动、财报、政策、价格、订单、产品周期跟踪
5. `Red Team`:反方论证、证伪路径、风险情景
6. `Briefing`:晨会纪要、收盘复盘、路演纪要、调研提纲
7. `PM Prep`:面向基金经理的决策摘要
### 模式自动选择规则
用户没有明确指定模式时:
- "怎么看 / 值不值得配 / 核心逻辑是什么" → `Thesis`
- "深挖某行业 / 某公司" → `Coverage`
- "预期差 / 一致预期 / 市场没反映什么" → `Consensus`
- "财报前看什么 / 催化剂 / 近期怎么跟踪" → `Catalyst`
- "反过来想 / 空头怎么看 / 最大的风险" → `Red Team`
- "整理成晨会 / 日报 / 纪要" → `Briefing`
- "给投资经理一页纸" → `PM Prep`
## 通用工作流
每次执行投研任务时遵循以下顺序:
1. **定义问题**:明确是行业判断、公司判断、事件判断,还是组合判断
2. **确定研究边界**:市场范围、时间窗口、比较基准、关键假设
3. **列证据清单**:事实、市场预期、可验证推演、待核验线索四类
4. **提炼核心矛盾**:什么变量决定股价,而不是只堆信息
5. **构造多空框架**:主逻辑、反逻辑、证伪点、跟踪指标
6. **输出行动项**:下一步应补的数据、要约的专家、要追的财报字段、需要更新的模型项
**不要**把以下几类内容混在一起:已证实事实、市场传闻、基于事实的推演、投资结论。必须显式标注哪些是事实,哪些是推演。
## 输出纪律
默认输出结构化、短结论、高信息密度,不追求"像研报",追求"可用于继续研究和决策"。
### 标准输出模块
1. `一句话结论`
2. `核心逻辑`
3. `关键证据`(带证据分级 F1/F2/M1/C1/H1)
4. `市场预期 / 预期差`
5. `催化剂`
6. `主要风险与证伪点`
7. `需继续核验的问题`
8. `下一步行动`
**如果信息不足**,不要强行给评级或目标价。先输出"当前不能下结论的原因"和"补足结论所需信息"。
---
## 模式细则
### Thesis
把模糊题目收敛成可研究、可验证、可跟踪的投资命题。
必须回答:
- 真正驱动股价的核心变量是什么
- 当前市场是否存在错误定价或错误预期
- 这是景气投资、困境反转、周期拐点、份额提升,还是估值切换
- 结论最可能被什么事实推翻
输出格式:
- 投资命题
- 命题成立的三个必要条件
- 当前最关键的验证点
- 最值得先跟踪的三项数据
### Coverage
行业深度、公司深度、覆盖启动和持续跟踪。
**覆盖行业时**至少包含:产业链地图、需求驱动、供给格局、价格与利润传导、关键公司定位、市场当前争议点
**覆盖公司时**至少包含:公司在产业链的位置、收入拆分与利润驱动、核心产品/客户/竞争壁垒、本轮市场关注点、与可比公司的异同、后续三个月最重要的跟踪指标
### Consensus
一致预期管理和预期差挖掘。重点不是复述共识,而是区分:
- 市场已经 price in 的内容
- 市场还没 price in 的边际变化
- 预期差来自哪里
- 变化是否足以穿透估值
输出格式:市场共识 → 被低估/高估的变量 → 预期差成立条件 → 对估值与仓位讨论的影响
### Catalyst
财报前瞻、政策点评、产业事件、订单、价格数据、产品发布等催化跟踪。
不是"新闻摘要",而是:
- 判断事件影响方向和持续性
- 判断影响的是收入、利润、估值,还是风险偏好
- 判断这是一次性扰动还是趋势性变化
输出格式:事件是什么 → 为什么重要 → 对哪些公司最相关 → 对盈利/估值/情绪分别影响 → 接下来一周到一个季度怎么跟踪
### Red Team
强制反方审视,防止单边叙事。至少输出:
- 多头最脆弱的三个假设
- 若结论错误,最早会在哪里暴露
- 什么数据一旦出现就应下修观点
- 还有哪些更好的替代标的/替代方向
**禁止**只写泛泛风险(如"宏观波动""政策风险")。风险必须可观测、可触发。
### Briefing
晨会、晚报、调研纪要、路演摘要、会议纪要。默认格式:
- 今日最重要的三件事
- 对组合或覆盖池最相关的影响
- 需要立刻跟踪/回答的问题
- 可转给基金经理或销售的精简表述
**调研提纲**输出:本次调研目的 → 必问问题 → 若回答 A/B/C 各自意味着什么
### PM Prep
给基金经理或投资决策会准备一页纸。压缩成"短而硬",避免大段背景介绍。
输出格式:结论 → 为什么现在看 → 市场可能错在哪 → 最关键催化 → 最大风险 → 建议下一步
---
## 证据分级
见 [../../core/evidence.md](../../core/evidence.md)。输出时为关键事实打 F1/F2/M1/C1/H1 标签。**不要**把 `H1` 当成结论核心。
## 合规边界
见 [../../core/compliance.md](../../core/compliance.md)。涉及评级、目标价、盈利预测调整时,提醒用户进行人工复核和内部合规检查。
## 模板
见 [../../core/templates.md](../../core/templates.md)。
## 默认行为
- 优先帮用户把研究问题定义清楚,而不是立即产出武断结论
- 优先给"研究框架 + 证据缺口 + 下一步动作"
- 当用户要求很笼统时,先输出一个可执行版本,而不是追问一长串问题
- 对关键数字、时间、比较基准和假设要写清楚
- 如果用户提供财务模型、会议纪要、PPT、研报摘要,应先吸收材料再进入对应模式
FILE:skills/sm-model-check/SKILL.md
---
name: sm-model-check
description: 证券分析师专用的财务模型检查 skill。用于审阅盈利预测与估值模型的关键假设、勾稽关系、收入利润桥、敏感性、情景假设和潜在断裂点,帮助发现模型里最容易误导投资结论的地方。
inputs:
- 财务模型文件(Excel)或模型结构描述
- 可选:公司历史财报、一致预期
outputs:
- 模型风险摘要 + 待核验清单
data_sources: 见 ../../core/adapters.md
markets: [CN-A, HK, US]
---
# SM Model Check
这个 skill 用于检查模型有没有把研究结论"算歪",重点不是排版,而是看模型逻辑是否站得住。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Model Check 特别注意:preamble Step 4 必须包含对比基线(模型输出 vs 历史财务 vs 一致预期)。若用户未提供模型文件,可以先按研究逻辑层面做"模型框架检查",但必须在 [Preflight] 中明确声明。
适用场景:
- 审阅盈利预测模型
- 更新财报后的模型
- 检查估值假设
- 给基金经理或研究总监过模型前做自检
## 核心任务
- 检查关键假设是否清晰
- 检查收入、毛利、费用、现金流之间是否勾稽
- 检查驱动变量与投资逻辑是否一致
- 检查估值方法和情景假设是否自洽
- 找出最可能误导结论的脆弱点
## 输出格式
- `模型目的`
- `核心假设清单`
- `收入驱动检查`
- `利润率 / 费用率检查`
- `现金流与资产负债表检查`
- `估值假设检查`
- `敏感性最高的三个变量`
- `最容易误导结论的地方`
- `需要立刻回头核验的项目`
## 检查重点
- 收入增长是否能拆到量、价、结构或客户层面
- 毛利率变化是否有合理驱动
- 费用率变化是否和扩张节奏匹配
- 现金流是否支持利润表结论
- Capex、折旧、营运资本是否自洽
- 估值倍数或目标价假设是否与赛道、阶段、可比公司匹配
## 约束
- 不要只说"模型合理"或"需要进一步验证"
- 必须指出哪一行逻辑最脆弱,以及为什么
- 若用户未提供模型文件,也可以先按研究逻辑层面做"模型框架检查"
## 参考
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/templates.md](../../core/templates.md)
- [../../core/adapters.md](../../core/adapters.md)
FILE:skills/sm-pm-brief/SKILL.md
---
name: sm-pm-brief
description: 面向基金经理或投资决策会的一页纸摘要 skill。用于把复杂研究压缩成高密度、可决策的短结论,突出为什么现在看、市场错在哪、核心催化、主要风险和下一步行动。
inputs:
- 前置研究结论或多份研究材料
outputs:
- 一页纸决策摘要
data_sources: 见 ../../core/adapters.md
markets: [CN-A, CN-FUND, HK, US, GLOBAL]
---
# SM PM Brief
这个 skill 用于把研究结论压缩成决策材料。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
PM Brief 特别注意:preamble Step 2 必须读取该公司**所有最近的相关 skill 输出**(thesis / deepdive / consensus / red-team / earnings)作为输入。PM Brief 的价值就是整合,没有前置研究等于没法做。
## 输出原则
- 短
- 硬
- 可决策
- 少背景,多判断
## 输出格式
- `结论`
- `为什么现在看`
- `市场可能错在哪`
- `最关键催化`
- `最大风险`
- `建议下一步`
## 约束
- 避免大段背景复述
- 避免使用不带边界的形容词
- 写清时间窗口和假设前提
- 涉及评级或目标价必须提醒人工复核
## 参考
- [../../core/templates.md](../../core/templates.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/adapters.md](../../core/adapters.md)
FILE:skills/sm-red-team/SKILL.md
---
name: sm-red-team
description: 二级市场反方论证与证伪 skill。用于对现有多头逻辑做空头审视,识别脆弱假设、证据断层、可能踩空的变量、替代标的和最早暴露错误的数据点,帮助降低单边叙事风险。
inputs:
- 现有多头逻辑(结论 + 支撑证据)
- 可选:公司或行业材料
outputs:
- 空头审视报告与证伪路径
data_sources: 见 ../../core/adapters.md
markets: [CN-A, HK, US]
---
# SM Red Team
这个 skill 专门负责"唱反调",目的是降低确认偏误。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Red Team 特别注意:preamble Step 4 的取数必须包含历史类似案例 + 行业周期拐点信号 + 空头观点 3 类。**强制读取用户的 `biases.md` 文件**并在结论中显式报告命中情况——这是 Red Team 区别于其他工具的核心。
适用场景:
- 多头逻辑太顺时
- 准备提交正式观点前
- 财报前或建仓前
- 市场高度一致时
## 输出格式
- `多头逻辑最脆弱的三个假设`
- `哪些证据目前还不够`
- `若结论错误,最早会暴露在哪里`
- `哪些数据出现后应下修观点`
- `更好的替代标的 / 替代方向`
- `当前结论的可信度评估`
## 约束
- 风险必须尽量可观测、可触发
- 不要只写套话式风险
- 必须指向具体变量、数据或时间点
## 参考
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/adapters.md](../../core/adapters.md)
FILE:skills/sm-roadshow-questions/SKILL.md
---
name: sm-roadshow-questions
description: 证券分析师专用的路演、调研与管理层交流提纲 skill。用于围绕市场争议点、盈利驱动、指引可信度、竞争格局、资本开支和现金流,设计高价值问题,并说明不同回答分别意味着什么。
inputs:
- 公司名 + 交流对象(管理层/专家/渠道)
- 可选:已有投资命题、研究材料
outputs:
- 高价值问题清单 + 不同回答的意义
data_sources: 见 ../../core/adapters.md
markets: [CN-A, HK, US]
---
# SM Roadshow Questions
这个 skill 用于生成真正有投研价值的调研问题,而不是一套公司很容易"标准回答"的泛问题。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Roadshow Questions 特别注意:preamble Step 4 必须包含市场争议点(近期研报、新闻)+ 历史沟通记录,否则会出"纸面问题"。preamble Step 2 必须读最近一份 deepdive 和 thesis。
适用场景:
- 管理层路演
- 业绩会提问准备
- 专家访谈前问题设计
- 渠道调研前假设验证
## 核心任务
- 明确这次交流到底要验证什么
- 设计能区分不同情景的问题
- 让每个问题都对应一个待验证假设
- 提前写出不同回答各自意味着什么
## 输出格式
- `本次交流目的`
- `需要优先验证的三个假设`
- `必问问题清单`
- `每个问题背后要验证什么`
- `若回答偏强 / 中性 / 偏弱,各自意味着什么`
- `哪些问题不要问得过于泛泛`
- `交流后应如何更新观点或模型`
## 推荐问题维度
- 需求与订单节奏
- 产品结构与价格
- 毛利率和费用率
- 客户结构与份额变化
- 竞争格局
- Capex 与扩产节奏
- 现金流与库存
- 下季度或全年指引
## 约束
- 问题要具体,避免"请介绍一下业务进展"这类泛问题
- 不要诱导对方提供敏感或非公开信息
- 不要把调研提纲设计成套话式采访稿
## 参考
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/templates.md](../../core/templates.md)
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/adapters.md](../../core/adapters.md)
FILE:skills/sm-tape-review/SKILL.md
---
name: sm-tape-review
description: 二级市场盘面复盘 + 技术面分析 skill。用于日内行情复盘、收盘技术面拆解、技术指标信号解读、量价关系分析、关键支撑/压力位识别和与基本面的一致性检验。适合每日盘后、加仓/减仓决策前的技术确认、重大事件后的盘面验证。
inputs:
- 公司名 / 股票代码
- 时间窗(日内 / 5 日 / 20 日 / 60 日,默认 20 日)
- 可选:基本面命题(用于一致性检验)
outputs:
- 7 段技术复盘报告(行情 / 资金 / K 线 / 指标 / 关键位 / 一致性 / 明日观察)
data_sources:
- 见 ../../core/adapters.md
- iFind get_stock_performance(技术指标 + 技术形态)
- iFind get_stock_summary(行情快览)
- iFind get_stock_events(异动事件)
markets: [CN-A, HK, US]
---
# SM Tape Review
> 盘面复盘 + 技术面分析。这是 Investor Harness 里**唯一**的纯技术 skill。
> 不替代基本面分析,只回答两个问题:
> 1. 今天/近期价格 + 量 + 资金在说什么?
> 2. 这个技术信号和你已有的基本面命题是否一致?
## 强制流程(v0.4 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 6 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 8 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Tape Review 特别注意:
- 数据源**必须**用 iFind get_stock_performance(最权威),未拉到则降级到公开网页
- 技术指标必须**真实计算或拉取**,**禁止凭印象编造**(如"MACD 金叉"必须有实际数据支撑)
- preamble Step 2 必须读取该公司最近一次 sm-company-deepdive 和 sm-thesis 输出,用于 §6 一致性检验
## 适用场景
- **日内复盘** — "今天宁德时代怎么涨/跌的"
- **收盘技术面** — "近 20 日 K 线 + 指标看一下"
- **重大事件后验证** — 财报后 / 政策后 / 行业事件后,技术面是否反应
- **加仓/减仓决策前的技术确认** — 基本面看多,技术面是否同向?
- **逃顶/抄底参考** — 关键位置 + 量价 + 指标的综合判断
- **stop loss 位置设定** — 给出技术面硬触发
## 不适用场景
- ❌ 短线择时 / 日内交易信号(这不是炒股工具)
- ❌ 期货 / 期权 / 衍生品技术分析
- ❌ 量化策略回测
- ❌ K 线占卜 / 江恩 / 缠论等无证据流派
## 必答问题
- 今日 / 近期的价格走势属于哪种形态?
- 量价关系是否健康(量价齐升 / 价升量缩 / 缩量回调 / 放量破位)?
- 关键技术指标(MACD / KDJ / RSI / BOLL)发出了什么信号?
- 当前价格相对于关键均线(5/10/20/60/250 日)的位置?
- 最近的支撑位 / 压力位在哪?突破或破位的量能要求是多少?
- 主力资金 / 北向资金 / 龙虎榜信号?
- 这套技术信号是否支持当前的基本面命题?
## 输出格式(7 段)
### §1 行情摘要
```
日期:{YYYY-MM-DD}
时间窗:{日内 / 5 日 / 20 日 / 60 日}
收盘价:XX.XX 元 (F2)
涨跌幅:±X.XX% (F2)
振幅:X.XX% (F2)
成交量:XX 万手 vs 60 日均量 XX 万手 → 量比 X.XX (F2)
换手率:X.XX% (F2)
区间表现(时间窗内):±X.XX% (F2)
区间最大回撤:±X.XX% (F2)
```
### §2 资金面
| 维度 | 数据 | 含义 |
|---|---|---|
| 北向资金净买入(当日 / 5 日) | ±XX 亿 (F2) | 外资态度 |
| 主力净流入(当日) | ±XX 万 (F2) | 大单/特大单方向 |
| 龙虎榜(如上榜) | 买入/卖出席位 (F2) | 游资 vs 机构信号 |
| 融资余额变化 | ±X.X% (F2) | 杠杆资金信号 |
⚠️ 缺失数据明确标注,不要凭印象编。
### §3 K 线形态 + 均线系统
**K 线形态判断**(带证据):
- {形态名,如"放量长阳"/"缩量十字星"/"长上影"/"破位阴线"} (F1-K 线观察)
- 形态出现在什么位置?(趋势中段 / 顶部区域 / 底部区域 / 关键位附近)
**均线系统**(按 5/10/20/60/250 日):
- 当前价格 vs 各均线位置:✅ 之上 / ❌ 之下
- 均线排列:多头排列 / 空头排列 / 纠缠
- 关键均线穿越:是否发生?哪两条?
**量价关系**:
- {量价齐升 / 价升量缩 / 缩量回调 / 放量破位 / 横盘缩量} (C1-基于成交量数据推演)
- 是否健康?
### §4 技术指标信号
| 指标 | 当前值 | 信号 | 历史对比 |
|---|---|---|---|
| MACD (DIF/DEA/MACD) | XX/XX/XX (F2) | 金叉/死叉/0 轴附近 | vs 上次 |
| KDJ (K/D/J) | XX/XX/XX (F2) | 超买/超卖/中性 | — |
| RSI (6/14/24) | XX/XX/XX (F2) | 超买/超卖/中性 | — |
| BOLL (上轨/中轨/下轨) | XX/XX/XX (F2) | 价格位置 | 带宽变化 |
| ATR (14 日) | X.XX (F2) | 波动率 | vs 60 日均 |
| OBV | 趋势 (F2) | 量能背离/同步 | — |
**信号汇总**:
- 共振方向:多 / 空 / 中性
- 背离信号:是否存在(顶背离 / 底背离)
- 信号强度:强 / 中 / 弱
⚠️ **禁止**凭印象写"金叉"、"超买"——必须有实际数据。
### §5 关键位
```
压力位:
- 短期压力:XX.XX 元 (基于 N 日高点 / 均线 / 形态)
- 中期压力:XX.XX 元
支撑位:
- 短期支撑:XX.XX 元 (基于 N 日低点 / 均线 / 形态)
- 中期支撑:XX.XX 元
- 强支撑:XX.XX 元 (250 日均线 / 历史成交密集区)
突破/破位条件:
- 有效突破压力:收盘价 > XX.XX + 量比 > X.X
- 有效破位支撑:收盘价 < XX.XX + 量比 > X.X (放量破位才算)
```
### §6 与基本面的一致性检验(核心段)
**前置任务**:preamble Step 2 应读取该公司的最新 sm-company-deepdive 和 sm-thesis 输出。
| 维度 | 基本面观点 | 技术面信号 | 一致性 |
|---|---|---|---|
| 方向 | 看多 / 看空 / 中性 (引用自 thesis) | 多头 / 空头 / 中性 | ✅ / ⚠️ / ❌ |
| 时间窗 | 6-12 个月 | 短期 / 中期 | — |
| 关键变量 | 命题里的核心驱动 | 技术面是否反映 | — |
**判断**:
- ✅ **完全一致**:基本面看多 + 技术面多头排列 → 加仓信心强
- ⚠️ **部分一致**:基本面看多 + 技术面调整中 → 等技术面修复或加仓节奏放缓
- ❌ **背离**:基本面看多 + 技术面破位 → **重新检视命题或承认市场可能比你早知道一些事**
**如果背离**:
- 是技术面错了(市场短期波动)还是基本面错了(命题被证伪)?
- 哪些数据可以判定?
- 给出 N 天观察期 + 触发条件
### §7 明日 / 下周观察点
```
明日开盘看:
- 是否高开/低开?多少为关键?
- 成交量初段是否能放?
收盘看:
- 是否守住/突破 XX.XX 元?
- MACD/KDJ 是否进一步金叉/背离?
- 北向资金当日方向?
本周需要等待的:
- {重要事件,如业绩会、政策窗口、产业数据发布}
- {同业公司业绩对照点}
如果发生 X,意味着 Y:
- 有效放量突破压力 → 趋势确认,可加仓
- 有效放量破位支撑 → 趋势反转,须减仓
- 缩量横盘 → 持仓不动等方向
```
## 约束
- ❌ **严禁**凭印象写技术指标值("MACD 金叉"必须有实际 DIF/DEA 数据)
- ❌ **严禁**做日内炒股建议(时间窗最短为日,不做小时级 / 分钟级)
- ❌ **严禁**给出"明天必涨"、"突破在即"等武断表述
- ❌ **严禁**用江恩 / 缠论 / 占卜流派的玄学指标
- ✅ **必须**显式说明每个信号来源的数据
- ✅ **必须**做基本面一致性检验(§6)
- ✅ 技术信号是**辅助决策依据**,不是决策本身
- ✅ 涉及"建议加减仓"的输出**必须**带"需人工复核"标注
## 输出归档路径
```
{coverage_root}/{ticker}_{name}/tape-review/{YYYY-MM-DD}-tape-review.md
```
## 与其他 skill 的关系
| 关系 | 说明 |
|---|---|
| **依赖** | sm-company-deepdive / sm-thesis 的最新输出(用于 §6 一致性检验) |
| **被依赖** | sm-pm-brief 在涉及决策时机时可引用 tape-review 的关键位 |
| **互补** | 基本面 skill 给"为什么",tape-review 给"什么时候"和"什么价格" |
| **冲突时** | 基本面命题与技术面强烈背离 → 触发 sm-red-team |
## 参考
- [../../core/preamble.md](../../core/preamble.md)
- [../../core/postamble.md](../../core/postamble.md)
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/output-archive.md](../../core/output-archive.md)
- [../../core/acceptance.md](../../core/acceptance.md)
- [../../core/adapters.md](../../core/adapters.md)
FILE:skills/sm-thesis/SKILL.md
---
name: sm-thesis
description: 二级市场投资命题拆解 skill。用于把模糊想法收敛成可验证的投资命题,识别核心矛盾、股价驱动、成立条件、证伪路径与优先跟踪指标。适合在决定"这条主线值不值得研究"时使用。
inputs:
- 模糊的研究方向 / 公司名 / 主题
outputs:
- 投资命题 + 成立条件 + 跟踪指标
data_sources: 见 ../../core/adapters.md
markets: [CN-A, HK, US, GLOBAL]
---
# SM Thesis
这个 skill 用于投研工作的第一步:把题目从"一个方向"压缩成"一个可验证的投资命题"。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Thesis 特别注意:数据需求最轻,但 preamble Step 2 必须检查是否有同标的的历史 deepdive / industry-map 输出。如果连基本认知都没有,先走 `sm-company-deepdive` 或 `sm-industry-map`。
适用场景:
- "这个方向值不值得看"
- "这家公司为什么现在值得研究"
- "市场到底在交易什么"
- "股价最核心的驱动变量是什么"
## 工作方式
默认按以下步骤输出:
1. 定义命题
2. 识别核心矛盾
3. 拆解命题成立的必要条件
4. 说明当前市场预期可能错在哪
5. 给出证伪路径和跟踪指标
## 输出格式
- `一句话命题`
- `核心矛盾`
- `股价驱动变量`
- `命题成立的三个必要条件`
- `市场可能忽略的点`
- `证伪点`
- `未来一个月最该跟踪的三项数据`
## 约束
- 不要直接给出武断结论
- 不要把信息堆砌当成逻辑
- 明确区分事实、预期和推演
## 参考
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/templates.md](../../core/templates.md)
- [../../core/adapters.md](../../core/adapters.md)
Open prompt stack for public-market investment research. Show this menu after install: 📊 Research: 1.Company Deep-dive 2.Industry Map 3.Investment Thesis 📈...
---
name: investor-harness
description: |
Open prompt stack for public-market investment research. Show this menu after install:
📊 Research: 1.Company Deep-dive 2.Industry Map 3.Investment Thesis
📈 Earnings: 4.Earnings Preview 5.Model Check
🔍 Tracking: 6.Consensus Watch 7.Catalyst Monitor 8.Roadshow Questions
⚔️ Risk: 9.Red Team
📋 Output: 10.PM Brief 11.Briefing
🤖 Auto: 12.Autopilot 13.Master Mode
Enter a number or describe your task to begin.
version: 0.6.4
author: joansongjr
license: MIT
tags:
- investing
- research
- A-shares
- HK-stocks
- US-stocks
- equity-research
- financial-analysis
- prompt-stack
- fund-manager
- analyst
---
# Investor Harness — Open Prompt Stack for Public-Market Research
> **⚡ Install:** `clawhub install investor-harness`
## After Installation — Show This Menu
When the user installs this skill or first triggers it, **display the full menu below immediately** (do not ask "want to see what this does?", do not abbreviate):
**🎯 Investor Harness is ready! What would you like to do?**
**📊 Research**
- 1️⃣ Company Deep-dive — Start or update coverage
- 2️⃣ Industry Map — Value chain, supply/demand, key players
- 3️⃣ Investment Thesis — Define core thesis, key variables
**📈 Earnings**
- 4️⃣ Earnings Preview — Key metrics, beat/miss paths, guidance
- 5️⃣ Model Check — Assumption review, sensitivity, break points
**🔍 Tracking**
- 6️⃣ Consensus Watch — Expectations gap, valuation anchors
- 7️⃣ Catalyst Monitor — Events, policy, orders, price drivers
- 8️⃣ Roadshow Questions — Research call prep, earnings Q&A
**⚔️ Risk**
- 9️⃣ Red Team — Challenge bull case, find falsification paths
**📋 Output**
- 🔟 PM Brief — One-page decision summary for fund managers
- 1️⃣1️⃣ Briefing — Morning notes, market recap, research notes
**🤖 Auto Mode**
- 1️⃣2️⃣ Autopilot — Give me a company/industry/event, I'll handle it
- 1️⃣3️⃣ Master Mode — All 7 modes, auto-detect which to use
**Enter a number or describe your task**, e.g.:
- "1" or "Deep-dive on NVIDIA"
- "4" or "Earnings preview for TSMC"
- "9" or "I'm bullish on AI capex, red team me"
- "Show me the semiconductor industry map"
### Menu-to-Skill Routing
| # | Skill | Description |
|---|-------|-------------|
| 1 | skills/sm-company-deepdive | 9-section company deep-dive |
| 2 | skills/sm-industry-map | Industry framework + value chain |
| 3 | skills/sm-thesis | Investment thesis construction |
| 4 | skills/sm-earnings-preview | Earnings preview |
| 5 | skills/sm-model-check | Financial model review |
| 6 | skills/sm-consensus-watch | Consensus expectations |
| 7 | skills/sm-catalyst-monitor | Catalyst tracking |
| 8 | skills/sm-roadshow-questions | Roadshow questions |
| 9 | skills/sm-red-team | Red team / devil's advocate |
| 10 | skills/sm-pm-brief | PM decision summary |
| 11 | skills/sm-briefing | Research briefing |
| 12 | skills/sm-autopilot | Auto-routing |
| 13 | skills/sm-master | Full 7-mode master |
### Routing Rules
1. User picks a number → read the corresponding skill SKILL.md → execute
2. User describes a task (no number) → auto-route via sm-autopilot logic
3. User says "show menu again" → re-display full menu
**Do NOT:**
- ✖ Ask "want to see what this skill does?" — just show the menu
- ✖ Say "installed" and stop — always follow with the menu
- ✖ Abbreviate the 13 options to 3 — show all 13
### Tips
For a better experience, consider maintaining these files in your workspace:
- watchlist.md — Your coverage universe
- biases.md — Your research bias log (Red Team will check this)
- decision-log.md — Investment decision journal
---
## What's Included
- **13 research skills** (from master control to specialized modules)
- **7 work modes**: Thesis / Coverage / Consensus / Catalyst / Red Team / Briefing / PM Prep
- **Evidence grading system** (F1/F2/M1/C1/H1)
- **Compliance boundaries and expression standards**
- **Data source adapter decision tree** (iFind MCP → cn-web-search → built-in search → manual)
## Data Sources (all optional)
1. iFind MCP (THS, A-shares / funds / macro)
2. cn-web-search (17 free Chinese search engines)
3. Built-in WebSearch / WebFetch
4. User-provided materials (fallback)
See `core/adapters.md` for details.
## Markets Covered
- A-shares (Shanghai/Shenzhen)
- Hong Kong stocks
- US equities
- Mutual funds
- Cross-market themes
## Compatibility
Claude Code / Codex / OpenCode / OpenClaw / any AI tool that reads Markdown.
## License
MIT © 2026 Joan Song
FILE:README.md
# Investor Harness
> 投研人的 AI 任务执行规范
> *An execution discipline harness for AI-assisted investment research*
**v0.6.0** · MIT License · A 股 / 港股 / 美股 / 公募 / 跨市场
---
## 为什么做这个
投研人现在都在用 AI 辅助工作——搜集数据、起 coverage、写前瞻、维护覆盖库。但 AI 在严肃投研场景下有四个**老大难问题**:
| 问题 | 你已经遇到过 |
|---|---|
| **❶ 幻觉** | AI 编数据,把市场猜测当成财报披露写出来 |
| **❷ 健忘** | AI 不记得你的覆盖池、不记得上次研究到哪、每次都从零开始 |
| **❸ 不成体系** | AI 输出格式每次都不一样,没法归档、对比、迭代 |
| **❹ 上下文溢出**(v0.4 新增) | 长会话或深度任务跑到一半,context 满了就丢失全部进度 |
**Investor Harness 是一套强制 AI 按投研工作纪律执行任务的开源规范**。
它不让 AI 变聪明,让 AI **可靠**——每次取数必须先列计划、每条事实必须标证据等级、每次输出必须承认"还有什么不知道"、所有输出归档到固定路径、跨会话能从断点接续。
跨平台开源(Claude Code / Codex / OpenCode / OpenClaw 全部支持),MIT 协议。
下面用真实任务做三组**深度对比**,让你自己判断值不值得装。
---
## 核心能力 1 · Company Deep-dive
### 任务
> 买方研究员接到任务:**起 coverage,标的是寒武纪 (688256.SH)**。
> 要求:两天内产出一份能进 IC 会议的深度,明确「为什么是它、核心驱动、竞争壁垒、未来三个月跟踪指标」。
---
### ❌ 不用 Investor Harness:裸 LLM 会给你什么
> 寒武纪科技是中国领先的 AI 芯片设计公司,成立于 2016 年,2020 年在科创板上市。公司专注于人工智能芯片产品的研发,产品覆盖云端训练、云端推理、边缘计算和终端四大场景。
>
> **核心竞争力**:公司在 AI 芯片领域具有深厚的技术积累,拥有自主可控的指令集架构和软件栈,在国产替代背景下具备稀缺性。
>
> **业务亮点**:
> - 云端产品线受益于国内 AI 算力需求快速增长
> - 国产 GPU 替代空间广阔
> - 已进入多个头部互联网厂商供应链
>
> **风险提示**:技术迭代风险、客户集中度风险、宏观经济波动风险、地缘政治风险。
>
> **结论**:寒武纪作为国产 AI 芯片龙头,长期受益于算力国产化趋势,建议关注。
**这份输出的问题**(按卖方研究标准逐条拆):
| 维度 | 问题 |
|---|---|
| 🔴 **产业链定位** | 只说"AI 芯片",没拆清是训练卡还是推理卡、对标 H100 还是 A100、在 HBM 价值链的什么位置 |
| 🔴 **收入驱动** | "受益于需求增长"——这是废话。没有量、价、结构、客户四个维度的拆分 |
| 🔴 **利润弹性** | 整段没提毛利率、研发费用率、经营杠杆 |
| 🔴 **竞争壁垒** | "技术积累深厚"是主观描述,不是可验证的壁垒(vs 海光、华为昇腾、摩尔线程的具体差异在哪?) |
| 🔴 **市场关注焦点** | 没有任何一致预期信息,不知道市场现在 price 了什么 |
| 🔴 **可比公司** | 完全缺失,没办法做横向估值 |
| 🔴 **跟踪指标** | "技术迭代""客户集中度"是类别,不是指标。看什么数、什么时候看,完全没说 |
| 🔴 **证据链** | 0 条引用、0 条数据来源、没有一个数字 |
| 🔴 **结论** | "建议关注"是典型无承诺话术,等于没说 |
| 🔴 **知道自己不知道什么** | 完全没有"仍需补的资料"——把 LLM 自己的猜测当成完整答案交付 |
**拿这个进 IC 会议 = 被老板当场质疑到崩溃**。
---
### ✅ 用 Investor Harness:触发 `sm-company-deepdive`
LLM 的行为会变成这样——
#### 第一步:明确取数计划(而不是直接开写)
```
[Preflight]
标的:寒武纪 (688256.SH)
市场:CN-A(科创板)
按 core/adapters.md 取数优先级:
1. iFind MCP → get_stock_summary / get_stock_financials / get_stock_shareholders
- 2022-2024 年报关键财务
- 股东结构变化
- 研发费用率历史
2. iFind → search_notice → 近 6 个月公告(产能扩张、重大合同)
3. cn-web-search → 近 3 篇卖方深度的核心观点
4. WebSearch → 竞品对比(海光、华为昇腾、摩尔线程的公开技术参数)
缺失项预判:
- 客户名单(可能仅在管理层交流中披露,公开材料无)
- 实际订单量 vs 出货量(需专家访谈或渠道调研)
→ 这些将在"仍需补的资料"段列出
```
#### 第二步:按 9 段结构输出,每条带证据等级
```markdown
# 寒武纪 (688256.SH) · Coverage Deepdive
数据来源:iFind MCP + cn-web-search + 公开披露 | 分析师:[you]
## 1. 公司定位
- **产业链位置**:AI 芯片设计公司(fabless),采用台积电代工 (F2-公司年报)
- **产品结构**:
- 云端训练卡:思元 370(对标 A100 级别,7nm)(F2)
- 云端推理卡:思元 590(对标 H100 级别,已流片)(F2-2024 年报)
- 边缘 / 终端:占比小,2024 收入贡献 < 10% (F2)
- **差异化**:
- vs 海光:海光是 x86 通用 CPU + DCU,寒武纪是纯 AI 专用 ASIC
- vs 华为昇腾:昇腾绑定华为生态,寒武纪相对中立
- vs 摩尔线程:摩尔线程 GPU 架构更通用,寒武纪指令集更定制 (C1-基于公开技术文档推演)
## 2. 业务拆分(FY2024)
| 业务线 | 收入占比 | YoY | 毛利率 | 证据 |
|---|---|---|---|---|
| 云端产品线 | ~85% | [需补] | [需补] | F2-年报披露但口径模糊 |
| 边缘 | ~10% | [需补] | [需补] | F2 |
| 终端 | ~5% | [需补] | [需补] | F2 |
⚠️ 2024 年报的收入拆分粒度不够,思元 370 / 590 分别贡献多少**未单独披露**。需通过业绩会、调研或卖方拆分补。
## 3. 收入驱动(2025-2027)
核心假设链:
1. **量**:思元 590 2025 H2 起量 → 2026 全年贡献 (C1-基于公司公告的流片时点推演)
2. **价**:国产 AI 卡当前 ASP 约 H100 的 60-70% (M1-卖方一致预期),2026 可能承压(竞争加剧)
3. **结构**:训练卡占比上升 → 收入单价提升 (C1)
4. **客户**:互联网大厂为主(字节、阿里云、腾讯云)(H1-渠道传闻,**未经核验**)
## 4. 利润驱动
- **毛利率**:2024 约 [XX]% (F2),高于设计公司行业均值
- 驱动:缺乏国产替代品 → 议价能力强 (C1)
- 风险:2026 随供给增加回落到 [XX]% (C1-卖方一致预期)
- **研发费用率**:持续高位(2024 约 [XX]%, F2),短期不会下降
- **经营杠杆**:收入规模到 [XX] 亿元后显著 (C1)
- **归母净利**:2024 仍亏损 (F2),预计 2025-2026 扭亏时点是核心预期差来源
## 5. 核心竞争力 / 风险点
**竞争力**(带验证路径):
1. **国产化稀缺性** (F1) — 验证:看美国对华出口管制是否覆盖 H20 等降级卡
2. **自主指令集 + 软件栈** (F2-招股书) — 验证:看客户是否愿意为适配成本买单
3. **流片节奏** (F2-公告) — 验证:看思元 590 的量产良率
**风险**(可观测、可触发):
1. **客户集中度过高** — 前五大客户占 > 70% (F2-年报)
→ 触发:任何头部客户切换到昇腾或自研 → 直接下修
2. **思元 590 良率不及预期** — 7nm 以下良率敏感
→ 触发:2025 Q2/Q3 出货量显著低于公司指引 → 下修
3. **美国出口管制放松** — H20 / MI325 重新大量进入中国 → 国产替代逻辑弱化
→ 触发:关注 BIS 公告
4. **公司持续亏损、现金流压力** — 现金储备仅支撑 N 个季度 (F2-需补最新季报)
→ 触发:定增或债券发行
## 6. 市场关注焦点(当前一致预期)
- 2025 能否扭亏 (M1)
- 思元 590 量产进度 (M1)
- 国内云厂商 AI capex 指引 (M1)
**当前市场共识**:乐观,2024 股价已反映部分扭亏预期 (M1)
**潜在预期差**:
- 向上:云厂商 2026 AI capex 超预期 → 量价齐升
- 向下:思元 590 量产延后 1-2 个季度 → 当前估值撑不住
(预期差的细致拆解建议交给 `sm-consensus-watch`)
## 7. 与可比公司的关键差异
| 维度 | 寒武纪 | 海光信息 | 华为昇腾 | NVIDIA (对照) |
|---|---|---|---|---|
| 架构 | 专用 ASIC | GPGPU (x86) | NPU + 生态绑定 | GPU + CUDA |
| 中立性 | 中立 | 中立 | 绑定华为 | 绑定自家生态 |
| 2024 收入 | [XX] 亿 | [XX] 亿 | 未披露 | — |
| PS (TTM) | [XX]x | [XX]x | — | — |
| 主要客户 | 云厂商 | 政企 + 云 | 华为系 + 自主可控 | 全球 |
⚠️ 估值倍数需用最新数据更新。海光和寒武纪的可比性**有限**,因为海光收入里大部分仍是 CPU 而非 DCU。直接 PS 对比会误导。
## 8. 未来三个月跟踪指标
| # | 指标 | 频率 | 获取路径 | 为什么重要 |
|---|---|---|---|---|
| 1 | 思元 590 量产 / 出货公告 | 事件驱动 | iFind search_notice | 决定 2026 收入 |
| 2 | 云厂商 capex 指引(阿里、腾讯、字节) | 季报 | 各公司业绩会 | 下游需求领先指标 |
| 3 | BIS 出口管制更新 | 事件驱动 | WebSearch SEC + 商务部 | 国产替代逻辑的外部变量 |
| 4 | 公司季度现金流 / 融资公告 | 月度 | iFind | 判断是否有定增压力 |
| 5 | 卖方一致预期修正方向 | 月度 | 卖方研报摘要 | 反向验证市场情绪 |
## 9. 仍需补的资料(⚠️ 强制段落)
**必需**:
- 2024 Q4 / 2025 Q1 最新财报的细分业务毛利率
- 前五大客户的最新披露
- 思元 590 流片 → 量产时间表的官方口径
- 最新现金储备和经营性现金流
**建议**:
- 卖方深度报告 3 篇(中金 / 华泰 / 招商任一)
- 产业链调研:AI 服务器代工厂对寒武纪卡出货节奏的反馈
- 与华为昇腾、海光 DCU 的独立技术评测
**不确定但影响判断**:
- 管理层对 2026 毛利率走势的口径
- 是否会新增合同负债 / 预收款(反映订单能见度)
---
⚠️ **合规声明**:本输出不构成投资建议。涉及评级 / 目标价 / 盈利预测调整,必须经持牌分析师人工复核。
```
---
### 维度化对比
| 维度 | 裸 LLM | Investor Harness | 差距量级 |
|---|---|---|---|
| **取数步骤** | 无 | 显式取数计划 + 工具调用 | 0 → 1 |
| **产业链定位** | 1 句泛泛描述 | 4 个竞品横向对比 | 4x |
| **业务拆分粒度** | 无 | 按产品线拆 + 标注披露口径 | 0 → 1 |
| **收入驱动** | "受益于需求增长" | 量 / 价 / 结构 / 客户四维分析 | 0 → 4 |
| **证据链** | 0 条 | 每行带 F1/F2/M1/C1/H1 标签 | 0 → 1 |
| **风险** | 4 条套话 | 4 条可观测可触发的具体指标 | 废话 → 可交付 |
| **可比公司** | 无 | 4 家带数据 + 可比性警告 | 0 → 1 |
| **跟踪指标** | 无 | 5 条带频率、路径、目的 | 0 → 5 |
| **承认不知道** | 无 | 强制"仍需补的资料"段(3 类) | 🔑 核心差距 |
| **能否直接交付** | ❌ | ✅ | — |
### 对你投研流程的长期影响
- **起 coverage 速度**:从 2 天 → 0.5 天(节省的不是"写字时间",是"知道该写什么"的时间)
- **质量上限**:从"看起来专业"→ "扛得住 PM 追问"
- **可复用性**:输出可以**直接进 coverage 库**,而不是每次重写
- **长期纪律**:强制"仍需补的资料"段 → 逼你建立真正的 coverage 档案,而不是假装全都懂
---
## 核心能力 2 · Earnings Preview
### 任务
> 卖方科技组分析师接到任务:**中芯国际 (0981.HK / 688981.SH) Q4 业绩前瞻**,下周二披露。
> 要求:2 小时内给销售和 PM 一份前瞻,明确市场关注点、beat/miss 路径、财报后第一时间 check 什么。
---
### ❌ 不用 Investor Harness:裸 LLM 会给你什么
> **中芯国际 Q4 业绩前瞻**
>
> 中芯国际作为国内晶圆代工龙头,Q4 业绩预计将保持稳健。随着国产替代趋势持续,公司产能利用率有望维持高位。
>
> **业绩驱动因素**:
> - 28nm 及以上成熟制程需求稳定
> - 先进制程产能释放
> - 国产替代加速
>
> **关注点**:
> - 毛利率走势
> - 资本开支计划
> - 下游需求指引
>
> **风险**:行业周期性、技术追赶难度、地缘政治。
**问题**:
| 维度 | 问题 |
|---|---|
| 🔴 **没有市场共识** | 一致预期收入多少?毛利率多少?不写 |
| 🔴 **没有可对标的上一季度** | Q3 实际数据、Q3 发布时的指引完全缺失 |
| 🔴 **敏感变量不具体** | "毛利率走势"是类别词,不是敏感变量 |
| 🔴 **没有 beat / miss 的具体路径** | 什么情况算 beat?什么情况算 miss?没说 |
| 🔴 **没有财报后 action plan** | 财报出来后第一时间看什么?完全没有 |
| 🔴 **对原投资命题的影响** | 如果 beat 或 miss,对原命题要不要修?没说 |
| 🔴 **没有指引听点** | 业绩会上管理层说什么要重点听?没说 |
**拿这个给销售和 PM**:他们会去找卖方同行的 preview 看,你的被跳过。
---
### ✅ 用 Investor Harness:触发 `sm-earnings-preview`
```markdown
# 中芯国际 (0981.HK / 688981.SH) · Q4 业绩前瞻
发布日:[下周二]
数据来源:iFind 历史财务 + 近 4 季度业绩会 + 卖方一致预期摘要 + 公开披露
## 一句话判断
Q4 是"指引 > 业绩"的财报:市场已经 price in 收入同比高增,
真正决定股价方向的是**2026 毛利率能否守住 20%** 和 **capex 节奏是否收敛**。(C1)
## 市场最关心的三个问题
1. **毛利率拐点是否到来**
- 一致预期 Q4 毛利率 [XX]% (M1)
- 关键:28nm 及以上成熟制程价格战是否见底
- 市场已经 price in 的情景:Q4 小幅回升
- 超预期路径:毛利率环比 +2pp 以上 → 2026 年利润弹性打开
2. **资本开支指引**
- 2024 全年 capex 指引 [XXX] 亿美元 (F2-Q3 业绩会)
- 关键:2025 capex 是否继续同比 +15% 以上
- 如果收敛:说明扩产节奏降温 → 短期利好毛利,长期影响收入增长
- 如果加码:说明 N+1 / N+2 节点持续投入 → 利空短期利润,长期 bullish
3. **成熟制程价格趋势**
- 下游应用(功率、CIS、PMIC)库存状态 (M1-卖方渠道调研)
- 关键:管理层对 2026 H1 ASP 的定性表态
## 本次财报最敏感的变量
| 科目 | 一致预期 | 敏感度 | beat 的信号 | miss 的信号 |
|---|---|---|---|---|
| **收入** | [XX] 亿美元 | 低 | 超 +3% | 低 -3% |
| **毛利率** | [XX]% | 🔴 最高 | > 22% | < 18% |
| **产能利用率** | [XX]% | 高 | > 90% | < 85% |
| **经营费用率** | [XX]% | 中 | — | 研发费用率跳涨 |
| **Q1 2026 指引收入** | [XX] 亿美元 | 🔴 最高 | 环比持平以上 | 环比 -5% 以上 |
| **2025 全年 capex 指引** | [XXX] 亿美元 | 高 | 低于一致预期 | 高于一致预期 |
🔑 **规律**:中芯国际的股价反应中,**指引占 70%,当期业绩占 30%**。
所以重点听管理层的 Q1 指引和 capex 口径,而不是 Q4 的绝对数字。
## 潜在超预期点
1. **成熟制程毛利率先于市场预期回升**(概率:中)
- 验证:28nm 产能利用率 Q4 是否回到 95% 以上
- 影响:2026 净利上修 15-20%
2. **先进制程(N+1 / N+2)新客户签约公告**(概率:低但影响大)
- 验证:业绩会管理层是否提及新合作
- 影响:重新评估长期增长天花板
3. **汽车电子 / 工控订单环比加速**(概率:中)
- 验证:该业务线占比是否 QoQ 提升
## 潜在低于预期点
1. **消费电子库存重新累积**(概率:中)
- 验证:Q1 指引是否反映环比下滑
- 影响:当前股价难以维持
2. **折旧压力集中释放**(概率:高)
- 验证:销售成本环比变化
- 原因:前两年 capex 高峰对应的折旧开始集中摊销
3. **汇率 / 地缘政治的一次性影响**
## 管理层指引最该听什么
| 听点 | 要听出什么 |
|---|---|
| Q1 2026 收入指引区间 | 中位值是否低于卖方一致预期 |
| 2025 capex 总额 | 是否低于 [XX] 亿美元 |
| 成熟制程 ASP 口径 | "稳定"/"回升"/"承压"三档 |
| 先进制程表态 | 是否暗示新客户 / 新订单 |
| 折旧与摊销口径 | 是否确认 2025 折旧压力高点 |
## 财报后第一时间检查清单
**T+0(财报发布后 30 分钟内)**:
- [ ] 实际 vs 一致预期:收入 / 毛利率 / 净利
- [ ] Q1 2026 指引中位值 vs 一致预期
- [ ] 2025 capex 指引 vs 一致预期
- [ ] 股价盘前 / 盘后反应
**T+1(业绩会后)**:
- [ ] 业绩会管理层对成熟制程 ASP 的口径
- [ ] 业绩会对先进制程的表态
- [ ] 分析师问答里最关注什么(反映市场焦点的变化)
**T+3(结论更新)**:
- [ ] 卖方研报一致预期是否上修 / 下修
- [ ] 如果管理层口径和我预期不同 → 原投资命题是否要修正
- [ ] 是否需要向 PM 发补充 note
## 若结果不同于预期,对原投资逻辑意味着什么
| 情景 | 对原命题的影响 |
|---|---|
| Beat(毛利率 > 22% + Q1 指引稳定) | 命题成立,可以考虑加仓 |
| In-line | 命题成立,维持 |
| Miss(毛利率 < 18% 或 Q1 指引 -5%) | 命题需要修正:2026 盈利能否兑现存疑 |
| 显著 Miss(两项都不及) | 命题证伪,重新评估 |
---
⚠️ **合规声明**:本输出不构成投资建议。一致预期数字需用卖方研报实际数据更新。
```
---
### 维度化对比
| 维度 | 裸 LLM | Investor Harness | 差距 |
|---|---|---|---|
| **市场共识引用** | 无 | 每个关键科目的一致预期数字 | 0 → 1 |
| **关注问题识别** | 3 条类别词 | 3 个具体问题 + 对股价的影响机制 | 3x 深度 |
| **敏感变量** | "毛利率走势" | 6 个科目的量化 beat/miss 阈值 | 废话 → 可执行 |
| **指引听点** | 无 | 5 个具体听点 + 解读规则 | 0 → 5 |
| **财报后 action** | 无 | T+0 / T+1 / T+3 分阶段 checklist | 0 → 1 |
| **对命题的反馈** | 无 | 4 种情景对应 4 种命题调整 | 0 → 1 |
| **规律总结** | 无 | "中芯国际指引占 70%,当期业绩占 30%" 这种投研常识 | 0 → 1 |
| **能否 T+0 快速响应** | ❌ | ✅ | — |
### 对你投研流程的长期影响
- **财报季速度**:一天能覆盖 5-8 家 → 而不是 2-3 家
- **质量**:前瞻不再是"看起来像前瞻的段落",而是**可以给 PM 当作决策依据**的工作底稿
- **T+0 响应**:财报出来的 30 分钟内你已经知道答案(因为清单已经写好)
- **长期复利**:每次前瞻留下一份结构化底稿 → 下一季度直接对比更新,而不是从头写
---
## 核心能力 3 · Red Team(反方审视)
### 任务
> 买方 PM 对你说:**"你看好 AI 算力 capex 持续超预期,这个逻辑听起来很顺——帮我反过来想一下,空头怎么看"**。
> 要求:两小时内,产出一份能让你自己不舒服的 red team 报告。
---
### ❌ 不用 Investor Harness:裸 LLM 会给你什么
> **AI 算力 capex 的潜在风险**
>
> 虽然 AI 算力需求持续旺盛,但仍存在以下风险:
>
> 1. **宏观经济不确定性** — 全球经济放缓可能影响企业 IT 支出
> 2. **技术迭代风险** — 下一代芯片可能使当前架构过时
> 3. **地缘政治** — 中美技术竞争可能影响供应链
> 4. **竞争加剧** — 更多玩家进入可能压缩利润率
> 5. **监管风险** — AI 监管可能影响下游应用
> 6. **估值泡沫** — 当前板块估值已处于历史高位
>
> 综合来看,AI 算力 capex 长期趋势依然向好,但短期波动难以避免,建议关注催化剂和风险点的边际变化。
**问题**:
| 维度 | 问题 |
|---|---|
| 🔴 **全是套话风险** | "宏观不确定""地缘政治""估值泡沫"——每只股票都能套,没有任何信息量 |
| 🔴 **不挑战具体多头假设** | 没有指向"你这个 thesis 最脆弱的是什么" |
| 🔴 **无可观测触发** | 不告诉你"看到什么数据就应该下修" |
| 🔴 **无替代方向** | 没说"如果你错了,资金应该去哪" |
| 🔴 **结尾还在讨好用户** | "长期趋势依然向好"——你本来就看多,这句话等于没反方 |
| 🔴 **不检查用户的历史偏差** | 不知道你有没有"追龙头"的倾向 |
**拿这个给 PM**:PM 会直接说"这不叫 red team,这叫免责声明"。
---
### ✅ 用 Investor Harness:触发 `sm-red-team`
```markdown
# Red Team · AI 算力 capex 持续超预期 · 反方审视
目标命题:AI 算力 capex 未来 8 个季度(2026-2027)持续超预期
多头代表:[你的名字]
反方审视:触发 sm-red-team + 查阅 biases.md
## 多头逻辑最脆弱的三个假设(及为什么脆弱)
### 假设 1:Hyperscaler capex YoY 增速维持在 25% 以上
**多头证据**:Meta/Microsoft/Google/AWS 2024 capex 合计 [XXX] 亿美元,2025 指引继续 +30% (F2)
**为什么脆弱**:
- 这些公司的经营现金流支撑 capex 的能力有上限,FCF / capex 比率已从 2020 的 2.5x 降到 2024 的 [X]x (F2-财报推算)
- 2024 股东回报(回购 + 分红)的优先级仍高于 capex,董事会压力在累积 (M1-股东信)
- 如果 2026 某季度**任意一家**把 capex 指引下修 → 板块整体杀估值(历史上云计算 capex 周期就是这样) (C1)
**触发信号**(可观测):
- 2026 任何一个季度 **hyperscaler 四家中至少两家** capex 指引同比 < 15%
- 2025 Q4 分析师问答里出现"capex efficiency"类问题集中 → 暗示董事会开始关心 ROI
### 假设 2:AI 模型的边际训练成本持续降低,不会导致 capex 饱和
**多头证据**:新模型训练需求持续增长,inference capex 占比上升 (M1)
**为什么脆弱**:
- DeepSeek 等效率模型的出现说明**边际训练 FLOPS 可以显著降低**,如果这个趋势持续 → capex 需求增速 decelerate 快于预期
- inference 需求虽然增长,但 unit economics 比训练更敏感,更容易被效率提升抵消
- 当模型能力达到某个阈值(GPT-5 / Claude Opus 4.6 级别)后,**边际效用递减**可能压低下一轮训练投入的 ROI (H1-待观察)
**触发信号**:
- 出现能力追平 GPT-5 但训练成本 < 1/5 的开源模型
- Hyperscaler 管理层在业绩会开始说"我们正在优化 training efficiency"(过往从不提)
- NVIDIA 的 data center 收入环比增速**首次**跌破 +10%
### 假设 3:国产算力的替代速度不会挤压 NVIDIA 的中国收入
**多头证据**:国产卡产能有限,性能差距仍大 (F1)
**为什么脆弱**:
- 美国出口管制持续收紧 → 中国厂商**被迫**加速自研 → 寒武纪 / 华为昇腾 / 海光的 2026 出货可能大超预期
- 中国云厂商的采购意愿从"性能优先"转向"可获得性优先"
- NVIDIA 的中国收入 2024 已是历史低点,但 2025 H20 若继续被禁 → 归零 (F2-需补)
**触发信号**:
- BIS 公告进一步收紧(H20 被禁)
- 国产 AI 卡出货量季度数据突破 [XX] 万片
- 中国云厂商 AI 服务器 BOM 表中国产卡占比 > 30%
## 证据缺口(多头阵营没说清的)
| 多头主张 | 实际证据 | 差距 |
|---|---|---|
| "AI capex 持续超预期" | Hyperscaler capex 指引 (F2) | 只到 2025,2026 没指引 |
| "训练需求持续增长" | 模型能力提升轨迹 (C1) | 无法证明需求斜率 |
| "效率提升不足以抵消需求" | [无明确证据] | 🔴 空白 |
| "GPU 供给紧张" | NVIDIA 财报 (F2) | 2024 已显著缓解 |
## 若多头错了,最早会在哪里暴露
**时间线**:
- **2026 Q1 财报季** (3-4 月):Hyperscaler capex 2026 全年指引公布
→ 如果至少两家 capex 指引 < 15% → 板块开始调整
- **2026 Q2-Q3**:NVIDIA 数据中心收入环比增速
→ 如果 < +10% → 确认周期拐点
- **2026 下半年**:可能出现"消化期"情景
## 硬触发的卖出条件(给 PM 作为监控 checklist)
```
[ ] Hyperscaler 四家中 ≥2 家 2026 capex 指引 YoY < 15%
[ ] NVIDIA 数据中心收入环比连续 2 个季度 < +10%
[ ] DeepSeek 或类似效率模型证明训练 FLOPS 可以减少 80% 而能力持平
[ ] 中国国产 AI 卡季度出货量 > 50 万片
[ ] 板块 PE 仍维持 > 40x 但以上任一条件成立
```
## 如果命题被证伪,资金应该去哪
- **产业链受益反转**:电力 / 变压器 / 液冷(这些是 capex 周期的滞后环节,如果 capex 见顶,它们还有 2-3 个季度的惯性)
- **估值更安全的变体**:全球 utility(AI capex 带来的电力需求长期存在,但估值没泡沫化)
- **反向交易**:做空估值最高的纯算力主题股,买软件应用层(如果算力便宜了,应用层受益)
## 🔑 查阅用户 biases.md 的检查结果
根据你的 `biases.md`,你历史上反复踩过的偏差:
1. **追龙头偏差** — ⚠️ 命中
你之前对"xx 赛道龙头"的看多判断,2023 Q2 踩过一次类似的 capex 拐点
→ 本次结论前请确认:你是否在假设"这次不一样"
2. **确认偏差** — ⚠️ 命中
你的多头命题里引用的证据 80% 来自 Hyperscaler 官方指引(M1-公司口径),缺少独立第三方验证
→ 本次结论前请强制加入至少 1 个独立信源(卖方独立调研 / 产业链访谈)
3. **锚定偏差** — 未命中
## 当前命题可信度评估
- **基本面逻辑**:强 (多头证据扎实)
- **时间窗口内可证伪性**:强 (有明确触发)
- **估值安全边际**:弱 (板块已经 price in 乐观情景)
- **反方可观测性**:强 (5 条硬触发)
**综合**:**中等偏高风险**。不是"不该看多",而是**仓位应该留出下修空间**,并严格按卖出 checklist 监控。
## 给多头的回复
你的命题不差,但你需要做三件事才算对得起这个判断:
1. **在 decision-log.md 里写下"我假设这次不是 2023 Q2 重演,因为 [理由]"**
2. **把上面 5 条硬触发放进每日监控清单**
3. **仓位不要超过你认为"错了能扛住"的上限**
---
⚠️ **合规声明**:本输出仅为反方审视工具,不构成投资建议。
```
---
### 维度化对比
| 维度 | 裸 LLM | Investor Harness | 差距 |
|---|---|---|---|
| **反方深度** | 6 条套话 | 3 个具体假设挑战 + 每个带触发 | 废话 → 可执行 |
| **触发可观测性** | 无 | 5 条硬指标(数字 + 时间) | 0 → 5 |
| **挑战多头假设** | 不挑战 | 逐一找出证据链断点 | 0 → 1 |
| **证据缺口表** | 无 | 4 行表格显示多头主张 vs 实际证据 | 0 → 1 |
| **替代方向** | 无 | 3 个具体的资金去向 | 0 → 3 |
| **自我偏差检查** | 无 | 查阅 biases.md + 命中报告 | 🔑 独有 |
| **给多头的"行动建议"** | "建议关注" | 3 条具体动作(写决策日志、监控清单、仓位上限) | 废话 → 可执行 |
| **结尾立场** | 讨好用户("长期向好") | 中性评估 + 明确风险等级 | 🔑 独有 |
### 对你投研流程的长期影响
- **最关键的差异**:Red Team 不是为了让你别买,而是为了让你**买得更硬**。当你的命题能扛住具体硬触发的检查,你的持仓信念会质变。
- **biases.md 的复利**:每次 red team 都查一次历史偏差 → 你会发现自己反复踩同一个坑 → 三次之后你不会再踩
- **组合管理**:硬触发 checklist 变成每日 / 每周监控,不再依赖"感觉股价不对了"才减仓
- **跟 PM 对话的质量**:当你能主动给出"我会在 X 触发时减仓",PM 会给你更大的仓位授权
---
## 三个能力之外:另外 13 个 skill
上面三个是**你最值得体验的**。Investor Harness v0.3.0 一共 16 个 skill,另外 13 个按同样纪律设计:
### 单点研究 skills(10 个)
| Skill | 适用场景 |
|---|---|
| `sm-autopilot` | 不想自己选 skill 时的总控入口,自动路由 |
| `sm-master` | 7 模式长形态总控,适合"只装一个 skill"的极简场景 |
| `sm-thesis` | 把模糊研究方向收敛成可验证的投资命题 |
| `sm-industry-map` | 行业框架 + 产业链地图 + 关键公司定位 |
| `sm-model-check` | 财务模型审阅:假设、勾稽、敏感性、断裂点 |
| `sm-consensus-watch` | 一致预期 + 预期差管理 + 重估值驱动因素 |
| `sm-catalyst-monitor` | 事件 / 政策 / 订单 / 价格等催化剂跟踪 |
| `sm-roadshow-questions` | 路演 / 调研 / 业绩会的高价值问题设计 |
| `sm-pm-brief` | 给基金经理 / IC 会议的一页纸摘要 |
| `sm-briefing` | 晨会 / 晚报 / 纪要整理 |
### 技术面 skill(v0.5 新增)
| Skill | 适用场景 |
|---|---|
| `sm-tape-review` | **盘面 + 技术面复盘** — 日内行情、收盘技术分析、K 线 / 量价 / MACD/KDJ/RSI/BOLL 指标解读、关键支撑压力位、与基本面命题的一致性检验 |
### 批量任务 skills(v0.3 新增)
| Skill | 适用场景 |
|---|---|
| `sm-batch-refresh` | 覆盖池批量刷新(行情/财务/股东/催化)— 每周/每月跑 |
| `sm-batch-earnings` | 财报季批量前瞻 / 复盘 — 财报季密集时跑 |
| `sm-catalyst-sweep` | 覆盖池每日 / 每周催化剂扫描 — 晨会前 30 分钟跑 |
每个 skill 都强制:
- **开始前**:执行 [`core/preamble.md`](core/preamble.md) 的 6 步流程(任务断点 → 识别市场 → 检查历史 → 检查任务 → Preflight → 实际取数)
- **结束后**:执行 [`core/postamble.md`](core/postamble.md) 的 8 步流程(增量 checkpoint → 证据自检 → 仍需补 → 合规 → 归档 → 更新任务 → 验收 → echo 简化)
- **归档**:按 [`core/output-archive.md`](core/output-archive.md) 命名规范写入固定路径
- **验收**:跑 [`core/acceptance.md`](core/acceptance.md) 清单(通用 + skill 专属)
> ⚠️ **关键最后一步**:装好 skills 之后**必须**把 [`INSTALL-PROMPT.md`](INSTALL-PROMPT.md) 里的"启用提示词"复制到 `~/.claude/系统提示词`,否则 LLM 不会自动按规则工作。详见 INSTALL-PROMPT.md。
---
## 设计哲学 · 为什么是 Prompt Stack 不是 Agent
Investor Harness 是**开放提示词栈**,不是 AI agent。它没有 runtime,依赖你的 AI 工具(Claude Code / Codex / OpenCode 等)作为 runtime 执行。
这是**刻意的设计选择**,不是缺失:
| 维度 | Agent 形式 | Prompt Stack(本项目) |
|---|---|---|
| 跨 AI 工具兼容 | ❌ 通常绑死一个 runtime | ✅ 任何支持 markdown 的工具 |
| 合规友好度 | ⚠️ "AI 替你做研究"引发监管疑虑 | ✅ 方法论是你的,AI 只是工具 |
| 可审计性 | ⚠️ Python 代码,分析师看不懂 | ✅ 纯 markdown,能看能改能审计 |
| 升级 / 修改门槛 | ⚠️ 需要懂代码 | ✅ 改文本就行 |
| 分析师价值保留 | ⚠️ 有被替代风险 | ✅ 强制分析师保持纪律 |
**一句话**:投研的核心价值是"分析师的纪律",不是"自动化"。Prompt Stack 让纪律被强制执行,而不是外包。
---
## 安装
### 路径 A · 最小安装(1 分钟)
把 `skills/sm-master/SKILL.md` 复制到任何 AI 工具的系统提示词里。1 个文件解决 80% 需求。
### 路径 B · 完整安装(5 分钟)
```bash
git clone https://github.com/joansongjr/investor-harness.git
cd investor-harness
clawhub install investor-harness # 或 codex.sh / opencode.sh / generic.sh
```
### 路径 C · 完整工作区(10 分钟,推荐机构和进阶用户)
```bash
clawhub install investor-harness
```
会生成一套分析师工作区模板:系统提示词 / memory.md / coverage.md / decision-log.md / biases.md / research-queue.md / **active-tasks.md** (v0.3 新增),填几个空就能开始用。
详见 [setup/README.md](setup/README.md)。
---
## 数据源
全部可选,按 `core/adapters.md` 的优先级自动降级:
1. **iFind MCP**(同花顺官方,A 股 / 基金 / 宏观 / 资讯)
2. **cn-web-search skill**(聚合 17 个中文搜索引擎)
3. **WebSearch / WebFetch**(所有 harness 内置)
4. **用户手动贴材料**(兜底)
未来接入 Wind / Bloomberg / FactSet / S&P CapIQ 等,只需在 `core/adapters.md` 增加优先级条目,**skill 文件不用改**。
---
## 适用 / 不适用
✅ 持牌卖方分析师 / 买方研究员 / 基金经理 / IC 成员 / 商学院金融方向学生
❌ 数字货币 / 一级市场 / 期权期货 / 散户量化 / 期望 AI 替你决策的人
---
## Changelog
### v0.6.0 — 交互式安装 + 更新向导
> 解决 v0.5 的最后一个门槛:**非技术用户装不了**。
> 手动跑 `git clone + clawhub install investor-harness + 复制粘贴 INSTALL-PROMPT` 步骤太多,容易卡。
> v0.6 提供**交互式向导**:一个命令全搞定。
**新增**:
- **`setup.sh`** — 交互式安装向导(交互式安装)
- 检测操作系统 / Shell / Git / 现有 harness
- 选择目标 harness(Claude Code / Codex / OpenClaw,可多选)
- 选择数据源(iFind / Alpha派 / 进门财经 / Wind / cn-web-search / WebSearch)
- 检测现有 .mcp.json 配置
- 安装 skills(默认 symlink 模式)
- 可选创建投研工作区(跑 bootstrap.sh)
- 验证安装
- **`update.sh`** — 交互式更新向导
- 检测本地 vs 远程版本
- 显示新 commit 列表
- 检测破坏性变更(major bump / skill 重命名 / core 文件变更)
- git pull(含 stash 保护)
- 检测 系统提示词 里启用提示词的版本,不一致时提示更新
- 备份机制完善
- **ClawHub** — clawhub install investor-harness
- clawhub install investor-harness
- 自动 git clone + 调用 setup.sh
- 适合首次安装场景
- 包含占位符(DATE / HARNESS_PATH / WORKSPACE_ROOT / DATA_SOURCES 等)
**四个数据源全部是 MCP**:
| 数据源 | 类型 | 默认优先级 |
|---|---|---|
| iFind MCP | MCP server | 1(A 股 / 公募最优)|
| Alpha派 MCP | MCP server | 2 |
| Wind MCP | MCP server | 3(全球覆盖)|
| 进门财经 MCP | MCP server | 4(路演/专家/研报)|
| cn-web-search | Skill | 5 |
| WebSearch | harness 内置 | 6(兜底)|
| 用户贴材料 | 手动 | 7(最后兜底)|
**安装路径对比**:
| 方式 | 命令 | 适合谁 |
|---|---|---|
| ClawHub | clawhub install investor-harness | All |
| 🟡 **clawhub install investor-harness` | 想看清楚每一步的人 |
| 🔴 **低级命令** | `clawhub install investor-harness`(原 v0.5)| 自动化脚本 |
**更新路径**:
```bash
cd ~/investor-harness
clawhub update investor-harness
```
自动处理:版本检查、破坏性变更警告、git pull、系统提示词 迁移。
### v0.5.1 — Dual Output Discipline 修正(云端用户友好)
> 修复 v0.4 over-optimization:原 Step 7 "对话只回 ~300 token 摘要"忽视了云端用户根本打不开本地文件。
**改动**:
- `core/postamble.md` Step 7 重写:从"Echo Discipline 只回摘要"改为"**Dual Output Discipline 双输出**"——对话里贴完整内容(云端用户能直接读)+ 同时写文件(归档 + 跨 skill 引用 + 长期 diff)
- 结尾追加 `📁 已归档:{path}` + 关键统计 + 下一步建议
- 例外:用户主动说"省 token 模式"才退回到 v0.4 纯摘要
- `_boot.md` Output discipline 段同步更新
- `setup/workspace/系统提示词.template` 同步更新
- `INSTALL-PROMPT.md` Step 7 描述同步更新
**Token 影响**:每任务对话成本 ~300 → ~5500 tokens。200k context 能跑的任务数从 ~50(理论但不可用)变为 ~25(真实可用)。
**为什么这个修正很重要**:
- 投研人很多在 Claude.ai web / Codex web / 远程 SSH 跑 Claude Code → 没有本地文件系统
- 即使是本地用户,"打开文件"也比"对话直读"麻烦
- 文件存档的核心价值是**跨 skill 引用 + 长期归档**,不是"对话不贴"
- 对话是 control plane + data plane 双重身份,文件是补充
### v0.5.0 — 技术面复盘 skill + 强制启用提示词
> 解决两个新发现的痛点:
> 1. 缺技术面 skill(基本面 13 个 skill 都覆盖了,技术面是空白)
> 2. markdown 规范没有强制力——非技术用户的 LLM 不会自动遵守
**新增**:
- **`sm-tape-review`** — 盘面 + 技术面复盘 skill(第 17 个)
- 7 段输出:行情摘要 / 资金面 / K 线形态 / 技术指标 / 关键位 / 一致性检验 / 明日观察
- 强制使用 iFind get_stock_performance 拉真实指标,禁止凭印象编造
- §6 必须引用同标的最新 sm-thesis / sm-company-deepdive 输出做基本面一致性检验
- 适用场景:日内复盘、收盘技术面、加减仓技术确认、stop loss 设定
- **`INSTALL-PROMPT.md`** — 启用提示词模板(关键文件)
- 解决"装好但 LLM 不遵守"的问题
- 用户复制粘贴到 `~/.claude/系统提示词` 之后,LLM 自动按 Investor Harness 流程工作
- 包含完整的 boot protocol / preamble / postamble / 自动路由规则
- 三种粘贴方式:全局 系统提示词 / 工作区 / 单次对话
- **`acceptance.md`** 新增 sm-tape-review 专属验收清单(10 条)
**更新**:
- 4 个 install 脚本(claude-code / codex / opencode / generic)安装完后**主动打印**INSTALL-PROMPT.md 路径和复制粘贴说明
- `core/_boot.md` 16 → 17 skills 速查
- README 添加技术面 skill 段落 + INSTALL-PROMPT.md 强调
#### 为什么要有 INSTALL-PROMPT.md
v0.4 之前的设计假设 LLM 会"看到 SKILL.md 就遵守",但现实是:
- 小白用户不知道说"用 sm-X",他们说"看一下 X"
- LLM 看到模糊请求会直接给百度百科段落,不会主动 invoke skill
- markdown 规则依赖 LLM 自觉遵守
INSTALL-PROMPT.md 是用户主动**给 LLM 灌输**"以后所有投研任务都按这套规则做"的指令。一次粘贴,永久生效。
### v0.4.0 — Context overflow 防御 + 三层加载优化
> 解决 v0.3 没解决的"上下文溢出 + 任务被打断后失忆"问题。
- **新增 `core/_boot.md`** — 启动文件,~1.2k tokens,每次新会话第一个读。包含 16 skill 一行说明、boot protocol、resume protocol、三层加载策略
- **新增 `core/task-pulse.md`** — `.task-pulse` 心跳信号文件规范(< 100 tokens 的 JSON),让 LLM 用极小代价知道工作区当前任务状态
- **新增 `core/checkpoint.md`** — `.checkpoint/{task-id}.md` 断点续跑机制,让任务被 compact / 重开会话后能从断点继续,不重复
- **preamble.md 新增 Step 0** — 任务断点检查(读 .task-pulse → 询问续跑或新建)
- **postamble.md 新增 Step 0** — 增量 checkpoint 写入(每完成一段就写,不是任务完才写)
- **postamble.md 新增 Step 7** — Context Echo Discipline:对话只回 ~300 token 的摘要,完整输出在文件里。**节省 ~90% 对话 token**
- **三层加载优化**:
- **Tier 0**(每次必读)_boot.md + .task-pulse + 系统提示词 ≈ 1.5k tokens
- **Tier 1**(skill 调用时)SKILL.md + preamble + postamble + adapters ≈ 6k tokens
- **Tier 2**(按需)evidence / compliance / output-archive / acceptance ≈ 5k tokens
- vs v0.3 每次任务 ~17k 静态成本,**节省 50-70%**
- **系统提示词.template** 升级为 v0.4 三层加载 + Context Overflow 保护
- **bootstrap.sh** 自动创建 `.task-pulse` 和 `.checkpoint/` 目录
#### v0.4 真实 token 测算
| 操作 | v0.3 token | v0.4 token | 节省 |
|---|---|---|---|
| 新会话启动 | ~10k | ~1.5k | 85% |
| 一次完整 skill 调用 | ~42k | ~15-20k | 50%+ |
| 200k context 能跑几个任务 | 4-5 个 | 8-10 个 | 100%+ |
| 任务被打断后续跑 | ❌ 丢失 | ✅ 完整恢复 | — |
### v0.3.0 — 兑现"治幻觉、健忘、杂乱"三大承诺
- **新增 `core/preamble.md`** — 强制开始前 5 步流程(治幻觉 + 治健忘)
- **新增 `core/postamble.md`** — 强制结束后 6 步流程(治幻觉 + 治不成体系)
- **新增 `core/output-archive.md`** — 输出归档命名规范,让所有 skill 输出可 diff、可 review、可引用
- **新增 `core/acceptance.md`** — 输出验收清单(通用 + 各 skill 专属),最后一道质量关卡
- **新增 `core/menu.md`** — 零配置入口菜单。用户首次使用 / 输入模糊时自动显示 16 个 skill 的编号菜单,直接按数字或描述选择任务。配套零配置工作区初始化(3 个问题搞定)
- **新增 `setup/workspace/active-tasks.md.template`** — 任务进度持久化机制,治"AI 忘记任务到哪了"
- **新增 3 个批量任务 skill**:
- `sm-batch-refresh` — 覆盖池批量刷新
- `sm-batch-earnings` — 财报季批量前瞻 / 复盘
- `sm-catalyst-sweep` — 每日催化剂扫描
- **重写所有 13 个旧 skill 的"开始前先取数"段** — 改为强制引用 preamble.md / postamble.md / output-archive.md / acceptance.md,每个 skill 加上独有的注意事项
- **更新 系统提示词.template** — 加入强制流程引用 + 主动报告进行中任务的规则
- **品牌定位升级** — 从"开放提示词栈" → "投研人的 AI 任务执行规范",三大痛点(幻觉/健忘/杂乱)显式列出
- **manifest.yaml 新增 `solves` 字段** — 机器可读的痛点声明
### v0.2.0
- 品牌正式命名为 **Investor Harness**
- 新建 `core/adapters.md` — 数据源优先级决策树
- 新建 `core/markets.md` — 市场识别与分市场差异
- 新增 `sm-master` skill — 7 模式长形态总控
- 新增 `setup/` — 投研工作区脚手架(系统提示词 / memory / 覆盖池 / 决策日志 / 偏差清单等模板)
- 新增 `setup/agents/` — 5 个多 agent 团队角色定义
- 所有 skill 的 frontmatter 补齐 `inputs / outputs / data_sources / markets`
- 增加顶层 `manifest.yaml`、`install/` 多 harness 安装脚本
### v0.1.0
- 12 个专业子 skill + autopilot
- Codex 安装脚本
---
## License
MIT © 2026 Joan Song
> ⚠️ **免责声明**:本工具不构成投资建议。所有 AI 生成内容仅供研究参考,使用者应自行核验关键数据、遵守所在机构合规要求。涉及投资决策必须进行人工复核。
---
**⭐ Star 让更多投研人看到** · [🐛 Issue](https://github.com/joansongjr/investor-harness/issues) · [🤝 PR](https://github.com/joansongjr/investor-harness/pulls)
FILE:core/_boot.md
# Investor Harness · Boot
> 🚀 每次新会话第一个读的文件。**< 1k tokens**。其他 core/* 按需懒加载。
## What this is
Investor Harness v0.4 — 投研人的 AI 任务执行规范。
治三大痛点:**幻觉 / 健忘 / 不成体系**。
## 17 skills (one-line each)
`sm-master`(7 模式总控) · `sm-autopilot`(自动路由) · `sm-thesis`(命题构建) · `sm-industry-map`(行业框架) · `sm-company-deepdive`(公司深度) · `sm-earnings-preview`(财报前瞻) · `sm-model-check`(模型审阅) · `sm-consensus-watch`(预期差) · `sm-catalyst-monitor`(事件跟踪) · `sm-roadshow-questions`(路演问题) · `sm-red-team`(反方审视) · `sm-pm-brief`(PM 一页纸) · `sm-briefing`(晨会晚报) · `sm-tape-review`(盘面 + 技术面复盘) · `sm-batch-refresh`(批量刷新) · `sm-batch-earnings`(财报季批量) · `sm-catalyst-sweep`(催化剂扫描)
## Boot protocol (新会话/compact 后)
1. 读 `.task-pulse`(如存在)
2. 读 `系统提示词`
3. 如 .task-pulse 有 in_progress 任务 → 主动告知用户 + 等选择,不要默认从头开始
4. 用户选了某 skill 才加载 SKILL.md
5. SKILL 内按需加载 core/preamble.md 等
## 三层加载(节省 token)
- **Tier 0** (always): _boot.md + .task-pulse + 系统提示词 ≈ 1.5k
- **Tier 1** (on skill invoke): SKILL.md + preamble + postamble + adapters ≈ 6k
- **Tier 2** (on demand): evidence / compliance / output-archive / acceptance ≈ 5k
⛔ 不要在不需要时加载 Tier 2。
## Resume protocol (断点续跑)
```
1. 读 .task-pulse → 找 in_progress 任务 id
2. 读 .checkpoint/{task-id}.md → 知道做到哪段
3. 加载对应 SKILL.md
4. 从断点继续,不重复
5. 完成后写最终输出到归档路径,更新 .task-pulse 标 done
```
## Output discipline (v0.5.1 双输出)
- 输出贴到对话即可。
- 对话里贴完整内容(人类读),文件里存完整内容(归档 + 跨 skill 引用)
- 结尾追加 `📁 已归档:{path}` 提示 + 关键统计 + 下一步建议
- **不要**只回摘要——很多人在云端跑,打不开本地文件
- 例外:用户明确说"省 token 模式"才退回到摘要
## Where to find more
| 需要时读 | 文件 |
|---|---|
| 完整 5 步开始前 | core/preamble.md |
| 完整 6 步结束后 | core/postamble.md |
| 数据源决策树 | core/adapters.md |
| 证据分级 F1-H1 | core/evidence.md |
| 合规边界 | core/compliance.md |
| 归档命名规范 | core/output-archive.md |
| 验收清单 | core/acceptance.md |
| 入口菜单 | core/menu.md |
| 市场识别 | core/markets.md |
| 任务持久化格式 | core/task-pulse.md |
| 断点续跑细节 | core/checkpoint.md |
FILE:core/acceptance.md
# Acceptance · 输出验收清单
> 每个 skill 输出完成后,必须按本清单逐条自检。任何一条没过 → 不算完成 → 必须补完再交付。
>
> 这是治"幻觉"和"不成体系"的最后一道关卡。
---
## 通用验收清单(所有 skill 都要过)
### A. Preamble 完成度(治健忘)
- [ ] **A1** 已识别市场(CN-A / CN-FUND / HK / US / GLOBAL)
- [ ] **A2** 已检查同标的的历史输出(即使结果是"无")
- [ ] **A3** 已检查 active-tasks.md(即使结果是"新任务")
- [ ] **A4** 已输出 `[Preflight]` 段,包含取数计划
- [ ] **A5** 已实际调用工具取数(不只是声称要取)
### B. 证据纪律(治幻觉)
- [ ] **B1** 每条事实陈述都带 F1/F2/M1/C1/H1 标签
- [ ] **B2** 关键结论由 F1 / F2 支撑(不是 M1 或 H1)
- [ ] **B3** 所有 C1 都附了推演链路说明
- [ ] **B4** 没有把 H1 当作结论的唯一依据
- [ ] **B5** 没有混淆"事实"和"推测"
### C. 输出结构(治不成体系)
- [ ] **C1** 输出按本 skill 规定的结构(不是自由发挥)
- [ ] **C2** "仍需补的资料"段非空且分了"必需 / 建议 / 不确定"三档
- [ ] **C3** 末尾有"合规声明"段
- [ ] **C4** 末尾有数据来源列表
- [ ] **C5** 末尾有时间戳和使用的 skill 名
### D. 归档与持久化(治不成体系 + 治健忘)
- [ ] **D1** 输出已写入 [output-archive.md](output-archive.md) 规定的路径
- [ ] **D2** 文件名符合命名规范(YYYY-MM-DD-skill-short.md)
- [ ] **D3** 如果是覆盖标的,已更新该 ticker 的 INDEX.md
- [ ] **D4** active-tasks.md 已更新(status / progress / output 字段)
### E. 合规(治幻觉的硬约束)
- [ ] **E1** 没有"确定会涨"、"已经确认"、"内部消息证实"等违禁表述
- [ ] **E2** 没有承诺收益
- [ ] **E3** 没有给具体目标价(除非已标注"需人工复核")
- [ ] **E4** 没有给评级(除非已标注"需人工复核")
- [ ] **E5** 没有伪造渠道反馈、专家纪要、订单数据
---
## 各 skill 专属验收清单
### sm-company-deepdive 专属
- [ ] 9 段结构齐全:公司定位 / 业务拆分 / 收入驱动 / 利润驱动 / 核心竞争力 / 市场关注 / 可比公司 / 跟踪指标 / 仍需补的资料
- [ ] 至少 3 家可比公司的横向对比
- [ ] 至少 3 个"未来三个月跟踪指标"
- [ ] 业务拆分有具体收入占比(即使是 H1)
### sm-thesis 专属
- [ ] 命题是**可证伪**的(不是"长期看好"这种)
- [ ] 列出至少 3 个"必要条件"
- [ ] 列出"最早暴露错误的地方"
- [ ] 列出"未来一个月最该跟踪的三项数据"
### sm-earnings-preview 专属
- [ ] 引用了一致预期数字(即使是 H1 待核验)
- [ ] 列出"市场最关心的三个问题"
- [ ] beat/miss 的具体阈值(数字,不是"超预期"这种词)
- [ ] 财报后第一时间检查清单(T+0 / T+1 / T+3 三档)
- [ ] "若结果不同于预期,对原投资逻辑的影响"段
### sm-red-team 专属
- [ ] 反方观点必须可观测、可触发(不是套话)
- [ ] 至少 3 个具体的硬触发条件
- [ ] 检查了 biases.md 并显式报告命中情况
- [ ] 给了"如果命题被证伪,资金应该去哪"
- [ ] 不能以"长期向好"等讨好用户的话结尾
### sm-consensus-watch 专属
- [ ] 明确分了"市场已 price in 的内容" vs "未充分反映的变量"
- [ ] 预期差成立的"具体条件"
- [ ] 对估值锚的影响
### sm-pm-brief 专属
- [ ] 一页纸长度(< 800 字)
- [ ] 没有大段背景复述
- [ ] 入场条件 / 卖出条件都是硬触发
- [ ] 任何评级 / 目标价都标了"需人工复核"
### sm-briefing 专属
- [ ] "今日最重要的三件事"恰好三件
- [ ] 每件事都说清"对覆盖池的影响"
- [ ] 一句话给基金经理的精简表述
### sm-industry-map 专属
- [ ] 产业链结构有上中下游
- [ ] 至少 5 家关键公司的分工标注
- [ ] 当前市场争议点(不是"前景广阔")
- [ ] 至少 3 个行业跟踪指标
### sm-model-check 专属
- [ ] 至少 3 条"敏感性最高的变量"
- [ ] 至少 1 条"最容易误导结论的地方"
- [ ] 假设链明确列出
### sm-roadshow-questions 专属
- [ ] 每个问题都附"背后要验证什么"
- [ ] "若回答偏强 / 中性 / 偏弱各自意味着什么"
- [ ] 没有"请介绍一下业务进展"这种泛问题
### sm-catalyst-monitor 专属
- [ ] 影响路径明确(事件 → 收入 / 利润 / 估值 / 情绪)
- [ ] 跟踪节奏明确(一周 / 一个月 / 一季度)
### sm-master 专属
- [ ] 已显式声明本次走的是 7 种模式中的哪一种
- [ ] 按对应模式的结构输出
### sm-autopilot 专属
- [ ] 已显式声明本次自动路由到了哪个 / 哪几个 skill
- [ ] 整合输出而不是堆砌每个 skill 的完整输出
### sm-batch-refresh 专属
- [ ] 列出了本次刷新的标的清单(数量 + 来源)
- [ ] 每个标的有"更新的字段"摘要
- [ ] 失败的标的明确列出原因
### sm-batch-earnings 专属
- [ ] 按财报日期排序
- [ ] 每家公司的 preview 都通过通用验收清单 + sm-earnings-preview 专属清单
### sm-catalyst-sweep 专属
- [ ] 时间窗明确(默认 24 小时)
- [ ] 命中事件按重要性分级
- [ ] 每条命中关联到具体的 ticker
### sm-tape-review 专属
- [ ] 7 段结构齐全:行情摘要 / 资金 / K 线形态 / 技术指标 / 关键位 / 一致性检验 / 明日观察
- [ ] §1 行情数据带具体数字(涨跌幅 / 成交量 / 量比 / 换手率,全部 F2)
- [ ] §3 K 线形态有明确判断(不只是描述)
- [ ] §4 技术指标**带实际数值**(禁止凭印象写"金叉")
- [ ] §5 至少 2 个支撑位 + 2 个压力位
- [ ] §6 一致性检验**必须**引用最新 sm-thesis 或 sm-company-deepdive 结论
- [ ] §7 明日观察点带"如果 X → 意味着 Y"的条件式判断
- [ ] 没有"必涨"、"突破在即"等武断表述
- [ ] 没有日内 / 小时级 / 分钟级建议
---
## 自检的执行方式
LLM 在输出末尾必须显式跑一遍验收,输出形如:
```markdown
---
## 📋 Acceptance Self-check
**通用清单**:
- A. Preamble: ✅ A1 ✅ A2 ✅ A3 ✅ A4 ✅ A5
- B. 证据: ✅ B1 ✅ B2 ✅ B3 ✅ B4 ✅ B5
- C. 结构: ✅ C1 ✅ C2 ✅ C3 ✅ C4 ✅ C5
- D. 归档: ✅ D1 ✅ D2 ✅ D3 ✅ D4
- E. 合规: ✅ E1 ✅ E2 ✅ E3 ✅ E4 ✅ E5
**sm-{skill} 专属**:
- ✅ {item 1}
- ✅ {item 2}
- ⚠️ {item 3 — 部分通过,原因}
**结论**:✅ 通过 / ⚠️ 部分通过(已标注) / ❌ 不通过(需重新输出)
```
如果有任何一项 ❌,**必须重新执行该步骤后再交付**,不允许跳过。
---
## 这套验收的设计原则
1. **可机读** — 每条都是 binary check,未来可以做 LLM judge 自动评测
2. **覆盖三大痛点** — A/D 治健忘、B/E 治幻觉、C/D 治不成体系
3. **强制性** — 没过 = 没做完,不允许灰色地带
4. **skill 专属补充** — 每个 skill 有自己的关键结构验证
---
## 给团队 lead / 机构客户的承诺
任何一份通过本清单的输出,都满足:
- 可追溯(每条事实有来源等级)
- 可审计(输出已归档到固定路径)
- 可 review(结构标准化,团队成员可对比)
- 可合规(违禁表述已自动排除)
- 可承认不知道(仍需补的资料段非空)
如果一份输出没通过本清单 → **不应该交付给 PM 或客户**。
FILE:core/adapters.md
# Data Adapters
所有 sm-* skills 在开始输出前,先按本文件的"数据获取协议"拿数据,再进入各自的分析流程。
这是**建议模式**的决策树:给出优先级和判断条件,但不强制写死调用参数,允许 LLM 根据当前任务灵活选择。
---
## 总原则
1. **先确认任务的市场归属**(A 股 / 港股 / 美股 / 跨市场),参见 [markets.md](markets.md)
2. **按优先级探测可用数据源**:MCP 工具 → skill 工具 → 通用搜索 → 兜底
3. **拿到什么数据就标什么证据等级**(见 [evidence.md](evidence.md))
4. **数据不足时不要编造**,先走兜底流程让用户补
---
## 数据源优先级(通用决策树)
```
Step 1 — 判断标的市场
│
├── A 股 / 公募 → 跳 §A
├── 港股 → 跳 §H
├── 美股 → 跳 §U
└── 跨市场 / 行业主题 → §A + §H + §U 并行
Step 2 — 按市场分支获取数据
Step 3 — 若全部失败 → 走"兜底协议"
```
---
## §A — A 股 / 公募基金
**优先级 1:iFind MCP(同花顺官方数据)**
检测方式:工具命名空间存在 `hexin-ifind-ds-*`
- 公司层:`get_stock_summary`, `get_stock_performance`, `get_stock_financials`, `get_stock_info`, `get_stock_shareholders`, `get_risk_indicators`, `get_stock_events`, `get_esg_data`
- 行业 / 选股:`search_stocks`
- 基金:`search_funds`, `get_fund_profile`, `get_fund_portfolio`, `get_fund_market_performance`, `get_fund_ownership`
- 宏观:`get_edb_data`, `search_edb`
- 资讯 / 公告:`search_notice`, `search_news`, `search_trending_news`
调用约定:
- 所有 `query` 参数使用**中文自然语言**,包含证券名称/代码 + 指标名 + 时间范围
- 财务指标用报告期:`2025-12-31`、`2025-06-30`
- 选股条件不要过于宽泛,资讯 size 上限 20
**优先级 2:cn-web-search skill**
检测方式:用户环境中存在 `cn-web-search` skill 或等效工具
典型查询:
- `{公司名} 年报 2024`
- `{公司名} 产业链地位`
- `{公司名} 一致预期`
- `{行业} 景气度 2025`
**优先级 3:WebSearch(通用兜底)**
所有主流 harness 都支持。典型查询:
- `{公司名} 财报 site:cninfo.com.cn`
- `{公司名} 公告 site:sse.com.cn OR site:szse.cn`
**优先级 4:让用户贴材料**(走"兜底协议")
---
## §H — 港股
**优先级 1:cn-web-search skill**(如果可用)
- `{公司名} 业绩 HKEX`
- `{公司名} 通告`
**优先级 2:WebFetch 直取 HKEX 官网**
- `https://www.hkexnews.hk/` 搜索公告
- `https://www.hkex.com.hk/` 公司页面
**优先级 3:WebSearch**
- `{stock name} annual report hkex`
- `{股票代码} 港股 公告`
**优先级 4:兜底协议**
---
## §U — 美股
**优先级 1:WebSearch + SEC EDGAR**
- `{ticker} 10-K site:sec.gov`
- `{ticker} 10-Q site:sec.gov`
- `{company name} earnings transcript`
**优先级 2:WebFetch SEC EDGAR 直取**
- `https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK={ticker}`
**优先级 3:其他公开财经源**(WSJ、Reuters、Bloomberg 摘要、公司 IR 页)
**优先级 4:兜底协议**
---
## 跨市场 / 行业主题
例如 "全球动力电池供给" 这类题目:
1. 先用 `sm-industry-map` skill 的框架搭产业链
2. 按"核心玩家清单"拆解到各自市场(§A/§H/§U)
3. 并行拉数据,最后在同一个证据表里汇总
---
## 兜底协议(所有市场通用)
当上述优先级全部不可用时:
1. **停下来**,不要开始分析
2. 按下面模板回复用户:
```
我当前无法直接获取 {公司/行业/主题} 的数据。要继续,需要你提供:
必需(至少选一项):
- 最新年报 / 季报(PDF 或关键财务指标文本)
- 近一个季度的公司公告或新闻
- 你对标的的现有观点、材料、或研究笔记
可选(提高分析质量):
- 可比公司清单
- 你关心的关键变量
- 时间窗口(近期事件 vs. 长期逻辑)
贴完后我会按 sm-{current-skill} 的标准流程输出。
```
3. 拿到材料后才开始正式流程,并在输出的"仍需补的资料"一栏列出仍缺的项。
---
## 对 LLM 的行为要求
- **不要**猜数据。缺数据就走兜底或降级到下一优先级
- **不要**混合真假数据。比如用一个工具拿到的数据和自己推演的数字放在一起而不标注
- **要**在输出开头一行注明本次分析的数据来源(例:`数据来源:iFind MCP + 用户提供资料`)
- **要**为每条关键事实打证据等级标签(F1/F2/M1/C1/H1)
- **要**在"仍需补的资料"一栏列出未能获取的关键项
---
## 新增数据源时怎么办
如果未来接入新的 MCP 或工具(例如 Wind MCP、Bloomberg API),只需要:
1. 在本文件对应 §A/§H/§U 段落里插入新的优先级条目
2. 不需要修改任何 skill 文件
3. 发布 patch 版本
这就是 adapter 层抽离的核心价值——**数据源变化不影响方法论**。
FILE:core/checkpoint.md
# Checkpoint · 任务断点续跑机制
> 让 skill 能在 context overflow / compaction / 重开会话之后**从断点继续**而不是从头开始。
> 这是 v0.4 解决"健忘"痛点的核心机制。
---
## 文件位置
```
{workspace_root}/.checkpoint/{task-id}.md
```
每个 in_progress 任务一个文件。
---
## 何时写 checkpoint
每个 sm-* skill 必须遵循以下规则:
### Rule 1:每完成一个 H2 段就写 checkpoint
不要等任务全部完成才写文件。每完成一段就更新 checkpoint。
例:sm-company-deepdive 9 段,每完成 §1、§2、§3... 都更新 checkpoint。
### Rule 2:每次取数后写 checkpoint
如果一次 iFind 调用返回了关键数据,立即写入 checkpoint,避免数据丢失。
### Rule 3:context budget 警告时强制写 checkpoint
LLM 估算到剩余 context < 30k tokens 时,必须立即:
1. 写完当前段的 checkpoint
2. 告知用户"已写入 checkpoint,建议开新会话续跑"
3. 不再继续新段
---
## Checkpoint 文件格式
```markdown
# Checkpoint · {task-id}
**task_id**: t-001
**skill**: sm-company-deepdive
**target**: 688256_寒武纪
**started**: 2026-04-07T14:00:00Z
**last_updated**: 2026-04-07T14:30:00Z
**step**: 6/9
**status**: in_progress
## Completed sections
### §1 公司定位 ✅
{完整内容,按最终输出格式}
### §2 业务拆分 ✅
{完整内容}
### §3 收入驱动 ✅
{完整内容}
### §4 利润驱动 ✅
{完整内容}
### §5 核心竞争力 / 风险点 ✅
{完整内容}
### §6 市场关注焦点 ✅
{完整内容}
## In progress
### §7 与可比公司的关键差异 (in_progress)
{已经写到的部分}
## Pending
- §7 (continue)
- §8 未来三个月跟踪指标
- §9 仍需补的资料
## Data fetched so far
| Source | Tool | Result |
|---|---|---|
| iFind | get_stock_summary | ✅ pulled |
| iFind | get_stock_financials | ✅ pulled |
| iFind | get_stock_shareholders | ✅ pulled |
| WebSearch | "寒武纪 海光 对比" | ⚠️ partial |
| - | 卖方一致预期 | ❌ pending |
## Resume instructions
下次会话用以下指令恢复:
```
继续 t-001
```
LLM 会自动:
1. 读本文件
2. 跳过已完成的 §1-§6
3. 继续 §7(从已写的部分接着)
4. 完成 §8、§9
5. 写最终输出到归档路径
6. 删除本 checkpoint
7. 更新 .task-pulse 标 done
```
---
## 如何续跑
### 用户视角
```
用户:继续 t-001
LLM: 检查 .task-pulse → 找到 t-001
LLM: 读 .checkpoint/t-001.md → 看到做到 §6
LLM: 读 sm-company-deepdive/SKILL.md
LLM: 加载 §1-§6 的内容(已完成的)
LLM: 从 §7 继续工作
LLM: 完成 §7-§9
LLM: 写最终输出到 coverage/688256_寒武纪/deepdive/2026-04-07-deepdive.md
LLM: 删除 .checkpoint/t-001.md
LLM: 更新 .task-pulse 移除 t-001
LLM: 输出摘要给用户
```
### 简化指令
用户可以用以下任一方式触发续跑:
- "继续 t-001"
- "continue t-001"
- "resume task 001"
- "接着上次的"(LLM 自动从 .task-pulse 找最近一个 in_progress 任务)
---
## Checkpoint 文件大小约束
- **典型大小**:3-10 KB(包含 6-8 段已完成内容)
- **最大**:50 KB(如果超过说明任务粒度太粗,应该拆分)
- **超过 50 KB 的应对**:
- 把已完成的段落归档到归档路径
- checkpoint 只保留"指针"和"剩余部分"
## 清理协议
| 状态 | 清理时机 |
|---|---|
| 任务完成 | 立即删除 checkpoint |
| 任务取消 | 立即删除 checkpoint |
| 任务超过 7 天没动 | 标记为 stale,提醒用户清理 |
| 任务超过 30 天没动 | 自动归档到 `.checkpoint/archive/`,从主目录移除 |
---
## 与 .task-pulse 的协作
```
用户开新会话
↓
LLM 读 .task-pulse(< 100 tokens)
↓
看到 t-001 in_progress, ckpt: .checkpoint/t-001.md
↓
用户:"继续 t-001"
↓
LLM 读 .checkpoint/t-001.md(~5 KB)
↓
LLM 加载 sm-company-deepdive
↓
从 §7 继续
```
总成本:~3k tokens 恢复完整任务状态,vs 从头跑 ~25k+ tokens。
**节省:90%+**。
---
## 边界场景
### Q: 用户在中途改了想法,想换一个 skill 怎么办?
- 提示用户:"t-001 还没做完,确定要切换吗?"
- 用户确认后,移动 checkpoint 到 `.checkpoint/abandoned/`,保留以便事后回看
### Q: 多个会话同时编辑同一个 task 怎么办?
- 用 ts 字段做"乐观锁"
- 写入前检查 ts,如果发现 ts 比自己读的新 → 拒绝写入,告知用户冲突
### Q: checkpoint 文件本身丢了怎么办?
- LLM 检测到 .task-pulse 有 task 但 ckpt 文件不存在 → 警告用户 → 提供"从头开始"或"标记 abandoned"选项
### Q: 任务没有明确 9 段结构(比如 sm-briefing)怎么 checkpoint?
- 用 logical sections("今日事件 1 - 已完成"、"事件 2 - 进行中")
- step 字段写 "2/3" 等
---
## 给 skill 设计者的硬约束
每个 sm-* skill 在设计时必须支持 checkpoint。必要条件:
1. **可分段**:能拆成 N 个顺序步骤,每步可独立写 checkpoint
2. **幂等**:从 checkpoint 续跑产出的最终输出和一次跑完的输出相同
3. **可追溯**:checkpoint 包含足够信息让 LLM 重建上下文
不满足这三条的 skill 设计应该重做。
FILE:core/compliance.md
# Compliance
这组 skills 仅用于研究辅助与效率提升,不替代持牌分析师判断、内部审批和合规审核。
## 必守边界
- 不承诺收益
- 不生成买卖指令
- 不伪造渠道反馈、专家纪要、订单数据
- 不把非公开信息包装为公开结论
- 涉及评级、目标价、盈利预测调整时,提醒人工复核
## 推荐表达
- “基于当前公开信息,市场可能低估了……”
- “若以下条件成立,则盈利弹性可能来自……”
- “该判断仍需通过后续财报 / 数据验证”
## 禁止表达
- “确定会涨”
- “已经确认订单翻倍”
- “内部消息证实”
- “这次一定超预期”
FILE:core/evidence.md
# Evidence
所有投研 skills 统一使用以下证据标签,避免把猜测写成事实。
- `F1`:公开事实,可直接验证
- `F2`:财报、公告、官方披露、权威数据库
- `M1`:市场观点或一致预期
- `C1`:基于事实的合理推演
- `H1`:待核验线索或假设
## 使用原则
- 关键结论优先由 `F1`、`F2` 支撑
- 可以使用 `M1` 描述市场共识,但不能把共识当事实
- `C1` 必须说明推演链路
- `H1` 不能成为最终结论的唯一依据
FILE:core/markets.md
# Markets
Investor Harness 覆盖的市场范围与识别规则。
## 支持的市场
| 标签 | 市场 | 识别特征 | 主要数据源 |
|---|---|---|---|
| `CN-A` | A 股(沪深) | 6 位数字代码(6xxxxx/0xxxxx/3xxxxx)、中文公司名、"股份有限公司" | iFind MCP → cn-web-search → WebSearch |
| `CN-FUND` | 公募基金 | 6 位代码以 0/1/5 开头、"基金"字样 | iFind Fund MCP → cn-web-search |
| `HK` | 港股 | 4-5 位数字代码、HKEX、港交所、中文/英文混合 | cn-web-search → WebFetch HKEX |
| `US` | 美股 | 字母 ticker(AAPL, NVDA)、NYSE/NASDAQ、SEC filings | WebSearch SEC → WebFetch EDGAR |
| `GLOBAL` | 跨市场主题 | 行业 / 宏观 / 主题类问题 | 并行多市场 |
## 市场识别规则
LLM 收到任务后,按以下顺序判断:
1. 用户明确指定市场 → 直接采用
2. 用户给出标的代码 → 按代码格式匹配(见上表)
3. 用户给出公司中文全名 → 默认 `CN-A`,若包含"港"/"HK"/"H 股"切 `HK`
4. 用户给出英文公司名或 ticker → 默认 `US`
5. 用户只说行业 / 主题 → `GLOBAL`,按 sm-industry-map 展开
## 合规分市场差异
- **CN-A / CN-FUND**:严格遵守 `compliance.md`,涉及评级、目标价、盈利预测调整必须提醒人工复核
- **HK**:注意公告延迟和信息披露差异
- **US**:SEC 文件为主要 primary source,分析师报告为 M1 级
- **GLOBAL**:跨市场对比必须注明不同会计准则、不同季度披露口径
## 不支持
以下市场暂不在 harness 覆盖范围内,遇到时明确告知用户:
- 数字货币 / 加密资产
- 未上市 / 一级市场 / PE/VC 标的
- 大宗商品期货(可通过 iFind EDB 查指标但不做交易分析)
- 衍生品(期权、CDS 等)
FILE:core/menu.md
# Menu · 零配置入口菜单
> 这是用户首次使用 Investor Harness 时看到的"前台菜单"。
> 当 LLM 检测到用户输入符合下列任一触发条件,**必须直接显示这个菜单**,不要先解释 harness 是什么。
---
## 触发条件
LLM 看到以下任一情况,立即显示菜单:
- 用户说 "investor harness" / "harness" / "你能做什么" / "帮帮我"
- 用户说 "菜单" / "menu" / "选项" / "怎么用"
- 用户在新会话开始时只发了一个问候("你好" / "在吗" / "ready")
- 用户输入完全模糊(不到 5 个字且没有任何标的、行业、动作关键词)
- 用户明确说 "显示菜单" / "show menu"
- 用户问 "能帮我做什么" / "你会什么"
---
## 菜单内容(直接复制输出)
```
🎯 Investor Harness 已就绪!请选择你想做什么:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📊 研究类
1️⃣ 公司深度研究 — 起 coverage 或更新跟踪
2️⃣ 行业图谱 — 产业链地图、供需格局、关键公司
3️⃣ 投资命题构建 — 定义核心矛盾、拆解研究问题
📈 财报类
4️⃣ 财报前瞻 — 关注点、beat/miss 路径、指引听点
5️⃣ 财务模型校验 — 假设审阅、敏感性分析、断裂点
🔍 跟踪类
6️⃣ 一致预期监控 — 预期差挖掘、估值锚变化
7️⃣ 催化剂跟踪 — 事件/政策/订单/价格驱动
8️⃣ 路演问题设计 — 调研提纲、业绩会高价值问题
⚔️ 风控类
9️⃣ 反方论证 (Red Team) — 挑战多头逻辑、找证伪点
📋 输出类
🔟 基金经理摘要 (PM Brief) — 一页纸决策摘要
1️⃣1️⃣ 投研简报 — 晨会纪要、收盘复盘、调研纪要
⚡ 批量类(v0.3 新增)
1️⃣2️⃣ 覆盖池批量刷新 — 行情/财务/股东/催化一次更
1️⃣3️⃣ 财报季批量前瞻 — 一周内多家财报排队前瞻
1️⃣4️⃣ 每日催化剂扫描 — 晨会前 30 分钟扫一遍覆盖池
🤖 自动模式
1️⃣5️⃣ Autopilot — 给我一个公司名/行业/事件,自动跑全流程
1️⃣6️⃣ Master 模式 — 7 种工作模式自动识别,一个 skill 搞定
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
输入编号或直接描述你的需求,例如:
• "1" 或 "帮我深度看一下宁德时代"
• "4" 或 "做中芯国际财报前瞻"
• "9" 或 "我看多 AI 算力,帮我反方论证一下"
• "帮我看一下光模块行业" → 自动进入行业图谱
───
💡 提示:你还可以设置个人投研工作区,让 Harness 更好用:
• coverage.md — 你的覆盖池(跟踪哪些股票)
• biases.md — 你的投研偏差记录(Red Team 会自动检查)
• decision-log.md — 投资决策日志(半年后回看用)
• active-tasks.md — 任务进度持久化(跨会话接续)
要现在初始化吗?输入 "初始化工作区" 即可,10 秒搞定。
```
---
## 编号到 skill 的映射
| 编号 | Skill | 说明 |
|---|---|---|
| 1 | sm-company-deepdive | 公司深度研究 |
| 2 | sm-industry-map | 行业图谱 |
| 3 | sm-thesis | 投资命题构建 |
| 4 | sm-earnings-preview | 财报前瞻 |
| 5 | sm-model-check | 财务模型校验 |
| 6 | sm-consensus-watch | 一致预期监控 |
| 7 | sm-catalyst-monitor | 催化剂跟踪 |
| 8 | sm-roadshow-questions | 路演问题设计 |
| 9 | sm-red-team | 反方论证 |
| 10 | sm-pm-brief | PM 一页纸 |
| 11 | sm-briefing | 投研简报 |
| 12 | sm-batch-refresh | 覆盖池批量刷新 |
| 13 | sm-batch-earnings | 财报季批量前瞻 |
| 14 | sm-catalyst-sweep | 每日催化剂扫描 |
| 15 | sm-autopilot | 自动路由 |
| 16 | sm-master | 全能 7 模式 |
---
## 用户输入解析规则
### Case 1:输入纯数字("1" / "4" / "11")
直接路由到对应 skill:
- 询问标的:"好的,要分析哪家公司?" 然后等用户回答
- 拿到标的后,**立即按对应 skill 的强制流程开跑**(preamble.md → skill 主体 → postamble.md)
### Case 2:输入自然语言描述
LLM 自动识别用户意图,匹配最合适的 skill:
- 出现公司名 + "深度 / 起 coverage / 看看" → sm-company-deepdive
- 出现行业名 + "看看 / 怎么看" → sm-industry-map
- 出现 "财报 / 业绩 / 前瞻" → sm-earnings-preview
- 出现 "反方 / 唱反调 / 空头 / 找问题" → sm-red-team
- 出现 "晨会 / 简报 / 整理" → sm-briefing
- 出现 "PM / 一页纸 / 给老板" → sm-pm-brief
- 出现 "调研 / 路演 / 业绩会问题" → sm-roadshow-questions
- 出现 "模型 / 估值 / DCF" → sm-model-check
- 出现 "一致预期 / 预期差" → sm-consensus-watch
- 出现 "催化 / 事件 / 政策" → sm-catalyst-monitor
- 出现 "刷新覆盖池 / 周度更新" → sm-batch-refresh
- 出现 "财报季 / 一周财报" → sm-batch-earnings
- 出现 "扫一遍 / 今日催化" → sm-catalyst-sweep
- 完全模糊 / 没线索 → sm-autopilot
### Case 3:输入 "初始化工作区"
走零配置初始化流程(见下节)。
### Case 4:用户输入完全跟投研无关
礼貌告知 Investor Harness 的范围,再次显示菜单。
---
## 零配置初始化流程
当用户输入"初始化工作区"或类似指令时,LLM 必须按以下流程操作:
### Step 1:检查 bootstrap.sh 是否可执行
如果用户安装了完整 harness,运行:
```bash
clawhub install investor-harness
```
如果模板文件不存在,手动创建(见下)。
### Step 2:交互填空(最少必填)
用户必须填的最少信息:
1. **你的角色** — 卖方分析师 / 买方研究员 / PM / 个人投资者 / 学习中
2. **覆盖范围** — 哪个市场 + 哪些行业(一句话)
3. **首批覆盖标的** — 至少 1 个(用来初始化 coverage.md)
```
让我帮你初始化工作区。回答 3 个问题就好:
1. 你是谁?(卖方分析师 / 买方研究员 / PM / 个人投资者 / 学习中)
2. 你覆盖什么?(一句话,例:A 股科技板块 / 美股半导体)
3. 你正在跟踪哪个标的?(至少给 1 个,可以是公司名或代码)
```
### Step 3:生成最小可用工作区
根据用户回答,**立即**生成:
- `系统提示词` — 填好用户角色和覆盖范围
- `memory.md` — 填好身份和触发约定
- `coverage.md` — 填好首批标的
- `active-tasks.md` — 空模板
`biases.md` / `decision-log.md` / `watchlist.md` / `research-queue.md` 暂时不创建,等用户实际用到时再问。
### Step 4:返回菜单 + 引导第一个任务
```
✅ 工作区初始化完成!
- 角色:{你填的}
- 覆盖:{你填的}
- 已添加首批标的到 coverage.md:{ticker}
要不要我现在帮你跑一次第一个任务?建议从这个开始:
🎯 用 sm-company-deepdive 起 coverage:{你填的标的}
要继续吗?(输入"继续"或选择菜单的其他选项)
```
---
## 不显示菜单的情况
LLM **不应该**显示菜单的情况:
- 用户已明确指定了 skill 和标的("用 sm-thesis 看一下宁德时代")
- 用户在 active-tasks.md 里有进行中任务,且新输入显然是接续原任务
- 用户在跟某个 skill 的中间步骤交互
- 用户问了一个具体问题,应该被路由而不是被菜单打断
---
## 在 系统提示词 中如何引用
任何工作区的 系统提示词 应在"默认行为"段加上一句:
> **Menu trigger**: 当用户输入符合 [`~/.claude/skills/investor-harness/core/menu.md`](~/.claude/skills/investor-harness/core/menu.md) 的触发条件时,必须显示该文件中的菜单内容。
这样无论是单 skill 模式(只装了 sm-master)还是完整套件模式,都能用到菜单。
FILE:core/output-archive.md
# Output Archive · 归档命名规范
> 所有 sm-* skill 的输出都要按本规范归档,不许散落在临时目录。
> 这是治"不成体系"的物理基础——没有归档协议,所有的"半年后回看"承诺都是空话。
---
## 为什么必须归档
1. **可 diff**:三个月后重跑同一个 skill,可以和上次输出做 diff
2. **可 review**:团队成员可以读到你的研究,PM 可以审计你的工作
3. **可引用**:其他 skill 可以读到同标的的历史输出(见 [preamble.md](preamble.md) Step 2)
4. **可追溯**:每次决策都能查到当时的研究底稿
5. **可批量更新**:周度刷新等批量任务依赖归档结构
---
## 默认目录结构
### 单股研究
```
{coverage_root}/
├── {ticker}_{name}/ ← 一家公司一个目录
│ ├── INDEX.md ← 公司元数据 + 当前命题摘要
│ │
│ ├── thesis/ ← sm-thesis 输出
│ │ ├── 2026-04-07-thesis.md
│ │ └── 2026-07-15-thesis-update.md
│ │
│ ├── deepdive/ ← sm-company-deepdive 输出
│ │ ├── 2026-04-07-deepdive.md
│ │ └── 2026-08-20-deepdive-update.md
│ │
│ ├── earnings/ ← sm-earnings-preview 输出
│ │ ├── 2026-Q1-preview.md
│ │ ├── 2026-Q1-postmortem.md
│ │ ├── 2026-Q2-preview.md
│ │ └── 2026-Q2-postmortem.md
│ │
│ ├── catalysts/ ← sm-catalyst-monitor 输出
│ │ └── 2026-04-07-event-{name}.md
│ │
│ ├── consensus/ ← sm-consensus-watch 输出
│ │ └── 2026-04-07-consensus.md
│ │
│ ├── red-team/ ← sm-red-team 输出
│ │ └── 2026-04-07-redteam.md
│ │
│ ├── model/ ← sm-model-check 输出 + 模型文件
│ │ └── 2026-04-07-modelcheck.md
│ │
│ ├── roadshow/ ← sm-roadshow-questions 输出
│ │ └── 2026-04-07-roadshow.md
│ │
│ ├── pm-brief/ ← sm-pm-brief 输出
│ │ └── 2026-04-07-pmbrief.md
│ │
│ ├── data/ ← 原始数据快照(财报、公告等)
│ │ ├── 2024-annual-report.pdf
│ │ └── 2025-Q3-financials.json
│ │
│ └── notes/ ← 路演纪要、调研、专家访谈
│ └── 2026-04-05-management-call.md
```
### 行业 / 主题研究
```
{workspace_root}/themes/
└── {theme-slug}/
├── INDEX.md
├── 2026-04-07-industry-map.md ← sm-industry-map 输出
├── 2026-04-07-thesis.md ← sm-thesis 输出
└── members/ ← 主题相关公司的索引(软链 / md 链接)
├── 寒武纪 → ../../coverage/688256_寒武纪/
└── 海光信息 → ../../coverage/688041_海光信息/
```
### 晨会 / 简报
```
{workspace_root}/briefings/
├── 2026-04-07-morning.md ← sm-briefing 输出
├── 2026-04-07-evening.md
└── weekly/
└── 2026-W14.md
```
---
## 命名规范
### 文件名格式
```
{YYYY-MM-DD}-{skill-short}[-{descriptor}].md
```
| 字段 | 说明 | 示例 |
|---|---|---|
| `YYYY-MM-DD` | 必填,输出当天日期 | `2026-04-07` |
| `skill-short` | skill 的简称 | `deepdive` / `thesis` / `preview` |
| `descriptor` | 可选,区分同日多次输出 | `update` / `postmortem` / `q4-special` |
### Skill 简称对照表
| Full skill name | Short name |
|---|---|
| `sm-master` | `master` |
| `sm-autopilot` | `autopilot` |
| `sm-thesis` | `thesis` |
| `sm-industry-map` | `industry` |
| `sm-company-deepdive` | `deepdive` |
| `sm-earnings-preview` | `earnings` |
| `sm-model-check` | `modelcheck` |
| `sm-consensus-watch` | `consensus` |
| `sm-catalyst-monitor` | `catalyst` |
| `sm-roadshow-questions` | `roadshow` |
| `sm-red-team` | `redteam` |
| `sm-pm-brief` | `pmbrief` |
| `sm-briefing` | `briefing` |
| `sm-batch-refresh` | `batch-refresh` |
| `sm-batch-earnings` | `batch-earnings` |
| `sm-catalyst-sweep` | `catalyst-sweep` |
### Ticker 目录命名
```
{ticker}_{name}/
```
- `ticker` 优先用交易所代码(A 股 6 位、港股 4-5 位、美股字母)
- `name` 用公司中文名(A 股、港股)或英文名(美股)
- 例:`688256_寒武纪/`、`0700_腾讯控股/`、`NVDA_NVIDIA/`
---
## 配置:coverage_root 在哪
每个工作区的 `系统提示词` 建议用户自行配置 coverage_root。
```yaml
# In 系统提示词
coverage_root: ../覆盖公司库
workspace_root: ./
```
如果用户没设置:
- 默认 `coverage_root: ./coverage`
- 默认 `workspace_root: ./`
skills 按用户指定的路径归档。
---
## INDEX.md 的作用
每个 ticker 目录下的 `INDEX.md` 是该公司的"元数据 + 命题摘要":
```markdown
# {Ticker} {Name}
**market**: CN-A
**sector**: 半导体
**started_coverage**: 2026-01-15
**last_updated**: 2026-04-07
**current_thesis**: "AI 算力国产替代龙头,2026 思元 590 量产是关键拐点"
**conviction**: medium
**latest_outputs**:
- thesis: thesis/2026-04-07-thesis.md
- deepdive: deepdive/2026-04-07-deepdive.md
- earnings: earnings/2026-Q1-preview.md
- red-team: red-team/2026-04-07-redteam.md
**next_catalysts**:
- 2026-05-XX 公司业绩会
- 2026-Q2 思元 590 量产指引
**watchlist_triggers**:
- 思元 590 量产延后 → 下修
- BIS 进一步收紧 → 上修
```
INDEX.md 是 LLM **每次** preamble Step 2 检查的首要文件。
---
## 历史输出的引用机制
当 preamble.md Step 2 发现历史输出时,LLM 应该:
1. 读取最近一份同 skill 的输出,diff 与本次的差异
2. 读取该公司的 INDEX.md 拿到 current_thesis
3. 读取相关其他 skill 的最近一份(如果做 deepdive,读 thesis;如果做 earnings preview,读 deepdive 和 consensus)
4. 在本次输出顶部声明:`本次为更新 — 上次 deepdive 2026-01-15,上次 thesis 2026-02-20`
---
## 团队场景(v0.4 预留)
未来团队版会增加:
- `coverage_root` 区分 `team-coverage/` vs `personal-coverage/`
- 输出归档时自动加 `author` 字段
- 团队 review 工作流
当前 v0.3 只支持单人工作区。
FILE:core/postamble.md
# Postamble · 强制结束后流程
> 所有 sm-* skill 在产生分析输出**之后**,必须按本文件依序完成 7 个步骤。
> 跳过任何一步视为未完成任务。
>
> 这是治"幻觉"和"不成体系"的核心机制。
>
> v0.4 改动:新增 Step 0(增量 checkpoint 写入)+ Step 7(context echo 简化),原 6 步保留。
---
## Step 0 · 增量 Checkpoint 写入(v0.4 新增 · 治健忘)
**每完成一段输出,立即更新 checkpoint,不要等任务全部完成**。
具体操作:
1. 写入 `.checkpoint/{task-id}.md` 的对应段落
2. 更新 `.task-pulse` 的 `step` 字段(如 "5/9" → "6/9")
3. 估算剩余 context budget:
- 剩余 > 30k → 继续下一段
- 剩余 < 30k → 写完当前段后**主动提醒**用户"context 紧张,建议本任务跑完后开新会话"
- 剩余 < 10k → **强制停止**,写 checkpoint,告知用户"已保存进度,请用'继续 {task-id}' 开新会话续跑"
详细机制见 [checkpoint.md](checkpoint.md)。
---
## Step 1 · 自检证据等级(治幻觉)
回看本次输出的每一段。每一条"事实陈述"必须有 F1/F2/M1/C1/H1 标签之一:
| 标签 | 含义 |
|---|---|
| **F1** | 公开事实,可直接验证 |
| **F2** | 财报 / 公告 / 权威披露 |
| **M1** | 市场观点 / 一致预期 |
| **C1** | 基于事实的合理推演(必须说明推演链路) |
| **H1** | 待核验线索或假设 |
**自检规则**:
- 没有标签的"事实"句子 → **必须**补标
- 关键结论必须有 F1 / F2 支撑
- M1 不能当事实
- C1 必须附推演链路
- H1 不能成为最终结论的唯一依据
详见 [evidence.md](evidence.md)。
---
## Step 2 · 输出"仍需补的资料"段(治幻觉的强制承认)
每份交付**必须**有这一段,按以下结构:
```markdown
## 仍需补的资料
**必需**(关键缺口,影响结论可靠性):
- {数据 1} — 应从 {来源} 获取
- {数据 2} — 应从 {来源} 获取
**建议**(提升分析质量):
- {数据 3}
- {数据 4}
**不确定但影响判断**:
- {假设性问题}
```
**这一段不能为空**。任何 skill 跑完都会有"我没拿到的数据",你必须老实列出来。
如果你觉得"什么都拿到了"——说明你没真的检视过自己的输出,回去再看一遍。
---
## Step 3 · 输出合规声明
每份交付末尾**必须**附以下段落(按场景调整):
```markdown
---
⚠️ **合规声明**:本输出不构成投资建议。
- 涉及评级 / 目标价 / 盈利预测调整 → 必须经持牌分析师人工复核
- 数据来源:{本次实际使用的数据源}
- 输出时间:{YYYY-MM-DD HH:MM}
- 使用的 skill:{sm-xxx}
```
详见 [compliance.md](compliance.md)。
---
## Step 4 · 归档输出(治不成体系)
按 [output-archive.md](output-archive.md) 的命名规范,把本次输出写入归档路径:
```
{coverage_root}/{ticker}/{skill}/{YYYY-MM-DD}-{skill}.md
```
或对于行业 / 主题任务:
```
{workspace_root}/themes/{theme}/{YYYY-MM-DD}-{skill}.md
```
**为什么必须归档**:
- 半年后回看可以 diff
- 团队成员可以 review
- 跨 skill 引用可以读到(preamble.md Step 2)
- 如果不归档,等于没做
如果用户没设置 coverage_root,归档到默认 `./output/{YYYY-MM-DD}-{skill}-{target}.md`。
---
## Step 5 · 更新任务进度(治健忘)
更新 `{workspace_root}/active-tasks.md`:
- 如果本次工作完成了某个 active task → 标记 `status: done` + 记录完成时间 + 输出归档路径
- 如果本次工作只完成了部分 → 更新 `progress` 字段,记录"做到哪一步"
- 如果本次工作产生了后续任务 → 在 `active-tasks.md` 添加新条目
---
## Step 6 · 验收清单
按 [acceptance.md](acceptance.md) 的清单逐条自检:
- [ ] Preamble 0-5 步全部完成
- [ ] 每条事实带证据等级
- [ ] "仍需补的资料"段非空
- [ ] 合规声明已附
- [ ] 输出已归档到正确路径
- [ ] .task-pulse + active-tasks.md 已更新
- [ ] .checkpoint 已删除(任务完成时)
**任何一条没过 → 不算完成 → 必须补完再交付**。
---
## Step 7 · Dual Output Discipline(v0.5.1 修正 · 双输出 + 文件备份)
> **v0.5.1 修正**:v0.4 原 Step 7 是"对话只回 ~300 token 摘要,完整输出在文件里"。
> 这个设计**忽视了云端用户**——很多人在 Claude.ai / Codex web / OpenCode hosted 上跑,**根本打不开本地文件**。
>
> **新原则**:完整输出**两份**——对话里贴一份(人类阅读),文件里存一份(归档 + 跨 skill 引用)。
---
### 核心规则
任务完成后**必须同时**:
1. **在对话里贴出完整输出** — 给用户直接读,包括 9 段全部内容、证据等级、仍需补的资料、合规声明
2. **写一份完整副本到归档路径** — 按 [output-archive.md](output-archive.md) 命名规范
3. **结尾追加一段简短的"📁 已归档"提示** — 告知用户文件位置 + 关键统计
---
### 标准结尾摘要(追加在完整输出末尾)
```
---
📁 **已归档**:{coverage_root}/{ticker}/{skill}/{YYYY-MM-DD}-{skill}.md
📊 文件大小:{N} KB · 段落数:{X/Y} · 证据:F1×{N} F2×{N} M1×{N} C1×{N} H1×{N}
🆔 Task ID:{task-id} · 状态:done
⚠️ 本输出不构成投资建议。涉及评级 / 目标价 / 盈利预测调整须经持牌分析师人工复核。
🔄 建议下一步:
- {推荐 1:基于本次输出的下一个 skill}
- {推荐 2:另一个相关 skill}
```
---
### 为什么是双输出而不是只贴对话或只写文件
| 场景 | 只贴对话(v0.3 老方式)| 只写文件(v0.4 错方式)| **双输出(v0.5.1 正确)** |
|---|---|---|---|
| 云端用户(Claude.ai / web) | ✅ 能看 | ❌ **打不开文件** | ✅ 直接读对话 |
| 本地用户 | ✅ 能看 | ⚠️ 要打开文件 | ✅ 对话直读 + 文件备份 |
| 跨 skill 引用 | ❌ 下次会话失效 | ✅ 文件可读 | ✅ 文件可读 |
| 长期归档 / diff | ❌ 没有 | ✅ 有 | ✅ 有 |
| context overflow | ✅ 输出还在文件 | ✅ 输出还在文件 | ✅ 输出还在文件 |
| 团队 review | ❌ 需要 ctrl+F | ✅ 可以 grep | ✅ 双方式 |
**结论**:双输出是唯一对所有用户都友好的方式。多花 5-10k tokens 换"全用户体验一致",值得。
---
### 上下文成本权衡
| 设计 | 每任务对话成本 | 200k context 能跑几个任务 |
|---|---|---|
| v0.3 旧方式(只贴对话) | ~5000 tokens | ~30 个 |
| v0.4 错方式(只回摘要) | ~300 tokens | ~50 个(理论但不可用) |
| **v0.5.1 双输出(推荐)** | **~5500 tokens** | **~25 个** |
25 个完整投研任务对一个会话来说足够了。**省 token 不能以牺牲可用性为代价**。
---
### 例外情况:用户主动要求"省 token 模式"
如果用户明确说**"只回摘要"** / **"省 token"** / **"我等会儿打开文件看"** → 可以退回到 v0.4 的纯摘要模式。
但**默认**必须双输出。
---
## 用户视角看到的最终输出(v0.5.1 双输出版)
```
[完整的 9 段 sm-company-deepdive 输出,按结构展开,每条带证据等级]
# 寒武纪 (688256.SH) · Coverage Deepdive
## 1. 公司定位
...
## 2. 业务拆分
...
[省略中间 7 段]
## 9. 仍需补的资料
...
---
📁 **已归档**:覆盖公司库/688256_寒武纪/deepdive/2026-04-07-deepdive.md
📊 文件大小:12.4 KB · 段落数:9/9 · 证据:F1×8 F2×15 M1×6 C1×9 H1×4
🆔 Task ID:t-001 · 状态:done
⚠️ 本输出不构成投资建议。涉及评级 / 目标价需人工复核。
🔄 建议下一步:
- sm-red-team 反方审视(推荐)
- sm-pm-brief 给 PM 一页纸
```
**总成本**:~5500 tokens 对话 + 12 KB 文件
**好处**:云端用户直接读,本地用户双备份,跨 skill 引用照常工作
FILE:core/preamble.md
# Preamble · 强制开始前流程
> 所有 sm-* skill 在产生任何分析输出**之前**,必须按本文件依序完成 6 个步骤。
> 这是治"幻觉"和"健忘"的核心机制——跳过任何一步视为未完成任务。
>
> v0.4 改动:新增 Step 0(任务断点检查),Steps 1-5 保留。
---
## Step 0 · 任务断点检查(v0.4 新增 · 治健忘)
在做任何其他事情之前:
1. **读 `.task-pulse`**(如果存在)
- 不存在 → 视为新工作区,跳过本 step
- 存在 → 解析 JSON,检查是否有进行中任务
2. **匹配本次请求**
- 如果用户输入是"继续 t-XXX"或类似 → 直接进入 [checkpoint.md](checkpoint.md) 的恢复流程
- 如果用户输入与 .task-pulse 中某个 in_progress 任务的 target 匹配 → 主动询问"你之前在做这个标的的 X 任务,要继续吗?"
- 如果不匹配 → 创建新 task 条目,分配 task-id
3. **创建 task 条目**
- 在 `.task-pulse` 添加新条目:`{id, skill, target, step:"0/N", ckpt:".checkpoint/{id}.md"}`
- 创建空的 `.checkpoint/{id}.md` 文件
4. **Context budget 估算**
- 如果当前会话已使用 > 150k tokens → 警告用户"建议本任务跑完后开新会话"
- 如果 > 180k → 强制只完成当前段,写 checkpoint,停止
---
## Step 1 · 识别市场
按 [markets.md](markets.md) 确定标的的市场归属:
- `CN-A` — A 股 / 沪深
- `CN-FUND` — 公募基金
- `HK` — 港股
- `US` — 美股
- `GLOBAL` — 跨市场主题 / 行业
输出标记:`市场:{CN-A | CN-FUND | HK | US | GLOBAL}`
---
## Step 2 · 检查历史输出(治健忘)
按 [output-archive.md](output-archive.md) 的归档路径检查:
```
{coverage_root}/{ticker}/research/
{coverage_root}/{ticker}/{skill}/
```
**如果存在同标的、同 skill 的历史输出**:
- 读取最近一次输出
- 在本次输出开头声明:`本次为更新(上次:YYYY-MM-DD)`
- 重点输出"自上次以来的变化",避免完全重写
**如果存在同标的、其他 skill 的历史输出**:
- 引用其结论作为本次工作的输入(标 M1 或 C1)
- 例:`命题来自 sm-thesis 输出 (2026-02-15)`
**如果完全无历史**:
- 在本次输出开头声明:`本次为首次研究`
- 进入下一步
---
## Step 3 · 检查任务进度(治健忘)
读取 `{workspace_root}/active-tasks.md`:
- 是否存在与本次任务相关的"进行中"任务?
- 如果是 → 读取 `progress` 字段,从断点继续
- 如果否 → 在本次工作开始时创建一条新的 active task
---
## Step 4 · 输出 [Preflight] 取数计划(治幻觉)
按 [adapters.md](adapters.md) 的数据源决策树,**强制**输出以下结构:
```
[Preflight]
标的:{公司/行业/主题}
市场:{Step 1 的结果}
历史状态:{Step 2 的结果,"首次研究" 或 "更新(上次 YYYY-MM-DD)"}
任务进度:{Step 3 的结果,"新任务" 或 "续 task-id"}
数据源优先级链:
1. {工具 A} → {预期拉取什么}
2. {工具 B} → {备用 / 补充}
3. {工具 C} → {兜底}
预期缺失项:
- {可能拿不到的关键数据 1}
- {可能拿不到的关键数据 2}
→ 这些将在末尾"仍需补的资料"段明确列出
```
**⛔ 严禁跳过 Preflight 直接开始分析输出。**
如果用户没给标的代码或者市场不明确:
- 先问一句歧义澄清问题(仅限同名标的、市场不明这两种情况)
- 拿到答案后再走完 Preflight
---
## Step 5 · 按优先级实际取数
按 Preflight 写的优先级链,**实际调用工具拿数据**:
- **不要**只在 Preflight 里"声称"要拿什么,要真去拿
- 拿到的每条数据**立即**标证据等级(F1/F2/M1/C1/H1,见 [evidence.md](evidence.md))
- 拿不到的数据**立即**记录到"缺失项实际清单",等会写进 postamble 的"仍需补的资料"段
---
## 完成 Preamble 之后
进入对应 skill 的具体分析流程。
分析输出的结尾必须按 [postamble.md](postamble.md) 走强制结束流程。
---
## 例外说明
**仅以下情况允许跳过 Preamble**:
- 用户明确说"不需要取数,我直接贴材料"——此时 Step 4 的优先级链直接写"用户提供材料"
- 用户明确说"快速看一下,不用深度"——此时仍需 Step 1/2/3,但 Step 4 可以简化
**任何其他情况跳过 Preamble 都视为违规。**
FILE:core/quick-prompts.md
# Quick Prompts
这份清单给“最低操作量”使用者。默认优先使用 `sm-autopilot`,尽量把输入压缩到一句话。
## 最常用一句话
- `请用 sm-autopilot 看一下宁德时代`
- `请用 sm-autopilot 看一下中际旭创,重点判断未来3个月预期差`
- `请用 sm-autopilot 看一下AI眼镜产业链`
- `请用 sm-autopilot 看一下英伟达发布会对A股算力链影响`
- `请用 sm-autopilot 做中芯国际财报前瞻`
- `请用 sm-autopilot 检查我上传的盈利预测模型`
- `请用 sm-autopilot 给我准备寒武纪业绩会提问`
## 更稳的一句话
如果愿意多给一点信息,推荐用下面格式:
```text
请用 sm-autopilot + 任务对象 + 关注点 + 时间窗
```
示例:
- `请用 sm-autopilot 看一下宁德时代,重点看储能和毛利率,时间窗未来3个月`
- `请用 sm-autopilot 做中芯国际财报前瞻,重点看成熟制程价格和下季指引`
- `请用 sm-autopilot 检查我上传的模型,重点看收入拆分、毛利率和capex`
## 团队内推荐统一口令
为了让团队输出更稳定,推荐统一使用这三种口令:
### 1. 看公司
```text
请用 sm-autopilot 看一下【公司名】,输出一句话结论、核心逻辑、预期差、风险和下一步行动。
```
### 2. 看财报
```text
请用 sm-autopilot 做【公司名】财报前瞻,输出市场最关心问题、潜在超预期点、潜在低于预期点和财报后检查清单。
```
### 3. 看模型
```text
请用 sm-autopilot 检查我上传的模型,输出最脆弱假设、最容易误导结论的地方和待核验项目。
```
## 不推荐的问法
- `分析一下XXX`
- `你怎么看`
- `简单说说`
这些问法不是不能用,而是容易让输出漂。最好至少补一个“关注点”。
FILE:core/task-pulse.md
# Task Pulse · 微型任务状态信号
> 一个 < 100 tokens 的 JSON 文件,让 LLM 在每次新会话用极小代价知道工作区当前状态。
> 类似 git 的 `.git/HEAD` —— 一个 pointer 文件维护整个工作区的"心跳"。
---
## 文件位置
```
{workspace_root}/.task-pulse
```
每个工作区一个。
---
## 文件格式(JSON)
```json
{
"v": "0.4",
"ts": "2026-04-07T14:30:00Z",
"tasks": [
{
"id": "t-001",
"skill": "deepdive",
"target": "688256_寒武纪",
"step": "6/9",
"ckpt": ".checkpoint/t-001.md"
},
{
"id": "t-002",
"skill": "earnings",
"target": "688981_中芯国际",
"step": "3/7",
"ckpt": ".checkpoint/t-002.md"
}
],
"compacted": false,
"warn": null
}
```
## 字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
| `v` | string | task-pulse 格式版本("0.4" 起) |
| `ts` | ISO 8601 | 最后一次更新时间 |
| `tasks` | array | 进行中的任务(最多 5 个) |
| `tasks[].id` | string | 任务唯一 id(短格式 t-NNN) |
| `tasks[].skill` | string | skill 简称(按 output-archive.md 简称表) |
| `tasks[].target` | string | 标的(ticker_name 或 theme-slug) |
| `tasks[].step` | string | 进度("6/9" 表示完成 6 段中的 9 段) |
| `tasks[].ckpt` | string | 该任务的 checkpoint 文件路径 |
| `compacted` | bool | 上次会话是否被 compact 过 |
| `warn` | string\|null | 上下文预警信息(context budget 剩余 < 30k 时设置) |
## 大小约束
- **目标**:< 500 字节
- **最大**:1 KB
- **超过 1 KB 触发清理**:archive 已完成任务,只保留 in_progress
## LLM 启动时的读取协议
1. 检查 `.task-pulse` 是否存在
- 不存在 → 视为新工作区,跳过任务恢复
2. 解析 JSON
- 解析失败 → 警告用户、跳过、不删除(避免数据丢失)
3. 如果 `compacted: true`
- 主动告知用户:"上次会话被 compact 过,已恢复任务状态"
4. 如果 `tasks` 非空
- 列出所有进行中任务给用户
- 等用户选择"继续 t-001"或"开始新任务"
5. 用户选择继续后
- 读对应 `ckpt` 文件
- 加载对应 skill
- 从 step 指示的位置继续
## LLM 完成 step 时的更新协议
每完成一段(不是每完成一个任务),更新 `.task-pulse` 的对应 task:
```
更新前: "step": "5/9"
更新后: "step": "6/9"
"ts": <当前时间>
```
并同时更新 `.checkpoint/{task-id}.md` 的内容。
## 任务完成时的清理协议
任务标 done 后:
- 从 `.task-pulse` 的 `tasks` 数组中移除该 task
- 把任务详情归档到 `active-tasks.md` 的"已完成"段
- 删除 `.checkpoint/{task-id}.md`
## 上下文预警协议
LLM 在每次输出后估算剩余 context budget。如果剩余 < 30k tokens:
1. 在 `.task-pulse` 设置 `warn: "context budget low: ~25k remaining"`
2. 在用户交互时主动告知:"上下文预算紧张,建议本任务跑完后开新会话"
3. 如果剩余 < 10k tokens
- **强制**写 checkpoint 后停止本任务
- 告知用户:"任务已保存到 .checkpoint/{id},请开新会话用 '继续 t-id' 接续"
## 与 active-tasks.md 的关系
| 文件 | 作用 | 大小 | 何时读 |
|---|---|---|---|
| `.task-pulse` | 心跳信号 | < 1 KB | **每次新会话**必读 |
| `active-tasks.md` | 完整任务历史 | 5-50 KB | **只在需要任务详情时**读 |
`.task-pulse` 是 active-tasks.md 的"索引"。LLM 默认只读 .task-pulse,**只在用户问详情时**才读 active-tasks.md。
这是 v0.4 节省 token 的核心设计。
FILE:core/templates.md
# Templates
## 默认整合输出
```text
一句话结论:
为什么现在值得看:
核心逻辑:
关键证据 / 预期差:
最关键催化:
最大风险与证伪点:
下一步行动:
本次默认假设:
```
## 一页纸摘要
```text
结论:
为什么现在看:
市场可能错在哪:
最关键催化:
最大风险:
建议下一步:
```
## 公司跟踪卡
```text
公司:
产业链位置:
收入驱动:
利润驱动:
市场关注点:
未来三个月关键指标:
仍需验证的问题:
```
## 晨会 / 晚报
```text
今日最重要的三件事:
1.
2.
3.
对覆盖池 / 组合的影响:
最值得跟踪的方向:
待回答问题:
一句话给基金经理:
```
## 财报前瞻
```text
公司:
财报日期:
一句话判断:
市场最关心的三个问题:
1.
2.
3.
本次财报最敏感的变量:
- 收入:
- 毛利率:
- 费用率:
- 现金流:
- 指引:
潜在超预期点:
潜在低于预期点:
财报后第一时间检查清单:
1.
2.
3.
```
## 模型检查
```text
模型目的:
核心假设:
-
-
-
收入驱动检查:
利润率 / 费用率检查:
现金流与资产负债表检查:
估值假设检查:
敏感性最高的三个变量:
1.
2.
3.
最容易误导结论的地方:
需要立刻回头核验的项目:
```
## 路演问题清单
```text
本次交流目的:
需要优先验证的三个假设:
1.
2.
3.
必问问题:
1.
2.
3.
每个问题背后验证什么:
若回答偏强 / 中性 / 偏弱,分别意味着什么:
交流后应如何更新观点或模型:
```
FILE:core/triggers.md
# Auto-Triggers · LLM 自动识别表
> 本文件解决 investor-harness 的根本问题:**LLM 默认走捷径,不会主动调 skill**。
>
> 用户 / 系统提示词 / agent.md 只能"软提醒",无法硬拦截。唯一的防御是:LLM 在看到用户消息的那一刻,用本文件的关键词表做 **pattern matching**,命中即触发对应 skill。
>
> v0.4 新增。配合 系统提示词 的 预加载ed 硬约束一起使用。
---
## 使用方法
LLM 在每次收到用户消息后,**第一件事**是扫描消息文本,匹配下表中的触发词:
1. 如果命中任一触发词 **且** 消息里提到覆盖池中的 ticker / 公司名
2. **立即停止"自由回答"模式**,改为"skill 调用"模式
3. 在回答开头明确声明:"识别到触发词 `{word}`,按 investor-harness 纪律执行 `sm-{skill}`"
4. 按 preamble.md 走 Step 0-5
5. 调对应 skill
6. 按 postamble.md 收尾
---
## 触发词表
### 估值类 → `sm-company-deepdive` + `sm-thesis`
| 中文触发词 | 英文触发词 |
|---|---|
| 估值怎么样 / 估值如何 | valuation / how is the valuation |
| 贵不贵 / 便宜不便宜 | expensive / cheap / overvalued / undervalued |
| P/E / PE 多少 | multiple / trading multiple |
| 值多少钱 / fair value | fair value / intrinsic value |
| 目标价 | target price / price target / TP |
| 合理估值 | justified multiple |
### 评级 / 买卖类 → `sm-thesis` + 必配 `sm-red-team`
| 中文 | 英文 |
|---|---|
| 值不值得买 | worth buying / should I buy |
| 看多看空 | bullish / bearish |
| 买入 / 卖出 / 持有建议 | buy / sell / hold recommendation |
| Rating / 评级 | rating / upgrade / downgrade |
| 多头逻辑 / 空头逻辑 | bull case / bear case |
### 业务 / 商业模式类 → `sm-company-deepdive`
| 中文 | 英文 |
|---|---|
| 做什么的 / 主营业务 | what does X do |
| 商业模式 | business model |
| 产业链位置 | value chain position |
| 收入来源 | revenue breakdown / segment |
| 客户结构 | customer concentration |
| 核心竞争力 | moat / competitive advantage |
### 财报类 → `sm-earnings-preview`
| 中文 | 英文 |
|---|---|
| 财报 / 业绩 | earnings / Q1 / Q2 / Q3 / Q4 results |
| 下季度 / 下次业绩 | next quarter |
| Beat / Miss | beat or miss |
| 预期 / 指引 | guidance / consensus |
### 比较类 → 两次 `sm-company-deepdive` + 合并
| 中文 | 英文 |
|---|---|
| A 和 B 对比 / 比较 | X vs Y / compare X and Y |
| 谁更好 | which is better |
| 相对估值 | relative valuation |
### 模型 / DCF 类 → `sm-model-check`
| 中文 | 英文 |
|---|---|
| 财务模型 | financial model |
| DCF 合理吗 | DCF reasonable |
| 假设怎么看 | assumptions check |
| WACC / 永续增长 | WACC / terminal growth |
### 催化剂 / 触发事件类 → `sm-catalyst-monitor`
| 中文 | 英文 |
|---|---|
| 催化剂 | catalyst |
| 下 3 个月关注什么 | next 3 months |
| 驱动因素 | driver |
### 一致预期类 → `sm-consensus-watch`
| 中文 | 英文 |
|---|---|
| 卖方最近怎么看 | sell-side view |
| 一致预期 | consensus estimate |
| 预期差 | expectation gap |
| 分析师评级变化 | analyst rating changes |
### 反方 / 红队类 → `sm-red-team`
| 中文 | 英文 |
|---|---|
| 反方 / 红队 | red team / devil's advocate |
| 多头逻辑有什么问题 | what could go wrong |
| 最大风险 | biggest risk |
### 路演 / 调研问题 → `sm-roadshow-questions`
| 中文 | 英文 |
|---|---|
| 见管理层问什么 | mgmt meeting questions |
| 路演问题 | roadshow questions |
| 调研清单 | diligence questions |
### PM 一页纸 → `sm-pm-brief`
| 中文 | 英文 |
|---|---|
| PM 视角 | PM view |
| 一页纸 | one-pager / brief |
| 投资要点 | investment summary |
### 简报类 → `sm-briefing`
| 中文 | 英文 |
|---|---|
| 今日动态 / 今天怎么样 | today's news |
| 本周要点 | weekly brief |
| 日报 / 周报 | daily briefing |
### 行业地图类 → `sm-industry-map`
| 中文 | 英文 |
|---|---|
| 产业链 / 行业全景 | industry map |
| 赛道玩家 | players in the space |
| 上下游 | value chain upstream/downstream |
---
## 防御规则
### 规则 1:宁可多触发,不可漏触发
触发了没必要的 skill → 代价是几秒钟额外 context read
漏触发 → 代价是违反纪律 + 用户被动发现 + 信任崩塌
**优先级:触发 > 效率**。
### 规则 2:模糊命中也要触发
用户说"NVDA 咋样"—— "咋样"不是精确触发词,但意图明显。**命中语义而非字面**。
### 规则 3:同一消息多词命中,取优先级最高
优先级:`sm-red-team > sm-thesis > sm-company-deepdive > 其他`
如果用户说"NVDA 值不值得买?要考虑反方"—— 同时触发 thesis + red-team,两个都要跑。
### 规则 4:用户明确说"快速看一下"时
仍然 MUST 执行最小集合:
1. `[Preflight]` 段(可以简化)
2. 关键事实带证据等级
3. 末尾合规声明
允许省略的:完整 9 段式 deepdive、历史输出检查、归档步骤
### 规则 5:**违规自我报告机制**
如果 LLM 发现自己**已经开始输出** 但意识到漏触发了,MUST 立即:
1. 停止当前输出
2. 说:"违规检测:我漏触发了 sm-{skill},现在回滚并按纪律重做"
3. 重启流程
---
## 反例集合(LLM 易犯错误)
### 反例 1:估值表格式输出
❌ **违规**:用户问"KEYS 和 MU 估值怎么样",LLM 直接拉 yfinance 数据出一张 fwd P/E 表格 + 多空观点。
✅ **正确**:识别"估值怎么样"+ "KEYS / MU 是覆盖池成员"→ 触发 `sm-company-deepdive`(两次)→ 完整 9 段式 → postamble 归档。
### 反例 2:闲聊式开场
❌ **违规**:用户说"最近 NVDA 跌了,怎么看",LLM 聊天式开始:"NVDA 最近回调主要因为..."
✅ **正确**:识别"怎么看"+ "NVDA"→ 触发 `sm-thesis`(命题构建)+ `sm-red-team`(反方)→ 按结构输出。
### 反例 3:只加合规声明不调 skill
❌ **违规**:LLM 写了一段自由分析,末尾加"以上仅供参考,不构成建议"—— 认为这样就合规。
✅ **正确**:合规声明**只是**交付的一部分,不是 skill 的替代。必须先调 skill 走流程,然后 postamble 才加合规声明。
### 反例 4:跳 Preflight
❌ **违规**:调了 skill 但直接开始 9 段式输出,没写 `[Preflight]`。
✅ **正确**:调 skill → 先写 `[Preflight]`(标的/市场/数据源链/缺失项)→ 再 9 段式。
---
## 落地建议
本文件需要配合以下两个机制之一才能发挥作用:
1. **系统提示词 预加载**(分析师工作区的 系统提示词 引用本文件,让 LLM 每次启动时都看到)
单独的 triggers.md 没有效果,必须有外部机制让 LLM 读到它。
---
## 版本
- v0.4.1(本版):首次引入 auto-trigger 概念,配合 系统提示词 硬约束
FILE:core/workflows.md
# Workflows
这组投研 skills 可以组合成类似 gstack 的研究流程。
## 最低操作量入口
- `sm-autopilot`
默认总控入口。适合不想自己挑 skill 的使用者。
## 推荐顺序
1. `sm-autopilot`
用于自动判断应该走哪条研究链路。
2. `sm-thesis`
用于定义问题和值不值得研究。
3. `sm-industry-map`
用于搭行业框架和产业链地图。
4. `sm-company-deepdive`
用于下沉到公司层面。
5. `sm-earnings-preview`
用于财报前瞻和财报后验证。
6. `sm-model-check`
用于检查盈利预测和估值模型。
7. `sm-consensus-watch`
用于判断市场预期差。
8. `sm-catalyst-monitor`
用于跟踪财报、政策和产业催化。
9. `sm-roadshow-questions`
用于准备路演和管理层交流问题。
10. `sm-red-team`
用于强制反方审视。
11. `sm-pm-brief` 或 `sm-briefing`
用于输出给基金经理、晨会或团队流转。
## 团队映射
- `sm-autopilot`:总控调度入口
- `sm-thesis`:基金经理 / 投资主理人
- `sm-industry-map`:行业研究员
- `sm-company-deepdive`:公司研究员
- `sm-earnings-preview`:财报季前瞻助理
- `sm-model-check`:模型审阅助理
- `sm-consensus-watch`:预期管理助理
- `sm-catalyst-monitor`:事件跟踪助理
- `sm-roadshow-questions`:调研提纲助理
- `sm-red-team`:反方风险官
- `sm-pm-brief`:面向投资决策层的输出官
- `sm-briefing`:晨会与材料整理助理
FILE:manifest.yaml
# Investor Harness 套件清单
# harness 开发者和 LLM 可读,用于发现、路由、依赖校验
name: investor-harness
display_name: Investor Harness
version: 0.6.0
description: 投研人的 AI 任务执行规范。17 个 sm-* skill 强制 LLM 在做投研工作时不出现幻觉、不丢失上下文、不输出杂乱。v0.5 新增技术面复盘 skill (sm-tape-review) + INSTALL-PROMPT.md 用户级强制提示词,让小白用户的 LLM 也能自动遵守规则。
license: MIT
author: Joan Song
homepage: https://github.com/joansongjr/investor-harness
compatible_harnesses:
- claude-code
- codex
- opencode
- openclaw
- generic # 任何支持"读取相对路径 markdown"的 harness
# 三大痛点定位 + v0.4 新增:上下文溢出保护
solves:
- hallucination: 强制取数协议 + 证据分级 + 仍需补的资料段
- task_forgetting: 持久化记忆系统 + .task-pulse + .checkpoint 断点续跑
- lack_of_structure: 16 个标准化 skill + 输出归档协议 + 验收清单
- context_overflow: 三层加载(Tier 0/1/2)+ 输出文件化 + Echo 简化 + 断点续跑
# 数据源:全部可选。skill 会按 adapters.md 的优先级逐级降级
data_sources:
optional:
- name: ifind-mcp
description: 同花顺 iFind MCP,覆盖 A 股、公募、宏观、资讯(用户需自备账号)
servers:
- hexin-ifind-ds-stock-mcp
- hexin-ifind-ds-fund-mcp
- hexin-ifind-ds-edb-mcp
- hexin-ifind-ds-news-mcp
- name: cn-web-search
description: 中文网页搜索 skill,聚合 17 个免费搜索引擎
- name: websearch
description: harness 内置的通用英文搜索(所有主流 harness 默认可用)
- name: webfetch
description: harness 内置的网页抓取(所有主流 harness 默认可用)
fallback: 用户手动贴材料(所有 skill 必须支持此模式)
markets:
- code: CN-A
name: A股(沪深)
- code: CN-FUND
name: 公募基金
- code: HK
name: 港股
- code: US
name: 美股
- code: GLOBAL
name: 跨市场主题
skills:
- id: sm-master
path: skills/sm-master
tier: entry
description: 单 skill 长形态总控,7 模式全量,适合"只装一个 skill"
- id: sm-autopilot
path: skills/sm-autopilot
tier: entry
description: 轻量路由入口,自动串联下游 skill
- id: sm-thesis
path: skills/sm-thesis
tier: framing
- id: sm-industry-map
path: skills/sm-industry-map
tier: framing
- id: sm-company-deepdive
path: skills/sm-company-deepdive
tier: research
- id: sm-earnings-preview
path: skills/sm-earnings-preview
tier: research
- id: sm-model-check
path: skills/sm-model-check
tier: research
- id: sm-consensus-watch
path: skills/sm-consensus-watch
tier: research
- id: sm-catalyst-monitor
path: skills/sm-catalyst-monitor
tier: monitoring
- id: sm-roadshow-questions
path: skills/sm-roadshow-questions
tier: monitoring
- id: sm-red-team
path: skills/sm-red-team
tier: challenge
- id: sm-pm-brief
path: skills/sm-pm-brief
tier: output
- id: sm-briefing
path: skills/sm-briefing
tier: output
# v0.5 新增技术面 skill
- id: sm-tape-review
path: skills/sm-tape-review
tier: technical
description: 盘面 + 技术面复盘(K 线 / 量价 / 指标 / 关键位 / 一致性检验)— v0.5 新增
# v0.3 新增 batch skills
- id: sm-batch-refresh
path: skills/sm-batch-refresh
tier: batch
description: 覆盖池批量刷新(行情/财务/股东/催化)— v0.3 新增
- id: sm-batch-earnings
path: skills/sm-batch-earnings
tier: batch
description: 财报季批量前瞻 / 复盘 — v0.3 新增
- id: sm-catalyst-sweep
path: skills/sm-catalyst-sweep
tier: batch
description: 覆盖池每日 / 每周催化剂扫描 — v0.3 新增
core:
- path: core/evidence.md
purpose: 证据分级 F1/F2/M1/C1/H1
- path: core/compliance.md
purpose: 合规边界与表达规范
- path: core/templates.md
purpose: 输出模板
- path: core/workflows.md
purpose: skill 协作顺序与团队映射
- path: core/adapters.md
purpose: 数据源优先级决策树
- path: core/markets.md
purpose: 市场识别与分市场差异
# v0.3 新增 core
- path: core/preamble.md
purpose: 强制开始前流程(识别市场→检查历史→检查任务→Preflight→实际取数)— v0.3 新增
- path: core/postamble.md
purpose: 强制结束后流程(证据自检→仍需补→合规声明→归档→更新任务→验收)— v0.3 新增
- path: core/output-archive.md
purpose: 输出归档命名规范 — v0.3 新增
- path: core/acceptance.md
purpose: 输出验收清单(通用 + 各 skill 专属)— v0.3 新增
- path: core/menu.md
purpose: 零配置入口菜单(首次使用 / 模糊输入时显示)— v0.3 新增
- path: core/_boot.md
purpose: 启动文件(每次新会话第一个读,~1.2k tokens)— v0.4 新增
- path: core/task-pulse.md
purpose: .task-pulse 心跳信号文件格式规范 — v0.4 新增
- path: core/checkpoint.md
purpose: .checkpoint/ 断点续跑机制规范 — v0.4 新增
user_install_prompt:
path: INSTALL-PROMPT.md
purpose: 用户复制粘贴到 ~/.claude/CLAUDE.md 的强制启用提示词,让 LLM 自动遵守 harness 规则 — v0.5 新增
critical: true
workspace_templates:
- path: setup/workspace/CLAUDE.md.template
purpose: 分析师 persona + 默认行为
- path: setup/workspace/memory.md.template
purpose: 记忆索引
- path: setup/workspace/coverage.md.template
purpose: 覆盖池清单
- path: setup/workspace/watchlist.md.template
purpose: 观察池
- path: setup/workspace/decision-log.md.template
purpose: 投资决策日志
- path: setup/workspace/biases.md.template
purpose: 已知偏差清单
- path: setup/workspace/research-queue.md.template
purpose: 待研究队列
- path: setup/workspace/active-tasks.md.template
purpose: 任务进度持久化 — v0.3 新增
recommended_workflows:
company_research:
- sm-company-deepdive
- sm-consensus-watch
- sm-red-team
- sm-pm-brief
industry_research:
- sm-thesis
- sm-industry-map
- sm-pm-brief
earnings_season:
- sm-earnings-preview
- sm-consensus-watch
- sm-model-check
- sm-pm-brief
event_driven:
- sm-catalyst-monitor
- sm-consensus-watch
- sm-pm-brief
daily_briefing:
- sm-briefing
# v0.3 新增批量工作流
weekly_coverage_refresh:
- sm-batch-refresh
- sm-catalyst-sweep
- sm-briefing
earnings_season_full:
- sm-batch-earnings
- sm-consensus-watch
- sm-pm-brief
daily_morning_routine:
- sm-catalyst-sweep
- sm-briefing
# v0.5 新增技术面工作流
daily_tape_review:
- sm-tape-review
add_position_decision:
- sm-thesis
- sm-red-team
- sm-tape-review
- sm-pm-brief
FILE:skills/sm-autopilot/SKILL.md
---
name: sm-autopilot
description: 二级市场投研总控入口 skill。面向最低操作量使用场景,自动识别用户是在看公司、行业、财报、模型、事件还是调研准备,并自动串联对应的投研 skills,优先直接产出可决策摘要而不是反复追问。
inputs:
- 公司名 / 股票代码 / 行业 / 主题 / 事件 / 文件
outputs:
- 整合型投研一页纸摘要
data_sources: 见 ../../core/adapters.md
markets: [CN-A, CN-FUND, HK, US, GLOBAL]
---
# SM Autopilot
这是整套投研 skill 组的"默认入口"。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Autopilot 特别注意:用户通常只给极少信息,preamble Step 4 的 [Preflight] 必须明确声明本次自动路由到了哪个 / 哪几个 sm-* 子 skill。
目标不是让使用者自己判断该用哪个 skill,而是让使用者只要给出最少的信息,比如:
- 一个公司名
- 一个行业 / 主题
- 一条新闻 / 一个事件
- 一个模型文件 / 财报 / PPT / 纪要
- 一句模糊需求
就能自动走到接近资深分析师工作流的输出。
## 最低输入要求
下面几种输入,任意一种都可以直接开工:
1. `公司 / 股票名` 例:`中际旭创怎么看`
2. `行业 / 主题` 例:`帮我看一下AI眼镜`
3. `事件` 例:`英伟达发布会对A股算力链影响`
4. `文件` 上传财报、模型、纪要、PPT,然后说 `帮我看重点`
5. `一个动作` 例:`帮我做财报前瞻`
如果用户只给了极少信息,不要立刻要求补一长串背景。优先基于默认规则推进,并在最后列出假设。
## 默认路由规则
收到任务后,先自动判断主任务类型,再决定调用哪些技能思路。不要把路由过程完整展示给用户,只展示整合后的最终结果。
### 1. 公司判断
**触发**:出现公司名、股票名、ticker;问"怎么看 / 值不值得看 / 给个判断"
**链路**:`sm-company-deepdive` → `sm-consensus-watch` → `sm-red-team`(轻量版)→ `sm-pm-brief`
**默认输出**:一页纸投资摘要
### 2. 行业 / 主题判断
**触发**:出现赛道、主题、产业链、行业
**链路**:`sm-thesis` → `sm-industry-map` → `sm-pm-brief`
**默认输出**:主线判断 + 产业链地图 + 核心跟踪指标
### 3. 财报前后任务
**触发**:出现财报、业绩、指引、预告、业绩会
**链路**:`sm-earnings-preview` → `sm-consensus-watch` → (如有模型)`sm-model-check` → `sm-pm-brief`
**默认输出**:财报前瞻摘要
### 4. 模型检查
**触发**:上传模型文件;提到盈利预测、估值、DCF、假设、勾稽
**链路**:`sm-model-check` → (如需)`sm-red-team` → `sm-pm-brief`
**默认输出**:模型风险摘要 + 待核验清单
### 5. 事件驱动 / 新闻影响
**触发**:出现政策、订单、价格、会议、发布会、出口限制、新产品、专家会
**链路**:`sm-catalyst-monitor` → `sm-consensus-watch` → `sm-pm-brief`
**默认输出**:事件影响判断 + 受益/受损方向 + 跟踪清单
### 6. 路演 / 调研 / 业绩会准备
**触发**:出现路演、调研、专家访谈、业绩会提问、管理层交流
**链路**:`sm-roadshow-questions` → (如需)`sm-thesis` 或 `sm-company-deepdive`
**默认输出**:可直接使用的问题清单
## 默认假设补全
如果用户没给完整背景,按下面规则自动补全,不要因为小缺口就停下来。
### 时间窗默认值
- 公司判断:未来 `3个月`
- 行业 / 主题:未来 `6个月`
- 财报任务:`当前季度` + `下季度指引`
- 模型检查:`未来12个月`,年度口径按 `未来2个财年`
- 事件驱动:`未来1周到1个季度`
### 输出默认值
如果用户没指定格式,默认输出:一句话结论 / 核心逻辑 / 关键证据 / 市场预期或预期差 / 催化剂或验证点 / 风险与证伪点 / 下一步行动
用户只说"简单看看"也不要只写两句话,仍要给一个可决策版本,只是压缩篇幅。
### 比较基准默认值
- A股:默认相对 `沪深300`
- 港股:默认相对 `恒生指数`
- 美股:默认相对 `标普500` 或 `纳指`
- 财报或模型:默认相对 `市场一致预期`
### 证据默认值
- 优先使用用户提供材料
- 无材料时,按 [../../core/adapters.md](../../core/adapters.md) 的兜底协议,基于公开信息框架输出,但必须明确哪些是待验证假设
## 追问规则
默认不要追问。只有下面三种情况允许追问一个问题:
- 同名公司 / 标的明显歧义
- 用户想要正式评级、目标价、盈利预测调整(合规边界)
- 上传了多个文件,但任务目标完全不明确
其他情况直接做,并在最后写 `本次默认假设`。
## 输出风格
优先输出最终整合稿,而不是把每个 skill 的中间过程都摊给用户看。
默认输出顺序:
1. `一句话结论`
2. `为什么现在值得看`
3. `核心逻辑`
4. `关键证据 / 预期差`(带证据等级 F1/F2/M1/C1/H1)
5. `最关键催化`
6. `最大风险与证伪点`
7. `下一步要做什么`
8. `本次默认假设`
## 极简使用法
以下输入都应能直接产出高质量结果:
- `请用 sm-autopilot 看一下宁德时代`
- `请用 sm-autopilot 看一下AI眼镜`
- `请用 sm-autopilot 做中芯国际财报前瞻`
- `请用 sm-autopilot 检查我上传的模型`
- `请用 sm-autopilot 给我准备寒武纪业绩会提问`
## 内部优先级
任务不明确时按以下优先级处理:
1. 先定义用户真正要解决的研究问题
2. 再选主 skill 路线
3. 再用其他 skill 作为辅助补强
4. 最后统一压缩成一个高密度输出
不要把用户变成调度员。这个 skill 的职责就是替用户做调度。
## 参考
- [../../core/workflows.md](../../core/workflows.md)
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/templates.md](../../core/templates.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/adapters.md](../../core/adapters.md)
- [../../core/markets.md](../../core/markets.md)
FILE:skills/sm-batch-earnings/SKILL.md
---
name: sm-batch-earnings
description: 财报季批量前瞻 / 复盘 skill。用于在一周或一个财报季内批量产出多家覆盖标的的财报前瞻或财报后复盘,按发布日期排序,统一输出格式,方便分析师团队在密集财报季高效响应。
inputs:
- 时间窗(如"下周"、"2026-Q1 财报季")
- 可选:标的范围(覆盖池子集 / 行业 / 全量)
- 可选:模式(preview 前瞻 / postmortem 复盘)
outputs:
- 按发布日期排序的批量财报报告
- 每家公司的标准前瞻或复盘
- 总体行业财报季节奏摘要
data_sources: 见 ../../core/adapters.md
markets: [CN-A, HK, US]
---
# SM Batch Earnings
这个 skill 用于**财报季的批量前瞻或复盘**——分析师团队在财报季最痛的时间窗。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Batch Earnings 特别注意:每家公司的子任务必须**完整调用 `sm-earnings-preview`** 的逻辑,不能简化。preamble Step 4 必须先列出本次时间窗内的全部财报日历。
## 适用场景
- **财报季前一周**:批量产出本周所有覆盖标的的前瞻
- **财报季中**:每天复盘前一日发布的多家结果
- **财报季后**:整合一个完整财报季的命题验证
## 工作流程
### 第一步:拉取财报日历
通过 iFind 或公司公告,拉出指定时间窗内的全部财报发布日:
```
[Earnings Calendar 2026-04-07 ~ 2026-04-14]
| 日期 | Ticker | 名称 | 类型 |
|---|---|---|---|
| 2026-04-08 | 688256 | 寒武纪 | Q1 财报 |
| 2026-04-10 | 0700 | 腾讯控股 | Q1 业绩会预告 |
| 2026-04-12 | NVDA | NVIDIA | FY26 Q1 |
```
### 第二步:按公司逐个跑完整 sm-earnings-preview
对每家公司:
- 调 `sm-earnings-preview` 完整流程
- 输出按 sm-earnings-preview 的结构
- 单家归档到 `{coverage_root}/{ticker}/earnings/{YYYY-QN}-preview.md`
### 第三步:生成总体节奏摘要
在每家完成后,汇总成一份"财报季节奏摘要":
```markdown
# Batch Earnings Preview · {Date Range}
## 本期覆盖
- N 家公司,按发布日期排序
## 行业层面观察
- AI 算力链:{X 家中 Y 家有上修指引可能}
- 半导体:{Z 家面临折旧压力高点}
- 新能源:{W 家受益储能放量}
## 高优先级关注
- 🔴 {ticker}:{为什么是高优先级}
- 🟡 {ticker}:{为什么}
## 各家详细前瞻链接
- [688256 寒武纪 Q1 Preview](coverage/688256_寒武纪/earnings/2026-Q1-preview.md)
- [688981 中芯国际 Q4 Preview](coverage/688981_中芯国际/earnings/2026-Q4-preview.md)
- ...
```
### 第四步(可选):复盘模式
如果是 postmortem 模式,对每家发布后的公司:
- 实际 vs 一致预期
- 实际 vs 你的 preview
- 对原 thesis 的影响
- 是否需要触发 sm-thesis update
## 输出验收(除通用清单外)
- [ ] 财报日历完整且按日期排序
- [ ] 每家公司的 preview / postmortem 都通过 sm-earnings-preview 的专属验收清单
- [ ] 行业层面观察非空
- [ ] 高优先级标的有显式标注
- [ ] 所有子输出已写入对应 ticker 目录
## 与其他 skill 的协作
- **每家 preview 内部**:触发 `sm-consensus-watch` 拿一致预期
- **postmortem 后**:如果实际显著偏离 preview → 触发 `sm-thesis update`
- **若高优先级**:自动建议跑 `sm-pm-brief` 给 PM 一页纸
- **批量收尾**:自动建议跑 `sm-briefing` 整合成晨会要点
## 性能与节流
- 大批量任务(>10 家)建议拆批执行
- 在 active-tasks.md 记录"批次进度",断点续做
- 单次会话不超过 20 家,超过分多个会话
## 参考
- [../../core/preamble.md](../../core/preamble.md)
- [../../core/postamble.md](../../core/postamble.md)
- [../../core/output-archive.md](../../core/output-archive.md)
- [../../core/acceptance.md](../../core/acceptance.md)
- [../sm-earnings-preview/SKILL.md](../sm-earnings-preview/SKILL.md)
FILE:skills/sm-batch-refresh/SKILL.md
---
name: sm-batch-refresh
description: 覆盖池批量刷新 skill。用于按周/月节奏批量更新覆盖公司的最新行情、财务、股东、催化剂等关键数据,并自动写入每家公司的归档目录。适合分析师团队维护几十到几百家覆盖标的。
inputs:
- 覆盖池清单(默认从 coverage_root/INDEX.md 读取)
- 可选:刷新范围(全量 / 子赛道 / 单家)
- 可选:刷新维度(全部 / 行情 / 财务 / 股东 / 催化剂)
outputs:
- 每家标的的批量更新摘要
- 失败标的清单 + 原因
- 总体覆盖池健康度报告
data_sources: 见 ../../core/adapters.md
markets: [CN-A, CN-FUND, HK, US]
---
# SM Batch Refresh
这个 skill 用于**批量维护覆盖公司池**——分析师团队最高频但最枯燥的工作。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Batch Refresh 特别注意:preamble Step 4 的 [Preflight] 必须列出本次刷新的标的清单 + 维度 + 预计的工具调用次数,确保用户知道这是大批量任务。
## 适用场景
- **每周一早晨**:刷新全部覆盖池的行情、本周公告、本周新闻
- **每月第一个工作日**:刷新所有公司的财务指标 + 股东结构
- **每季度财报季前**:批量预拉财报披露日历
- **临时全扫**:行业事件后批量看影响("美国限令更新,扫一遍 AI 算力链")
## 核心任务
1. **读取覆盖池清单**:从 `{coverage_root}/INDEX.md` 拉全部 ticker
2. **筛选范围**:按用户指定(全量 / 子赛道 / 个别)筛
3. **逐个执行**:对每个 ticker 调用对应的取数工具
4. **自动归档**:每家更新写入 `{coverage_root}/{ticker}_{name}/data/{YYYY-MM-DD}-refresh.md`
5. **生成总报告**:汇总成功 / 失败 / 显著变化
## 输出格式
### 总体摘要
```markdown
# Batch Refresh · {YYYY-MM-DD}
**范围**:{全量 82 家 / 光模块子赛道 22 家 / ...}
**维度**:{行情+公告+新闻 / 全部财务字段 / ...}
**用时**:{X 分钟}
## 摘要
- ✅ 成功更新:N 家
- ⚠️ 部分成功:M 家
- ❌ 失败:K 家
## 显著变化(关注点)
| Ticker | 名称 | 变化类型 | 详情 |
|---|---|---|---|
| 688256 | 寒武纪 | 重大公告 | 新增订单合同 (F2) |
| 688981 | 中芯国际 | 财务异常 | Q4 毛利率超预期 (F2) |
## 失败清单
| Ticker | 名称 | 失败原因 |
|---|---|---|
| {ticker} | {name} | iFind 超时 / 数据未披露 |
```
### 每家标的的更新明细(写入 data/ 目录)
```markdown
# {ticker} {name} · Refresh {YYYY-MM-DD}
## 行情快照
- 收盘价 / 周涨跌 / 月涨跌 / YTD (F2-iFind)
## 财务最新
- 最近一期 PE / PB / PS / ROE (F2-iFind)
- 营收 / 净利 / 毛利率 同比 (F2-iFind)
## 股东变化
- 十大股东最新一期 (F2-iFind)
- 与上一期对比 (C1)
## 本周公告 / 新闻
- {公告 1} (F2)
- {新闻 1} (M1)
## 自动告警
- ⚠️ 任何"显著变化"必须在这里标出(毛利率突变、股东大幅减持、重大公告等)
## 仍需补的资料
- {缺失项}
```
## 批量执行的最佳实践
### 节流
- 每个 ticker 之间至少 200ms 间隔,避免触发数据源 rate limit
- iFind MCP 单次会话最多 100 个 query,超过分批
### 失败重试
- 任何 ticker 失败立即记入失败清单,**不要中断整个批量任务**
- 全部跑完后统一汇报失败
### 增量更新
- 对比上次 refresh 的快照,**只输出有变化的字段**
- 避免每次都把全部数据重写一遍
### 任务持久化
- 长批量任务必须支持中断恢复
- 在 active-tasks.md 里记录"已完成 N/总 M",断点继续
## 与其他 skill 的协作
- **触发深度研究**:如果某只标的检测到"显著变化",**自动**触发 `sm-catalyst-monitor` 单点分析
- **触发反方审视**:如果某只标的本周涨幅超过 20%,**自动建议**走 `sm-red-team`
- **触发命题更新**:如果财务数据与上一份 thesis 假设矛盾,**主动提醒**用户跑 `sm-thesis` update
## 输出验收(除通用清单外)
- [ ] 已列出本次刷新的标的清单
- [ ] 每个标的有"更新的字段"摘要
- [ ] 失败的标的明确列出原因
- [ ] 显著变化已标注并触发后续 skill 建议
## 参考
- [../../core/preamble.md](../../core/preamble.md)
- [../../core/postamble.md](../../core/postamble.md)
- [../../core/output-archive.md](../../core/output-archive.md)
- [../../core/acceptance.md](../../core/acceptance.md)
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/compliance.md](../../core/compliance.md)
FILE:skills/sm-briefing/SKILL.md
---
name: sm-briefing
description: 晨会、晚报、调研纪要和路演提纲整理 skill。用于把零散信息整理成适合投研团队和基金经理阅读的结构化摘要,并明确最重要的事项、覆盖池影响和待跟踪问题。
inputs:
- 零散材料(新闻、纪要、公告、路演记录)
- 可选:覆盖池清单
outputs:
- 晨会/晚报结构化摘要
data_sources: 见 ../../core/adapters.md
markets: [CN-A, CN-FUND, HK, US, GLOBAL]
---
# SM Briefing
这个 skill 用于把材料整理成投研团队能直接使用的摘要。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Briefing 特别注意:通常需要拉近 24 小时内的资讯,preamble Step 4 的 [Preflight] 必须包含资讯类工具调用。
适用场景:
- 晨会要点
- 收盘复盘
- 调研纪要
- 路演摘要
- 问题清单
## 默认输出格式
- `今日最重要的三件事`
- `对覆盖池 / 组合的影响`
- `最值得跟踪的公司或方向`
- `待回答问题`
- `一句话给基金经理`
如果用户要调研提纲,改为输出:
- `调研目的`
- `必问问题`
- `不同回答分别意味着什么`
## 参考
- [../../core/templates.md](../../core/templates.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/adapters.md](../../core/adapters.md)
FILE:skills/sm-catalyst-monitor/SKILL.md
---
name: sm-catalyst-monitor
description: 事件催化与财报前瞻 skill。用于跟踪政策、财报、价格、订单、产品发布、产业数据等催化剂,判断其对收入、利润、估值或情绪的影响,并输出短中期跟踪清单。
inputs:
- 事件 / 新闻 / 政策 / 产业数据
- 可选:相关公司或板块清单
outputs:
- 事件影响判断 + 短中期跟踪清单
data_sources: 见 ../../core/adapters.md
markets: [CN-A, HK, US, GLOBAL]
---
# SM Catalyst Monitor
这个 skill 用于事件驱动研究和财报前瞻,不是简单新闻摘要。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Catalyst Monitor 特别注意:事件跟踪需要交叉多源(政策 + 公告 + 行业媒体),preamble Step 4 的 [Preflight] 必须列出至少 2 个独立信源。
## 核心任务
- 判断事件影响方向
- 区分一次性扰动和趋势性变化
- 判断影响收入、利润、估值还是风险偏好
- 给出跟踪节奏
## 输出格式
- `事件概述`
- `为什么重要`
- `影响路径`
- `最相关的公司 / 板块`
- `对盈利 / 估值 / 情绪的影响`
- `接下来一周到一个季度的跟踪清单`
## 典型适用任务
- 财报前瞻
- 政策点评
- 产业价格周跟踪
- 新品发布影响分析
- 订单 / 渠道 / 出货节奏变化跟踪
## 参考
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/templates.md](../../core/templates.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/adapters.md](../../core/adapters.md)
FILE:skills/sm-catalyst-sweep/SKILL.md
---
name: sm-catalyst-sweep
description: 覆盖池每日 / 每周催化剂扫描 skill。用于在固定时间窗内扫描全部覆盖标的的公告、新闻、政策、价格异动等催化剂信号,按重要性分级并关联到具体标的。适合做晨会前批量扫描和持仓异动监控。
inputs:
- 时间窗(默认 24 小时)
- 可选:标的范围(默认全覆盖池)
- 可选:催化剂类型筛选(公告 / 新闻 / 价格异动 / 政策)
outputs:
- 按重要性分级的催化剂清单
- 每条催化剂关联到具体 ticker 和影响判断
- 高优先级催化剂的后续 skill 调用建议
data_sources: 见 ../../core/adapters.md
markets: [CN-A, CN-FUND, HK, US, GLOBAL]
---
# SM Catalyst Sweep
这个 skill 用于**批量扫描覆盖池的所有催化剂信号**——分析师晨会前最该跑一次。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Catalyst Sweep 特别注意:preamble Step 4 必须明确时间窗(默认过去 24 小时),并按"覆盖池 → 子赛道 → 全市场"三层依次扫描。
## 适用场景
- **每日晨会前 30 分钟**:扫一遍覆盖池过去 24 小时的所有催化
- **重大事件后**:扫一遍受影响的子赛道("美国对华出口管制更新,扫一遍 AI 算力链")
- **每周一早晨**:扫上周末的政策、产业新闻、海外动态
- **持仓异动告警**:股价异常变动后追溯催化原因
## 工作流程
### 第一步:定义扫描范围
```
[Preflight - Sweep]
时间窗:{2026-04-06 09:00 ~ 2026-04-07 09:00}
标的范围:覆盖池 82 家
催化类型:公告 / 新闻 / 价格异动 / 政策
预计调用:iFind search_notice (82 次) + search_trending_news (按子赛道)
```
### 第二步:分类型扫描
**类型 A:公司层公告**
- 对每家覆盖标的调 `iFind.search_notice query="{name} 最近24小时公告"`
- 命中的写入候选清单
**类型 B:行业 / 政策新闻**
- 按子赛道调 `iFind.search_trending_news query="{sector} 今日热点"`
- 国家级政策调 `WebSearch site:gov.cn` 或新华社
**类型 C:价格异动**
- 调 `iFind.get_stock_performance` 拿覆盖池涨跌幅
- 标记 |变动| > 5% 的标的
### 第三步:按重要性分级
每条命中按以下标准打分:
| 级别 | 标准 | 处理 |
|---|---|---|
| 🔴 高 | 直接影响盈利预测的事件(重大合同、业绩预告、监管处罚) | 必须人工立即看 + 触发 sm-catalyst-monitor |
| 🟡 中 | 影响估值或叙事的事件(政策变化、行业数据) | 写入晨会要点 |
| 🟢 低 | 仅作为背景信息(一般新闻、例行公告) | 归档到 catalyst-log |
### 第四步:输出总扫描报告
```markdown
# Catalyst Sweep · {YYYY-MM-DD HH:MM}
**时间窗**:过去 24 小时
**覆盖范围**:82 家覆盖标的 + 5 个行业 + 政策面
**总命中**:N 条事件
## 🔴 高优先级(M 条)
### 1. {ticker} {name} - {事件标题}
- **类型**:业绩预告 / 重大合同 / 监管 / ...
- **影响方向**:⬆️ / ⬇️ / 中性
- **影响路径**:{一句话说明对哪个变量的影响}
- **建议下一步**:调 sm-catalyst-monitor 做深度分析
- **证据**:F2 - {链接}
### 2. ...
## 🟡 中优先级(K 条)
| Ticker | 名称 | 事件 | 影响方向 | 证据 |
|---|---|---|---|---|
| ... | ... | ... | ⬆️/⬇️ | F2 |
## 🟢 低优先级(J 条 - 仅归档)
[折叠列表]
## 行业级观察
- {子赛道 1}:{今日整体情绪/事件}
- {子赛道 2}:{今日整体情绪/事件}
## 政策面
- {国家级政策 1}
- {国家级政策 2}
## 价格异动 Top 5
| Ticker | 涨跌幅 | 原因(如已知) |
|---|---|---|
| ... | +X% | ... |
```
## 与其他 skill 的协作
- **🔴 高优先级标的** → **自动建议**调 `sm-catalyst-monitor` 做单事件深度
- **行业级共振** → **自动建议**调 `sm-industry-map update`
- **多个高优先级** → **自动建议**调 `sm-briefing` 整合成晨会要点
- **价格异动 Top 1-2** → **自动建议**调 `sm-red-team` 检查多空逻辑
## 输出验收(除通用清单外)
- [ ] 时间窗明确(具体到小时)
- [ ] 命中事件按 高/中/低 三级分类
- [ ] 每条命中关联具体 ticker(不能是"行业利好")
- [ ] 价格异动 Top 5 已附
- [ ] 高优先级事件都给出"建议下一步" skill
## 性能与节流
- 全量扫 82 家公告 + 行业新闻约需 5-8 分钟
- 节流:每个 query 之间 200ms
- 失败的标的记入失败清单,不中断扫描
- 进度写入 active-tasks.md
## 与 sm-batch-refresh 的区别
| 维度 | sm-catalyst-sweep | sm-batch-refresh |
|---|---|---|
| **频率** | 每日(24h 时间窗) | 每周/每月 |
| **重点** | 事件 / 催化 / 异动 | 财务 / 行情 / 股东 |
| **输出** | 行动导向(建议下一步) | 数据导向(更新数据) |
| **协作** | 触发 sm-catalyst-monitor | 触发 sm-thesis update |
两者互补,建议都跑。
## 参考
- [../../core/preamble.md](../../core/preamble.md)
- [../../core/postamble.md](../../core/postamble.md)
- [../../core/output-archive.md](../../core/output-archive.md)
- [../../core/acceptance.md](../../core/acceptance.md)
- [../sm-catalyst-monitor/SKILL.md](../sm-catalyst-monitor/SKILL.md)
- [../sm-briefing/SKILL.md](../sm-briefing/SKILL.md)
FILE:skills/sm-company-deepdive/SKILL.md
---
name: sm-company-deepdive
description: 二级市场公司深度研究 skill。用于拆解公司商业模式、收入利润驱动、产业链位置、竞争壁垒、关键客户、财务弹性和未来三个月跟踪指标。适合覆盖启动、公司更新和财报前准备。
inputs:
- 公司名 / 股票代码
- 可选:研究材料、年报、纪要、卖方摘要
outputs:
- 公司深度跟踪卡(9 段)
data_sources: 见 ../../core/adapters.md
markets: [CN-A, HK, US]
---
# SM Company Deepdive
这个 skill 用于公司层面的深度研究,不写空泛概述,要尽量回答"为什么是这家公司,而不是别人"。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Company Deepdive 是最吃数据的 skill,缺数据时**严禁**开始输出结论。如果 preamble 拿不到关键数据(最近一期财报、股东、可比公司),必须走兜底协议让用户贴材料。
适用场景:
- 覆盖启动
- 公司更新
- 财报前准备
- 可比公司比较
## 必答问题
- 公司在产业链里的位置是什么
- 收入增长靠什么驱动
- 利润弹性来自哪里
- 市场当前为什么关注它
- 与同行相比真正不同的地方是什么
- 下一个验证节点是什么
## 输出格式
- `公司定位`
- `业务拆分`
- `收入驱动`
- `利润驱动`
- `核心竞争力 / 风险点`
- `市场关注焦点`
- `与可比公司的关键差异`
- `未来三个月跟踪指标`
- `仍需补的资料`
## 约束
- 没有证据时,不要假设客户、订单或份额变化
- 避免把管理层表述直接当成事实
- 优先突出影响盈利和估值的变量
- 关键事实必须带证据等级(F1/F2/M1/C1/H1)
## 参考
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/templates.md](../../core/templates.md)
- [../../core/adapters.md](../../core/adapters.md)
- [../../core/markets.md](../../core/markets.md)
FILE:skills/sm-consensus-watch/SKILL.md
---
name: sm-consensus-watch
description: 一致预期与预期差管理 skill。用于判断市场已 price in 的内容、被低估或高估的变量、盈利与估值的偏差来源,以及哪些边际变化可能带来股价重估。适合财报季、估值切换和预期差挖掘。
inputs:
- 公司名 / 行业
- 可选:卖方一致预期、市场观点、公司指引
outputs:
- 预期差矩阵与验证节点
data_sources: 见 ../../core/adapters.md
markets: [CN-A, HK, US]
---
# SM Consensus Watch
这个 skill 用于研究"市场在想什么"以及"市场可能错在哪"。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Consensus Watch 特别注意:必须重点获取卖方一致预期(iFind `get_stock_performance` 或卖方研报摘要),缺这层数据时**禁止**输出预期差判断,必须明确告知用户"无法判断预期差"并走兜底。
## 核心任务
- 识别市场共识
- 判断哪些变量已被定价
- 找出边际变化
- 分析预期差对盈利、估值和仓位的影响
## 输出格式
- `市场共识`
- `已 price in 的内容`
- `可能未充分反映的变量`
- `预期差成立条件`
- `对盈利预测 / 估值锚 / 仓位讨论的影响`
- `最关键验证节点`
## 约束
- 不要把"我觉得"当作共识
- 不要脱离时间窗口谈预期差
- 尽量写清比较基准和估值语境
- 市场共识标 `M1`,被低估变量的支撑证据标 `F1`/`F2`
## 参考
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/templates.md](../../core/templates.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/adapters.md](../../core/adapters.md)
FILE:skills/sm-earnings-preview/SKILL.md
---
name: sm-earnings-preview
description: 证券分析师专用的财报前瞻与财报后验证 skill。用于围绕一致预期、模型假设、市场关注点和管理层指引,输出财报前需要验证的核心问题、潜在超预期或低于预期项,以及财报发布后的第一时间检查清单。
inputs:
- 公司名 + 财报日期
- 可选:历史财报、一致预期、卖方摘要、自建模型
outputs:
- 财报前瞻摘要 + 财报后第一时间检查清单
data_sources: 见 ../../core/adapters.md
markets: [CN-A, HK, US]
---
# SM Earnings Preview
这个 skill 用于财报季最常见的两类任务:
- 财报前瞻
- 财报后第一时间验证
目标不是重复一遍公司背景,而是回答"这次财报最该看什么,市场会对什么最敏感,什么结果会改变原来的投资命题"。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Earnings Preview 特别注意:preamble Step 4 的 [Preflight] 必须包含历史财务数据 + 一致预期 + 近期公告 + 行业同业数据 4 类。preamble Step 2 必须读取该公司最近一次 deepdive 和 thesis 输出作为基线。
## 适用场景
- "帮我做下周财报前瞻"
- "这次市场最关心哪三个问题"
- "财报后我要先核验什么"
- "哪些项目可能超预期 / 低于预期"
## 工作方式
默认按以下顺序输出:
1. 明确市场最关心的问题
2. 写清本次财报的关键变量
3. 区分收入、毛利、费用、现金流、指引五个层面的敏感项
4. 识别潜在超预期和低于预期来源
5. 给出财报后第一时间验证清单
## 输出格式
- `一句话判断`
- `市场最关心的三个问题`
- `本次财报最敏感的变量`
- `潜在超预期点`
- `潜在低于预期点`
- `管理层指引最该听什么`
- `财报后第一时间检查清单`
- `若结果不同于预期,对原投资逻辑意味着什么`
## 分析要求
- 一定要写清比较基准(同比、环比、相对一致预期)
- 一定要写清时间窗口(本季、下季指引、半年)
- 一定要区分"影响盈利"和"影响估值"的变量
- 如果用户给了模型、预期或卖方摘要,要优先基于这些材料展开
## 约束
- 不要凭空捏造一致预期数字
- 不要把管理层口径默认视为高可信度事实
- 没有足够信息时,应明确列出仍待验证项
## 参考
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/templates.md](../../core/templates.md)
- [../../core/adapters.md](../../core/adapters.md)
FILE:skills/sm-industry-map/SKILL.md
---
name: sm-industry-map
description: 二级市场行业框架与产业链拆解 skill。用于构建行业研究框架、供需逻辑、价格传导、竞争格局、关键公司地图和当前市场争议点。适合行业深度、主线梳理和赛道筛选。
inputs:
- 行业 / 主题名称
- 可选:已有研究材料、产业链初步认知
outputs:
- 行业框架图 + 关键公司地图 + 跟踪指标
data_sources: 见 ../../core/adapters.md
markets: [CN-A, HK, US, GLOBAL]
---
# SM Industry Map
这个 skill 用于行业和赛道层面的研究框架搭建。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Industry Map 特别注意:preamble Step 4 的 [Preflight] 必须包含产业链代表公司清单 + 行业指标 + 行业报告政策 3 类。归档路径在 `themes/{theme-slug}/`。
适用场景:
- 行业深度
- 赛道梳理
- 主题投资主线判断
- 周期与景气跟踪
## 输出重点
- 产业链地图
- 需求驱动因素
- 供给格局
- 价格与利润传导机制
- 关键公司定位
- 当前争议点和预期差来源
## 输出格式
- `行业一句话判断`
- `产业链结构`
- `需求侧驱动`
- `供给侧变化`
- `价格 / 利润传导`
- `重点公司与分工`
- `当前市场争议点`
- `最值得跟踪的行业指标`
## 约束
- 不要只列公司名单
- 不要把宏观背景写得过长
- 最终要落到"谁受益、谁受损、何时验证"
## 参考
- [../../core/workflows.md](../../core/workflows.md)
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/templates.md](../../core/templates.md)
- [../../core/adapters.md](../../core/adapters.md)
- [../../core/markets.md](../../core/markets.md)
FILE:skills/sm-master/SKILL.md
---
name: sm-master
description: 二级市场投研总控 skill(长形态)。7 种模式 Thesis/Coverage/Consensus/Catalyst/Red Team/Briefing/PM Prep 的全量说明,适合当作"单一 skill 入口"独立使用。若已安装完整 Investor Harness 套件,优先用 sm-autopilot 做路由,再进入各专门 skill。
inputs:
- 公司名 / 股票代码 / 行业 / 主题
- 可选:研究材料、财务模型、纪要、新闻链接
outputs:
- 按 7 模式之一产出结构化分析
data_sources:
- 见 ../../core/adapters.md
markets:
- CN-A
- CN-FUND
- HK
- US
- GLOBAL
license: MIT
---
# SM Master(二级市场投研总控)
这是 Investor Harness 的**长形态总控 skill**。如果你只想装一个 skill 就能跑全套流程,用这个。如果你装了完整套件(12 个专业子 skill),请优先使用 `sm-autopilot` 路由到具体子 skill。
## 适用对象
- 持牌证券分析师
- 买方研究员 / 基金经理 / 助理研究员
- 需要快速形成"观点、证据、催化、风险、跟踪清单"的投研团队
## 不适用场景
- 自动下单、交易执行、收益承诺
- 绕过研究合规、信息隔离墙或保密要求
- 将未经核验的传闻直接写成投资结论
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
SM Master 特别注意:作为长形态总控,必须在 [Preflight] 中**显式声明本次走的是 7 种模式中的哪一种**,并按对应模式的结构输出。
## 启动原则
收到投研类任务后,先判断当前任务属于哪一种模式,再按该模式输出,不要一上来就写长篇结论。
### 7 种模式
1. `Thesis`:形成投资主线、判断核心矛盾、拆解研究问题
2. `Coverage`:行业或公司深度跟踪
3. `Consensus`:一致预期、市场预期差、估值锚变化
4. `Catalyst`:事件驱动、财报、政策、价格、订单、产品周期跟踪
5. `Red Team`:反方论证、证伪路径、风险情景
6. `Briefing`:晨会纪要、收盘复盘、路演纪要、调研提纲
7. `PM Prep`:面向基金经理的决策摘要
### 模式自动选择规则
用户没有明确指定模式时:
- "怎么看 / 值不值得配 / 核心逻辑是什么" → `Thesis`
- "深挖某行业 / 某公司" → `Coverage`
- "预期差 / 一致预期 / 市场没反映什么" → `Consensus`
- "财报前看什么 / 催化剂 / 近期怎么跟踪" → `Catalyst`
- "反过来想 / 空头怎么看 / 最大的风险" → `Red Team`
- "整理成晨会 / 日报 / 纪要" → `Briefing`
- "给投资经理一页纸" → `PM Prep`
## 通用工作流
每次执行投研任务时遵循以下顺序:
1. **定义问题**:明确是行业判断、公司判断、事件判断,还是组合判断
2. **确定研究边界**:市场范围、时间窗口、比较基准、关键假设
3. **列证据清单**:事实、市场预期、可验证推演、待核验线索四类
4. **提炼核心矛盾**:什么变量决定股价,而不是只堆信息
5. **构造多空框架**:主逻辑、反逻辑、证伪点、跟踪指标
6. **输出行动项**:下一步应补的数据、要约的专家、要追的财报字段、需要更新的模型项
**不要**把以下几类内容混在一起:已证实事实、市场传闻、基于事实的推演、投资结论。必须显式标注哪些是事实,哪些是推演。
## 输出纪律
默认输出结构化、短结论、高信息密度,不追求"像研报",追求"可用于继续研究和决策"。
### 标准输出模块
1. `一句话结论`
2. `核心逻辑`
3. `关键证据`(带证据分级 F1/F2/M1/C1/H1)
4. `市场预期 / 预期差`
5. `催化剂`
6. `主要风险与证伪点`
7. `需继续核验的问题`
8. `下一步行动`
**如果信息不足**,不要强行给评级或目标价。先输出"当前不能下结论的原因"和"补足结论所需信息"。
---
## 模式细则
### Thesis
把模糊题目收敛成可研究、可验证、可跟踪的投资命题。
必须回答:
- 真正驱动股价的核心变量是什么
- 当前市场是否存在错误定价或错误预期
- 这是景气投资、困境反转、周期拐点、份额提升,还是估值切换
- 结论最可能被什么事实推翻
输出格式:
- 投资命题
- 命题成立的三个必要条件
- 当前最关键的验证点
- 最值得先跟踪的三项数据
### Coverage
行业深度、公司深度、覆盖启动和持续跟踪。
**覆盖行业时**至少包含:产业链地图、需求驱动、供给格局、价格与利润传导、关键公司定位、市场当前争议点
**覆盖公司时**至少包含:公司在产业链的位置、收入拆分与利润驱动、核心产品/客户/竞争壁垒、本轮市场关注点、与可比公司的异同、后续三个月最重要的跟踪指标
### Consensus
一致预期管理和预期差挖掘。重点不是复述共识,而是区分:
- 市场已经 price in 的内容
- 市场还没 price in 的边际变化
- 预期差来自哪里
- 变化是否足以穿透估值
输出格式:市场共识 → 被低估/高估的变量 → 预期差成立条件 → 对估值与仓位讨论的影响
### Catalyst
财报前瞻、政策点评、产业事件、订单、价格数据、产品发布等催化跟踪。
不是"新闻摘要",而是:
- 判断事件影响方向和持续性
- 判断影响的是收入、利润、估值,还是风险偏好
- 判断这是一次性扰动还是趋势性变化
输出格式:事件是什么 → 为什么重要 → 对哪些公司最相关 → 对盈利/估值/情绪分别影响 → 接下来一周到一个季度怎么跟踪
### Red Team
强制反方审视,防止单边叙事。至少输出:
- 多头最脆弱的三个假设
- 若结论错误,最早会在哪里暴露
- 什么数据一旦出现就应下修观点
- 还有哪些更好的替代标的/替代方向
**禁止**只写泛泛风险(如"宏观波动""政策风险")。风险必须可观测、可触发。
### Briefing
晨会、晚报、调研纪要、路演摘要、会议纪要。默认格式:
- 今日最重要的三件事
- 对组合或覆盖池最相关的影响
- 需要立刻跟踪/回答的问题
- 可转给基金经理或销售的精简表述
**调研提纲**输出:本次调研目的 → 必问问题 → 若回答 A/B/C 各自意味着什么
### PM Prep
给基金经理或投资决策会准备一页纸。压缩成"短而硬",避免大段背景介绍。
输出格式:结论 → 为什么现在看 → 市场可能错在哪 → 最关键催化 → 最大风险 → 建议下一步
---
## 证据分级
见 [../../core/evidence.md](../../core/evidence.md)。输出时为关键事实打 F1/F2/M1/C1/H1 标签。**不要**把 `H1` 当成结论核心。
## 合规边界
见 [../../core/compliance.md](../../core/compliance.md)。涉及评级、目标价、盈利预测调整时,提醒用户进行人工复核和内部合规检查。
## 模板
见 [../../core/templates.md](../../core/templates.md)。
## 默认行为
- 优先帮用户把研究问题定义清楚,而不是立即产出武断结论
- 优先给"研究框架 + 证据缺口 + 下一步动作"
- 当用户要求很笼统时,先输出一个可执行版本,而不是追问一长串问题
- 对关键数字、时间、比较基准和假设要写清楚
- 如果用户提供财务模型、会议纪要、PPT、研报摘要,应先吸收材料再进入对应模式
FILE:skills/sm-model-check/SKILL.md
---
name: sm-model-check
description: 证券分析师专用的财务模型检查 skill。用于审阅盈利预测与估值模型的关键假设、勾稽关系、收入利润桥、敏感性、情景假设和潜在断裂点,帮助发现模型里最容易误导投资结论的地方。
inputs:
- 财务模型文件(Excel)或模型结构描述
- 可选:公司历史财报、一致预期
outputs:
- 模型风险摘要 + 待核验清单
data_sources: 见 ../../core/adapters.md
markets: [CN-A, HK, US]
---
# SM Model Check
这个 skill 用于检查模型有没有把研究结论"算歪",重点不是排版,而是看模型逻辑是否站得住。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Model Check 特别注意:preamble Step 4 必须包含对比基线(模型输出 vs 历史财务 vs 一致预期)。若用户未提供模型文件,可以先按研究逻辑层面做"模型框架检查",但必须在 [Preflight] 中明确声明。
适用场景:
- 审阅盈利预测模型
- 更新财报后的模型
- 检查估值假设
- 给基金经理或研究总监过模型前做自检
## 核心任务
- 检查关键假设是否清晰
- 检查收入、毛利、费用、现金流之间是否勾稽
- 检查驱动变量与投资逻辑是否一致
- 检查估值方法和情景假设是否自洽
- 找出最可能误导结论的脆弱点
## 输出格式
- `模型目的`
- `核心假设清单`
- `收入驱动检查`
- `利润率 / 费用率检查`
- `现金流与资产负债表检查`
- `估值假设检查`
- `敏感性最高的三个变量`
- `最容易误导结论的地方`
- `需要立刻回头核验的项目`
## 检查重点
- 收入增长是否能拆到量、价、结构或客户层面
- 毛利率变化是否有合理驱动
- 费用率变化是否和扩张节奏匹配
- 现金流是否支持利润表结论
- Capex、折旧、营运资本是否自洽
- 估值倍数或目标价假设是否与赛道、阶段、可比公司匹配
## 约束
- 不要只说"模型合理"或"需要进一步验证"
- 必须指出哪一行逻辑最脆弱,以及为什么
- 若用户未提供模型文件,也可以先按研究逻辑层面做"模型框架检查"
## 参考
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/templates.md](../../core/templates.md)
- [../../core/adapters.md](../../core/adapters.md)
FILE:skills/sm-pm-brief/SKILL.md
---
name: sm-pm-brief
description: 面向基金经理或投资决策会的一页纸摘要 skill。用于把复杂研究压缩成高密度、可决策的短结论,突出为什么现在看、市场错在哪、核心催化、主要风险和下一步行动。
inputs:
- 前置研究结论或多份研究材料
outputs:
- 一页纸决策摘要
data_sources: 见 ../../core/adapters.md
markets: [CN-A, CN-FUND, HK, US, GLOBAL]
---
# SM PM Brief
这个 skill 用于把研究结论压缩成决策材料。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
PM Brief 特别注意:preamble Step 2 必须读取该公司**所有最近的相关 skill 输出**(thesis / deepdive / consensus / red-team / earnings)作为输入。PM Brief 的价值就是整合,没有前置研究等于没法做。
## 输出原则
- 短
- 硬
- 可决策
- 少背景,多判断
## 输出格式
- `结论`
- `为什么现在看`
- `市场可能错在哪`
- `最关键催化`
- `最大风险`
- `建议下一步`
## 约束
- 避免大段背景复述
- 避免使用不带边界的形容词
- 写清时间窗口和假设前提
- 涉及评级或目标价必须提醒人工复核
## 参考
- [../../core/templates.md](../../core/templates.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/adapters.md](../../core/adapters.md)
FILE:skills/sm-red-team/SKILL.md
---
name: sm-red-team
description: 二级市场反方论证与证伪 skill。用于对现有多头逻辑做空头审视,识别脆弱假设、证据断层、可能踩空的变量、替代标的和最早暴露错误的数据点,帮助降低单边叙事风险。
inputs:
- 现有多头逻辑(结论 + 支撑证据)
- 可选:公司或行业材料
outputs:
- 空头审视报告与证伪路径
data_sources: 见 ../../core/adapters.md
markets: [CN-A, HK, US]
---
# SM Red Team
这个 skill 专门负责"唱反调",目的是降低确认偏误。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Red Team 特别注意:preamble Step 4 的取数必须包含历史类似案例 + 行业周期拐点信号 + 空头观点 3 类。**强制读取用户的 `biases.md` 文件**并在结论中显式报告命中情况——这是 Red Team 区别于其他工具的核心。
适用场景:
- 多头逻辑太顺时
- 准备提交正式观点前
- 财报前或建仓前
- 市场高度一致时
## 输出格式
- `多头逻辑最脆弱的三个假设`
- `哪些证据目前还不够`
- `若结论错误,最早会暴露在哪里`
- `哪些数据出现后应下修观点`
- `更好的替代标的 / 替代方向`
- `当前结论的可信度评估`
## 约束
- 风险必须尽量可观测、可触发
- 不要只写套话式风险
- 必须指向具体变量、数据或时间点
## 参考
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/adapters.md](../../core/adapters.md)
FILE:skills/sm-roadshow-questions/SKILL.md
---
name: sm-roadshow-questions
description: 证券分析师专用的路演、调研与管理层交流提纲 skill。用于围绕市场争议点、盈利驱动、指引可信度、竞争格局、资本开支和现金流,设计高价值问题,并说明不同回答分别意味着什么。
inputs:
- 公司名 + 交流对象(管理层/专家/渠道)
- 可选:已有投资命题、研究材料
outputs:
- 高价值问题清单 + 不同回答的意义
data_sources: 见 ../../core/adapters.md
markets: [CN-A, HK, US]
---
# SM Roadshow Questions
这个 skill 用于生成真正有投研价值的调研问题,而不是一套公司很容易"标准回答"的泛问题。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Roadshow Questions 特别注意:preamble Step 4 必须包含市场争议点(近期研报、新闻)+ 历史沟通记录,否则会出"纸面问题"。preamble Step 2 必须读最近一份 deepdive 和 thesis。
适用场景:
- 管理层路演
- 业绩会提问准备
- 专家访谈前问题设计
- 渠道调研前假设验证
## 核心任务
- 明确这次交流到底要验证什么
- 设计能区分不同情景的问题
- 让每个问题都对应一个待验证假设
- 提前写出不同回答各自意味着什么
## 输出格式
- `本次交流目的`
- `需要优先验证的三个假设`
- `必问问题清单`
- `每个问题背后要验证什么`
- `若回答偏强 / 中性 / 偏弱,各自意味着什么`
- `哪些问题不要问得过于泛泛`
- `交流后应如何更新观点或模型`
## 推荐问题维度
- 需求与订单节奏
- 产品结构与价格
- 毛利率和费用率
- 客户结构与份额变化
- 竞争格局
- Capex 与扩产节奏
- 现金流与库存
- 下季度或全年指引
## 约束
- 问题要具体,避免"请介绍一下业务进展"这类泛问题
- 不要诱导对方提供敏感或非公开信息
- 不要把调研提纲设计成套话式采访稿
## 参考
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/templates.md](../../core/templates.md)
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/adapters.md](../../core/adapters.md)
FILE:skills/sm-tape-review/SKILL.md
---
name: sm-tape-review
description: 二级市场盘面复盘 + 技术面分析 skill。用于日内行情复盘、收盘技术面拆解、技术指标信号解读、量价关系分析、关键支撑/压力位识别和与基本面的一致性检验。适合每日盘后、加仓/减仓决策前的技术确认、重大事件后的盘面验证。
inputs:
- 公司名 / 股票代码
- 时间窗(日内 / 5 日 / 20 日 / 60 日,默认 20 日)
- 可选:基本面命题(用于一致性检验)
outputs:
- 7 段技术复盘报告(行情 / 资金 / K 线 / 指标 / 关键位 / 一致性 / 明日观察)
data_sources:
- 见 ../../core/adapters.md
- iFind get_stock_performance(技术指标 + 技术形态)
- iFind get_stock_summary(行情快览)
- iFind get_stock_events(异动事件)
markets: [CN-A, HK, US]
---
# SM Tape Review
> 盘面复盘 + 技术面分析。这是 Investor Harness 里**唯一**的纯技术 skill。
> 不替代基本面分析,只回答两个问题:
> 1. 今天/近期价格 + 量 + 资金在说什么?
> 2. 这个技术信号和你已有的基本面命题是否一致?
## 强制流程(v0.4 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 6 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 8 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Tape Review 特别注意:
- 数据源**必须**用 iFind get_stock_performance(最权威),未拉到则降级到公开网页
- 技术指标必须**真实计算或拉取**,**禁止凭印象编造**(如"MACD 金叉"必须有实际数据支撑)
- preamble Step 2 必须读取该公司最近一次 sm-company-deepdive 和 sm-thesis 输出,用于 §6 一致性检验
## 适用场景
- **日内复盘** — "今天宁德时代怎么涨/跌的"
- **收盘技术面** — "近 20 日 K 线 + 指标看一下"
- **重大事件后验证** — 财报后 / 政策后 / 行业事件后,技术面是否反应
- **加仓/减仓决策前的技术确认** — 基本面看多,技术面是否同向?
- **逃顶/抄底参考** — 关键位置 + 量价 + 指标的综合判断
- **stop loss 位置设定** — 给出技术面硬触发
## 不适用场景
- ❌ 短线择时 / 日内交易信号(这不是炒股工具)
- ❌ 期货 / 期权 / 衍生品技术分析
- ❌ 量化策略回测
- ❌ K 线占卜 / 江恩 / 缠论等无证据流派
## 必答问题
- 今日 / 近期的价格走势属于哪种形态?
- 量价关系是否健康(量价齐升 / 价升量缩 / 缩量回调 / 放量破位)?
- 关键技术指标(MACD / KDJ / RSI / BOLL)发出了什么信号?
- 当前价格相对于关键均线(5/10/20/60/250 日)的位置?
- 最近的支撑位 / 压力位在哪?突破或破位的量能要求是多少?
- 主力资金 / 北向资金 / 龙虎榜信号?
- 这套技术信号是否支持当前的基本面命题?
## 输出格式(7 段)
### §1 行情摘要
```
日期:{YYYY-MM-DD}
时间窗:{日内 / 5 日 / 20 日 / 60 日}
收盘价:XX.XX 元 (F2)
涨跌幅:±X.XX% (F2)
振幅:X.XX% (F2)
成交量:XX 万手 vs 60 日均量 XX 万手 → 量比 X.XX (F2)
换手率:X.XX% (F2)
区间表现(时间窗内):±X.XX% (F2)
区间最大回撤:±X.XX% (F2)
```
### §2 资金面
| 维度 | 数据 | 含义 |
|---|---|---|
| 北向资金净买入(当日 / 5 日) | ±XX 亿 (F2) | 外资态度 |
| 主力净流入(当日) | ±XX 万 (F2) | 大单/特大单方向 |
| 龙虎榜(如上榜) | 买入/卖出席位 (F2) | 游资 vs 机构信号 |
| 融资余额变化 | ±X.X% (F2) | 杠杆资金信号 |
⚠️ 缺失数据明确标注,不要凭印象编。
### §3 K 线形态 + 均线系统
**K 线形态判断**(带证据):
- {形态名,如"放量长阳"/"缩量十字星"/"长上影"/"破位阴线"} (F1-K 线观察)
- 形态出现在什么位置?(趋势中段 / 顶部区域 / 底部区域 / 关键位附近)
**均线系统**(按 5/10/20/60/250 日):
- 当前价格 vs 各均线位置:✅ 之上 / ❌ 之下
- 均线排列:多头排列 / 空头排列 / 纠缠
- 关键均线穿越:是否发生?哪两条?
**量价关系**:
- {量价齐升 / 价升量缩 / 缩量回调 / 放量破位 / 横盘缩量} (C1-基于成交量数据推演)
- 是否健康?
### §4 技术指标信号
| 指标 | 当前值 | 信号 | 历史对比 |
|---|---|---|---|
| MACD (DIF/DEA/MACD) | XX/XX/XX (F2) | 金叉/死叉/0 轴附近 | vs 上次 |
| KDJ (K/D/J) | XX/XX/XX (F2) | 超买/超卖/中性 | — |
| RSI (6/14/24) | XX/XX/XX (F2) | 超买/超卖/中性 | — |
| BOLL (上轨/中轨/下轨) | XX/XX/XX (F2) | 价格位置 | 带宽变化 |
| ATR (14 日) | X.XX (F2) | 波动率 | vs 60 日均 |
| OBV | 趋势 (F2) | 量能背离/同步 | — |
**信号汇总**:
- 共振方向:多 / 空 / 中性
- 背离信号:是否存在(顶背离 / 底背离)
- 信号强度:强 / 中 / 弱
⚠️ **禁止**凭印象写"金叉"、"超买"——必须有实际数据。
### §5 关键位
```
压力位:
- 短期压力:XX.XX 元 (基于 N 日高点 / 均线 / 形态)
- 中期压力:XX.XX 元
支撑位:
- 短期支撑:XX.XX 元 (基于 N 日低点 / 均线 / 形态)
- 中期支撑:XX.XX 元
- 强支撑:XX.XX 元 (250 日均线 / 历史成交密集区)
突破/破位条件:
- 有效突破压力:收盘价 > XX.XX + 量比 > X.X
- 有效破位支撑:收盘价 < XX.XX + 量比 > X.X (放量破位才算)
```
### §6 与基本面的一致性检验(核心段)
**前置任务**:preamble Step 2 应读取该公司的最新 sm-company-deepdive 和 sm-thesis 输出。
| 维度 | 基本面观点 | 技术面信号 | 一致性 |
|---|---|---|---|
| 方向 | 看多 / 看空 / 中性 (引用自 thesis) | 多头 / 空头 / 中性 | ✅ / ⚠️ / ❌ |
| 时间窗 | 6-12 个月 | 短期 / 中期 | — |
| 关键变量 | 命题里的核心驱动 | 技术面是否反映 | — |
**判断**:
- ✅ **完全一致**:基本面看多 + 技术面多头排列 → 加仓信心强
- ⚠️ **部分一致**:基本面看多 + 技术面调整中 → 等技术面修复或加仓节奏放缓
- ❌ **背离**:基本面看多 + 技术面破位 → **重新检视命题或承认市场可能比你早知道一些事**
**如果背离**:
- 是技术面错了(市场短期波动)还是基本面错了(命题被证伪)?
- 哪些数据可以判定?
- 给出 N 天观察期 + 触发条件
### §7 明日 / 下周观察点
```
明日开盘看:
- 是否高开/低开?多少为关键?
- 成交量初段是否能放?
收盘看:
- 是否守住/突破 XX.XX 元?
- MACD/KDJ 是否进一步金叉/背离?
- 北向资金当日方向?
本周需要等待的:
- {重要事件,如业绩会、政策窗口、产业数据发布}
- {同业公司业绩对照点}
如果发生 X,意味着 Y:
- 有效放量突破压力 → 趋势确认,可加仓
- 有效放量破位支撑 → 趋势反转,须减仓
- 缩量横盘 → 持仓不动等方向
```
## 约束
- ❌ **严禁**凭印象写技术指标值("MACD 金叉"必须有实际 DIF/DEA 数据)
- ❌ **严禁**做日内炒股建议(时间窗最短为日,不做小时级 / 分钟级)
- ❌ **严禁**给出"明天必涨"、"突破在即"等武断表述
- ❌ **严禁**用江恩 / 缠论 / 占卜流派的玄学指标
- ✅ **必须**显式说明每个信号来源的数据
- ✅ **必须**做基本面一致性检验(§6)
- ✅ 技术信号是**辅助决策依据**,不是决策本身
- ✅ 涉及"建议加减仓"的输出**必须**带"需人工复核"标注
## 输出归档路径
```
{coverage_root}/{ticker}_{name}/tape-review/{YYYY-MM-DD}-tape-review.md
```
## 与其他 skill 的关系
| 关系 | 说明 |
|---|---|
| **依赖** | sm-company-deepdive / sm-thesis 的最新输出(用于 §6 一致性检验) |
| **被依赖** | sm-pm-brief 在涉及决策时机时可引用 tape-review 的关键位 |
| **互补** | 基本面 skill 给"为什么",tape-review 给"什么时候"和"什么价格" |
| **冲突时** | 基本面命题与技术面强烈背离 → 触发 sm-red-team |
## 参考
- [../../core/preamble.md](../../core/preamble.md)
- [../../core/postamble.md](../../core/postamble.md)
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/output-archive.md](../../core/output-archive.md)
- [../../core/acceptance.md](../../core/acceptance.md)
- [../../core/adapters.md](../../core/adapters.md)
FILE:skills/sm-thesis/SKILL.md
---
name: sm-thesis
description: 二级市场投资命题拆解 skill。用于把模糊想法收敛成可验证的投资命题,识别核心矛盾、股价驱动、成立条件、证伪路径与优先跟踪指标。适合在决定"这条主线值不值得研究"时使用。
inputs:
- 模糊的研究方向 / 公司名 / 主题
outputs:
- 投资命题 + 成立条件 + 跟踪指标
data_sources: 见 ../../core/adapters.md
markets: [CN-A, HK, US, GLOBAL]
---
# SM Thesis
这个 skill 用于投研工作的第一步:把题目从"一个方向"压缩成"一个可验证的投资命题"。
## 强制流程(v0.3 硬约束)
> ⛔ **任何分析输出之前**,必须严格执行 [`../../core/preamble.md`](../../core/preamble.md) 的 5 步开始前流程
>
> ⛔ **任何输出完成之前**,必须严格执行 [`../../core/postamble.md`](../../core/postamble.md) 的 6 步结束后流程
>
> 输出归档按 [`../../core/output-archive.md`](../../core/output-archive.md) 命名规范
> 输出验收按 [`../../core/acceptance.md`](../../core/acceptance.md) 清单逐条自检
>
> **跳过任何一环视为未完成任务。**
Thesis 特别注意:数据需求最轻,但 preamble Step 2 必须检查是否有同标的的历史 deepdive / industry-map 输出。如果连基本认知都没有,先走 `sm-company-deepdive` 或 `sm-industry-map`。
适用场景:
- "这个方向值不值得看"
- "这家公司为什么现在值得研究"
- "市场到底在交易什么"
- "股价最核心的驱动变量是什么"
## 工作方式
默认按以下步骤输出:
1. 定义命题
2. 识别核心矛盾
3. 拆解命题成立的必要条件
4. 说明当前市场预期可能错在哪
5. 给出证伪路径和跟踪指标
## 输出格式
- `一句话命题`
- `核心矛盾`
- `股价驱动变量`
- `命题成立的三个必要条件`
- `市场可能忽略的点`
- `证伪点`
- `未来一个月最该跟踪的三项数据`
## 约束
- 不要直接给出武断结论
- 不要把信息堆砌当成逻辑
- 明确区分事实、预期和推演
## 参考
- [../../core/evidence.md](../../core/evidence.md)
- [../../core/compliance.md](../../core/compliance.md)
- [../../core/templates.md](../../core/templates.md)
- [../../core/adapters.md](../../core/adapters.md)
Create new OpenClaw agents and connect them to messaging channels (Telegram, Discord, Slack, Feishu, WhatsApp, Signal, Google Chat). Includes workspace scaff...
---
name: multi-agent-create
description: Create new OpenClaw agents and connect them to messaging channels (Telegram, Discord, Slack, Feishu, WhatsApp, Signal, Google Chat). Includes workspace scaffolding and channel configuration guide.
tags:
- create-agent
- new-agent
- multi-agent
- add-agent
- bot-setup
- telegram-bot
- discord-bot
- slack-bot
- feishu-bot
- whatsapp-bot
- signal-bot
---
# Multi-Agent Create
> **⚡ One-line install:**
> ```bash
> clawhub install multi-agent-create
> ```
Add a new AI agent to your OpenClaw gateway and connect it to any messaging channel.
---
## Interactive Workflow
When the user triggers this skill (e.g. "create a new agent", "add a bot"), follow this guided flow:
### Step 1: Ask for Agent Name & Channel
Prompt the user:
> 🤖 Let's create a new agent! First, tell me:
>
> 1. **Agent name** — What should this agent be called? (e.g. Luna, Marketing Bot)
> 2. **Which channel** do you want to connect it to?
>
> Supported channels:
> | # | Channel | Description |
> |---|---------|-------------|
> | 1 | **Telegram** | Telegram Bot |
> | 2 | **Discord** | Discord Bot |
> | 3 | **Slack** | Slack App |
> | 4 | **Feishu / Lark** | 飞书 / Lark Bot |
> | 5 | **WhatsApp** | WhatsApp (QR scan) |
> | 6 | **Signal** | Signal (QR scan) |
> | 7 | **Google Chat** | Google Workspace Bot |
>
> Reply with the agent name and channel number (or name), e.g. "Luna, Telegram"
Wait for the user's reply before proceeding.
### Step 2: Guide Credential Setup (per channel)
Based on the user's chosen channel, provide the specific credential instructions:
#### Telegram
> 🔑 **Get your Telegram Bot Token:**
> 1. Open Telegram and search for **@BotFather**
> 2. Send `/newbot` and follow the prompts to name your bot
> 3. BotFather will give you a **Bot Token** like `123456789:ABCdefGHI...`
> 4. Paste that token here
Required: `botToken`
#### Discord
> 🔑 **Get your Discord Bot Token:**
> 1. Go to [Discord Developer Portal](https://discord.com/developers/applications)
> 2. Click **New Application** → name it → go to **Bot** tab
> 3. Click **Reset Token** and copy the token
> 4. Under **Privileged Gateway Intents**, enable **Message Content Intent**
> 5. Paste the token here
Required: `token`
#### Slack
> 🔑 **Get your Slack App credentials:**
> 1. Go to [Slack API](https://api.slack.com/apps) → **Create New App**
> 2. Enable **Socket Mode** → copy the **App-Level Token** (starts with `xapp-`)
> 3. Go to **OAuth & Permissions** → install to workspace → copy the **Bot Token** (starts with `xoxb-`)
> 4. Paste both tokens here
Required: `appToken`, `botToken`
#### Feishu / Lark
> 🔑 **获取飞书机器人凭证:**
> 1. 打开 [飞书开放平台](https://open.feishu.cn/) → **创建企业自建应用**
> 2. 在应用的 **凭证与基本信息** 页面找到 **App ID** 和 **App Secret**
> 3. 在 **机器人** 功能页启用机器人能力
> 4. 把 App ID 和 App Secret 发给我
>
> For **Lark** (international): same steps at [Lark Developer](https://open.larksuite.com/)
Required: `appId`, `appSecret` (add `"domain": "lark"` for Lark international)
#### WhatsApp
> 📱 **WhatsApp uses QR code login:**
> 1. I'll run the login command for you
> 2. A QR code will appear — scan it with your WhatsApp app
> 3. That's it!
>
> Ready? Just say "go" and I'll start the QR scan.
Action: run `openclaw channels login --channel whatsapp --account {name}`
#### Signal
> 📱 **Signal uses QR code login:**
> 1. I'll run the login command for you
> 2. A QR code will appear — scan it with your Signal app (Settings → Linked Devices)
> 3. That's it!
>
> Ready? Just say "go" and I'll start the QR scan.
Action: run `openclaw channels login --channel signal --account {name}`
#### Google Chat
> 🔑 **Get your Google Chat Service Account:**
> 1. Go to [Google Cloud Console](https://console.cloud.google.com/) → create/select a project
> 2. Enable the **Google Chat API**
> 3. Create a **Service Account** → download the JSON key file
> 4. Send me the path to the JSON file on this server
Required: `serviceAccountPath`
Wait for the user to provide credentials before proceeding.
### Step 3: Create Workspace
Run the helper script or create manually:
```bash
./scripts/setup-agent.sh {name} {channel}
```
This creates a workspace at `workspace-groups/{name}/` with standard files:
- `IDENTITY.md` — Name, role, emoji
- `SOUL.md` — Personality and behavior
- `AGENTS.md` — Startup instructions
- `USER.md` — Owner info
- `HEARTBEAT.md`, `TOOLS.md`
### Step 4: Register Agent
```bash
openclaw agents add {name}-agent
```
### Step 5: Configure Channel
Add account entry and binding to the gateway config.
**Binding format (all channels):**
```json
{
"agentId": "{name}-agent",
"match": {
"channel": "{channel}",
"accountId": "{name}"
}
}
```
> Use `accountId` in the match block — not `account`.
**Channel account config reference:**
| Channel | Config Path | Required Fields |
|---------|------------|-----------------|
| Telegram | `channels.telegram.accounts.{name}` | `botToken` |
| Discord | `channels.discord.accounts.{name}` | `token` |
| Slack | `channels.slack.accounts.{name}` | `mode: "socket"`, `appToken`, `botToken` |
| Feishu | `channels.feishu.accounts.{name}` | `appId`, `appSecret` |
| WhatsApp | `channels.whatsapp.accounts.{name}` | QR scan via CLI |
| Signal | `channels.signal.accounts.{name}` | QR scan via CLI |
| Google Chat | `channels.googlechat.accounts.{name}` | `serviceAccountPath` |
### Step 6: Verify & Restart
```bash
openclaw gateway restart
openclaw agents list --bindings
openclaw channels status --probe
```
### Step 7: Pairing
For DM-based channels, the owner sends `/start` (or first message) to the bot, then approves:
```bash
openclaw pairing approve {channel} {CODE}
```
Report completion:
> ✅ Agent **{name}** is live on **{channel}**!
>
> - Workspace: `~/.openclaw/workspace-groups/{name}/`
> - All agents share your existing model API keys — no extra keys needed
> - Add more channels anytime by running this skill again
---
## Notes
- All agents share existing model credentials — no extra API keys needed
- One channel is enough to bring an agent online
- Add more channels later by repeating the workflow
FILE:README.md
# Multi-Agent Create
> **⚡ One-line install:**
> ```bash
> clawhub install multi-agent-create
> ```
Create a new OpenClaw agent and connect it to any messaging channel — with an interactive guided workflow.
## Supported Channels
| Channel | Credentials Needed |
|---------|-------------------|
| **Telegram** | Bot Token (from [@BotFather](https://t.me/BotFather)) |
| **Discord** | Bot Token (from [Developer Portal](https://discord.com/developers/applications)) |
| **Slack** | App Token + Bot Token (from [Slack API](https://api.slack.com/apps)) |
| **Feishu / Lark** | App ID + App Secret (from [飞书开放平台](https://open.feishu.cn/)) |
| **WhatsApp** | QR code scan |
| **Signal** | QR code scan |
| **Google Chat** | Service Account JSON |
## How It Works
Just tell your agent:
> "Create a new agent" / "Add a bot"
The skill guides you step by step:
1. 🤖 **Pick a name & channel** — Choose from 7 supported platforms
2. 🔑 **Get credentials** — Platform-specific instructions (where to go, what to click)
3. 📁 **Workspace created** — Identity, personality, and memory files auto-generated
4. ⚙️ **Registered & configured** — Gateway config updated automatically
5. ✅ **Verify & go live** — Restart, pair, done!
No extra API keys needed — all agents share your existing model credentials.
## Manual Setup
You can also use the helper script directly:
```bash
./scripts/setup-agent.sh luna telegram
```
## Tags
`create-agent` · `new-agent` · `multi-agent` · `add-agent` · `bot-setup` · `telegram` · `discord` · `slack` · `feishu` · `whatsapp` · `signal`
## License
MIT-0
FILE:scripts/setup-agent.sh
#!/bin/bash
# Setup a new OpenClaw agent with workspace and channel binding.
# Usage: ./setup-agent.sh <agent_name> <channel> [channel_credentials...]
#
# Examples:
# ./setup-agent.sh luna telegram "BOT_TOKEN_HERE"
# ./setup-agent.sh coder discord "BOT_TOKEN_HERE"
# ./setup-agent.sh helper slack "APP_TOKEN" "BOT_TOKEN"
# ./setup-agent.sh team feishu "APP_ID" "APP_SECRET"
set -e
AGENT_NAME="?Usage: setup-agent.sh <name> <channel> [credentials...]"
CHANNEL="?Please specify channel: telegram|discord|slack|feishu|whatsapp|signal|googlechat"
AGENT_ID="AGENT_NAME,,-agent"
AGENT_DIR="AGENT_NAME,,"
STATE_DIR="-$HOME/.openclaw"
WORKSPACE_DIR="STATE_DIR/workspace-groups/AGENT_DIR"
CONFIG_PATH="STATE_DIR/openclaw.json"
echo "Creating agent: AGENT_NAME (AGENT_ID) on CHANNEL"
# 1. Backup config
cp "CONFIG_PATH" "CONFIG_PATH.bak.$(date +%Y%m%d%H%M%S)"
# 2. Create workspace
mkdir -p "WORKSPACE_DIR"
# 3. Register agent
openclaw agents add "AGENT_ID" 2>/dev/null || true
# 4. Generate workspace files
cat > "WORKSPACE_DIR/IDENTITY.md" << EOF
# IDENTITY.md
- **Name:** AGENT_NAME
- **Role:** [Define role here]
- **Emoji:** 🤖
EOF
cat > "WORKSPACE_DIR/SOUL.md" << EOF
# SOUL.md
You are AGENT_NAME, an independent AI assistant.
Be genuinely helpful. Have opinions. Try before asking.
Keep private things private. Never send half-baked replies.
EOF
cat > "WORKSPACE_DIR/AGENTS.md" << EOF
# AGENTS.md
## On startup
1. Read SOUL.md
2. Read IDENTITY.md
3. Read USER.md if present
## Memory
Write important notes to memory/YYYY-MM-DD.md
EOF
cat > "WORKSPACE_DIR/USER.md" << EOF
# USER.md
- **Name:** [User Name]
- **Timezone:** UTC
EOF
touch "WORKSPACE_DIR/HEARTBEAT.md"
touch "WORKSPACE_DIR/TOOLS.md"
echo "✅ Workspace created at WORKSPACE_DIR"
echo ""
echo "Next steps:"
echo " 1. Update openclaw.json with channel account and binding"
echo " 2. Run: openclaw gateway restart"
echo " 3. Run: openclaw agents list --bindings"
echo " 4. Send /start to the bot and approve pairing"
Create new OpenClaw agents and connect them to messaging channels (Telegram, Discord, Slack, Feishu, WhatsApp, Signal, Google Chat). Supports single and batc...
---
name: new-agent
description: Create new OpenClaw agents and connect them to messaging channels (Telegram, Discord, Slack, Feishu, WhatsApp, Signal, Google Chat). Supports single and batch mode. Batch mode creates all agents at once with a single config write and gateway restart to avoid connection churn.
---
# New Agent
Add one or more agents to your OpenClaw gateway with dedicated workspaces and messaging channels.
## When to Use
- User wants to add a new AI agent or bot
- User wants to connect a bot to a messaging platform
- User wants to create a **team of agents** at once (batch mode)
## Modes
| Mode | When | Script |
|------|------|--------|
| **Single** | Add one agent | `scripts/setup-agent.sh` |
| **Batch** | Add multiple agents at once | `scripts/batch-setup.sh` |
> ⚠️ **Always prefer batch mode when creating 2+ agents.** Single-agent creation modifies `openclaw.json` each time, triggering a gateway hot reload per agent. For channels with persistent connections (Feishu WebSocket, Discord gateway), this causes repeated disconnects. Batch mode writes config **once** and restarts **once**.
---
## Single Agent Mode
### Required Information
| Field | Example |
|-------|---------|
| Agent name | "Luna" |
| Channel | telegram / discord / slack / feishu / whatsapp / signal / googlechat |
| Credentials | Bot token, app secret, or QR scan |
### Step 1: Workspace + Registration
```bash
./scripts/setup-agent.sh {name}
```
This creates workspace files and registers the agent with `openclaw agents add --non-interactive --workspace`.
### Step 2: Channel Configuration
Each channel needs **two things** in `openclaw.json`:
1. An **account entry** under `channels.{channel}.accounts`
2. A **binding** in the **top-level `bindings` array**
> ⚠️ The `bindings` array is at the **root level** of `openclaw.json`, NOT under `agents`.
#### Account Entry Templates
Add under `channels.{channel}.accounts.{name}`:
**Telegram:**
```json
{
"dmPolicy": "pairing",
"botToken": "YOUR_BOT_TOKEN",
"groupPolicy": "open",
"streaming": "partial"
}
```
**Discord:**
```json
{
"token": "YOUR_BOT_TOKEN"
}
```
**Slack:**
```json
{
"mode": "socket",
"appToken": "xapp-...",
"botToken": "xoxb-..."
}
```
**Feishu / Lark:**
```json
{
"appId": "YOUR_APP_ID",
"appSecret": "YOUR_APP_SECRET"
}
```
For Lark (global), add `"domain": "lark"`.
**WhatsApp / Signal** — Use interactive login:
```bash
openclaw channels login --channel whatsapp --account {name}
openclaw channels login --channel signal --account {name}
```
#### Binding (Top-Level)
```json
{
"agentId": "{name}-agent",
"match": {
"channel": "{channel}",
"accountId": "{name}"
}
}
```
#### Agent-to-Agent (Optional)
Add `"{name}-agent"` to `tools.agentToAgent.allow`.
### Step 3: Verify & Pair
```bash
openclaw gateway restart
openclaw agents list --bindings
openclaw channels status --probe
```
For DM channels, send `/start` to the bot, then:
```bash
openclaw pairing approve {channel} {CODE}
```
---
## Batch Mode (Recommended for 2+ Agents)
### Why Batch?
When creating multiple agents one-by-one:
- Each `openclaw agents add` modifies `openclaw.json` → triggers hot reload
- Each channel account addition → another hot reload
- **Feishu/Discord WebSocket disconnects and reconnects each time**
- Messages sent during reload may be lost
Batch mode: **all workspaces first, one config write, one restart.**
### Step 1: Define Agents
Create a JSON manifest file listing all agents:
```json
[
{
"name": "基金经理",
"id": "fund-manager",
"role": "管理投资研究团队",
"emoji": "📈",
"channel": "feishu",
"appId": "cli_xxx",
"appSecret": "xxx"
},
{
"name": "科技研究员",
"id": "tech-researcher",
"role": "科技行业投资研究",
"emoji": "💻",
"channel": "feishu",
"appId": "cli_yyy",
"appSecret": "yyy"
}
]
```
Fields:
- `name` — Display name (used in IDENTITY.md)
- `id` — Agent ID slug (lowercase, used for agent-id, account-id, workspace dir)
- `role` — Role description (used in SOUL.md)
- `emoji` — Agent emoji
- `channel` — Channel type
- For Telegram: add `"botToken": "..."`
- For Feishu: add `"appId": "..."` and `"appSecret": "..."`
- For Discord: add `"token": "..."`
- For Slack: add `"appToken": "..."` and `"botToken": "..."`
### Step 2: Run Batch Setup
```bash
./scripts/batch-setup.sh agents.json
```
This will:
1. ✅ Create all workspaces (IDENTITY.md, SOUL.md, AGENTS.md, USER.md)
2. ✅ Register all agents (`openclaw agents add --non-interactive`)
3. ✅ Add all channel accounts to `openclaw.json` in **one write**
4. ✅ Add all bindings in **one write**
5. ✅ Add all agents to `agentToAgent.allow` in **one write**
6. ✅ Restart gateway **once**
### Step 3: Pair
For each agent, send a message in the channel, then approve:
```bash
openclaw pairing approve {channel} {CODE}
```
---
## Shared Channel (Multiple Agents, One Bot)
You can route multiple agents through a **single bot** using group-based bindings:
```json
{
"agentId": "tech-researcher",
"match": {
"channel": "feishu",
"accountId": "shared-bot",
"groupId": "oc_xxxxx"
}
}
```
- DM → routes to default agent for that account
- Group messages → route based on `groupId` match
- One bot, multiple brains
---
## Notes
- All agents share existing model credentials — no extra API keys needed
- One channel is enough to bring an agent online
- Add more channels later by repeating the single-agent steps
- The default model comes from `agents.defaults.model.primary` in your config
- **Batch mode prevents hot-reload churn** — always use it for 2+ agents
FILE:README.md
# New Agent
Create a new OpenClaw agent and connect it to any messaging channel.
## Supported Channels
| Channel | Credentials Needed |
|---------|-------------------|
| Telegram | Bot Token (from @BotFather) |
| Discord | Bot Token (from Developer Portal) |
| Slack | App Token + Bot Token |
| Feishu / Lark | App ID + App Secret |
| WhatsApp | QR code scan |
| Signal | QR code scan |
| Google Chat | Service Account JSON |
## Quick Start
```bash
clawhub install new-agent
```
Or clone from GitHub:
```bash
git clone https://github.com/joansongjr/new-agent.git
```
## Usage
Tell your OpenClaw agent:
> "Create a new agent called Luna, here's the Telegram token: 123456:ABC..."
The skill guides the agent through:
1. Creating a dedicated workspace with identity files
2. Registering the agent in your gateway config
3. Connecting the messaging channel
4. Verifying the setup
## Manual Setup
You can also use the helper script directly:
```bash
./scripts/setup-agent.sh luna telegram
```
## License
MIT-0
FILE:scripts/batch-setup.sh
#!/bin/bash
# Batch setup multiple OpenClaw agents from a JSON manifest.
# Creates all workspaces, registers agents, and updates config in ONE write.
#
# Usage: ./batch-setup.sh <manifest.json>
#
# Manifest format: JSON array of objects with:
# name - Display name (e.g. "基金经理")
# id - Agent slug (e.g. "fund-manager")
# role - Role description
# emoji - Emoji (default: 🤖)
# channel - Channel type (telegram/feishu/discord/slack)
# For Telegram: botToken
# For Feishu: appId, appSecret
# For Discord: token
# For Slack: appToken, botToken
#
# Example:
# [
# {"name":"基金经理","id":"fund-manager","role":"管理研究团队","emoji":"📈","channel":"feishu","appId":"cli_xxx","appSecret":"xxx"},
# {"name":"科技研究员","id":"tech-researcher","role":"科技行业研究","emoji":"💻","channel":"feishu","appId":"cli_yyy","appSecret":"yyy"}
# ]
set -e
MANIFEST="?Usage: batch-setup.sh <manifest.json>"
if [ ! -f "$MANIFEST" ]; then
echo "❌ Manifest file not found: $MANIFEST"
exit 1
fi
STATE_DIR="-$HOME/.openclaw"
CONFIG_PATH="STATE_DIR/openclaw.json"
# Validate JSON
if ! python3 -c "import json; json.load(open('$MANIFEST'))" 2>/dev/null; then
echo "❌ Invalid JSON in manifest file"
exit 1
fi
AGENT_COUNT=$(python3 -c "import json; print(len(json.load(open('$MANIFEST'))))")
export MANIFEST_PATH="$MANIFEST"
echo "🚀 Batch creating AGENT_COUNT agents..."
echo ""
# 1. Backup config
cp "CONFIG_PATH" "CONFIG_PATH.bak.$(date +%Y%m%d%H%M%S)"
echo "📦 Config backed up"
# 2. Create all workspaces
echo ""
echo "━━━ Phase 1: Creating workspaces ━━━"
python3 << 'PYEOF'
import json, os, sys
manifest_path = os.environ["MANIFEST_PATH"]
state_dir = os.environ.get("OPENCLAW_STATE_DIR", os.path.expanduser("~/.openclaw"))
with open(manifest_path) as f:
agents = json.load(f)
for agent in agents:
name = agent["name"]
agent_id = agent["id"]
emoji = agent.get("emoji", "🤖")
role = agent.get("role", "AI 助手")
workspace = os.path.join(state_dir, "workspace-groups", agent_id)
os.makedirs(workspace, exist_ok=True)
with open(os.path.join(workspace, "IDENTITY.md"), "w") as f:
f.write(f"""# IDENTITY.md - Who Am I?
- **Name:** {name}
- **Role:** {role}
- **Emoji:** {emoji}
""")
with open(os.path.join(workspace, "SOUL.md"), "w") as f:
f.write(f"""# SOUL.md - Who You Are
你是 **{name}** {emoji}。
## 职责
{role}
## 核心原则
- 专业、严谨、高效
- 有问必答,遇到不确定的事情诚实说
- 用简洁的语言沟通
""")
with open(os.path.join(workspace, "AGENTS.md"), "w") as f:
f.write("""# AGENTS.md
## Session Startup
1. Read **SOUL.md** - 了解你的角色
2. Read **IDENTITY.md** - 确认身份
3. Read **USER.md** - 了解用户需求
""")
with open(os.path.join(workspace, "USER.md"), "w") as f:
f.write("""# USER.md - About Your Human
- **Name:** [User Name]
- **Timezone:** UTC
""")
print(f" ✅ {name} ({agent_id}) → {workspace}")
PYEOF
# 3. Register all agents (this modifies config, but we'll overwrite channel config in one shot)
echo ""
echo "━━━ Phase 2: Registering agents ━━━"
python3 -c "
import json, subprocess, os
state_dir = os.environ.get('OPENCLAW_STATE_DIR', os.path.expanduser('~/.openclaw'))
with open('$MANIFEST') as f:
agents = json.load(f)
for agent in agents:
agent_id = agent['id'] + '-agent' if not agent['id'].endswith('-agent') else agent['id']
workspace = os.path.join(state_dir, 'workspace-groups', agent['id'])
result = subprocess.run(
['openclaw', 'agents', 'add', agent_id, '--workspace', workspace, '--non-interactive'],
capture_output=True, text=True
)
if result.returncode == 0:
print(f' ✅ Registered {agent_id}')
else:
# Might already exist
print(f' ⚠️ {agent_id}: {result.stderr.strip() or result.stdout.strip() or \"already exists?\"}')
"
# 4. Update config in ONE write (channels + bindings + agentToAgent)
echo ""
echo "━━━ Phase 3: Configuring channels (single write) ━━━"
python3 << 'PYEOF2'
import json, os, sys
state_dir = os.environ.get("OPENCLAW_STATE_DIR", os.path.expanduser("~/.openclaw"))
config_path = os.path.join(state_dir, "openclaw.json")
manifest_path = os.environ.get("MANIFEST_PATH")
with open(manifest_path) as f:
agents = json.load(f)
with open(config_path) as f:
config = json.load(f)
# Ensure structures exist
config.setdefault("channels", {})
config.setdefault("bindings", [])
config.setdefault("tools", {}).setdefault("agentToAgent", {}).setdefault("allow", [])
existing_binding_ids = {b.get("agentId") for b in config["bindings"]}
for agent in agents:
agent_id = agent["id"] + "-agent" if not agent["id"].endswith("-agent") else agent["id"]
account_id = agent["id"]
channel = agent.get("channel", "telegram")
# Ensure channel section exists
config["channels"].setdefault(channel, {"enabled": True, "accounts": {}})
config["channels"][channel].setdefault("accounts", {})
# Add account
if channel == "telegram":
config["channels"][channel]["accounts"][account_id] = {
"dmPolicy": "pairing",
"botToken": agent.get("botToken", "MISSING_TOKEN"),
"groupPolicy": "open",
"streaming": "partial"
}
elif channel == "feishu":
config["channels"][channel]["accounts"][account_id] = {
"appId": agent.get("appId", "MISSING_APP_ID"),
"appSecret": agent.get("appSecret", "MISSING_APP_SECRET")
}
elif channel == "discord":
config["channels"][channel]["accounts"][account_id] = {
"token": agent.get("token", "MISSING_TOKEN")
}
elif channel == "slack":
config["channels"][channel]["accounts"][account_id] = {
"mode": "socket",
"appToken": agent.get("appToken", "MISSING_APP_TOKEN"),
"botToken": agent.get("botToken", "MISSING_BOT_TOKEN")
}
print(f" 📡 {channel}/{account_id} account added")
# Add binding (if not exists)
if agent_id not in existing_binding_ids:
config["bindings"].append({
"agentId": agent_id,
"match": {
"channel": channel,
"accountId": account_id
}
})
print(f" 🔗 {agent_id} → {channel}/{account_id} binding added")
# Add to agentToAgent allow
if agent_id not in config["tools"]["agentToAgent"]["allow"]:
config["tools"]["agentToAgent"]["allow"].append(agent_id)
# Write config ONCE
with open(config_path, "w") as f:
json.dump(config, f, indent=2, ensure_ascii=False)
print(f"\n 💾 Config written (single write, {len(agents)} agents)")
PYEOF2
# 5. Restart gateway ONCE
echo ""
echo "━━━ Phase 4: Restarting gateway ━━━"
if openclaw gateway restart 2>&1; then
echo " ✅ Gateway restarted"
else
echo " ⚠️ Gateway restart returned non-zero (may still be starting)"
fi
# 6. Summary
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "✅ Batch setup complete! AGENT_COUNT agents created."
echo ""
echo "Next steps:"
echo " 1. Send a message to each bot"
echo " 2. Approve pairing for each:"
echo " openclaw pairing approve {channel} {CODE}"
echo " 3. Verify: openclaw agents list --bindings"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
FILE:scripts/setup-agent.sh
#!/bin/bash
# Setup a new OpenClaw agent workspace and register it.
# Usage: ./setup-agent.sh <agent_name>
#
# Examples:
# ./setup-agent.sh luna
# ./setup-agent.sh pear
#
# After running this script, you still need to:
# 1. Add channel account + binding to openclaw.json (see SKILL.md Step 3)
# 2. Restart gateway: openclaw gateway restart
# 3. Pair: send /start to the bot, then openclaw pairing approve ...
set -e
AGENT_NAME="?Usage: setup-agent.sh <agent_name>"
AGENT_NAME_LOWER="AGENT_NAME,,"
AGENT_ID="AGENT_NAME_LOWER-agent"
STATE_DIR="-$HOME/.openclaw"
WORKSPACE_DIR="STATE_DIR/workspace-groups/AGENT_NAME_LOWER"
CONFIG_PATH="STATE_DIR/openclaw.json"
echo "🤖 Creating agent: AGENT_NAME (AGENT_ID)"
# 1. Backup config
if [ -f "CONFIG_PATH" ]; then
cp "CONFIG_PATH" "CONFIG_PATH.bak.$(date +%Y%m%d%H%M%S)"
echo "📦 Config backed up"
fi
# 2. Create workspace
mkdir -p "WORKSPACE_DIR"
# 3. Generate workspace files
cat > "WORKSPACE_DIR/IDENTITY.md" << EOF
# IDENTITY.md - Who Am I?
- **Name:** AGENT_NAME
- **Role:** AI 助手
- **Emoji:** 🤖
EOF
cat > "WORKSPACE_DIR/SOUL.md" << EOF
# SOUL.md - Who You Are
你是 **AGENT_NAME**,一个 AI 助手。
## 核心原则
- 友好、靠谱、高效
- 有问必答,遇到不确定的事情诚实说
- 用简洁的语言沟通
## 工作流程
1. 读 IDENTITY.md 和 USER.md 了解上下文
2. 认真回答问题
3. 重要信息记录到 MEMORY.md
EOF
cat > "WORKSPACE_DIR/AGENTS.md" << EOF
# AGENTS.md
## Session Startup
1. Read **SOUL.md** - 了解你的角色
2. Read **IDENTITY.md** - 确认身份
3. Read **USER.md** - 了解用户需求
EOF
cat > "WORKSPACE_DIR/USER.md" << EOF
# USER.md - About Your Human
- **Name:** [User Name]
- **Timezone:** UTC
EOF
echo "📁 Workspace created at WORKSPACE_DIR"
# 4. Register agent (non-interactive)
if openclaw agents add "AGENT_ID" \
--workspace "WORKSPACE_DIR" \
--non-interactive 2>/dev/null; then
echo "✅ Agent AGENT_ID registered"
else
echo "⚠️ Agent registration failed or already exists. Check manually:"
echo " openclaw agents add AGENT_ID --workspace WORKSPACE_DIR --non-interactive"
fi
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "✅ Workspace + registration done!"
echo ""
echo "Next steps (see SKILL.md Step 3):"
echo " 1. Add channel account to openclaw.json"
echo " → channels.{channel}.accounts.AGENT_NAME_LOWER"
echo " 2. Add binding to top-level 'bindings' array:"
echo ' {"agentId": "'AGENT_ID'", "match": {"channel": "...", "accountId": "'AGENT_NAME_LOWER'"}}'
echo " 3. openclaw gateway restart"
echo " 4. openclaw agents list --bindings"
echo " 5. Send /start to bot → openclaw pairing approve ..."
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
中文网页搜索 - 聚合 28 个免费搜索引擎,无需 API Key,纯网页抓取,支持公众号/财经/技术/学术/知识/美股/宏观/Pre-IPO搜索。
---
name: cn-web-search
version: 2.4.0
description: 中文网页搜索 - 聚合 28 个免费搜索引擎,无需 API Key,纯网页抓取,支持公众号/财经/技术/学术/知识/美股/宏观/Pre-IPO搜索。
author: joansongjr
author_url: https://github.com/joansongjr
repository: https://github.com/joansongjr/cn-web-search
license: MIT
tags:
- search
- chinese
- wechat
- 公众号
- web-search
- 360-search
- sogou
- bing
- qwant
- startpage
- duckduckgo
- stackoverflow
- github
- caixin
- baidu
- brave-search
- yahoo
- mojeek
- toutiao
- jisilu
- wikipedia
- no-api-key
- free
- 中文搜索
- 百度
- 头条搜索
- 东方财富
- A股
- 财经
- 技术搜索
- 多引擎
- 聚合搜索
- 免费无需API
- 投资
- 知识百科
- 美股
- 港股
- 全球宏观
- 美债
- 散户情绪
- reddit
- wsb
- pre-ipo
- 独角兽
---
# 中文网页搜索 (CN Web Search)
> **⚡ 安装:**
> ```bash
> clawhub install cn-web-search
> ```
多引擎聚合搜索,**全部免费,无需 API Key,纯网页抓取**。28 个引擎覆盖中英文、公众号、技术、财经、知识百科、美股深度、全球宏观、Pre-IPO。
## 引擎总览(28 个)
| 类别 | 引擎 | 数量 |
|------|------|------|
| 公众号 | 搜狗微信、必应索引 | 2 |
| 中文综合 | 360、搜狗、必应中文、百度、头条搜索 | 5 |
| 英文综合 | DDG Lite、Qwant、Startpage、必应英文、Yahoo、Brave Search、Mojeek | 7 |
| 技术社区 | Stack Overflow、GitHub Trending | 2 |
| 财经/投资 | 东方财富、集思录、财新 | 3 |
| 知识百科 | Wikipedia 中文、Wikipedia 英文 | 2 |
| 美股深度 | Seeking Alpha、Finviz、Macrotrends | 3 |
| 全球宏观 | BEA、Treasury、Census | 3 |
| 政治/情绪 | Reddit WSB、Nitter (Trump) | 2 |
| Pre-IPO | IPOScoop、StockAnalysis、CB Insights | 3 |
> 全部通过 `web_fetch` 抓取网页,零 API 依赖。
---
## 1. 公众号搜索
### 1.1 搜狗微信
`https://weixin.sogou.com/weixin?type=2&query=QUERY&page=1`
### 1.2 必应公众号索引
`https://cn.bing.com/search?q=site:mp.weixin.qq.com+QUERY`
---
## 2. 中文综合搜索
### 2.1 360 搜索
`https://m.so.com/s?q=QUERY`
### 2.2 搜狗网页
`https://www.sogou.com/web?query=QUERY`
### 2.3 必应中文
`https://cn.bing.com/search?q=QUERY`
### 2.4 百度
`https://www.baidu.com/s?wd=QUERY`
中文搜索覆盖最全,结果丰富。
### 2.5 头条搜索
`https://so.toutiao.com/search?keyword=QUERY`
字节跳动旗下,中文资讯和短视频内容强。
---
## 3. 英文综合搜索
### 3.1 DuckDuckGo Lite
`https://lite.duckduckgo.com/lite/?q=QUERY`
### 3.2 Qwant
`https://www.qwant.com/?q=QUERY&t=web`
### 3.3 Startpage
`https://www.startpage.com/do/search?q=QUERY&cluster=web`
### 3.4 必应英文
`https://www.bing.com/search?q=QUERY`
### 3.5 Yahoo
`https://search.yahoo.com/search?p=QUERY`
老牌英文搜索引擎,结果稳定。
### 3.6 Brave Search
`https://search.brave.com/search?q=QUERY`
独立索引(非 Bing/Google 代理),隐私友好,结果质量高。
### 3.7 Mojeek
`https://www.mojeek.com/search?q=QUERY`
独立爬虫索引,不依赖任何大厂,适合多样化结果。
---
## 4. 技术社区
### 4.1 Stack Overflow
`https://stackoverflow.com/search?q=QUERY`
### 4.2 GitHub Trending
`https://github.com/trending?since=weekly`
---
## 5. 财经/投资(中文)
### 5.1 东方财富
`https://search.eastmoney.com/search?keyword=QUERY`
### 5.2 集思录
`https://www.jisilu.cn/explore/?keyword=QUERY`
投资社区,可转债、基金、LOF 等投资品种讨论。
### 5.3 财新
`https://search.caixin.com/search/?keyword=QUERY`
---
## 6. 知识百科
### 6.1 Wikipedia 中文
`https://zh.wikipedia.org/w/index.php?search=QUERY&title=Special:Search`
中文维基百科,知识查询首选。
### 6.2 Wikipedia 英文
`https://en.wikipedia.org/w/index.php?search=QUERY&title=Special:Search`
英文维基百科,信息量最大的免费百科全书。
---
## 7. 美股深度
### 7.1 Seeking Alpha
`https://seekingalpha.com/symbol/TICKER`
公司基本面描述、业务分析。返回公司介绍、产品线、行业定位。
**示例:** `https://seekingalpha.com/symbol/AAPL`
### 7.2 Finviz
`https://finviz.com/quote.ashx?t=TICKER`
美股筛选器,返回 P/E、EPS、Market Cap、内部人交易、机构持仓、技术指标。
**示例:** `https://finviz.com/quote.ashx?t=NVDA`
### 7.3 Macrotrends
`https://www.macrotrends.net/stocks/charts/TICKER/NAME/revenue`
历史财务数据,年度/季度收入、利润、EPS、股价趋势。
**示例:** `https://www.macrotrends.net/stocks/charts/AAPL/apple/revenue`
---
## 8. 全球宏观
### 8.1 BEA(美国经济分析局)
`https://www.bea.gov/news/current-releases`
GDP、个人收入、国际贸易、企业利润等经济数据发布日历。
### 8.2 Treasury(美国财政部)
`https://home.treasury.gov/`
国债收益率曲线(1个月-30年),实时利率数据。
**抓取内容:** Daily Treasury Par Yield Curve Rates
### 8.3 Census(美国人口普查局)
`https://www.census.gov/economic-indicators/`
经济指标:建筑许可、住房、零售贸易、批发贸易、制造业 PMI。
---
## 9. 政治 / 散户情绪
### 9.1 Reddit WSB(RSS)
`https://www.reddit.com/r/wallstreetbets/top/.rss`
散户情绪、热帖标题、讨论热点。
**其他 RSS:**
- 最新:`https://www.reddit.com/r/wallstreetbets/new/.rss`
- 搜索:`https://www.reddit.com/r/wallstreetbets/search.rss?q=TICKER&sort=new`
### 9.2 Nitter(Trump X/Twitter RSS)
`https://nitter.net/realDonaldTrump/rss`
Trump 推文全文 RSS,政策风向监测。
**其他账号:** `https://nitter.net/USERNAME/rss`
---
## 10. Pre-IPO
### 10.1 IPOScoop
`https://www.iposcoop.com/ipo-calendar/`
即将上市的 IPO 日历:公司名、代码、承销商、发行价区间、预计上市日期、SCOOP 评级。
### 10.2 StockAnalysis
`https://stockanalysis.com/ipos/`
最近 200 个 IPO:首日涨幅、当前价格、破发情况。
### 10.3 CB Insights(独角兽)
`https://www.cbinsights.com/research-unicorn-companies`
全球独角兽名单:估值、成立时间、国家、行业、投资方。
**Top 5:** OpenAI ($840B)、ByteDance ($480B)、SpaceX ($400B)、Anthropic ($380B)、Stripe ($159B)
---
## 使用示例
**中文搜索:**
- 百度:`web_fetch(url="https://www.baidu.com/s?wd=英伟达财报", extractMode="text", maxChars=12000)`
- 360:`web_fetch(url="https://m.so.com/s?q=英伟达财报", extractMode="text", maxChars=12000)`
**英文搜索:**
- Brave:`web_fetch(url="https://search.brave.com/search?q=AI+news", extractMode="text", maxChars=8000)`
- DDG:`web_fetch(url="https://lite.duckduckgo.com/lite/?q=AI+news", extractMode="text", maxChars=8000)`
**美股深度:**
- Seeking Alpha:`web_fetch(url="https://seekingalpha.com/symbol/AAPL", extractMode="text", maxChars=8000)`
- Finviz:`web_fetch(url="https://finviz.com/quote.ashx?t=NVDA", extractMode="text", maxChars=8000)`
- Macrotrends:`web_fetch(url="https://www.macrotrends.net/stocks/charts/AAPL/apple/revenue", extractMode="text", maxChars=8000)`
**宏观数据:**
- Treasury 收益率:`web_fetch(url="https://home.treasury.gov/", extractMode="text", maxChars=8000)`
- BEA 发布:`web_fetch(url="https://www.bea.gov/news/current-releases", extractMode="text", maxChars=8000)`
**Pre-IPO:**
- IPO 日历:`web_fetch(url="https://www.iposcoop.com/ipo-calendar/", extractMode="text", maxChars=8000)`
- 独角兽:`web_fetch(url="https://www.cbinsights.com/research-unicorn-companies", extractMode="text", maxChars=8000)`
**情绪/政治:**
- Reddit WSB:`web_fetch(url="https://www.reddit.com/r/wallstreetbets/top/.rss", extractMode="text", maxChars=8000)`
- Trump:`web_fetch(url="https://nitter.net/realDonaldTrump/rss", extractMode="text", maxChars=8000)`
**公众号:**
- 搜狗微信:`web_fetch(url="https://weixin.sogou.com/weixin?type=2&query=英伟达&page=1", extractMode="text", maxChars=10000)`
**知识查询:**
- Wikipedia:`web_fetch(url="https://zh.wikipedia.org/w/index.php?search=量子计算&title=Special:Search", extractMode="text", maxChars=8000)`
**投资:**
- 集思录:`web_fetch(url="https://www.jisilu.cn/explore/?keyword=可转债", extractMode="text", maxChars=8000)`
---
## 引擎选择建议
| 场景 | 推荐引擎 |
|------|---------|
| 中文通用搜索 | 百度 → 360 → 搜狗 |
| 英文通用搜索 | Brave → DDG → Bing |
| 公众号文章 | 搜狗微信 → 必应索引 |
| 技术问题 | Stack Overflow → GitHub |
| 最新资讯 | 头条搜索 → 百度 |
| A股/投资 | 东方财富 → 集思录 |
| 财经深度 | 财新 |
| 知识/定义 | Wikipedia 中文 → Wikipedia 英文 |
| 隐私优先 | Brave → Mojeek → DDG |
| 美股基本面 | Seeking Alpha → Macrotrends |
| 美股数据 | Finviz(内部人交易+筛选器) |
| 宏观数据 | Treasury(美债)→ BEA(GDP)→ Census(PMI) |
| 散户情绪 | Reddit WSB |
| 政策风向 | Nitter Trump |
| IPO 日历 | IPOScoop → StockAnalysis |
| 独角兽/Pre-IPO | CB Insights |
---
## 实战对比:有 cn-web-search vs 没有
> 以投研场景为例,问同一个问题:**"英伟达2026年Q1财报业绩如何?"**
### ❌ 没有 cn-web-search(纯模型)
```
回答:"我的训练数据有截止日期,无法提供最新财报数据。
建议您查看英伟达官网 investor.nvidia.com。"
```
**结果:什么有用信息都拿不到。**
### ✅ 装了 cn-web-search(百度 + 360 + 搜狗,3 个免费引擎)
```python
web_fetch(url="https://www.baidu.com/s?wd=英伟达2027财年Q1业绩指引", extractMode="text", maxChars=3000)
web_fetch(url="https://m.so.com/s?q=英伟达2026财报Q1业绩", extractMode="text", maxChars=3000)
web_fetch(url="https://www.sogou.com/web?query=英伟达财报2026Q1业绩预测", extractMode="text", maxChars=3000)
```
**拿到的实时数据(多源交叉验证):**
| 数据点 | 百度 | 360 | 搜狗 |
|--------|:----:|:---:|:----:|
| FY2026 Q1 营收 441 亿美元 (+69%) | ✅ | ✅ | ✅ |
| FY2026 Q4 营收 681 亿美元 (+73%) | ✅ | ✅ | ✅ |
| FY2026 全年营收 2159 亿美元 (+65%) | ✅ | ✅ | ✅ |
| FY2027 Q1 指引 780 亿(超预期 7%) | ✅ | ✅ | ✅ |
| H20 禁令影响 80 亿美元 | ✅ | ✅ | ✅ |
| 毛利率 75% | ✅ | ✅ | — |
| 黄仁勋:"代理式 AI 拐点已到来" | ✅ | — | ✅ |
### 对比总结
| 维度 | 无 Skill | cn-web-search |
|------|:--------:|:-------------:|
| 实时数据 | ❌ | ✅ |
| 数据准确性 | N/A | ✅ 多源交叉验证 |
| 成本 | — | 免费 |
| 投研可用性 | 零 | 营收/利润/指引/管理层表态 |
| 信息来源 | 无 | 百度+360+搜狗+雪球+东方财富 |
> **结论:没有 cn-web-search 的 agent 在投研场景下基本是废的。装上后等于给 agent 开了一扇窗,能看到实时世界——而且完全免费。**
---
## 更新日志
### v2.4.0
- 🆕 新增 11 个海外信息源:
- 美股深度:Seeking Alpha、Finviz、Macrotrends
- 全球宏观:BEA、Treasury、Census
- 政治/情绪:Reddit WSB (RSS)、Nitter (Trump RSS)
- Pre-IPO:IPOScoop、StockAnalysis、CB Insights
- 📊 引擎总数:17 → 28
- 🎯 覆盖美股、美债、宏观、散户情绪、IPO、独角兽
### v2.3.0
- 优化 SKILL.md 格式:纯 Markdown 列表替代代码块,ClawHub 页面可读性提升
### v2.2.0
- 📊 新增「实战对比」章节:有 cn-web-search vs 没有(以英伟达财报投研为例)
- 📈 展示多源交叉验证效果
### v2.1.0
- 🗑️ 移除所有 API 端点引擎(Hacker News、Reddit、ArXiv、DDG API、Wolfram Alpha)
- ✅ 全部 17 个引擎均为纯网页抓取,零 API 依赖
- 📋 更新引擎总览表和选择建议
### v2.0.0
- 🆕 新增 9 个引擎:百度、Yahoo、Brave Search、Mojeek、头条搜索、集思录、Wikipedia 中英文、DDG Instant Answer API
- 📊 引擎总数:13 → 22
### v1.0.0
- ✅ 全新发布!聚合 13+ 免费中文搜索引擎
- ✅ 无需 API Key,真正免费
- ✅ 支持公众号、知乎、财经(A股)、技术搜索
FILE:README.md
# CN Web Search - 中文网页搜索
**13+ 免费搜索引擎聚合**,全部免费,无需 API Key!包含公众号文章搜索。
## 引擎
| 类别 | 引擎 |
|------|------|
| 公众号 | 搜狗微信、必应索引 ⭐ |
| 中文 | 360、搜狗、必应 |
| 英文 | DDG、Qwant、Startpage、必应 |
| 技术 | Stack Overflow、GitHub Trending |
| 专用 | Hacker News、Reddit、ArXiv |
| 投资/深度 | 东方财富、财新、Wolfram Alpha |
## 安装
```bash
clawhub install cn-web-search
```
## 使用
```
"搜公众号 英伟达 文章"
"搜一下半导体产业链"
```
## 更新
### v0.9.0
- 全部免费,移除付费引擎
FILE:_meta.json
{
"ownerId": "kn7bwe5zrs5ghyr5qzz2byttf980shq8",
"slug": "cn-web-search",
"version": "2.0.0",
"publishedAt": 1774117678550
}
FILE:package.json
{
"name": "cn-web-search",
"version": "0.9.0",
"description": "中文网页搜索 - 聚合360搜索+DuckDuckGo,无需API Key",
"author": "joansongjr",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/joansongjr/cn-web-search"
},
"keywords": [
"search",
"chinese",
"web-search",
"openclaw",
"clawhub",
"skill"
]
}
Email infrastructure for AI agents — create inboxes, send and receive real emails, search messages, manage threads. Alternative to AgentMail with MCP server,...
--- name: clawaimail version: 0.2.0 description: Email infrastructure for AI agents — create inboxes, send and receive real emails, search messages, manage threads. Alternative to AgentMail with MCP server, REST API, webhooks, and WebSocket streaming. author: ClawAIMail author_url: https://clawaimail.com repository: https://github.com/joansongjr/clawaimail license: MIT tags: - email - inbox - send-email - receive-email - ai-agent - mcp-server - mcp - api - automation - email-agent - mailbox - webhook - smtp --- # ClawAIMail - Email for AI Agents Give your AI agent its own email address. Create inboxes, send and receive real emails, search messages, and manage threads — all through a simple API. ## What it does - **Create Inboxes**: Instantly create email addresses like `[email protected]` - **Send Emails**: Send real emails from your agent's address - **Receive Emails**: Get notified when emails arrive via webhook or WebSocket - **Read & Search**: Read messages, search by keyword, track threads - **Manage**: Labels, custom domains, and more ## Setup 1. Get your API key at https://clawaimail.com (free tier: 3 inboxes, 3K emails/month) 2. Set your environment variable: ``` CLAWAIMAIL_API_KEY=pb_your_api_key ``` ## MCP Server Configuration ```json { "mcpServers": { "clawaimail": { "command": "npx", "args": ["clawaimail-mcp"], "env": { "CLAWAIMAIL_API_KEY": "pb_your_api_key" } } } } ``` ## Available Tools | Tool | Description | |------|-------------| | `list_inboxes` | List all your email inboxes | | `create_inbox` | Create a new email inbox (e.g. [email protected]) | | `send_email` | Send an email from an inbox | | `list_messages` | List messages in an inbox | | `read_email` | Read a specific email message | | `search_emails` | Search emails by keyword | | `delete_inbox` | Delete an inbox and all its messages | | `account_info` | Get account info, plan limits, and usage | ## Example Usage ### Create an inbox and send an email ``` User: Create an email inbox called "assistant" Agent: [calls create_inbox with username "assistant"] Created inbox: [email protected] User: Send an email to [email protected] saying hello Agent: [calls send_email with to "[email protected]", subject "Hello", text "Hello from your AI assistant!"] Email sent successfully. ``` ### Check for new messages ``` User: Check my inbox for new messages Agent: [calls list_messages with inbox_id 1, unread true] You have 3 unread messages: 1. From: [email protected] - Subject: "Meeting tomorrow" 2. From: [email protected] - Subject: "Your ticket #1234" 3. From: [email protected] - Subject: "Weekly digest" ``` ### Search emails ``` User: Find any emails about invoices Agent: [calls search_emails with query "invoice"] Found 2 emails mentioning "invoice": 1. From: [email protected] - "Invoice #5678 - Due March 15" 2. From: [email protected] - "Updated invoice attached" ``` ## Pricing - **Free**: 3 inboxes, 3K emails/month - **Starter** ($5/mo): 10 inboxes, 5K emails/month - **Pro** ($29/mo): 50 inboxes, 50K emails/month, custom domains - **Business** ($99/mo): 200 inboxes, 200K emails/month ## Links - Website: https://clawaimail.com - API Docs: https://clawaimail.com/docs/ - GitHub: https://github.com/joansongjr/clawaimail - Node.js SDK: `npm install clawaimail` - Python SDK: `pip install clawaimail` FILE:README.md # ClawAIMail MCP Server MCP Server for ClawAIMail, letting AI tools (OpenClaw, Claude Code, Cursor) manage email. ## Setup ### Claude Code / Cursor Add to your MCP config (`~/.claude/mcp.json` or Cursor settings): ```json { "mcpServers": { "clawaimail": { "command": "node", "args": ["/path/to/agent-mail/mcp/index.js"], "env": { "CLAWAIMAIL_API_KEY": "pb_your_api_key", "CLAWAIMAIL_BASE_URL": "https://api.clawaimail.com" } } } } ``` ### OpenClaw Add to `openclaw.json` tools section or install as a plugin. ## Available Tools | Tool | Description | |------|-------------| | `list_inboxes` | List all email inboxes | | `create_inbox` | Create a new inbox | | `send_email` | Send an email | | `list_messages` | List messages in an inbox | | `read_email` | Read a specific email | | `search_emails` | Search emails by keyword | | `delete_inbox` | Delete an inbox | | `account_info` | Get account info and usage | FILE:index.js #!/usr/bin/env node import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { z } from 'zod'; const API_KEY = process.env.CLAWAIMAIL_API_KEY; const BASE_URL = process.env.CLAWAIMAIL_BASE_URL || 'https://api.clawaimail.com'; async function api(method, path, body) { const opts = { method, headers: { 'Authorization': `Bearer API_KEY`, 'Content-Type': 'application/json' } }; if (body) opts.body = JSON.stringify(body); const res = await fetch(`BASE_URLpath`, opts); return res.json(); } const server = new McpServer({ name: 'clawaimail', version: '0.1.0' }); // === Tools === server.tool( 'list_inboxes', 'List all email inboxes', {}, async () => { const result = await api('GET', '/v1/inboxes'); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } ); server.tool( 'create_inbox', 'Create a new email inbox', { username: z.string().describe('Email username (e.g. "mybot" creates [email protected])') }, async ({ username }) => { const result = await api('POST', '/v1/inboxes', { username }); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } ); server.tool( 'send_email', 'Send an email from an inbox', { inbox_id: z.number().describe('Inbox ID to send from'), to: z.string().describe('Recipient email address'), subject: z.string().describe('Email subject'), text: z.string().optional().describe('Plain text body'), html: z.string().optional().describe('HTML body') }, async ({ inbox_id, to, subject, text, html }) => { const result = await api('POST', '/v1/messages/send', { inbox_id, to, subject, text, html }); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } ); server.tool( 'list_messages', 'List messages in an inbox', { inbox_id: z.number().describe('Inbox ID'), limit: z.number().optional().describe('Max messages to return (default 20)'), unread: z.boolean().optional().describe('Only show unread messages') }, async ({ inbox_id, limit = 20, unread }) => { const params = new URLSearchParams({ limit }); if (unread) params.set('unread', 'true'); const result = await api('GET', `/v1/inboxes/inbox_id/messages?params`); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } ); server.tool( 'read_email', 'Read a specific email message', { inbox_id: z.number().describe('Inbox ID'), message_id: z.number().describe('Message ID') }, async ({ inbox_id, message_id }) => { const result = await api('GET', `/v1/inboxes/inbox_id/messages/message_id`); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } ); server.tool( 'search_emails', 'Search emails by keyword', { inbox_id: z.number().describe('Inbox ID'), query: z.string().describe('Search query') }, async ({ inbox_id, query }) => { const params = new URLSearchParams({ q: query }); const result = await api('GET', `/v1/inboxes/inbox_id/search?params`); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } ); server.tool( 'delete_inbox', 'Delete an inbox and all its messages', { inbox_id: z.number().describe('Inbox ID to delete') }, async ({ inbox_id }) => { const result = await api('DELETE', `/v1/inboxes/inbox_id`); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } ); server.tool( 'account_info', 'Get account info, plan limits, and usage', {}, async () => { const result = await api('GET', '/v1/me'); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } ); // === Start === const transport = new StdioServerTransport(); await server.connect(transport); FILE:mcp.json { "mcpServers": { "clawaimail": { "command": "npx", "args": ["clawaimail-mcp"], "env": { "CLAWAIMAIL_API_KEY": "your_api_key_here" } } } } FILE:package-lock.json { "name": "clawaimail-mcp", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "clawaimail-mcp", "version": "0.1.0", "dependencies": { "@modelcontextprotocol/sdk": "^1.0.0" }, "bin": { "clawaimail-mcp": "index.js" } }, "node_modules/@hono/node-server": { "version": "1.19.11", "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.11.tgz", "integrity": "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==", "license": "MIT", "engines": { "node": ">=18.14.1" }, "peerDependencies": { "hono": "^4" } }, "node_modules/@modelcontextprotocol/sdk": { "version": "1.27.1", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.27.1.tgz", "integrity": "sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==", "license": "MIT", "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "engines": { "node": ">=18" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1", "zod": "^3.25 || ^4.0" }, "peerDependenciesMeta": { "@cfworker/json-schema": { "optional": true }, "zod": { "optional": false } } }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" }, "engines": { "node": ">= 0.6" } }, "node_modules/ajv": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" }, "funding": { "type": "github", "url": "https://github.com/sponsors/epoberezkin" } }, "node_modules/ajv-formats": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "license": "MIT", "dependencies": { "ajv": "^8.0.0" }, "peerDependencies": { "ajv": "^8.0.0" }, "peerDependenciesMeta": { "ajv": { "optional": true } } }, "node_modules/body-parser": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "license": "MIT", "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" }, "engines": { "node": ">=18" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" }, "engines": { "node": ">= 0.4" } }, "node_modules/call-bound": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/content-disposition": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "license": "MIT", "engines": { "node": ">=18" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/content-type": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-signature": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "license": "MIT", "engines": { "node": ">=6.6.0" } }, "node_modules/cors": { "version": "2.8.6", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", "license": "MIT", "dependencies": { "object-assign": "^4", "vary": "^1" }, "engines": { "node": ">= 0.10" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" }, "engines": { "node": ">= 8" } }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" }, "engines": { "node": ">=6.0" }, "peerDependenciesMeta": { "supports-color": { "optional": true } } }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "license": "MIT" }, "node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-errors": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "license": "MIT" }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/eventsource": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", "license": "MIT", "dependencies": { "eventsource-parser": "^3.0.1" }, "engines": { "node": ">=18.0.0" } }, "node_modules/eventsource-parser": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", "license": "MIT", "engines": { "node": ">=18.0.0" } }, "node_modules/express": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" }, "engines": { "node": ">= 18" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/express-rate-limit": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.3.0.tgz", "integrity": "sha512-KJzBawY6fB9FiZGdE/0aftepZ91YlaGIrV8vgblRM3J8X+dHx/aiowJWwkx6LIGyuqGiANsjSwwrbb8mifOJ4Q==", "license": "MIT", "dependencies": { "ip-address": "10.1.0" }, "engines": { "node": ">= 16" }, "funding": { "url": "https://github.com/sponsors/express-rate-limit" }, "peerDependencies": { "express": ">= 4.11" } }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, "node_modules/fast-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/fastify" }, { "type": "opencollective", "url": "https://opencollective.com/fastify" } ], "license": "BSD-3-Clause" }, "node_modules/finalhandler": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "license": "MIT", "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" }, "engines": { "node": ">= 18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/fresh": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/get-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, "engines": { "node": ">= 0.4" } }, "node_modules/hono": { "version": "4.12.5", "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.5.tgz", "integrity": "sha512-3qq+FUBtlTHhtYxbxheZgY8NIFnkkC/MR8u5TTsr7YZ3wixryQ3cCwn3iZbg8p8B88iDBBAYSfZDS75t8MN7Vg==", "license": "MIT", "engines": { "node": ">=16.9.0" } }, "node_modules/http-errors": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/iconv-lite": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, "node_modules/ip-address": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", "license": "MIT", "engines": { "node": ">= 12" } }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "license": "MIT", "engines": { "node": ">= 0.10" } }, "node_modules/is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, "node_modules/jose": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.0.tgz", "integrity": "sha512-xsfE1TcSCbUdo6U07tR0mvhg0flGxU8tPLbF03mirl2ukGQENhUg4ubGYQnhVH0b5stLlPM+WOqDkEl1R1y5sQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" } }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT" }, "node_modules/json-schema-typed": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", "license": "BSD-2-Clause" }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/media-typer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/merge-descriptors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "license": "MIT", "engines": { "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/mime-db": { "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { "mime-db": "^1.54.0" }, "engines": { "node": ">=18" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/negotiator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "license": "MIT", "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, "engines": { "node": ">= 0.8" } }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "license": "ISC", "dependencies": { "wrappy": "1" } }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/path-to-regexp": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/pkce-challenge": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", "license": "MIT", "engines": { "node": ">=16.20.0" } }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" }, "engines": { "node": ">= 0.10" } }, "node_modules/qs": { "version": "6.15.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/raw-body": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "license": "MIT", "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.10" } }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "license": "MIT", "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" }, "engines": { "node": ">= 18" } }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, "node_modules/send": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "license": "MIT", "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" }, "engines": { "node": ">= 18" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/serve-static": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "license": "MIT", "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" }, "engines": { "node": ">= 18" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, "engines": { "node": ">=8" } }, "node_modules/shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/side-channel-list": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/side-channel-map": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/side-channel-weakmap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "license": "MIT", "engines": { "node": ">=0.6" } }, "node_modules/type-is": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", "license": "MIT", "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" }, "engines": { "node": ">= 0.6" } }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" }, "engines": { "node": ">= 8" } }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, "node_modules/zod": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } }, "node_modules/zod-to-json-schema": { "version": "3.25.1", "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", "license": "ISC", "peerDependencies": { "zod": "^3.25 || ^4" } } } } FILE:package.json { "name": "clawaimail-mcp", "version": "0.1.1", "description": "ClawAIMail MCP Server - Email tools for AI agents (Claude, Cursor, OpenClaw)", "main": "index.js", "mcpName": "io.github.joansongjr/clawaimail", "type": "module", "bin": { "clawaimail-mcp": "./index.js" }, "keywords": [ "mcp", "mcp-server", "email", "ai", "agent", "claude", "cursor", "openclaw", "clawaimail", "model-context-protocol", "ai-tools" ], "author": "ClawAIMail <[email protected]>", "license": "MIT", "homepage": "https://clawaimail.com", "repository": { "type": "git", "url": "https://github.com/joansongjr/clawaimail" }, "dependencies": { "@modelcontextprotocol/sdk": "^1.0.0", "zod": "^3.22.0" }, "files": ["index.js"] } FILE:server.json { "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", "name": "io.github.joansongjr/clawaimail", "description": "Email infrastructure for AI agents. Create inboxes, send/receive email, and search messages.", "repository": { "url": "https://github.com/joansongjr/clawaimail", "source": "github" }, "version": "0.1.1", "packages": [ { "registryType": "npm", "identifier": "clawaimail-mcp", "version": "0.1.1", "runtimeHint": "npx", "transport": { "type": "stdio" }, "environmentVariables": [ { "description": "Your ClawAIMail API key. Get one at https://clawaimail.com", "isRequired": true, "isSecret": true, "name": "CLAWAIMAIL_API_KEY" } ] } ] }
Give your AI agent a real email address. Send, receive, and manage emails via API.
--- name: clawaimail display_name: ClawAIMail - Email for AI Agents version: 0.2.7 description: Give your AI agent a real email address. Send, receive, and manage emails via API. author: ClawAIMail author_url: https://clawaimail.com repository: https://github.com/joansongjr/clawaimail license: MIT tags: - email - inbox - send-email - receive-email - ai-agent - mcp-server - api - automation --- # ClawAIMail - Email for AI Agents Give your AI agent its own email address. Create inboxes, send and receive real emails, search messages, and manage threads — all through a simple API. ## What it does - **Create Inboxes**: Instantly create email addresses like `[email protected]` - **Send Emails**: Send real emails from your agent's address - **Receive Emails**: Get notified when emails arrive via webhook or WebSocket - **Read & Search**: Read messages, search by keyword, track threads - **Manage**: Labels, custom domains, and more ## Setup 1. Get your API key at https://clawaimail.com (free tier: 3 inboxes, 3K emails/month) 2. Set your environment variable: ``` CLAWAIMAIL_API_KEY=pb_your_api_key ``` ## OpenClaw Configuration ⚠️ **Important**: Do NOT add `mcpServers` to `openclaw.json` — that field is not supported and will crash the Gateway. Use **mcporter** (OpenClaw's MCP management tool) to configure: ```bash # Add ClawAIMail as an MCP server mcporter config add clawaimail "npx -y clawaimail-mcp" --env CLAWAIMAIL_API_KEY="pb_your_api_key" # Test it works mcporter call clawaimail.list_inboxes # Check status mcporter status ``` mcporter manages its own config at `~/.openclaw/config/mcporter.json`, separate from the OpenClaw Gateway config. ### Troubleshooting | Problem | Cause | Fix | |---------|-------|-----| | Gateway crashes on startup | `mcpServers` added to `openclaw.json` | Remove it from `openclaw.json`, use `mcporter` instead | | "CLAWAIMAIL_API_KEY not set" warning | Missing env var | Add `--env CLAWAIMAIL_API_KEY="..."` to mcporter config | | API calls return errors | Invalid API key or service unreachable | Check key at https://clawaimail.com/dashboard | ## MCP Server Configuration (Claude Desktop / Cursor) For non-OpenClaw MCP clients: ```json { "mcpServers": { "clawaimail": { "command": "npx", "args": ["-y", "clawaimail-mcp"], "env": { "CLAWAIMAIL_API_KEY": "pb_your_api_key" } } } } ``` ## Available Tools | Tool | Description | |------|-------------| | `list_inboxes` | List all your email inboxes | | `create_inbox` | Create a new email inbox (e.g. [email protected]) | | `send_email` | Send an email from an inbox | | `list_messages` | List messages in an inbox | | `read_email` | Read a specific email message | | `search_emails` | Search emails by keyword | | `delete_inbox` | Delete an inbox and all its messages | | `account_info` | Get account info, plan limits, and usage | ## Example Usage ### Create an inbox and send an email ``` User: Create an email inbox called "assistant" Agent: [calls create_inbox with username "assistant"] Created inbox: [email protected] User: Send an email to [email protected] saying hello Agent: [calls send_email with to "[email protected]", subject "Hello", text "Hello from your AI assistant!"] Email sent successfully. ``` ### Check for new messages ``` User: Check my inbox for new messages Agent: [calls list_messages with inbox_id 1, unread true] You have 3 unread messages: 1. From: [email protected] - Subject: "Meeting tomorrow" 2. From: [email protected] - Subject: "Your ticket #1234" 3. From: [email protected] - Subject: "Weekly digest" ``` ### Search emails ``` User: Find any emails about invoices Agent: [calls search_emails with query "invoice"] Found 2 emails mentioning "invoice": 1. From: [email protected] - "Invoice #5678 - Due March 15" 2. From: [email protected] - "Updated invoice attached" ``` ## Pricing - **Free**: 3 inboxes, 3K emails/month - **Starter** ($5/mo): 10 inboxes, 5K emails/month - **Pro** ($29/mo): 50 inboxes, 50K emails/month, custom domains - **Business** ($99/mo): 200 inboxes, 200K emails/month ## Changelog ### 0.1.2 - Fix: Added error handling to all API calls (no more crashes on missing API key or network errors) - Fix: Accept both number and string IDs for inbox_id/message_id - Added startup warning when CLAWAIMAIL_API_KEY is not set - Added global exception handlers to prevent process crashes ### 0.1.0 - Initial release ## Links - Website: https://clawaimail.com - API Docs: https://clawaimail.com/docs/ - GitHub: https://github.com/joansongjr/clawaimail - npm: https://www.npmjs.com/package/clawaimail-mcp - ClawHub: https://clawhub.com/skills/clawaimail - Node.js SDK: `npm install clawaimail` - Python SDK: `pip install clawaimail` FILE:README.md # ClawAIMail MCP Server MCP Server for ClawAIMail, letting AI tools (OpenClaw, Claude Code, Cursor) manage email. ## Setup ### Claude Code / Cursor Add to your MCP config (`~/.claude/mcp.json` or Cursor settings): ```json { "mcpServers": { "clawaimail": { "command": "node", "args": ["/path/to/agent-mail/mcp/index.js"], "env": { "CLAWAIMAIL_API_KEY": "pb_your_api_key", "CLAWAIMAIL_BASE_URL": "https://api.clawaimail.com" } } } } ``` ### OpenClaw Add to `openclaw.json` tools section or install as a plugin. ## Available Tools | Tool | Description | |------|-------------| | `list_inboxes` | List all email inboxes | | `create_inbox` | Create a new inbox | | `send_email` | Send an email | | `list_messages` | List messages in an inbox | | `read_email` | Read a specific email | | `search_emails` | Search emails by keyword | | `delete_inbox` | Delete an inbox | | `account_info` | Get account info and usage | FILE:_meta.json { "ownerId": "kn7bwe5zrs5ghyr5qzz2byttf980shq8", "slug": "clawaimail", "version": "0.2.7", "publishedAt": 1773635263844 } FILE:glama.json { "$schema": "https://glama.ai/mcp/schemas/server.json", "maintainers": [ "joansongjr" ] } FILE:index.js #!/usr/bin/env node import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { z } from 'zod'; import { randomBytes } from 'crypto'; const API_KEY = process.env.CLAWAIMAIL_API_KEY; const BASE_URL = process.env.CLAWAIMAIL_BASE_URL || 'https://api.clawaimail.com'; // Warn if API key is missing if (!API_KEY) { console.error('[clawaimail] WARNING: CLAWAIMAIL_API_KEY not set. All API calls will fail.'); } // Log unhandled errors and exit cleanly process.on('uncaughtException', (err) => { console.error('[clawaimail] Uncaught exception:', err.message); process.exit(1); }); process.on('unhandledRejection', (err) => { console.error('[clawaimail] Unhandled rejection:', err?.message || err); process.exit(1); }); // Flexible ID schema: accepts number or numeric string const idSchema = z.union([ z.number(), z.string().transform((v) => { const n = Number(v); if (isNaN(n)) throw new Error(`Invalid ID: v`); return n; }) ]).describe('ID (number or numeric string)'); async function api(method, path, body) { try { if (!API_KEY) { return { error: 'CLAWAIMAIL_API_KEY not configured. Set it in your environment variables.' }; } const opts = { method, headers: { 'Authorization': `Bearer API_KEY`, 'Content-Type': 'application/json' } }; if (body) opts.body = JSON.stringify(body); const res = await fetch(`BASE_URLpath`, opts); const text = await res.text(); let data; try { data = JSON.parse(text); } catch { return { error: `Server returned non-JSON response (HTTP res.status): text.slice(0, 200)` }; } if (!res.ok) { return { error: data?.message || data?.error || `HTTP res.status`, status: res.status, details: data }; } return data; } catch (err) { return { error: `Request failed: err.message` }; } } // === Default inbox auto-provisioning === // Cached default inbox so we don't query every time let _defaultInbox = null; async function getDefaultInbox() { if (_defaultInbox) return _defaultInbox; // Check if user already has any inboxes const list = await api('GET', '/v1/inboxes'); if (list.error) return { error: list.error }; const inboxes = list.inboxes || list.data || list; if (Array.isArray(inboxes) && inboxes.length > 0) { _defaultInbox = inboxes[0]; return _defaultInbox; } // No inboxes exist — auto-create one so the user can start immediately const randomName = `agent-randomBytes(4).toString('hex')`; console.error(`[clawaimail] No inboxes found. Creating default inbox: randomName@clawaimail.com`); const created = await api('POST', '/v1/inboxes', { username: randomName }); if (created.error) return { error: `Failed to auto-create inbox: created.error` }; _defaultInbox = created.inbox || created; console.error(`[clawaimail] Default inbox ready: _defaultInbox.address || randomName + '@clawaimail.com'`); return _defaultInbox; } function inboxId(inbox) { return inbox?.id || inbox?.inbox_id; } const server = new McpServer({ name: 'clawaimail', version: '0.2.1' }); // === Tools === server.tool( 'list_inboxes', 'List all email inboxes', {}, async () => { const result = await api('GET', '/v1/inboxes'); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } ); server.tool( 'create_inbox', 'Create a new email inbox (optional — a default inbox is auto-created if needed)', { username: z.string().describe('Email username (e.g. "mybot" creates [email protected])') }, async ({ username }) => { const result = await api('POST', '/v1/inboxes', { username }); if (!result.error) _defaultInbox = null; // reset cache return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } ); server.tool( 'send_email', 'Send an email. If inbox_id is omitted, uses the default inbox (auto-created if needed).', { inbox_id: idSchema.optional().describe('Inbox ID to send from (optional, uses default inbox)'), to: z.string().describe('Recipient email address'), subject: z.string().describe('Email subject'), text: z.string().optional().describe('Plain text body'), html: z.string().optional().describe('HTML body') }, async ({ inbox_id, to, subject, text, html }) => { if (!inbox_id) { const inbox = await getDefaultInbox(); if (inbox.error) return { content: [{ type: 'text', text: JSON.stringify(inbox, null, 2) }] }; inbox_id = inboxId(inbox); } const result = await api('POST', '/v1/messages/send', { inbox_id, to, subject, text, html }); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } ); server.tool( 'list_messages', 'List messages. If inbox_id is omitted, uses the default inbox.', { inbox_id: idSchema.optional().describe('Inbox ID (optional, uses default inbox)'), limit: z.number().optional().describe('Max messages to return (default 20)'), unread: z.boolean().optional().describe('Only show unread messages') }, async ({ inbox_id, limit = 20, unread }) => { if (!inbox_id) { const inbox = await getDefaultInbox(); if (inbox.error) return { content: [{ type: 'text', text: JSON.stringify(inbox, null, 2) }] }; inbox_id = inboxId(inbox); } const params = new URLSearchParams({ limit: String(limit) }); if (unread) params.set('unread', 'true'); const result = await api('GET', `/v1/inboxes/inbox_id/messages?params`); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } ); server.tool( 'read_email', 'Read a specific email message. If inbox_id is omitted, uses the default inbox.', { inbox_id: idSchema.optional().describe('Inbox ID (optional, uses default inbox)'), message_id: idSchema.describe('Message ID') }, async ({ inbox_id, message_id }) => { if (!inbox_id) { const inbox = await getDefaultInbox(); if (inbox.error) return { content: [{ type: 'text', text: JSON.stringify(inbox, null, 2) }] }; inbox_id = inboxId(inbox); } const result = await api('GET', `/v1/inboxes/inbox_id/messages/message_id`); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } ); server.tool( 'search_emails', 'Search emails by keyword. If inbox_id is omitted, uses the default inbox.', { inbox_id: idSchema.optional().describe('Inbox ID (optional, uses default inbox)'), query: z.string().describe('Search query') }, async ({ inbox_id, query }) => { if (!inbox_id) { const inbox = await getDefaultInbox(); if (inbox.error) return { content: [{ type: 'text', text: JSON.stringify(inbox, null, 2) }] }; inbox_id = inboxId(inbox); } const params = new URLSearchParams({ q: query }); const result = await api('GET', `/v1/inboxes/inbox_id/search?params`); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } ); server.tool( 'delete_inbox', 'Delete an inbox and all its messages', { inbox_id: idSchema.describe('Inbox ID to delete') }, async ({ inbox_id }) => { const result = await api('DELETE', `/v1/inboxes/inbox_id`); if (!result.error) _defaultInbox = null; // reset cache return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } ); server.tool( 'account_info', 'Get account info, plan limits, and usage', {}, async () => { const result = await api('GET', '/v1/me'); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } ); server.tool( 'my_email', 'Get your agent\'s email address (auto-creates one if none exists)', {}, async () => { const inbox = await getDefaultInbox(); if (inbox.error) return { content: [{ type: 'text', text: JSON.stringify(inbox, null, 2) }] }; return { content: [{ type: 'text', text: JSON.stringify({ email: inbox.email || inbox.address || `inbox.username@clawaimail.com`, inbox_id: inboxId(inbox), ...inbox }, null, 2) }] }; } ); // === Start === const transport = new StdioServerTransport(); await server.connect(transport); FILE:mcp.json { "mcpServers": { "clawaimail": { "command": "npx", "args": ["clawaimail-mcp"], "env": { "CLAWAIMAIL_API_KEY": "your_api_key_here" } } } } FILE:package-lock.json { "name": "clawaimail-mcp", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "clawaimail-mcp", "version": "0.1.0", "dependencies": { "@modelcontextprotocol/sdk": "^1.0.0" }, "bin": { "clawaimail-mcp": "index.js" } }, "node_modules/@hono/node-server": { "version": "1.19.11", "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.11.tgz", "integrity": "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==", "license": "MIT", "engines": { "node": ">=18.14.1" }, "peerDependencies": { "hono": "^4" } }, "node_modules/@modelcontextprotocol/sdk": { "version": "1.27.1", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.27.1.tgz", "integrity": "sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==", "license": "MIT", "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "engines": { "node": ">=18" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1", "zod": "^3.25 || ^4.0" }, "peerDependenciesMeta": { "@cfworker/json-schema": { "optional": true }, "zod": { "optional": false } } }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" }, "engines": { "node": ">= 0.6" } }, "node_modules/ajv": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" }, "funding": { "type": "github", "url": "https://github.com/sponsors/epoberezkin" } }, "node_modules/ajv-formats": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "license": "MIT", "dependencies": { "ajv": "^8.0.0" }, "peerDependencies": { "ajv": "^8.0.0" }, "peerDependenciesMeta": { "ajv": { "optional": true } } }, "node_modules/body-parser": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "license": "MIT", "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" }, "engines": { "node": ">=18" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" }, "engines": { "node": ">= 0.4" } }, "node_modules/call-bound": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/content-disposition": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "license": "MIT", "engines": { "node": ">=18" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/content-type": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-signature": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "license": "MIT", "engines": { "node": ">=6.6.0" } }, "node_modules/cors": { "version": "2.8.6", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", "license": "MIT", "dependencies": { "object-assign": "^4", "vary": "^1" }, "engines": { "node": ">= 0.10" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" }, "engines": { "node": ">= 8" } }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" }, "engines": { "node": ">=6.0" }, "peerDependenciesMeta": { "supports-color": { "optional": true } } }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "license": "MIT" }, "node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-errors": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "license": "MIT" }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/eventsource": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", "license": "MIT", "dependencies": { "eventsource-parser": "^3.0.1" }, "engines": { "node": ">=18.0.0" } }, "node_modules/eventsource-parser": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", "license": "MIT", "engines": { "node": ">=18.0.0" } }, "node_modules/express": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" }, "engines": { "node": ">= 18" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/express-rate-limit": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.3.0.tgz", "integrity": "sha512-KJzBawY6fB9FiZGdE/0aftepZ91YlaGIrV8vgblRM3J8X+dHx/aiowJWwkx6LIGyuqGiANsjSwwrbb8mifOJ4Q==", "license": "MIT", "dependencies": { "ip-address": "10.1.0" }, "engines": { "node": ">= 16" }, "funding": { "url": "https://github.com/sponsors/express-rate-limit" }, "peerDependencies": { "express": ">= 4.11" } }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, "node_modules/fast-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/fastify" }, { "type": "opencollective", "url": "https://opencollective.com/fastify" } ], "license": "BSD-3-Clause" }, "node_modules/finalhandler": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "license": "MIT", "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" }, "engines": { "node": ">= 18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/fresh": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/get-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, "engines": { "node": ">= 0.4" } }, "node_modules/hono": { "version": "4.12.5", "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.5.tgz", "integrity": "sha512-3qq+FUBtlTHhtYxbxheZgY8NIFnkkC/MR8u5TTsr7YZ3wixryQ3cCwn3iZbg8p8B88iDBBAYSfZDS75t8MN7Vg==", "license": "MIT", "engines": { "node": ">=16.9.0" } }, "node_modules/http-errors": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/iconv-lite": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, "node_modules/ip-address": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", "license": "MIT", "engines": { "node": ">= 12" } }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "license": "MIT", "engines": { "node": ">= 0.10" } }, "node_modules/is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, "node_modules/jose": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.0.tgz", "integrity": "sha512-xsfE1TcSCbUdo6U07tR0mvhg0flGxU8tPLbF03mirl2ukGQENhUg4ubGYQnhVH0b5stLlPM+WOqDkEl1R1y5sQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" } }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT" }, "node_modules/json-schema-typed": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", "license": "BSD-2-Clause" }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/media-typer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/merge-descriptors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "license": "MIT", "engines": { "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/mime-db": { "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { "mime-db": "^1.54.0" }, "engines": { "node": ">=18" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/negotiator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "license": "MIT", "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, "engines": { "node": ">= 0.8" } }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "license": "ISC", "dependencies": { "wrappy": "1" } }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/path-to-regexp": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/pkce-challenge": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", "license": "MIT", "engines": { "node": ">=16.20.0" } }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" }, "engines": { "node": ">= 0.10" } }, "node_modules/qs": { "version": "6.15.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/raw-body": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "license": "MIT", "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.10" } }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "license": "MIT", "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" }, "engines": { "node": ">= 18" } }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, "node_modules/send": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "license": "MIT", "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" }, "engines": { "node": ">= 18" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/serve-static": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "license": "MIT", "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" }, "engines": { "node": ">= 18" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, "engines": { "node": ">=8" } }, "node_modules/shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/side-channel-list": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/side-channel-map": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/side-channel-weakmap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "license": "MIT", "engines": { "node": ">=0.6" } }, "node_modules/type-is": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", "license": "MIT", "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" }, "engines": { "node": ">= 0.6" } }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" }, "engines": { "node": ">= 8" } }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, "node_modules/zod": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } }, "node_modules/zod-to-json-schema": { "version": "3.25.1", "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", "license": "ISC", "peerDependencies": { "zod": "^3.25 || ^4" } } } } FILE:package.json { "name": "clawaimail-mcp", "version": "0.2.1", "description": "ClawAIMail MCP Server - Email tools for AI agents (Claude, Cursor, OpenClaw)", "main": "index.js", "mcpName": "io.github.joansongjr/clawaimail", "type": "module", "bin": { "clawaimail-mcp": "./index.js" }, "keywords": [ "mcp", "mcp-server", "email", "ai", "agent", "claude", "cursor", "openclaw", "clawaimail", "model-context-protocol", "ai-tools" ], "author": "ClawAIMail <[email protected]>", "license": "MIT", "homepage": "https://clawaimail.com", "repository": { "type": "git", "url": "https://github.com/joansongjr/clawaimail" }, "dependencies": { "@modelcontextprotocol/sdk": "^1.0.0", "zod": "^3.22.0" }, "files": [ "index.js" ] } FILE:server.json { "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", "name": "io.github.joansongjr/clawaimail", "description": "Email infrastructure for AI agents. Create inboxes, send/receive email, and search messages.", "repository": { "url": "https://github.com/joansongjr/clawaimail", "source": "github" }, "version": "0.2.1", "packages": [ { "registryType": "npm", "identifier": "clawaimail-mcp", "version": "0.2.1", "runtimeHint": "npx", "transport": { "type": "stdio" }, "environmentVariables": [ { "description": "Your ClawAIMail API key. Get one at https://clawaimail.com", "isRequired": true, "isSecret": true, "name": "CLAWAIMAIL_API_KEY" } ] } ] }
用日常穿搭比喻解释代码,帮助小白理解。当用户要求用穿搭、穿衣、衣柜、outfit 比喻解释代码,或提到 Coding as Dressing 时使用。
---
name: coding-as-dressing
description: 用日常穿搭比喻解释代码,帮助小白理解。当用户要求用穿搭、穿衣、衣柜、outfit 比喻解释代码,或提到 Coding as Dressing 时使用。
---
# Coding as Dressing - 穿搭式代码解释
用普通人日常穿衣服的逻辑,帮小白理解代码结构和问题。
## 使用时机
- 用户选中代码并说「用穿搭/穿衣比喻解释」
- 用户说「这段代码什么意思」「帮我用简单的话解释」
- 用户提到 Coding as Dressing
## 解释风格
- **口语化**:像聊天,不说「宛如」「恰似」
- **精简**:一句话说清楚,不堆砌
- **日常**:白T、牛仔裤、帆布鞋,不说礼服蕾丝
- **可操作**:指出能删、能并、要补的地方
---
## 代码 ↔ 穿搭 映射表
### 基础概念
| 代码 | 穿搭比喻 |
|------|----------|
| 变量 | 可换的配饰:帽子、包、鞋,换一个就是新效果 |
| 函数 | 一件完整单品:上衣、裤子、外套,有固定作用 |
| 循环 | 同一件衣服反复穿,做同样的事 |
| 条件 if/else | 看天气选穿啥:下雨穿外套,晴天穿短袖 |
| 项目入口 | 出门前的第一件:先穿上衣还是先穿裤子 |
| 依赖/import | 衣服之间的搭配:这件上衣得配那条裤子 |
### 问题与修改
| 代码问题 | 穿搭比喻 | 建议 |
|----------|----------|------|
| 冗余/重复函数 | 衣柜里两件几乎一样的白T | 留一件就行 |
| 死代码 | 买来没穿过的衣服 | 可以断舍离 |
| 重复逻辑 | 两条差不多款式的牛仔裤 | 合并成一条 |
| 缺失错误处理 | 上衣有了,没配裤子 | 补上 |
| 依赖缺失 | 穿了外套没穿内搭 | 把缺的补上 |
---
## 输出格式
1. **先给一句话总览**:这段代码在干嘛
2. **按结构拆解**:用穿搭比喻说清各部分
3. **有问题就指出**:冗余、缺失、重复,用比喻说明+建议
---
## 示例
**输入代码:**
```python
def get_user(id):
return users[id]
def fetch_user(id):
return users[id]
```
**输出(穿搭式):**
这段代码在干一件事:根据 id 找人。但你有**两件一样的白T**——`get_user` 和 `fetch_user` 做的完全相同,相当于衣柜里两条一模一样的牛仔裤。留一个就行,删掉 `fetch_user`,以后统一用 `get_user`。
---
**输入代码:**
```javascript
for (let i = 0; i < 5; i++) {
console.log("Hello");
}
```
**输出(穿搭式):**
这是一个**同一件衣服穿五次**——循环把同一件事重复做 5 遍,每次都输出 "Hello"。就像你这周连续五天穿同一件卫衣上班,每次出门都是同一套动作。
---
**输入代码:**
```python
if weather == "rain":
wear("coat")
else:
wear("tshirt")
```
**输出(穿搭式):**
这是**看天气选穿啥**——下雨穿外套,不下雨穿短袖。if/else 就是根据条件选不同的「单品」,二选一,每次只穿一套。