Skip to content

部署形态 + ToolSet 集成 — 实施 Plan

Date: 2026-05-08 Status: Draft (pending user review) Owner: liang Sibling docs:

  • docs/planning/01-data-layer.md(数据层 / 仓库化 / 字段明细)
  • docs/planning/superpowers/specs/2026-05-08-tushare-integration-design.md(Provider 抽象 / Composer / cache 策略)

本 plan 是可执行的 rollout 计划,把过去几轮对话沉淀的架构决策落到一步步的 task。设计层细节在 sibling docs 里,本 plan 不重复,只引用。


一、本 plan 沉淀的 4 个架构决策

  1. Twilight 与 Hermes 是两个独立 Docker image(不能合并打包)
  2. Build context 清理通过 .dockerignore,docs / node_modules / .git 不进 build
  3. Provider 配置三层划分:模块化代码 + env vars (.env) + 可选 YAML override;provider 列表不进 YAML
  4. Hermes ToolSet 集成模式:一个共享 client 库 + 多个 thin tool scripts,统一通过 HTTPS 走 api.fsagent.cc

二、目标架构(图)

┌─────────────────────────────────────────────────────────────────────┐
│                        用户机器(任意)                              │
│  ┌────────────────────────────────────────────────────────────────┐ │
│  │ Hermes runtime(v0.2.0 进程;未来 Docker image 可选)          │ │
│  │                                                                │ │
│  │  ┌──────────────────────────────────────────────────┐         │ │
│  │  │ profile: stock-research-agent                    │         │ │
│  │  │ skills/twilight/                                 │         │ │
│  │  │   ├── SKILL.md                                   │         │ │
│  │  │   ├── fetch_price.py        ─┐                   │         │ │
│  │  │   ├── fetch_fundamentals.py ─┤  统一调           │         │ │
│  │  │   ├── screen_stocks.py      ─┤                   │         │ │
│  │  │   ├── compare_indices.py    ─┘  TwilightClient   │         │ │
│  │  │   └── twilight_client.py    ←── 共享 lib         │         │ │
│  │  └──────────────────────────────────────────────────┘         │ │
│  │                          │                                     │ │
│  │                          │ HTTPS + Bearer token                │ │
│  │                          ▼                                     │ │
│  └────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘

                              │ Cloudflared tunnel

┌─────────────────────────────────────────────────────────────────────┐
│                          tvps (Vultr)                                │
│  ┌──────────────────────┐  ┌────────────────────────────────────┐  │
│  │ twilight-cloudflared │  │ twilight-backend                   │  │
│  │ (cloudflare/cloud-   │  │ (ghcr.io/lacatfly/twilight-drive)  │  │
│  │  flared:latest)      │  │                                    │  │
│  │                      │  │  - FastAPI (uvicorn)               │  │
│  │  api.fsagent.cc      │  │  - APScheduler ingest              │  │
│  │  ←→ :8081 (host)     │──│  - DuckDB warehouse + cache        │  │
│  └──────────────────────┘  │  - Provider registry / Composer    │  │
│                            └────────────────────────────────────┘  │
│                                       │                            │
│                                       ▼                            │
│                            ┌────────────────────────────────────┐  │
│                            │ ~/twilight/data/  (host volume)    │  │
│                            │   ├── warehouse.duckdb             │  │
│                            │   ├── bearers.sqlite               │  │
│                            │   └── config/runtime.yaml (可选)   │  │
│                            └────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────┘

三、决策一:Docker 微服务模式

3.1 四个独立 service

serviceimagehost资源卷挂载
twilight-backendghcr.io/lacatfly/twilight-drive:latesttvps0.75 vCPU / 1500 MB~/twilight/data → /data~/twilight/logs → /var/log/...
twilight-cloudflaredcloudflare/cloudflared:latesttvps0.1 vCPU / 64 MB~/.cloudflared → /etc/cloudflared
twilight-provisionerghcr.io/lacatfly/twilight-drive:latest (同 image, 不同 entrypoint)tvps0.25 vCPU / 256 MB~/twilight → /twilight、docker socket
hermes (per-user)ghcr.io/forrestchang/hermes:<tag>任意用户机器--memory 150m --cpus 0.5~/.hermes/profiles/<name> → /hermes/profile

