主题
部署形态 + 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 个架构决策
- Twilight 与 Hermes 是两个独立 Docker image(不能合并打包)
- Build context 清理通过
.dockerignore,docs / node_modules / .git 不进 build - Provider 配置三层划分:模块化代码 + env vars (
.env) + 可选 YAML override;provider 列表不进 YAML - 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
| service | image | host | 资源 | 卷挂载 |
|---|---|---|---|---|
twilight-backend | ghcr.io/lacatfly/twilight-drive:latest | tvps | 0.75 vCPU / 1500 MB | ~/twilight/data → /data、~/twilight/logs → /var/log/... |
twilight-cloudflared | cloudflare/cloudflared:latest | tvps | 0.1 vCPU / 64 MB | ~/.cloudflared → /etc/cloudflared |
twilight-provisioner | ghcr.io/lacatfly/twilight-drive:latest (同 image, 不同 entrypoint) | tvps | 0.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 backend | Hermes | |
|---|---|---|
| 角色 | 数据后端 / 多客户端 / 长寿命 | Agent runtime / 单用户 / 进程级 |
| 状态 | DuckDB 仓库(GB 级) + bearer DB | profiles / sessions(用户私有) |
| Tushare token | ✅ 持有 | ❌ 已经移走(v0.2.0 P1.0 Task 12 干的事) |
| 升级周期 | 数据 schema / API contract | LLM 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 -d | docker 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 key | env var (.env) | TUSHARE_TOKEN=xxx | v0.2.0 现状,不动 |
| DuckDB memory_limit / threads | env var (default) + YAML (override) | TWILIGHT_DUCKDB_MEMORY_LIMIT=512MB | operator 想试参数不该改代码 |
| Backfill 自启 / 调度 cron | env var | TWILIGHT_BACKFILL_AUTO_START=false | 紧急关停不该 rebuild image |
| 数据质量阈值 | YAML | quality.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(再总结)
- Provider 实现是 first-party 安全敏感代码 —— code review 比 YAML review 严格
- 加新 provider 必然写 Python class —— YAML 多列一份是冗余 friction
- YAML config drift 是已知 bug 来源
- 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 tocore.data.*)_resolve_secret()从 env / macOS Keychain 获取 tokennormalize_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.py 加 screen() / 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 code | stdout | 意义 |
|---|---|---|
| 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.duckdb的normalized_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已实现(ServiceClientHTTPS +DirectClientcore.data fallback +_resolve_secretKeychain +normalize_codeA 股代码后缀映射 +emitJSON 输出),见 §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.py6 场景(direct mode Tushare via respx / akshare routing / fundamentals / search_reports stub / no-token error / service mode urlopen mock);本 PR 加normalize_codeunit 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.pylifespan 注入 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:
bashcurl -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/dailyendpoint 上线 + 单元测试[ ] 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.py的get_price标 deprecated,内部转调 Composer - [ ] T4.4
scripts/install-skill.shv2 —— 同步把整个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/fundamentalsendpoint 上线 - [ ] 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.6 老
daily_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 | 概率 | 影响 | 缓解 |
|---|---|---|---|---|
| 1 | tvps RAM 紧(951 MB 物理) | 高 | DuckDB OOM 或大量 swap | 显式 memory_limit=512MB + threads=1 + 监控 swap |
| 2 | Backfill 中断(网络 / 重启) | 中 | 重头来 | backfill_progress 表幂等,/admin/ingest/backfill/resume 续跑 |
| 3 | /price breaking change | 中 | fetch_price 调用方崩 | W4 fetch_price.py 同步发,Hermes profile 一次 reinstall 一切搞定 |
| 4 | Tool 数量增长后重复代码 | 中 | 维护成本 | W1 就建 twilight_client.py 共享库,强制每个新 tool 走 client |
| 5 | trade_cal 接口不稳(120 文档说要 2000) | 低 | 调度判定挂 | 已探针证实可调;如失效,硬编码节假日表兜底(W7+) |
| 6 | T3 季报 backfill 7h 超时 | 中 | 中断 | 进度持久化 + 4 worker 并发 + screen 后台跑 |
| 7 | DuckDB schema 演进破坏 | 低 | normalized 表数据丢 | Raw 层永远在,必要时回放 |
| 8 | Hermes 那边 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.md | Status: 🟢 → ✅ implemented;保留作为参考 |
docs/planning/superpowers/specs/2026-05-08-tushare-integration-design.md | Status: Draft → Implemented |
| 本 plan | Status: Draft → Completed;checkbox 全勾 |
docs/architecture/adr/0003-warehouse-and-toolset.md | 新增:摘要本 plan 的 4 个架构决策 |
docs/status/index.md | v0.3.0 上线段更新 |
docs/planning/superpowers/specs/2026-05-07-twilight-drive-phase2.md | §A "data warehouse" 标 superseded(已经在 01 里写过) |
十一、开放问题
scripts/install-skill.shv2 的运行频率。 Hermes profile 的 skills 改了之后必须重 install 才生效。要不要做 watcher / file sync 自动同步?还是手动每次 reinstall?倾向手动 + 在 SKILL.md 里写明。- WarehouseSettings 的配置 reload。 YAML 改了要不要 hot reload?还是必须重启容器?倾向重启(简单可靠)。
- Tool script 的 stderr 日志。 Hermes 是不是会捕获 stderr?需要查 Hermes 文档;如果是,stderr 不能太啰嗦。
- TwilightClient 的 retry 策略。 网络错重试几次?exponential backoff?直接固定 2 次间隔 1s 简单点。倾向固定 2 次。
- ToolSet 的版本管理。 SKILL.md 要不要带 version?install 时检查兼容性?倾向 W1 不做,W6 收尾时再考虑。
- 是否要给 Hermes 起一个独立的 GHCR repo? 还是先继续在 Hermes upstream 跟着走?取决于用户对 Hermes 上游的依赖程度,目前不急。
- screen_stocks.py 的 filter 语法。 自定义 mini-DSL(
{"pe": "<20"})还是直接接 SQL fragment(pe < 20)?前者安全,后者灵活。倾向前者 + 转 SQL。
十二、第一步:开始 W0
今天 / 明天就能干的事:
.dockerignorePR —— 5 分钟,独立,不影响任何 plan- 建分支
feat/v0.3.0-warehouse-toolsetfrom main - 创建 W1 task tracker(GitHub project / TodoWrite / 此 plan 的 checkbox 任选其一)
要不要我现在直接开 .dockerignore 这个 PR 把 W0 跑起来?