-
Notifications
You must be signed in to change notification settings - Fork 110
Expand file tree
/
Copy pathconfig.example.yaml
More file actions
755 lines (731 loc) · 34 KB
/
Copy pathconfig.example.yaml
File metadata and controls
755 lines (731 loc) · 34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
# Hone configuration example
#
# Usage:
# 1) Copy this file to config.yaml
# 2) Fill in or adjust the values as needed. Most provider tokens are config-owned;
# public SMS/Captcha and selected operational secrets use runtime env as noted below.
# UI / CLI display language: zh or en
language: zh
# Process runtime timezone (IANA name). This is the single default for cron,
# date keys, report schedules, and user-visible local timestamps. In production
# containers, set it explicitly because host detection commonly resolves to UTC.
timezone: "Asia/Shanghai"
# iMessage config
imessage:
enabled: false
# Leave empty to listen to all users; otherwise only the specified user is tracked
target_handle: ""
db_path: "~/Library/Messages/chat.db"
poll_interval: 2 # polling interval in seconds
# Local HTTP listener used by iMessage-side scheduled task callbacks
listen_addr: "127.0.0.1:8078"
# Feishu channel config (Rust business process + Go official SDK facade)
feishu:
enabled: false
# Feishu credentials are read from config.yaml
app_id: ""
app_secret: ""
# Internal allowlist of email addresses; empty means allow all; supports "*"
allow_emails: []
# Internal allowlist of mobile numbers; accepts "+8613800138000" or "13800138000"
allow_mobiles: []
# Fallback allowlist: when the contact API cannot provide an email or mobile number, allow the open_id directly
allow_open_ids: []
# Chat scope:
# - DM_ONLY: only process direct messages
# - GROUPCHAT_ONLY: only process group chats
# - ALL: process both
# Legacy dm_only is still accepted for backward compatibility.
chat_scope: DM_ONLY
# Maximum length of a single message; longer messages are split on the Rust side
max_message_length: 3500
# Local JSON-RPC address from Rust to the Go facade
facade_url: "http://127.0.0.1:18115/rpc"
# Listener address for callback events from the Go facade to Rust
callback_addr: "127.0.0.1:18116"
# The Go facade's own listener address; used for local health checks
facade_addr: "127.0.0.1:18115"
# Timeout, in seconds, for waiting on the facade long connection at startup
startup_timeout_seconds: 20
# Telegram Bot config
telegram:
enabled: false
# Telegram Bot token
bot_token: "REPLACE_ME"
# Allowed user ID list; empty means allow all; supports "*"
allow_from: []
# Chat scope:
# - DM_ONLY: only process direct messages
# - GROUPCHAT_ONLY: only process group chats
# - ALL: process both
# Legacy dm_only is still accepted for backward compatibility.
chat_scope: DM_ONLY
# Maximum length of a single message (Telegram sendMessage limit is about 4096)
max_message_length: 3500
# Discord Bot config
discord:
enabled: false
# Discord Bot token
bot_token: ""
# Allowed user ID list; empty means allow all; supports "*"
allow_from: []
# Chat scope:
# - DM_ONLY: only process direct messages
# - GROUPCHAT_ONLY: only process group chats
# - ALL: process both
# Legacy dm_only is still accepted for backward compatibility.
chat_scope: DM_ONLY
# Maximum length of a single message (Discord limit is 2000)
max_message_length: 1800
group_reply:
# Whether explicit-trigger group replies are enabled
enabled: true
watch:
enabled: false
# Channel IDs to watch; can also be specified on the command line with --channel-id (higher priority)
channel_ids: []
# Run mode: true = long-running loop; false = one-shot run (suitable for cron)
loop: true
# Whether to print verbose logs (also prints on ticks with no new messages)
verbose: false
# Group-chat shared session / context compression policy
group_context:
# Whether group-context governance is enabled
enabled: true
# Whether each group shares one session
shared_session_enabled: true
# Whether untriggered group text should be buffered for the next explicit trigger
pretrigger_window_enabled: true
# Maximum buffered group messages to carry into the next explicit trigger
pretrigger_window_max_messages: 10
# Only keep buffered group messages from the latest N seconds
pretrigger_window_max_age_seconds: 300
# Number of recent valid messages to restore for a shared group session
recent_context_limit: 18
# Trigger compression after the shared session exceeds this number of messages
compress_threshold_messages: 24
# Trigger compression after the shared session exceeds this many bytes
compress_threshold_bytes: 49152
# Keep the latest N messages after compression
retain_recent_after_compress: 8
# Nano Banana image generation config
nano_banana:
enabled: true
# Single implementation: use the OpenRouter image generation API (modalities=["image","text"])
base_url: "https://openrouter.ai/api/v1"
model: "google/gemini-2.0-flash-exp"
default_image_count: 3
# API key prefers the llm.providers.openrouter.api_key/api_keys pool; legacy single-key
# OpenRouter fields remain readable during migration.
# Request timeout, max_tokens, temperature, HTTP referrer, and title currently use fixed client defaults.
download_dir: "gen_images"
# Financial Modeling Prep API config
# Outbound transactional email for push subscriptions (Cloudflare Email Sending).
# Leave api_token empty and export HONE_CLOUDFLARE_EMAIL_API_TOKEN instead — a credential
# that can send mail from a verified domain must never live in the repository.
# With no token resolved the feature is simply off: pushes still deliver, they
# just do not also arrive by mail.
email:
account_id: "52dfc1420d779b403c08196b792ce926"
from_address: "no-reply@hone-claw.com"
from_name: "HONE"
api_token: ""
api_token_env: "HONE_CLOUDFLARE_EMAIL_API_TOKEN"
api_base: "https://api.cloudflare.com/client/v4"
timeout: 20
# Hone's own ceiling, below Cloudflare's daily quota, so a scheduler fault
# cannot burn the whole allowance in one morning.
daily_limit: 150
# Signs the login-free unsubscribe links carried by every delivered push.
# Environment-only. Empty means no link is emitted rather than a broken one.
unsubscribe_secret_env: "HONE_UNSUBSCRIBE_SECRET"
fmp:
# Legacy single-key fallback; prefer api_keys for new configs
api_key: ""
# Financial Modeling Prep API key pool with failover support
api_keys: []
base_url: "https://financialmodelingprep.com/api"
timeout: 60
# Proactive event engine: polls FMP for market events, deduplicates, and
# dispatches to subscribers (per-holding or global). High-severity events push
# immediately; Medium/Low roll up into pre/post-market digests.
event_engine:
# Master switch. Default off — enable only when you want proactive pushes.
enabled: false
# poll_intervals 覆盖 news / price,以及需要分钟级发现的 earnings_surprise。
# earnings calendar / corp_action / macro / analyst_grade / sec_filings 走 cron-aligned ——
# 在 digest.default_slots 各 slot 前 `prefetch_offset_mins` 分钟跑一次,
# 保证 flush 推送的数据永远是刚拉的,不受用户重启时机漂移。
# earnings_surprise 只在美股常见盘前/盘后财报发布窗口访问网络,窗口外 no-op;
# 冷启动时每个 poller 立即跑一次。
poll_intervals:
# 新闻。最小推荐 300 (5m),典型 600-1800 (10-30m),最大 3600 (1h)。
# 低于 300 时 FMP 返回不会更新,只是多烧配额。
news_secs: 1800 # 30 min
# 盘中价格异动。最小推荐 60 (1m),典型 180-600 (3-10m),最大 900 (15m)。
# 降到 60 时 N 只持仓 × 每分钟一次 quote,会显著吃 FMP 配额;
# 非交易时段 poller 会自动 skip,不必担心夜里空烧。
price_secs: 900 # 15 min
# 正式财报实际值。仅 ET 工作日 04:00-10:00、16:00-23:00 请求;默认 10m,
# 配置下限 60s。成功质量判断后同一季度不会重复调用 SEC/LLM。
earnings_surprise_secs: 600
digest:
# 管理员视角默认槽位时刻 —— 在 actor 没有自定义 prefs.digest_slots 时,
# UnifiedDigestScheduler 用这组时刻作为默认 slot 触发推送。每个 slot 可配
# `time`(本地 HH:MM)和可选 `label`(渲染 header 用)。
# Defaults target CN users: 08:30 卷起夜里队列成早间摘要;09:00 把美股盘后
# 隔夜汇总延后到醒来后,避免半夜打扰。
default_slots:
- {time: "08:30", label: "盘前摘要"}
- {time: "09:00", label: "晨间摘要"}
# Max items rendered per digest flush. Events beyond this (sorted by severity
# desc, occurred_at desc) are dropped with a "…… 另 N 条已省略" footer so a
# Low-severity storm can't bury the user. 0 disables the cap.
max_items_per_batch: 20
# cron-aligned poller 在每个 default slot 时刻前多少分钟执行拉取。
# 日频来源不再按固定 24h interval 轮询,而是在 default_slots 各 slot 前 offset 跑一次,
# 保证推送数据永远是 flush 前刚拉的。
# 默认 30:数值越小数据越新,但留给 EventStore/Router 的缓冲越紧;低于 5 不推荐。
prefetch_offset_mins: 30
# 同一用户两次 digest 的最小间隔。用户配置多个窗口时,避免 09:00/12:00/16:00
# 反复消费同一批主题;0 表示不限制。
min_gap_minutes: 180
thresholds:
# |pct| < low → no event; low ≤ |pct| < high → Low (digest); |pct| ≥ high → High (immediate push)
# Production defaults tuned for US equities: 10% rarely triggers, 5% misses many real moves.
price_alert_low_pct: 2.5
price_alert_high_pct: 6.0
volume_sigma: 2.0
high_severity_daily_cap: 8
# Minimum minutes between two High sink pushes for the *same* ticker.
# Protects against one stock firing price + news + filing in quick succession.
# Later Highs within the window get demoted to digest (status="cooled_down").
# 0 disables the cooldown.
same_symbol_cooldown_minutes: 60
# Low→Medium news convergence caps. Per-symbol prevents one ticker from
# dominating; per-tick prevents broad multi-ticker bursts crowding digest.
news_upgrade_per_symbol_per_tick: 3
news_upgrade_per_tick: 12
# 用户 per-actor price_high_pct_override 低于该值时,只会让价格异动进 digest;
# 即时推送仍要求达到该系统最小阈值,除非 payload 标明高仓位。
price_min_direct_pct: 6.0
# 价格异动跨档再提醒步长。high=6, step=2 时,盘中跨 +6/+8/+10
# 或 -6/-8/-10 会形成独立事件;未跨新档只更新摘要最新态。
price_realert_step_pct: 2.0
# 价格 band 单一推送规则(v0.5.2 起替代旧 cap+gap 双保险):新档 pct 必须比
# 当日已 sink-sent 的最大档高出本字段值,否则降级 digest。0 = 关闭(无脑全推)。
# 默认 2.0 与 price_realert_step_pct 一致,意为「每跨一个新 band 必推」 ——
# 避免大行情长尾失声(POC 实证 AAOI 6→16 序列 cap=2 仅 6/8,advance=2 全 6 档)。
price_band_min_advance_pct: 2.0
# 收盘 price_close 默认只进摘要,避免美股收盘在北京时间凌晨即时打扰。
price_close_direct_enabled: false
large_position_weight_pct: 20.0
# High macro 只有临近发生窗口才即时推;未来 7 天日历保留为摘要/预告。
macro_immediate_lookahead_hours: 6
macro_immediate_grace_hours: 2
renderer:
# Severity list that goes through LLM polish. Empty list = pure template.
# polish_llm names an llm.profiles entry; empty falls back to legacy llm.openrouter.sub_model/model.
llm_polish_for: []
polish_llm: aux
template_dir: "./data/event_templates"
# 财报 poller 参数。
# - window_days:EarningsPoller 每 tick 向 FMP earning_calendar 拉 [today, today+N]。
# 这决定 Hone 从多早开始"关注"一家公司的财报 —— 默认 14 天:启动时你会一次看到
# 未来 14 天内所有持仓的财报预告(Medium 级,进 digest)。
# **v0.1.46 起**,poller 只产出稳定 id 的 `earnings:{SYM}:{DATE}` teaser 事件
# (Medium 入 digest);T-3/T-2/T-1 倒计时由 UnifiedDigestScheduler 在每个 slot
# 触发时从 EventStore 现算 —— 这样 poller cron 漂移不会让倒计时 off-by-one,
# T-1 也由早 8:30 的 pre-market 窗口天然覆盖,不再单独升 High。整条 lifecycle
# 共享 `earnings_upcoming` kind,把它加进 `blocked_kinds` 即全程静音。
# 典型取值:7(仅本周)、14(两周,默认)、21(三周,但信号老化)。小于 3 会让 T-3
# 倒计时失效(因为 poller 看不到 T-3 的财报)。
# quality_review: EarningsSurprisePoller 原始数据只有 EPS actual vs estimate。
# 对亏损公司或 EPS 接近 0 的公司,百分比 surprise 会非常误导。开启后,若近期
# SEC 8-K 财报新闻稿可抓取且 OpenRouter 可用,会用 LLM 综合收入、指引、backlog、
# GAAP/non-GAAP 利润、EBIT/EBITA/EBITDA、现金流与风险来判断 immediate / digest。
# 失败、缺少上下文或低置信时直接跳过 candidate,不再产出 EPS-only 推送。
earnings:
window_days: 14
quality_review:
enabled: true
llm: earnings_quality
model: x-ai/grok-4.5
max_review_tokens: 1800
min_review_confidence: 0.65
min_immediate_confidence: 0.9
sec_recent_hours: 72
context_max_chars: 9000
# A-tier 公司在财报投递后异步执行,不阻塞 T0。它逐项核对画像里的未决问题
# 与管理层承诺,因此必须使用独立于短财报卡的 completion budget。
continuity_review:
enabled: true
llm: earnings_continuity
model: x-ai/grok-4.5
max_review_tokens: 3600
# SEC filings poller 配置。
# forms: 每 tick 对每只 watchlist ticker 拉哪些 form 类型。FMP 的 /v3/sec_filings
# 必须按 type 过滤,不支持一次取多 type;每个 form 一次 HTTP。
# Severity 由 form 决定(代码硬映射,不在 config 里):
# 8-K / S-1 → High(突发披露 / 增发,稀释信号)
# 10-Q / 10-K → Medium(季报 / 年报)
# DEF 14A → Low(委托书 / 治理薪酬)
# 想关掉某 form 直接从这里删掉它,不需要改代码。空数组等于关闭整个 poller。
# enrichment: 是否给 SEC filing 调 LLM 生成 ~200 字业务摘要(长期主线投资者
# 视角:跳过 GAAP 数字,抓 backlog / 资本配置 / 风险因子新增)。
# 当前默认使用 x-ai/grok-4.3 替代已下线的 Grok 4.1 Fast;
# 实际质量、延迟和成本以 OpenRouter 当前模型为准。
# 失败 fallback 走原始 form/link body,不阻塞推送。
sec_filings:
forms:
- 8-K
- 10-Q
- 10-K
- S-1
- DEF 14A
enrichment:
enabled: true
llm: filing_summary
model: x-ai/grok-4.3
max_summary_tokens: 800
# SEC EDGAR 强制要求 User-Agent 包含联系邮箱,否则会被限流或拒绝。
# 部署方应改成自己的真实联系邮箱(SEC 不强制可达,但需有公司 / 产品名 + 邮箱)。
user_agent: "honeclaw event-engine ops@honeclaw.local"
# 全局 digest LLM 子配置 —— UnifiedDigestScheduler 在每个 slot 触发时把这一节
# 作为 global news path 的采集 / dedup / LLM 旋钮使用。
# 触发完全由 per-actor `prefs.digest_slots` 驱动,这里不再有调度时刻。
# 候选池流水:
# - 候选池 = RSS news + FMP trusted news(允许 Low 进入预选);collector 再过滤
# legal_ad / transcript / 已广播事件。Macro floor 不从这里采集,由 personalize 分类产生。
# - Pass 1 (pass1_llm/pass1_model) 批量打分 + cluster + 一句话 takeaway
# - Pass 2 (pass2_llm/pass2_model) 抓原文(若 fetch_full_text=true) + 精读 + 短评 + 排序
# 输出经 unified scheduler per-actor fan-out,与 buffer/synth 候选合流后渲染。
# 默认 enabled=false。`enabled=false` 时 unified scheduler 不装配 global curator,
# global news section 跳过;pipeline 仍按 buffer/synth 候选推送 actor。
global_digest:
enabled: false
lookback_hours: 24 # 候选池回看窗口
# *_llm fields name llm.profiles entries; matching *_model fields are legacy OpenRouter fallbacks.
pass1_llm: digest_fast
pass1_model: x-ai/grok-4.3
pass2_llm: digest_strong
pass2_model: x-ai/grok-4.3 # 替代已下线的 Grok 4.1 Fast;实际价格 / context / reasoning 能力以 OpenRouter 当前模型为准
pass2_top_n: 15 # Pass 1 排序后送 Pass 2 精读的候选数上限
final_pick_n: 8 # 单次推送最终保留的条数上限
fetch_full_text: false # Pass 2 是否 GET 原文 → html2text;失败 fallback FMP text
# Jina Reader API key,用于 Pass 2 抓不到原文时(reuters / wsj / barrons / nyt 等
# 付费墙站点)走 r.jina.ai 二次抓取。免费层 1M tokens/月,jina.ai 注册即得。
# 留空则跳过 Jina fallback,直接落到 FMP text。
jina_api_key: ""
# 事件级去重(POC 验证 2026-04-26):collector 之后 / Pass1 之前,用强 LLM
# 把同事件多源报道合并成 1 条代表,避免 picks 被 5 条 Hormuz 这种重复挤满。
# 必须用强模型,nova-lite 这种会过度归类成 theme(把不同事件合到大筐里)。
event_dedupe_enabled: true
event_dedupe_llm: digest_strong
mainline_distill_llm: mainline_short
event_dedupe_model: x-ai/grok-4.3
# Per-source 开关。每个字段对应 hone-event-engine 内一个 EventSource,
# 设成 false 即不 spawn 该 source(最省 FMP 配额)。
# 想要"poller 仍跑、只是 router 丢弃某 kind"的兜底关法,改用下方 disabled_kinds。
sources:
news: true # /v3/stock_news → NewsCritical
price: true # /v3/quote 按 watch pool 拉 → PriceAlert / Weekly52High / Weekly52Low
extended_hours: true # /v3/historical-chart/1min?extended=true → pre/post-market PriceAlert
earnings_calendar: true # /v3/earning_calendar → EarningsUpcoming
corp_action: true # 拆股 / 分红日历 → Split / Dividend
sec_filings: true # SEC filings per-ticker → SecFiling(forms come from sec_filings.forms above)
macro_calendar: true # /v3/economic_calendar → MacroEvent
analyst_grade: true # 按 watch pool 拉 → AnalystGrade
earnings_surprise: true # 按 watch pool 拉 → EarningsReleased
# 通用 RSS 新闻源 —— 给 global_digest 候选池补 FMP 漏掉的料。
# POC 验证 FMP 漏掉 Bloomberg 93%、SpaceNews 100%、STAT News 100% 的关键料。
# 入 events 表 source = "rss:{handle}",collector 与 FMP news 一同拉。
rss_feeds:
- handle: bloomberg_markets
url: https://feeds.bloomberg.com/markets/news.rss
interval_secs: 1800
- handle: spacenews
url: https://spacenews.com/feed/
interval_secs: 3600
- handle: stat_news
url: https://www.statnews.com/feed/
interval_secs: 3600
# 大V速报:白毛使用用户确认的 aichainmap 公共整理 feed,条目仍以 X 原链
# 为内容来源;SemiAnalysis 使用官方 RSS。Jukan 仍需部署方配置合法 bridge。
- handle: influencer_serenity
url: https://serenity-webhook.pages.dev/feed
interval_secs: 900
- handle: influencer_semianalysis
url: https://semianalysis.com/feed
interval_secs: 3600
# 关键事件链一手来源:只有注册的 key_event_* handle 且 feed 与条目均在
# 对应官方域名时,才可标为“一手确认”。没有稳定官方 RSS 的公司应通过
# 管理员研究资料库导入官方原文,不能用搜索摘要或自媒体替代。
- handle: key_event_openai
url: https://openai.com/news/rss.xml
interval_secs: 3600
# Telegram 公开频道监听(web preview `t.me/s/<handle>`),产出 social_post。
# 空数组表示不启用;开启时每条配置会启动一个独立 poller loop。
telegram_channels: []
# 全局 event kind 黑名单。router 在 per-user NotificationPrefs 之前先过一遍;
# 入库仍然发生(便于日报 / 统计),只是不再分发给任何 actor。即使用户把某个
# kind 放进 allow_kinds,在这里禁用后仍然不会推。合法 tag:
# earnings_upcoming, earnings_released, earnings_call_transcript,
# news_critical,
# price_alert, weekly52_high, weekly52_low,
# dividend, split, sec_filing, analyst_grade,
# macro_event, social_post
disabled_kinds: []
# news_classifier_llm names an llm.profiles entry; news_classifier_model is the
# legacy OpenRouter fallback when that profile is empty. Keep CI/tests mocked;
# use real API only for manual live-quality checks.
news_classifier_llm: news_classifier
news_classifier_model: "x-ai/grok-4.3"
# Global default phrase for judging whether uncertain-source news is important.
# Per-actor notif_prefs news_importance_prompt overrides this value.
news_importance_prompt: "公司或潜在影响公司长期逻辑和宏观叙事的重大事件"
llm:
provider: openrouter
default_profile: main
auxiliary_profile: aux
openrouter:
# Legacy config-only fallback. Prefer the llm.providers.openrouter.api_key/api_keys pool.
model: "moonshotai/kimi-k2.5"
# Legacy auxiliary fallback model for heartbeats / session compression / other background checks.
# This example uses llm.auxiliary_profile instead.
sub_model: "moonshotai/kimi-k2.5"
timeout: 120
max_retries: 3
max_tokens: 32768
providers:
openrouter:
# OpenRouter-specialized OpenAI-compatible provider kind.
# Use openai_compatible for other OpenAI-compatible endpoints.
kind: openrouter
base_url: "https://openrouter.ai/api/v1"
api_key: ""
api_keys: []
timeout: 120
max_retries: 3
profiles:
main:
provider: openrouter
model: "moonshotai/kimi-k2.5"
params:
max_tokens: 32768
aux:
provider: openrouter
model: "moonshotai/kimi-k2.5"
params:
max_tokens: 4096
news_classifier:
provider: openrouter
model: "x-ai/grok-4.3"
params:
max_tokens: 64
temperature: 0
filing_summary:
provider: openrouter
model: "x-ai/grok-4.3"
params:
max_tokens: 800
temperature: 0.2
# SEC enrichment 的 prompt/renderer 契约是纯文本;不要在这里强制 json_object。
earnings_quality:
provider: openrouter
model: "x-ai/grok-4.5"
params:
max_tokens: 1800
temperature: 0.2
reasoning:
effort: low
response_format:
type: json_object
earnings_continuity:
provider: openrouter
model: "x-ai/grok-4.5"
params:
max_tokens: 3600
temperature: 0.2
reasoning:
effort: low
response_format:
type: json_object
digest_fast:
provider: openrouter
model: "x-ai/grok-4.3"
params:
max_tokens: 1200
temperature: 0.2
digest_strong:
provider: openrouter
model: "x-ai/grok-4.3"
params:
max_tokens: 1600
temperature: 0.2
reasoning:
effort: low
mainline_short:
provider: openrouter
model: "x-ai/grok-4.3"
params:
max_tokens: 1200
temperature: 0.2
auxiliary:
# Optional legacy OpenAI-compatible auxiliary path for heartbeats / session compression.
# Used only when llm.auxiliary_profile is empty; then it overrides openrouter.sub_model.
base_url: ""
api_key: ""
model: ""
timeout: 120
max_retries: 3
max_tokens: 32768
storage:
# Anchors file-backed state paths; sessions themselves live in PostgreSQL.
sessions_dir: "./data/sessions"
# Per-actor daily conversation quota files. Legacy conversation_quota_db_path
# is still accepted as an alias, but new configs should use this directory key.
conversation_quota_dir: "./data/conversation_quota"
llm_audit_retention_days: 30
llm_audit_enabled: true
portfolio_dir: "./data/portfolio"
cron_jobs_dir: "./data/cron_jobs"
gen_images_dir: "./data/gen_images"
notif_prefs_dir: "./data/notif_prefs"
cloud:
# PostgreSQL is the mandatory authoritative store in every deployment mode.
# OSS remains optional; without it, generated files use their local fallback path.
# Keep real PG / OSS credentials in the process environment or local .env only.
# Set cloud.strict_no_local_storage=true to reject those optional local file fallbacks.
# HONE_CLOUD_STRICT_NO_LOCAL_STORAGE=true has the same startup-fail effect.
strict_no_local_storage: false
# Private-R2 public-community delivery is opt-in. Keep `off` until the edge
# Worker, private bucket binding, and shared signing secret are ready.
community_delivery:
# off | shadow | prefer. Both shadow/prefer may issue the short-lived edge
# cookie; clients continue using the legacy API unless separately enabled.
mode: "off"
# Runtime clamps this value to 60..3600 seconds.
token_ttl_secs: 900
# Name of the environment variable containing the HMAC secret. After
# trimming whitespace it must be 32..1024 UTF-8 bytes. Never put the
# secret bytes themselves in this YAML file.
secret_env: "HONE_COMMUNITY_EDGE_HMAC_SECRET"
postgres:
database_url: ""
database_url_env: "DATABASE_URL"
host: ""
host_env: "HONE_POSTGRES_HOST"
port: 0
port_env: "HONE_POSTGRES_PORT"
user: ""
user_env: "HONE_POSTGRES_USER"
password: ""
password_env: "HONE_POSTGRES_PASSWORD"
database: ""
database_env: "HONE_POSTGRES_DATABASE"
sslmode: "disable"
# Optional local proxy, for example socks5://127.0.0.1:1082.
proxy: ""
proxy_env: "HONE_POSTGRES_PROXY"
# Force direct TCP for PG even if proxy is configured in env/config.
no_proxy: false
no_proxy_env: "HONE_POSTGRES_NO_PROXY"
oss:
# aliyun_oss | r2 | s3
provider: "aliyun_oss"
provider_env: "HONE_OSS_PROVIDER"
access_key_id: ""
access_key_id_env: "HONE_OSS_ACCESS_KEY_ID"
access_key_secret: ""
access_key_secret_env: "HONE_OSS_ACCESS_KEY_SECRET"
bucket: ""
bucket_env: "HONE_OSS_BUCKET"
endpoint: ""
endpoint_env: "HONE_OSS_ENDPOINT"
region: ""
region_env: "HONE_OSS_REGION"
public_upload_prefix: "public-uploads"
# Optional reqwest proxy, for example socks5://127.0.0.1:1082.
proxy: ""
proxy_env: "HONE_OSS_PROXY"
logging:
level: "INFO"
# Parsed for compatibility, but setup_logging currently always installs the
# console formatter and does not create a file appender from logging.file.
console: true
file: "./data/logs/hone.log"
# Local UDP log sink port. null uses the runtime default port 18118; there is
# currently no config-level disable switch.
udp_port: null
admins:
# iMessage admin handle list (phone number or Apple ID)
# These users have admin privileges in the iMessage channel (they can modify code and restart Hone)
imessage_handles:
- "" # example: "+13234567890" or "admin@example.com"
# Telegram admin user ID list (Telegram numeric IDs)
telegram_user_ids:
- "" # example: "8039067465"
# Feishu admin email list
feishu_emails:
- "" # example: "admin@example.com"
# Feishu admin mobile list
feishu_mobiles:
- "" # example: "+8613800138000"
# Feishu admin open_id list
feishu_open_ids:
- "" # example: "ou_xxx"
# Discord admin user ID list (Discord numeric IDs)
discord_user_ids:
- "" # example: "123456789012345678"
# Optional runtime admin registration passphrase.
# Prefer setting this through the env var below instead of committing plaintext secrets.
runtime_admin_registration_passphrase: ""
# Env var name used when runtime_admin_registration_passphrase is empty
runtime_admin_registration_passphrase_env: "HONE_ADMIN_REGISTER_PASSPHRASE"
web:
# Bearer token for the Web console (recommended for remote deployments; can be left empty locally)
auth_token: ""
# Research report API
research_api_base: "https://research.example.com"
research_api_key: ""
# Local private workflow runner base URL used by the cross-channel /report shortcut
local_workflow_api_base: "http://127.0.0.1:3213"
# Validate code required by the local private workflow runner /report shortcut
local_workflow_validate_code: ""
# Env var name used when local_workflow_validate_code is empty
local_workflow_validate_code_env: "HONE_REPORT_VALIDATE_CODE"
# Public SMS login uses Aliyun PNVS VerifyCode APIs and is configured by env:
# - ALIBABA_CLOUD_ACCESS_KEY_ID / ALIBABA_CLOUD_ACCESS_KEY_SECRET (required)
# Compat aliases: ALIYUN_ACCESS_KEY_* or HONE_ALIYUN_ACCESS_KEY_*
# - HONE_ALIYUN_SMS_ENDPOINT (default: dypnsapi.aliyuncs.com)
# - HONE_ALIYUN_SMS_COUNTRY_CODE (default: 86; backend sends local CN numbers)
# - HONE_ALIYUN_SMS_SIGN_NAME (default: 速通互联验证码)
# - HONE_ALIYUN_SMS_TEMPLATE_CODE (default: 100001)
# - HONE_ALIYUN_SMS_TEMPLATE_PARAM (default: {"code":"##code##","min":"5"})
# - HONE_PUBLIC_SECURE_COOKIE=true/1/yes or false/0/no may force the public
# session cookie Secure flag; invalid values keep Secure=true.
# Existing admin-created Web invite users are treated as the public-login invite list.
# Optional Aliyun Captcha 2.0 guard for public SMS sends is configured by env:
# - ALIBABA_CLOUD_ACCESS_KEY_ID / ALIBABA_CLOUD_ACCESS_KEY_SECRET (same AccessKey env as SMS)
# - HONE_ALIYUN_CAPTCHA_PREFIX / HONE_ALIYUN_CAPTCHA_SCENE_ID (required to enable)
# - HONE_ALIYUN_CAPTCHA_REGION (default: cn; use sgp for Singapore)
# - HONE_ALIYUN_CAPTCHA_ENDPOINT (optional override)
# - HONE_ALIYUN_CAPTCHA_ENABLED=false disables the guard even when prefix/scene are set.
security:
# Whether KB queries are isolated by actor/session (recommended to avoid cross-user retrieval)
kb_actor_isolation: true
tool_guard:
enabled: true
# block | audit (audit only records the warning and does not block)
mode: "block"
# Tool matching rules to apply (supports "*" and "!<pattern>" exclusions)
apply_tools:
- "*"
- "!web_search"
- "!data_fetch"
# High-risk fragments that trigger blocking (matched in lowercase)
deny_patterns:
- "rm -rf"
- "rm -fr"
- "rm -r /"
- "rm -rf /"
- "rm -fr /"
- "mkfs"
- "dd if=/dev/zero"
- "dd if=/dev/random"
- "shutdown -h"
- "shutdown -r"
- "reboot"
- "poweroff"
- "halt"
- ":(){ :|:& };:"
- "del /s /q"
- "rd /s /q"
- "format c:"
- "curl | sh"
- "wget | sh"
agent:
# Recommended: hone_cloud | codex_acp | opencode_acp.
# Other supported runners: gemini_cli | codex_cli.
# This example uses Codex ACP as the default local runner.
# gemini_acp is disabled at runtime and kept below only for migration/reference.
runner: "codex_acp"
# Only used when runner=codex_cli; empty means use the codex-cli default model
codex_model: "gpt-5.6-sol"
# Daily successful-reply quota for user conversations. Set to 0 to disable the limit.
daily_conversation_limit: 100
# Single-step timeout used by internal runner phases such as initialize/load and stream idle gaps
step_timeout_seconds: 180
# Full-run timeout used for one complete answer round
overall_timeout_seconds: 1200
# Verbose runner debug logging is controlled by HONE_AGENT_DEBUG, not by a config field.
system_prompt_path: "./soul.md"
gemini_acp:
# Deserializable legacy config only; do not set agent.runner=gemini_acp.
command: "gemini"
args: [ "--experimental-acp", "--sandbox", "--approval-mode", "plan" ]
# Optional; if unset, reuse the local gemini-cli login state
api_key: ""
# Optional; empty uses the gemini CLI default model
model: "gemini-2.5-pro"
codex_acp:
command: "codex-acp"
args: []
# Startup checks: @openai/codex >= 0.146.0 and @agentclientprotocol/codex-acp >= 1.1.7.
codex_command: "codex"
# GPT-5.6 Sol is the default high-capability Codex ACP model.
# Hone applies model, reasoning effort, safety settings, and native developer
# instructions through the codex-acp CODEX_CONFIG boundary before startup.
# One deterministic Hone conversation maps to one persistent native Codex session;
# later turns resume it and let the Codex harness own history and compaction.
model: "gpt-5.6-sol"
# Reasoning effort passed to Codex as model_reasoning_effort.
variant: "xhigh"
# Recommended: keep workspace-write + never, and let Hone run inside the actor sandbox
sandbox_mode: "workspace-write"
approval_policy: "never"
dangerously_bypass_approvals_and_sandbox: false
# Open network inside the workspace-write sandbox; without this, curl/git inside
# the actor sandbox will hit DNS timeouts (codex defaults network_access=false).
# Keep this convenience list for common workspace-write permissions. Advanced
# settings may also use `extra_config_overrides` and are merged into CODEX_CONFIG.
sandbox_permissions: ["network-full-access"]
extra_config_overrides: []
opencode:
command: "opencode"
args: [ "acp" ]
# Leave empty to inherit your local opencode global config
# (~/.config/opencode/opencode.json or opencode.jsonc)
model: ""
# Optional; only used together with a Hone-side model override
variant: ""
# Optional Hone-side provider/base URL override; leave empty to inherit local opencode config
api_base_url: ""
# Optional Hone-side API key override; leave empty to inherit local opencode auth/provider config
api_key: ""
earnings_workflow:
# Administrator-only earnings preview/analysis route. This does not change
# the runner or model used by ordinary conversations.
runner: "opencode_acp"
model: "google/gemini-3.1-pro-preview"
hone_cloud:
# Hosted service route seeded by this sample; runtime appends /api/public/v1/chat/completions when needed.
base_url: "https://hone-claw.com"
# Per-user Hone Cloud API key. Contact bm@hone-claw.com for an invite and key.
api_key: ""
# OpenAI-compatible model id placeholder used by the client request.
model: "hone-cloud"
search:
# Tavily is the only runtime search provider today. search.provider /
# search.search_depth / search.topic stay in the config schema for compatibility
# but are not wired into requests yet; the current web_search tool reads
# search.api_keys and search.max_results only. Runtime caps max_results to 3
# to keep Tavily response size and credits predictable for heartbeat workloads.
provider: tavily
# Tavily API key pool with failover support
api_keys:
- ""
search_depth: "basic"
topic: "general"
max_results: 3