3.2 为什么不合并

Twilight backendHermes
角色数据后端 / 多客户端 / 长寿命Agent runtime / 单用户 / 进程级
状态DuckDB 仓库(GB 级) + bearer DBprofiles / sessions(用户私有)
Tushare token✅ 持有❌ 已经移走(v0.2.0 P1.0 Task 12 干的事)
升级周期数据 schema / API contractLLM provider / skills
横向扩展未来可能多实例(多租户)永远 1:1 与用户

合并 = 抹掉 v0.2.0 整个一个月的解耦工作。永远保持分离

3.3 通信契约

  • Hermes → Twilight:HTTPS + Bearer token(已就绪)
  • API 表面:OpenAPI / FastAPI 自动文档
  • 所有跨进程数据:JSON 序列化,不存在共享内存 / 共享文件

3.4 升级独立性

Twilight 升级Hermes 升级
git push main → GHCR build → ssh tvps && docker compose pull && up -ddocker pull hermes:<tag> + provisioner 自动用新 image 启动新容器
不影响 Hermes(API contract 守住即可)不影响 Twilight

四、决策二:Build context 清理

4.1 现状问题

deploy/Dockerfile 是 multi-stage,运行时 image 只 COPY core/(wheel)+ src/docs / node_modules / dist 进不了 image。但 build context(docker build . 整个 tar 送给 daemon)没有 .dockerignore 兜底。

实测当前 build context 估算 200+ MB(node_modules 是大头,docs ~10 MB,.git ~50 MB),CI build 慢 + GHCR upload 慢。

4.2 解决方案

新增 .dockerignore(5 分钟独立 PR,跟仓库化 plan 解耦):

.git
.github
node_modules
dist
docs
*.md
!core/README.md
!src/README.md
.venv
.venv-*
__pycache__
*.pyc
.pytest_cache
.ruff_cache
*.egg-info
*.duckdb
*.sqlite
.DS_Store
.env
.env.*
!deploy/.env.example

预期 build context < 5 MB(只剩 core/ src/ deploy/ 和必要的 README)。


五、决策三:Provider 配置分层

之前 02 spec §4 已定 ABC + Registry + 显式注册。剩下"配置来源"这个 axis,决定如下:

配置类别放哪儿例子理由
Provider 类列表 / 启用与否代码 (lifespan 里 register)ProviderRegistry.register(TushareDailyProvider(...))安全敏感、加 provider 必然写 Python class,YAML 多列一份是冗余 friction
Tushare token / API keyenv var (.env)TUSHARE_TOKEN=xxxv0.2.0 现状,不动
DuckDB memory_limit / threadsenv var (default) + YAML (override)TWILIGHT_DUCKDB_MEMORY_LIMIT=512MBoperator 想试参数不该改代码
Backfill 自启 / 调度 cronenv varTWILIGHT_BACKFILL_AUTO_START=false紧急关停不该 rebuild image
数据质量阈值YAMLquality.daily_row_count_min: 4500频繁调,不属于"密码"也不属于"代码"

形态:

python
# src/service/config.py
class WarehouseSettings(BaseSettings):
    tushare_token: SecretStr
    duckdb_memory_limit: str = "512MB"
    duckdb_read_pool_size: int = 4
    duckdb_threads: int = 1
    backfill_auto_start: bool = False
    backfill_stage: int = 1
    config_yaml_path: Path | None = Path("/data/config/runtime.yaml")

    model_config = SettingsConfigDict(env_prefix="TWILIGHT_", env_file=".env")
yaml
# /data/config/runtime.yaml (挂载卷,不进 image)
quality:
  daily_row_count_min: 4500
  freshness_warning_hours: 36
  cross_source_diff_warning_pct: 1.0
  cross_source_diff_critical_pct: 5.0

ingest_schedule:
  daily_batch_cron: "30 18 * * *"
  event_scan_cron:  "0 9 * * *"
  trade_cal_check_cron: "30 17 * * *"

5.1 反对纯 YAML 驱动 provider list(再总结)

  1. Provider 实现是 first-party 安全敏感代码 —— code review 比 YAML review 严格
  2. 加新 provider 必然写 Python class —— YAML 多列一份是冗余 friction
  3. YAML config drift 是已知 bug 来源
  4. Hermes 用 plugin manifest 是因为支持第三方扩展 —— 我们没第三方扩展,这个间接层只是给自己挖坑

六、决策四:Hermes ToolSet 集成模式

6.1 当前状态(已盘点 2026-05-09)

本节早期版本基于错误假设,正确情况如下:

  • skill/stock-research/SKILL.md 已存在 + 完备(含 frontmatter / workflow / references / templates)
  • skill/stock-research/scripts/_client.py 已实现共享 client:
    • ServiceClient (HTTPS to backend) + DirectClient (fallback to core.data.*)
    • _resolve_secret() 从 env / macOS Keychain 获取 token
    • normalize_code() A 股代码后缀映射 (600/601/603/605/688 → SH; 000/001/002/003/300/301 → SZ; 8/4 → BJ)
    • emit() JSON 输出
    • get_client() 自动选择 mode
  • skill/stock-research/scripts/fetch_price.py / fetch_fundamentals.py / search_reports.py 都已经用 _client.py
  • Service mode 已经在 v0.2.0 P1.0 Task 12 上线(Hermes profile 走 HTTPS to api.fsagent.cc)
  • scripts/install-skill.sh 已存在(安装到 Hermes profile)

实际 gap:normalize_code() 是纯函数但缺独立 unit test 覆盖(其他都被 core/tests/integration/test_skill_scripts.py 6 个场景覆盖)。

6.2 目标 ToolSet 结构(已实现)

实际现有结构(不是新建 core/skill/,而是 skill/stock-research/):

skill/stock-research/
├── SKILL.md                  # ✅ Hermes-side 描述 + workflow + references
├── scripts/
│   ├── _client.py            # ✅ ServiceClient + DirectClient + Keychain fallback
│   ├── fetch_price.py        # ✅ 用 _client.get_client()
│   ├── fetch_fundamentals.py # ✅ 用 _client.get_client()
│   └── search_reports.py     # ✅ stub (P2 ingest)
├── references/               # ✅ tool-usage / session-context / price-freshness
└── templates/                # ✅ operation-strategy.md

未来扩展(W4-W6): screen_stocks.py / compare_indices.py / fetch_holders.py 等新工具加入 scripts/ 目录;_client.pyscreen() / get_index_daily() / freshness() / health() 方法(依赖 backend /warehouse/* /quality/* endpoints 在 W4-W6 上线)。

6.3 共享 client 的契约

python
# core/skill/twilight_client.py
class TwilightClient:
    """统一 HTTPS client,所有 tool script 共享。"""

    def __init__(
        self,
        base_url: str | None = None,           # default from TWILIGHT_SERVICE_URL
        token: str | None = None,              # default from TWILIGHT_API_TOKEN
        timeout: float = 10.0,
        retries: int = 2,                      # 网络错才 retry,4xx 不
    ): ...

    # 数据查询
    def get_price(self, code: str, *, trade_date: str | None = None) -> Quote: ...
    def get_fundamentals(self, code: str, *, period: str) -> Fundamentals: ...
    def screen(self, *, filters: dict, trade_date: str | None = None) -> list[Quote]: ...
    def get_index_daily(self, ts_code: str, *, start: str, end: str) -> list[Quote]: ...

    # 元数据
    def freshness(self) -> dict: ...
    def health(self) -> dict: ...

6.4 Tool script 契约(CLI ↔ JSON)

每个 tool script 是 thin CLI wrapper:

python
# fetch_price.py 的本质
def main():
    args = parse_args()                        # argparse
    client = TwilightClient()                  # env-driven
    try:
        quote = client.get_price(args.code, trade_date=args.trade_date)
        json.dump(asdict(quote), sys.stdout)   # stdout = tool result for Hermes
        sys.exit(0)
    except TwilightAPIError as e:
        json.dump({"error_kind": e.kind, "message": str(e)}, sys.stdout)
        sys.exit(2 if e.kind == "validation" else 1)

约定:

Exit codestdout意义
0正常 JSON成功
1{"error_kind": "transient", ...}网络 / 配额 / 5xx —— Hermes 可重试
2{"error_kind": "validation", ...}用户错(错的 ts_code 等)—— Hermes 不重试
3{"error_kind": "data_unavailable", ...}数据真的没有(如未来日期)—— Hermes 不重试

stderr: 调试信息,不要 emit JSON(避免 Hermes 误解析)。

6.5 SKILL.md 模板

每个 ToolSet 配一份 SKILL.md,Hermes 读取后注入到 LLM 的 system prompt:

markdown
# Twilight A-Share Data Toolset

提供 A 股投研所需的实时 / 历史 / 基本面数据。所有数据来自 Twilight 后端
(api.fsagent.cc),由内部 DuckDB 仓库 + Tushare 联合提供。

## Available tools

- `fetch_price.py --code <ts_code> [--trade-date YYYYMMDD]`
  返回 quote envelope(close_raw / close_qfq / close_hfq / freshness_seconds /
  source_chain)。trade_date 缺省 = 最新交易日。

- `fetch_fundamentals.py --code <ts_code> --period YYYYMMDD`
  返回该季度财务数据(三大表 + fina_indicator)。

- `screen_stocks.py --filters '<json>' [--trade-date YYYYMMDD]`
  按多条件筛选 A 股全市场。filters 例:`{"pe": "<20", "dv_ratio": ">3"}`

- ...

## Conventions

- 价格单位:元(4 位小数)
- 复权:默认 close_qfq;要原价用 close_raw;要后复权用 close_hfq
- 时区:trade_date 是上海日期;as_of 是 UTC ISO
- 错误:exit code 0 = 成功;1 = 重试;2 = 用户错;3 = 数据不存在

6.6 install-skill.sh 改造

现有脚本只 copy 单脚本;改造为 copy 整个 twilight_toolset/ 目录到 Hermes profile:

bash
# scripts/install-skill.sh (v2)
PROFILE_DIR="${HERMES_PROFILE_DIR:-$HOME/.hermes/profiles/stock-research-agent}"
TARGET="$PROFILE_DIR/skills/twilight"

mkdir -p "$TARGET"
cp -r core/skill/twilight_toolset/* "$TARGET/"
cp core/skill/twilight_client.py "$TARGET/"
chmod +x "$TARGET"/*.py

echo "Installed Twilight toolset to $TARGET"

七、按周实施计划

每周一个分支,周末 merge。每个 task 颗粒度 = 半天到一天能完成。

W0 — 准备(1-2 天,独立)

  • [ ] T0.1.dockerignore —— 单独 PR
    • 复制 §4.2 的内容到仓库根目录
    • CI 跑一次验证 build context 真的瘦了(看 CI log "Sending build context to Docker daemon" 行的 size)
    • 合并
  • [ ] T0.2 ssh tvps df -h 验证(已知:13 GB free,足够;记录到 01 §14 Q1 标 Resolved)
  • [ ] T0.3 建分支 feat/v0.3.0-warehouse-toolset,所有后续 W1-W6 在此分支或子分支推进

W1 — 仓库基础设施 + ToolSet 骨架(约 5 天)

仓库侧(核心交付:DataProvider 抽象 + trade_cal + 连接管理)

  • [x] T1.1 core/data/providers/base.py —— ABC / Capability / MarketState / Quote / FreshnessReport / HealthStatus / 5 种 typed exception 【PR #24】
  • [x] T1.2 core/data/providers/__init__.py —— ProviderRegistry 【PR #24】
  • [x] T1.3 scripts/seed_trade_cal.py —— 从 Tushare 拉 today-30d ~ today+365d,写入 ~/twilight/data/warehouse.duckdbnormalized_trade_cal 表 【PR #25】
  • [x] T1.4 core/data/providers/_market_state.py —— MarketStateResolver 【PR #25】
  • [x] T1.5 src/service/db.py —— WarehousePool (read 池) + WarehouseWriter(写单例),含 DuckDB memory_limit / threads 配置 【PR #26】
  • [x] T1.6 单元测试:Quote dataclass / Capability 校验 / MarketStateResolver 边界(9:29:59 / 11:30:00 / 15:00:00 / 15:04:59 / 15:05:00 / 周末 / 春节)【PR #24 + #25 + #26 共 71 tests】

ToolSet 侧(核心交付:共享 client 库)—— 已存在于 v0.2.0 P1.0

  • [x] T1.7 Shared client —— skill/stock-research/scripts/_client.py 已实现(ServiceClient HTTPS + DirectClient core.data fallback + _resolve_secret Keychain + normalize_code A 股代码后缀映射 + emit JSON 输出),见 §6.1
  • [x] T1.8 skill/stock-research/SKILL.md 已存在(Hermes-style frontmatter + workflow + references + templates)
  • [x] T1.9 fetch_price.py / fetch_fundamentals.py / search_reports.py 已经用 _client.get_client()
  • [x] T1.10 Client 测试 —— core/tests/integration/test_skill_scripts.py 6 场景(direct mode Tushare via respx / akshare routing / fundamentals / search_reports stub / no-token error / service mode urlopen mock);本 PR 加 normalize_code unit test 补完最后一个 gap

End of W1:本地 pytest 全绿(生产未动;切流 / lifespan 注入 / 部署都在 W2+)。

W2 — Provider 包装 + Composer 上线(约 5 天)

  • [ ] T2.1 core/data/providers/tushare_daily.py —— 包装现有 core/data/tushare.py,加 adj_factor 调用、单位严格校验、CanonicalUnitViolation
  • [ ] T2.2 core/data/providers/akshare_spot.py —— 包装现有 core/data/akshare.py,单位严格转换(成交额 元 → 千元;volume 股 → 手)
  • [ ] T2.3 core/data/composer.py —— QuoteComposer + ROUTES 表(02 spec §6.1)
  • [ ] T2.4 core/data/quote_cache.py —— DuckDB-backed cache,市场感知 TTL(02 spec §7)
  • [ ] T2.5 Provider conformance 测试套(每个 provider 跑同一组用例)
  • [ ] T2.6 Regression 测试:5 起 v0.2.0 真实事故的 case 全部 pass(02 spec §1)
  • [ ] T2.7 src/service/main.py lifespan 注入 ProviderRegistry / Composer
  • [ ] T2.8 部署到 tvps(仅 Composer,不改 /price 路由),监控 1 天 audit log 看路由是否符合预期

End of W2:Composer 已在 tvps 跑,但 /price 还没切流;老 cache 还在用。

W3 — T1 落仓 + Stage 1 回填(约 5 天)

  • [ ] T3.1 src/service/ingest/scheduler.py —— APScheduler 接入

  • [ ] T3.2 src/service/ingest/jobs/daily_batch.py —— daily / daily_basic / adj_factor 三个 ingest 任务

  • [ ] T3.3 src/service/routes/admin.py —— /admin/ingest/backfill/{start,status,resume,cancel} 四个 endpoint,要 internal plan bearer

  • [ ] T3.4 backfill_progress 表 + 幂等保证

  • [ ] T3.5 scripts/backfill_tushare_t1.py 一次性脚本(CLI + admin endpoint 双入口)

  • [ ] T3.6 部署到 tvps,触发 Stage 1 backfill:

    bash
    curl -X POST https://api.fsagent.cc/admin/ingest/backfill/start?stage=1 \
         -H "Authorization: Bearer $TOKEN"
    watch curl https://api.fsagent.cc/admin/ingest/backfill/status \
         -H "Authorization: Bearer $TOKEN"

    预期 ~15 分钟,~510 MB 落盘。

  • [ ] T3.7 物理排序优化(01 §6.5.1)

  • [ ] T3.8 /warehouse/daily endpoint 上线 + 单元测试

  • [ ] T3.9 在 Hermes profile 里手动 smoke test:fetch_price.py 600519 --trade-date 20260301,验证拿到的是 warehouse provider 的 quote

End of W3:T1 数据齐全,warehouse endpoint 可用,/price 仍未切流。

W4 — /price 切流 + T2 落仓 + ToolSet 扩张(约 7 天)

切流(breaking change)

  • [ ] T4.1 src/service/routes/price.py —— 改用 Composer,响应 schema 升级到 02 spec §9.2
  • [ ] T4.2 core/skill/twilight_toolset/fetch_price.py —— 解析新 schema,默认输出 close_qfq
  • [ ] T4.3 core/core/data/schemas.pyget_price 标 deprecated,内部转调 Composer
  • [ ] T4.4 scripts/install-skill.sh v2 —— 同步把整个 twilight_toolset/ 装到 Hermes profile
  • [ ] T4.5 Hermes profile 跑一次 install-skill.sh,重启 profile
  • [ ] T4.6 在 Hermes 里手动 smoke test 5 个 case:当日 open / close 期 / 历史日 / 错的 ts_code / 退市股

T2 落仓

  • [ ] T4.7 stk_limit / moneyflow / margin / index_daily / index_dailybasic / disclosure_date 接入 ingest
  • [ ] T4.8 T2 两年回填(~10 分钟)
  • [ ] T4.9 core/skill/twilight_toolset/screen_stocks.py —— cross-section 查询 tool(用 daily_basic 的 PE/PB/dv_ratio 过滤)
  • [ ] T4.10 core/skill/twilight_toolset/compare_indices.py —— 多指数对比 tool

End of W4:/price 已切到新 schema,老 cache 仍并行;ToolSet 有 4 个工具。

W5 — T3 财报 + 季报 ToolSet(约 7 天)

  • [ ] T5.1 income / balancesheet / cashflow / fina_indicator / forecast / express 接入 ingest
  • [ ] T5.2 季报窗口调度(4-5 月 / 8-9 月 / 10-11 月 / 次年 4-5 月每日 02:00 跑)
  • [ ] T5.3 T3 两年回填(~7 小时,过夜跑screen 起 backfill,第二天检查)
  • [ ] T5.4 core/skill/twilight_toolset/fetch_fundamentals.py —— 替换现有版本,输出三大表 + fina_indicator 全字段
  • [ ] T5.5 /warehouse/fundamentals endpoint 上线
  • [ ] T5.6 /fundamentals 路由切换到 Composer

End of W5:财报数据可查;ToolSet 5 个工具。

W6 — T4 + 可观测性 + WarehouseProvider 接入 + 老 cache 下线(约 5 天)

  • [ ] T6.1 T4 事件类落仓(dividend / top10_holders / share_float / repurchase / stk_holdertrade)
  • [ ] T6.2 core/data/providers/warehouse.py —— WarehouseProvider 实现,接入 ProviderRegistry
  • [ ] T6.3 Composer ROUTES 验证 WarehouseProvider 优先级正确(02 spec §6.1)
  • [ ] T6.4 provider_audit_log / provider_freshness / provider_diff_log 三张表 + 监测代码
  • [ ] T6.5 /quality/freshness / /quality/audit / /quality/diff 三个 endpoint
  • [ ] T6.6daily_cache / fundamentals_cache 数据 backfill 进 quote_cache,老表保留只读
  • [ ] T6.7 一周稳定运行后下掉老 cache 表(独立 PR)
  • [ ] T6.8 core/core/data/_market.py 删(被 MarketStateResolver 替代)
  • [ ] T6.9 core/skill/twilight_toolset/fetch_holders.py 等剩余 tool 上线
  • [ ] T6.10 Hermes profile 全量 smoke test:所有 ToolSet 工具 + 真实用户问题(5 起事故的 regression)

End of W6:v0.3.0 仓库化全部上线;老 cache 表下线;ToolSet 完整。

W7+ — 扩展(独立 spec,不阻塞 v0.3.0 收尾)

  • TDX 跨源验证(spec 待写,独立 W7+)
  • Stage 2 深度回填(再补 3 年;触发条件见 01 §8.5)
  • Hermes Docker image 构建流程完善(GHCR + multi-arch)
  • Phase 2 §B Profile manager / 多主机调度

八、Risks 清单

#Risk概率影响缓解
1tvps RAM 紧(951 MB 物理)DuckDB OOM 或大量 swap显式 memory_limit=512MB + threads=1 + 监控 swap
2Backfill 中断(网络 / 重启)重头来backfill_progress 表幂等,/admin/ingest/backfill/resume 续跑
3/price breaking changefetch_price 调用方崩W4 fetch_price.py 同步发,Hermes profile 一次 reinstall 一切搞定
4Tool 数量增长后重复代码维护成本W1 就建 twilight_client.py 共享库,强制每个新 tool 走 client
5trade_cal 接口不稳(120 文档说要 2000)调度判定挂已探针证实可调;如失效,硬编码节假日表兜底(W7+)
6T3 季报 backfill 7h 超时中断进度持久化 + 4 worker 并发 + screen 后台跑
7DuckDB schema 演进破坏normalized 表数据丢Raw 层永远在,必要时回放
8Hermes 那边 fetch_price.py 被人手改过install-skill.sh 覆盖时丢改动安装前 diff 检查;profile 改动应该提交回 twilight-drive

九、显式不做(Out of Scope)

  • ❌ Hermes 本身的功能 / 改造
  • ❌ Phase 2 §C 的 New-API + SearXNG token gateway
  • ❌ Phase 2 §B 的 profile manager / 多主机调度
  • ❌ Postgres 迁移(DuckDB 单文件 v0.3.0 够用)
  • ❌ Mac Mini PRIMARY → Vultr REPLICA(仍按单机 tvps 方案;Phase 2 后置)
  • ❌ 实时 / 分钟数据(独立付费权限)
  • ❌ 港股 / 美股 / ETF / 期货
  • ❌ TDX (通达信) 跨源验证(W7+ 独立 spec)

十、文档同步

实施完成后:

文档操作
docs/planning/01-data-layer.mdStatus: 🟢 → ✅ implemented;保留作为参考
docs/planning/superpowers/specs/2026-05-08-tushare-integration-design.mdStatus: Draft → Implemented
本 planStatus: Draft → Completed;checkbox 全勾
docs/architecture/adr/0003-warehouse-and-toolset.md新增:摘要本 plan 的 4 个架构决策
docs/status/index.mdv0.3.0 上线段更新
docs/planning/superpowers/specs/2026-05-07-twilight-drive-phase2.md§A "data warehouse" 标 superseded(已经在 01 里写过)

十一、开放问题

  1. scripts/install-skill.sh v2 的运行频率。 Hermes profile 的 skills 改了之后必须重 install 才生效。要不要做 watcher / file sync 自动同步?还是手动每次 reinstall?倾向手动 + 在 SKILL.md 里写明。
  2. WarehouseSettings 的配置 reload。 YAML 改了要不要 hot reload?还是必须重启容器?倾向重启(简单可靠)。
  3. Tool script 的 stderr 日志。 Hermes 是不是会捕获 stderr?需要查 Hermes 文档;如果是,stderr 不能太啰嗦。
  4. TwilightClient 的 retry 策略。 网络错重试几次?exponential backoff?直接固定 2 次间隔 1s 简单点。倾向固定 2 次。
  5. ToolSet 的版本管理。 SKILL.md 要不要带 version?install 时检查兼容性?倾向 W1 不做,W6 收尾时再考虑。
  6. 是否要给 Hermes 起一个独立的 GHCR repo? 还是先继续在 Hermes upstream 跟着走?取决于用户对 Hermes 上游的依赖程度,目前不急。
  7. screen_stocks.py 的 filter 语法。 自定义 mini-DSL({"pe": "<20"})还是直接接 SQL fragment(pe < 20)?前者安全,后者灵活。倾向前者 + 转 SQL。

十二、第一步:开始 W0

今天 / 明天就能干的事:

  1. .dockerignore PR —— 5 分钟,独立,不影响任何 plan
  2. 建分支 feat/v0.3.0-warehouse-toolset from main
  3. 创建 W1 task tracker(GitHub project / TodoWrite / 此 plan 的 checkbox 任选其一)

要不要我现在直接开 .dockerignore 这个 PR 把 W0 跑起来?

团队内部文档