herm-tui 1.0.0-dev.1 → 1.0.0-dev.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/db.worker.js +81 -0
  2. package/highlights-eq9cgrbb.scm +604 -0
  3. package/highlights-ghv9g403.scm +205 -0
  4. package/highlights-hk7bwhj4.scm +284 -0
  5. package/highlights-r812a2qc.scm +150 -0
  6. package/highlights-x6tmsnaa.scm +115 -0
  7. package/index.js +10374 -0
  8. package/injections-73j83es3.scm +27 -0
  9. package/package.json +14 -64
  10. package/parser.worker.js +8 -0
  11. package/tree-sitter-3jzf13jk.wasm +0 -0
  12. package/tree-sitter-javascript-nd0q4pe9.wasm +0 -0
  13. package/tree-sitter-markdown-411r6y9b.wasm +0 -0
  14. package/tree-sitter-markdown_inline-j5349f42.wasm +0 -0
  15. package/tree-sitter-typescript-zxjzwt75.wasm +0 -0
  16. package/tree-sitter-zig-e78zbjpm.wasm +0 -0
  17. package/scripts/postinstall.ts +0 -29
  18. package/src/app/gateway.tsx +0 -83
  19. package/src/app/gatewayEvents.ts +0 -203
  20. package/src/app/launch.ts +0 -41
  21. package/src/app/skin.tsx +0 -31
  22. package/src/app/spawnHistory.ts +0 -75
  23. package/src/app/tabs.ts +0 -23
  24. package/src/app/turnReducer.ts +0 -390
  25. package/src/app/useAppKeys.ts +0 -268
  26. package/src/app/useAtRefPopover.ts +0 -99
  27. package/src/app/useInputHistory.ts +0 -66
  28. package/src/app/useSession.ts +0 -102
  29. package/src/app/useSlashCommands.ts +0 -70
  30. package/src/app/useSlashPopover.ts +0 -48
  31. package/src/app.tsx +0 -917
  32. package/src/commands/slash.ts +0 -151
  33. package/src/components/avatar/AnimatedAvatar.tsx +0 -66
  34. package/src/components/avatar/eikon.ts +0 -144
  35. package/src/components/avatar/states/error.ts +0 -1155
  36. package/src/components/avatar/states/idle.ts +0 -1155
  37. package/src/components/avatar/states/index.ts +0 -30
  38. package/src/components/avatar/states/listening.ts +0 -1155
  39. package/src/components/avatar/states/speaking.ts +0 -1155
  40. package/src/components/avatar/states/thinking.ts +0 -1155
  41. package/src/components/avatar/states/working.ts +0 -1155
  42. package/src/components/chat/AtRefPopover.tsx +0 -54
  43. package/src/components/chat/CodeBlock.tsx +0 -67
  44. package/src/components/chat/Composer.tsx +0 -347
  45. package/src/components/chat/DiffBlock.tsx +0 -116
  46. package/src/components/chat/ErrorBlock.tsx +0 -70
  47. package/src/components/chat/MediaChip.tsx +0 -114
  48. package/src/components/chat/MessageItem.tsx +0 -282
  49. package/src/components/chat/MessageList.tsx +0 -114
  50. package/src/components/chat/PromptCard.tsx +0 -359
  51. package/src/components/chat/SlashPopover.tsx +0 -158
  52. package/src/components/chat/ThoughtCloud.tsx +0 -185
  53. package/src/components/chat/TypingIndicator.tsx +0 -25
  54. package/src/components/chat/tool/Subagent.tsx +0 -75
  55. package/src/components/chat/tool/frame.tsx +0 -69
  56. package/src/components/chat/tool/index.tsx +0 -65
  57. package/src/components/chat/tool/preview.ts +0 -57
  58. package/src/components/sidebar/ContextGauge.tsx +0 -102
  59. package/src/components/sidebar/Sidebar.tsx +0 -143
  60. package/src/components/tabs/TabBar.tsx +0 -50
  61. package/src/components/ui/FileLink.tsx +0 -52
  62. package/src/config/index.ts +0 -156
  63. package/src/config/lane.ts +0 -161
  64. package/src/config/models.ts +0 -95
  65. package/src/config/rules.ts +0 -80
  66. package/src/config/schema.ts +0 -308
  67. package/src/dialogs/alert.tsx +0 -52
  68. package/src/dialogs/chafa.tsx +0 -72
  69. package/src/dialogs/confirm.tsx +0 -58
  70. package/src/dialogs/curator.tsx +0 -153
  71. package/src/dialogs/eikon-picker.tsx +0 -95
  72. package/src/dialogs/help.tsx +0 -80
  73. package/src/dialogs/history.tsx +0 -92
  74. package/src/dialogs/info.tsx +0 -115
  75. package/src/dialogs/keys.tsx +0 -170
  76. package/src/dialogs/logs.tsx +0 -42
  77. package/src/dialogs/message.tsx +0 -38
  78. package/src/dialogs/model-picker.tsx +0 -123
  79. package/src/dialogs/new-profile.tsx +0 -69
  80. package/src/dialogs/new-task.tsx +0 -103
  81. package/src/dialogs/profile.tsx +0 -55
  82. package/src/dialogs/rollback.tsx +0 -190
  83. package/src/dialogs/spawn-history.tsx +0 -80
  84. package/src/dialogs/text-prompt.tsx +0 -68
  85. package/src/dialogs/theme-picker.tsx +0 -50
  86. package/src/home/index.ts +0 -23
  87. package/src/home/store.ts +0 -267
  88. package/src/index.tsx +0 -113
  89. package/src/keys/catalog.ts +0 -115
  90. package/src/keys/chord.ts +0 -125
  91. package/src/keys/conflicts.ts +0 -48
  92. package/src/keys/context.tsx +0 -112
  93. package/src/keys/index.ts +0 -5
  94. package/src/keys/list.ts +0 -94
  95. package/src/keys/oc-compat.ts +0 -87
  96. package/src/tabs/Agents.tsx +0 -607
  97. package/src/tabs/Analytics.tsx +0 -154
  98. package/src/tabs/Chat.tsx +0 -50
  99. package/src/tabs/Config.tsx +0 -605
  100. package/src/tabs/Context.tsx +0 -599
  101. package/src/tabs/Cron.tsx +0 -294
  102. package/src/tabs/Env.tsx +0 -227
  103. package/src/tabs/Kanban.tsx +0 -367
  104. package/src/tabs/Memory.tsx +0 -294
  105. package/src/tabs/Sessions.tsx +0 -786
  106. package/src/tabs/Skills.tsx +0 -507
  107. package/src/tabs/Toolsets.tsx +0 -266
  108. package/src/theme/builtin.ts +0 -78
  109. package/src/theme/context.tsx +0 -106
  110. package/src/theme/index.ts +0 -4
  111. package/src/theme/resolve.ts +0 -134
  112. package/src/theme/syntax.ts +0 -31
  113. package/src/theme/themes/aura.json +0 -69
  114. package/src/theme/themes/ayu.json +0 -80
  115. package/src/theme/themes/carbonfox.json +0 -248
  116. package/src/theme/themes/catppuccin-frappe.json +0 -233
  117. package/src/theme/themes/catppuccin-macchiato.json +0 -233
  118. package/src/theme/themes/catppuccin.json +0 -112
  119. package/src/theme/themes/cobalt2.json +0 -228
  120. package/src/theme/themes/cursor.json +0 -249
  121. package/src/theme/themes/dracula.json +0 -219
  122. package/src/theme/themes/everforest.json +0 -241
  123. package/src/theme/themes/flexoki.json +0 -237
  124. package/src/theme/themes/github.json +0 -233
  125. package/src/theme/themes/gruvbox.json +0 -242
  126. package/src/theme/themes/kanagawa.json +0 -77
  127. package/src/theme/themes/lucent-orng.json +0 -237
  128. package/src/theme/themes/material.json +0 -235
  129. package/src/theme/themes/matrix.json +0 -77
  130. package/src/theme/themes/mercury.json +0 -252
  131. package/src/theme/themes/monokai.json +0 -221
  132. package/src/theme/themes/nightowl.json +0 -221
  133. package/src/theme/themes/nord.json +0 -223
  134. package/src/theme/themes/one-dark.json +0 -84
  135. package/src/theme/themes/opencode.json +0 -245
  136. package/src/theme/themes/orng.json +0 -249
  137. package/src/theme/themes/osaka-jade.json +0 -93
  138. package/src/theme/themes/palenight.json +0 -222
  139. package/src/theme/themes/rosepine.json +0 -234
  140. package/src/theme/themes/solarized.json +0 -223
  141. package/src/theme/themes/synthwave84.json +0 -226
  142. package/src/theme/themes/tokyonight.json +0 -243
  143. package/src/theme/themes/vercel.json +0 -245
  144. package/src/theme/themes/vesper.json +0 -218
  145. package/src/theme/themes/zenburn.json +0 -223
  146. package/src/theme/types.ts +0 -119
  147. package/src/types/message.ts +0 -97
  148. package/src/ui/ChafaImage.tsx +0 -64
  149. package/src/ui/Splash.tsx +0 -118
  150. package/src/ui/borders.ts +0 -28
  151. package/src/ui/command.tsx +0 -104
  152. package/src/ui/dialog-select.tsx +0 -164
  153. package/src/ui/dialog.tsx +0 -102
  154. package/src/ui/fmt.ts +0 -82
  155. package/src/ui/kv.tsx +0 -28
  156. package/src/ui/shell.tsx +0 -45
  157. package/src/ui/spinner.tsx +0 -59
  158. package/src/ui/splash-art.ts +0 -123
  159. package/src/ui/table.tsx +0 -117
  160. package/src/ui/ticker.tsx +0 -90
  161. package/src/ui/toast.tsx +0 -130
  162. package/src/utils/categorical.ts +0 -77
  163. package/src/utils/chafa.ts +0 -173
  164. package/src/utils/clipboard.ts +0 -67
  165. package/src/utils/context-segments.ts +0 -317
  166. package/src/utils/control.ts +0 -495
  167. package/src/utils/drop.ts +0 -25
  168. package/src/utils/editor.ts +0 -33
  169. package/src/utils/fuzzy.ts +0 -45
  170. package/src/utils/gateway-client.ts +0 -253
  171. package/src/utils/gateway-types.ts +0 -282
  172. package/src/utils/git.ts +0 -57
  173. package/src/utils/hermes-analytics.ts +0 -134
  174. package/src/utils/hermes-home.ts +0 -821
  175. package/src/utils/hermes-kanban.ts +0 -154
  176. package/src/utils/hermes-profiles.ts +0 -217
  177. package/src/utils/interpolate.ts +0 -31
  178. package/src/utils/math-unicode.ts +0 -818
  179. package/src/utils/memory-activity.ts +0 -140
  180. package/src/utils/open-file.ts +0 -13
  181. package/src/utils/paths.ts +0 -52
  182. package/src/utils/perf.ts +0 -235
  183. package/src/utils/preferences.ts +0 -150
  184. package/src/utils/sessions-db.ts +0 -396
  185. package/src/utils/subagent-tree.ts +0 -146
  186. package/src/utils/terminal-reset.ts +0 -129
  187. package/src/utils/tips.ts +0 -67
  188. package/src/utils/tokens.ts +0 -87
@@ -1,80 +0,0 @@
1
- /**
2
- * Hand-curated validation overlay for config fields. Each rule takes
3
- * the *raw string buffer* as typed (pre-coercion) and returns an error
4
- * message, or null if valid. Rules run on Enter-commit in the Config
5
- * tab; a non-null result blocks the commit and renders inline.
6
- *
7
- * Schema-derived type coercion (int/float/bool) happens in lane.ts
8
- * *after* these pass, so rules only need to check semantic bounds,
9
- * not "is this a number".
10
- */
11
-
12
- type Rule = (raw: string) => string | null
13
-
14
- const int = (lo: number, hi: number, what = `${lo}–${hi}`): Rule => raw => {
15
- const n = Number(raw)
16
- if (!Number.isInteger(n)) return `expected integer ${what}`
17
- if (n < lo || n > hi) return `expected ${what}`
18
- return null
19
- }
20
-
21
- const float = (lo: number, hi: number): Rule => raw => {
22
- const n = Number(raw)
23
- if (!Number.isFinite(n)) return `expected number ${lo}–${hi}`
24
- if (n < lo || n > hi) return `expected ${lo}–${hi}`
25
- return null
26
- }
27
-
28
- const oneOf = (...opts: string[]): Rule => raw =>
29
- opts.includes(raw) ? null : `expected one of: ${opts.join(" | ")}`
30
-
31
- const nonNeg: Rule = raw => {
32
- const n = Number(raw)
33
- return Number.isFinite(n) && n >= 0 ? null : "expected ≥ 0"
34
- }
35
-
36
- export const RULES: Record<string, Rule> = {
37
- // ratios
38
- "compression.threshold": float(0.1, 0.95),
39
- "compression.target_ratio": float(0.05, 0.9),
40
- "prompt_caching.cache_ttl": raw =>
41
- /^\d+[smhd]$/.test(raw.trim()) ? null : "expected duration e.g. 5m, 1h",
42
-
43
- // turn/iteration budgets
44
- "agent.max_turns": int(1, 10000),
45
- "delegation.max_iterations": int(1, 10000),
46
- "delegation.max_concurrent_children": int(1, 64),
47
- "delegation.max_spawn_depth": int(1, 3),
48
-
49
- // timeouts (seconds; 0 usually means "disabled")
50
- "agent.gateway_timeout": nonNeg,
51
- "agent.gateway_timeout_warning": nonNeg,
52
- "agent.gateway_notify_interval": nonNeg,
53
- "agent.restart_drain_timeout": nonNeg,
54
- "delegation.child_timeout_seconds": int(30, 86400),
55
- "browser.command_timeout": int(1, 600),
56
- "approvals.timeout": int(1, 3600),
57
- "security.tirith_timeout": int(1, 120),
58
-
59
- // retries / limits
60
- "agent.api_max_retries": int(0, 20),
61
- "tool_output.max_bytes": int(1024, 10_000_000),
62
- "tool_output.max_lines": int(10, 100_000),
63
- "sessions.retention_days": int(1, 3650),
64
- "sessions.min_interval_hours": int(1, 720),
65
-
66
- // enums the schema doesn't carry
67
- "agent.service_tier": oneOf("", "fast", "standard"),
68
- "display.busy_input_mode": oneOf("queue", "steer", "interrupt"),
69
- "display.details_mode": oneOf("hidden", "collapsed", "expanded"),
70
- "display.thinking_mode": oneOf("collapsed", "truncated", "full"),
71
- "display.tool_progress": oneOf("off", "new", "all", "verbose"),
72
- "display.final_response_markdown": oneOf("render", "strip", "raw"),
73
- "logging.level": oneOf("DEBUG", "INFO", "WARNING", "ERROR"),
74
- "approvals.mode": oneOf("manual", "ask", "yolo", "deny"),
75
- "code_execution.mode": oneOf("project", "strict"),
76
- }
77
-
78
- /** Validate a field's buffer. Unknown keys pass. */
79
- export const check = (key: string, raw: string): string | null =>
80
- RULES[key]?.(raw) ?? null
@@ -1,308 +0,0 @@
1
- // Generated by scripts/gen-schema.ts — do not edit by hand.
2
- // Source: hermes-agent@f98b5d00a hermes_cli/config.py
3
- // Keys: 289
4
-
5
- export type ConfigType = "bool" | "int" | "float" | "str" | "list" | "dict" | "null"
6
- export type ConfigEffect = "live" | "session" | "restart"
7
-
8
- export interface ConfigSchemaEntry {
9
- type: ConfigType
10
- default: unknown
11
- doc: string
12
- group: string
13
- effect: ConfigEffect
14
- }
15
-
16
- export const SCHEMA: Record<string, ConfigSchemaEntry> = {
17
- "agent.api_max_retries": {"type":"int","default":3,"doc":"Max app-level retry attempts for API errors (connection drops, provider timeouts, 5xx, etc.) before the agent surfaces the failure. The OpenAI SDK already does its own low-level retries (max_retries=2 default) for transient network errors; this is the Hermes-level retry loop that wraps the whole call. Lower this to 1 if you use fallback providers and want fast failover on flaky primaries; raise it if you prefer to tolerate longer provider hiccups on a single provider.","group":"agent","effect":"session"},
18
- "agent.disabled_toolsets": {"type":"list","default":[],"doc":"","group":"agent","effect":"session"},
19
- "agent.gateway_auto_continue_freshness": {"type":"int","default":3600,"doc":"Freshness window for the gateway auto-continue note (seconds). After a gateway crash/restart/SIGTERM mid-run, the next user message gets a \"[System note: your previous turn was interrupted — process the unfinished tool result(s) first]\" prepended so the model picks up where it left off. That's the right behaviour while the interruption is fresh, but stale markers (transcript last touched hours or days ago) can revive an unrelated old task when the user's next message starts new work. This window is the max age of the last persisted transcript row for which we still inject the continue note. Default 3600s comfortably covers a long turn (gateway_timeout default is 1800s) plus runtime slack. Set to 0 to disable the gate and restore pre-fix behaviour (always inject).","group":"agent","effect":"session"},
20
- "agent.gateway_notify_interval": {"type":"int","default":180,"doc":"Periodic \"still working\" notification interval (seconds). Sends a status message every N seconds so the user knows the agent hasn't died during long tasks. 0 = disable notifications. Lower values mean faster feedback on slow tasks but more chat noise; 180s is a compromise that catches spinning weak-model runs (60+ tool iterations with tiny output) before users assume the bot is dead and /restart.","group":"agent","effect":"session"},
21
- "agent.gateway_timeout": {"type":"int","default":1800,"doc":"Inactivity timeout for gateway agent execution (seconds). The agent can run indefinitely as long as it's actively calling tools or receiving API responses. Only fires when the agent has been completely idle for this duration. 0 = unlimited.","group":"agent","effect":"session"},
22
- "agent.gateway_timeout_warning": {"type":"int","default":900,"doc":"Staged inactivity warning: send a warning to the user at this threshold before escalating to a full timeout. The warning fires once per run and does not interrupt the agent. 0 = disable warning.","group":"agent","effect":"session"},
23
- "agent.image_input_mode": {"type":"str","default":"auto","doc":"How user-attached images are presented to the main model on each turn. \"auto\" — attach natively when the active model reports supports_vision=True AND the user hasn't explicitly configured auxiliary.vision.provider. Otherwise fall back to text (vision_analyze pre-analysis). \"native\" — always attach natively; non-vision models will either error at the provider or get a last-chance text fallback (see run_agent._prepare_messages_for_api). \"text\" — always pre-analyze with vision_analyze and prepend the description as text; the main model never sees pixels. Affects gateway platforms, the TUI, and CLI /attach. vision_analyze remains available as a tool regardless of this setting — the routing only controls how inbound user images are presented.","group":"agent","effect":"session"},
24
- "agent.max_turns": {"type":"int","default":90,"doc":"","group":"agent","effect":"session"},
25
- "agent.reasoning_effort": {"type":"str","default":"","doc":"Reasoning effort for the main agent: none | minimal | low | medium | high | xhigh.","group":"agent","effect":"live"},
26
- "agent.restart_drain_timeout": {"type":"int","default":60,"doc":"Graceful drain timeout for gateway stop/restart (seconds). The gateway stops accepting new work, waits for running agents to finish, then interrupts any remaining runs after the timeout. 0 = no drain, interrupt immediately.","group":"agent","effect":"session"},
27
- "agent.service_tier": {"type":"str","default":"","doc":"","group":"agent","effect":"live"},
28
- "agent.system_prompt": {"type":"str","default":"","doc":"System-prompt override applied by the active personality.","group":"agent","effect":"session"},
29
- "agent.tool_use_enforcement": {"type":"str","default":"auto","doc":"Tool-use enforcement: injects system prompt guidance that tells the model to actually call tools instead of describing intended actions. Values: \"auto\" (default — applies to gpt/codex models), true/false (force on/off for all models), or a list of model-name substrings to match (e.g. [\"gpt\", \"codex\", \"gemini\", \"qwen\"]).","group":"agent","effect":"session"},
30
- "approvals.cron_mode": {"type":"str","default":"deny","doc":"","group":"approvals","effect":"live"},
31
- "approvals.mcp_reload_confirm": {"type":"bool","default":true,"doc":"When true, /reload-mcp asks the user to confirm before rebuilding the MCP tool set for the active session. Reloading invalidates the provider prompt cache (tool schemas are baked into the system prompt), so the next message re-sends full input tokens — this can be expensive on long-context or high-reasoning models. Users click \"Always Approve\" to silence the prompt permanently; that flips this key to false.","group":"approvals","effect":"live"},
32
- "approvals.mode": {"type":"str","default":"manual","doc":"","group":"approvals","effect":"live"},
33
- "approvals.timeout": {"type":"int","default":60,"doc":"","group":"approvals","effect":"live"},
34
- "auxiliary.approval.api_key": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
35
- "auxiliary.approval.base_url": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
36
- "auxiliary.approval.extra_body": {"type":"dict","default":{},"doc":"","group":"auxiliary","effect":"session"},
37
- "auxiliary.approval.model": {"type":"str","default":"","doc":"fast/cheap model recommended (e.g. gemini-flash, haiku)","group":"auxiliary","effect":"session"},
38
- "auxiliary.approval.provider": {"type":"str","default":"auto","doc":"","group":"auxiliary","effect":"session"},
39
- "auxiliary.approval.timeout": {"type":"int","default":30,"doc":"","group":"auxiliary","effect":"session"},
40
- "auxiliary.compression.api_key": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
41
- "auxiliary.compression.base_url": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
42
- "auxiliary.compression.extra_body": {"type":"dict","default":{},"doc":"","group":"auxiliary","effect":"session"},
43
- "auxiliary.compression.model": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
44
- "auxiliary.compression.provider": {"type":"str","default":"auto","doc":"","group":"auxiliary","effect":"session"},
45
- "auxiliary.compression.timeout": {"type":"int","default":120,"doc":"seconds — compression summarises large contexts; increase for local models","group":"auxiliary","effect":"session"},
46
- "auxiliary.curator.api_key": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
47
- "auxiliary.curator.base_url": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
48
- "auxiliary.curator.extra_body": {"type":"dict","default":{},"doc":"","group":"auxiliary","effect":"session"},
49
- "auxiliary.curator.model": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
50
- "auxiliary.curator.provider": {"type":"str","default":"auto","doc":"","group":"auxiliary","effect":"session"},
51
- "auxiliary.curator.timeout": {"type":"int","default":600,"doc":"","group":"auxiliary","effect":"session"},
52
- "auxiliary.mcp.api_key": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
53
- "auxiliary.mcp.base_url": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
54
- "auxiliary.mcp.extra_body": {"type":"dict","default":{},"doc":"","group":"auxiliary","effect":"session"},
55
- "auxiliary.mcp.model": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
56
- "auxiliary.mcp.provider": {"type":"str","default":"auto","doc":"","group":"auxiliary","effect":"session"},
57
- "auxiliary.mcp.timeout": {"type":"int","default":30,"doc":"","group":"auxiliary","effect":"session"},
58
- "auxiliary.session_search.api_key": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
59
- "auxiliary.session_search.base_url": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
60
- "auxiliary.session_search.extra_body": {"type":"dict","default":{},"doc":"","group":"auxiliary","effect":"session"},
61
- "auxiliary.session_search.max_concurrency": {"type":"int","default":3,"doc":"Clamp parallel summaries to avoid request-burst 429s on small providers","group":"auxiliary","effect":"session"},
62
- "auxiliary.session_search.model": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
63
- "auxiliary.session_search.provider": {"type":"str","default":"auto","doc":"","group":"auxiliary","effect":"session"},
64
- "auxiliary.session_search.timeout": {"type":"int","default":30,"doc":"","group":"auxiliary","effect":"session"},
65
- "auxiliary.skills_hub.api_key": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
66
- "auxiliary.skills_hub.base_url": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
67
- "auxiliary.skills_hub.extra_body": {"type":"dict","default":{},"doc":"","group":"auxiliary","effect":"session"},
68
- "auxiliary.skills_hub.model": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
69
- "auxiliary.skills_hub.provider": {"type":"str","default":"auto","doc":"","group":"auxiliary","effect":"session"},
70
- "auxiliary.skills_hub.timeout": {"type":"int","default":30,"doc":"","group":"auxiliary","effect":"session"},
71
- "auxiliary.title_generation.api_key": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
72
- "auxiliary.title_generation.base_url": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
73
- "auxiliary.title_generation.extra_body": {"type":"dict","default":{},"doc":"","group":"auxiliary","effect":"session"},
74
- "auxiliary.title_generation.model": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
75
- "auxiliary.title_generation.provider": {"type":"str","default":"auto","doc":"","group":"auxiliary","effect":"session"},
76
- "auxiliary.title_generation.timeout": {"type":"int","default":30,"doc":"","group":"auxiliary","effect":"session"},
77
- "auxiliary.vision.api_key": {"type":"str","default":"","doc":"API key for base_url (falls back to OPENAI_API_KEY)","group":"auxiliary","effect":"session"},
78
- "auxiliary.vision.base_url": {"type":"str","default":"","doc":"direct OpenAI-compatible endpoint (takes precedence over provider)","group":"auxiliary","effect":"session"},
79
- "auxiliary.vision.download_timeout": {"type":"int","default":30,"doc":"seconds — image HTTP download timeout; increase for slow connections","group":"auxiliary","effect":"session"},
80
- "auxiliary.vision.extra_body": {"type":"dict","default":{},"doc":"OpenAI-compatible provider-specific request fields","group":"auxiliary","effect":"session"},
81
- "auxiliary.vision.model": {"type":"str","default":"","doc":"e.g. \"google/gemini-2.5-flash\", \"gpt-4o\"","group":"auxiliary","effect":"session"},
82
- "auxiliary.vision.provider": {"type":"str","default":"auto","doc":"auto | openrouter | nous | codex | custom","group":"auxiliary","effect":"session"},
83
- "auxiliary.vision.timeout": {"type":"int","default":120,"doc":"seconds — LLM API call timeout; vision payloads need generous timeout","group":"auxiliary","effect":"session"},
84
- "auxiliary.web_extract.api_key": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
85
- "auxiliary.web_extract.base_url": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
86
- "auxiliary.web_extract.extra_body": {"type":"dict","default":{},"doc":"","group":"auxiliary","effect":"session"},
87
- "auxiliary.web_extract.model": {"type":"str","default":"","doc":"","group":"auxiliary","effect":"session"},
88
- "auxiliary.web_extract.provider": {"type":"str","default":"auto","doc":"","group":"auxiliary","effect":"session"},
89
- "auxiliary.web_extract.timeout": {"type":"int","default":360,"doc":"seconds (6min) — per-attempt LLM summarization timeout; increase for slow local models","group":"auxiliary","effect":"session"},
90
- "bedrock.discovery.enabled": {"type":"bool","default":true,"doc":"Auto-discover models via ListFoundationModels","group":"bedrock","effect":"live"},
91
- "bedrock.discovery.provider_filter": {"type":"list","default":[],"doc":"Only show models from these providers (e.g. [\"anthropic\", \"amazon\"])","group":"bedrock","effect":"live"},
92
- "bedrock.discovery.refresh_interval": {"type":"int","default":3600,"doc":"Cache discovery results for this many seconds","group":"bedrock","effect":"live"},
93
- "bedrock.guardrail.guardrail_identifier": {"type":"str","default":"","doc":"Amazon Bedrock Guardrails — content filtering and safety policies. Create a guardrail in the Bedrock console, then set the ID and version here. See: https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html","group":"bedrock","effect":"live"},
94
- "bedrock.guardrail.guardrail_version": {"type":"str","default":"","doc":"e.g. \"1\" or \"DRAFT\"","group":"bedrock","effect":"live"},
95
- "bedrock.guardrail.stream_processing_mode": {"type":"str","default":"async","doc":"\"sync\" or \"async\"","group":"bedrock","effect":"live"},
96
- "bedrock.guardrail.trace": {"type":"str","default":"disabled","doc":"\"enabled\", \"disabled\", or \"enabled_full\"","group":"bedrock","effect":"live"},
97
- "bedrock.region": {"type":"str","default":"","doc":"AWS region for Bedrock API calls (empty = AWS_REGION env var → us-east-1)","group":"bedrock","effect":"live"},
98
- "browser.allow_private_urls": {"type":"bool","default":false,"doc":"Allow navigating to private/internal IPs (localhost, 192.168.x.x, etc.)","group":"browser","effect":"live"},
99
- "browser.auto_local_for_private_urls": {"type":"bool","default":true,"doc":"When a cloud provider is set, auto-spawn local Chromium for LAN/localhost URLs instead of sending them to the cloud","group":"browser","effect":"live"},
100
- "browser.camofox.managed_persistence": {"type":"bool","default":false,"doc":"When true, Hermes sends a stable profile-scoped userId to Camofox so the server maps it to a persistent Firefox profile automatically. When false (default), each session gets a random userId (ephemeral).","group":"browser","effect":"live"},
101
- "browser.cdp_url": {"type":"str","default":"","doc":"Optional persistent CDP endpoint for attaching to an existing Chromium/Chrome","group":"browser","effect":"live"},
102
- "browser.command_timeout": {"type":"int","default":30,"doc":"Timeout for browser commands in seconds (screenshot, navigate, etc.)","group":"browser","effect":"live"},
103
- "browser.dialog_policy": {"type":"str","default":"must_respond","doc":"CDP supervisor — dialog + frame detection via a persistent WebSocket. Active only when a CDP-capable backend is attached (Browserbase or local Chrome via /browser connect). See website/docs/developer-guide/browser-supervisor.md.","group":"browser","effect":"live"},
104
- "browser.dialog_timeout_s": {"type":"int","default":300,"doc":"Safety auto-dismiss after N seconds under must_respond","group":"browser","effect":"live"},
105
- "browser.inactivity_timeout": {"type":"int","default":120,"doc":"","group":"browser","effect":"live"},
106
- "browser.record_sessions": {"type":"bool","default":false,"doc":"Auto-record browser sessions as WebM videos","group":"browser","effect":"live"},
107
- "checkpoints.auto_prune": {"type":"bool","default":false,"doc":"Auto-maintenance: shadow repos accumulate forever under ~/.hermes/checkpoints/ (one per cd'd working directory). Field reports put the typical offender at 1000+ repos / ~12 GB. When auto_prune is on, hermes sweeps at startup (at most once per min_interval_hours) and deletes: * orphan repos: HERMES_WORKDIR no longer exists on disk * stale repos: newest mtime older than retention_days Opt-in so users who rely on /rollback against long-ago sessions never lose data silently.","group":"checkpoints","effect":"live"},
108
- "checkpoints.delete_orphans": {"type":"bool","default":true,"doc":"","group":"checkpoints","effect":"live"},
109
- "checkpoints.enabled": {"type":"bool","default":true,"doc":"","group":"checkpoints","effect":"live"},
110
- "checkpoints.max_snapshots": {"type":"int","default":50,"doc":"Max checkpoints to keep per directory","group":"checkpoints","effect":"live"},
111
- "checkpoints.min_interval_hours": {"type":"int","default":24,"doc":"","group":"checkpoints","effect":"live"},
112
- "checkpoints.retention_days": {"type":"int","default":7,"doc":"","group":"checkpoints","effect":"live"},
113
- "code_execution.mode": {"type":"str","default":"project","doc":"Execution mode: project (default) — scripts run in the session's working directory with the active virtualenv/conda env's python, so project deps (pandas, torch, project packages) and relative paths resolve. strict — scripts run in an isolated temp directory with hermes-agent's own python (sys.executable). Maximum isolation and reproducibility; project deps and relative paths won't work. Env scrubbing (strips *_API_KEY, *_TOKEN, *_SECRET, ...) and the tool whitelist apply identically in both modes.","group":"code_execution","effect":"live"},
114
- "command_allowlist": {"type":"list","default":[],"doc":"Permanently allowed dangerous command patterns (added via \"always\" approval)","group":"general","effect":"live"},
115
- "compression.enabled": {"type":"bool","default":true,"doc":"","group":"compression","effect":"live"},
116
- "compression.hygiene_hard_message_limit": {"type":"int","default":400,"doc":"gateway session-hygiene force-compress threshold by message count","group":"compression","effect":"live"},
117
- "compression.protect_last_n": {"type":"int","default":20,"doc":"minimum recent messages to keep uncompressed","group":"compression","effect":"live"},
118
- "compression.target_ratio": {"type":"float","default":0.2,"doc":"fraction of threshold to preserve as recent tail","group":"compression","effect":"live"},
119
- "compression.threshold": {"type":"float","default":0.5,"doc":"compress when context usage exceeds this ratio","group":"compression","effect":"live"},
120
- "context.engine": {"type":"str","default":"compressor","doc":"","group":"context","effect":"live"},
121
- "credential_pool_strategies": {"type":"dict","default":{},"doc":"","group":"general","effect":"live"},
122
- "cron.max_parallel_jobs": {"type":"null","default":null,"doc":"Maximum number of due jobs to run in parallel per tick. null/0 = unbounded (limited only by thread count). 1 = serial (pre-v0.9 behaviour). Also overridable via HERMES_CRON_MAX_PARALLEL env var.","group":"cron","effect":"live"},
123
- "cron.wrap_response": {"type":"bool","default":true,"doc":"Wrap delivered cron responses with a header (task name) and footer (\"The agent cannot see this message\"). Set to false for clean output.","group":"cron","effect":"live"},
124
- "curator.archive_after_days": {"type":"int","default":90,"doc":"Archive a skill (move to skills/.archive/) after this many days without use. Archived skills are recoverable — no auto-deletion.","group":"curator","effect":"live"},
125
- "curator.backup.enabled": {"type":"bool","default":true,"doc":"","group":"curator","effect":"live"},
126
- "curator.backup.keep": {"type":"int","default":5,"doc":"retain last N regular snapshots","group":"curator","effect":"live"},
127
- "curator.enabled": {"type":"bool","default":true,"doc":"","group":"curator","effect":"live"},
128
- "curator.interval_hours": {"type":"int","default":168,"doc":"How long to wait between curator runs (hours). Default: 7 days.","group":"curator","effect":"live"},
129
- "curator.min_idle_hours": {"type":"int","default":2,"doc":"Only run when the agent has been idle at least this long (hours).","group":"curator","effect":"live"},
130
- "curator.stale_after_days": {"type":"int","default":30,"doc":"Mark a skill as \"stale\" after this many days without use.","group":"curator","effect":"live"},
131
- "custom_prompt": {"type":"str","default":"","doc":"Ad-hoc system-prompt addendum set via /prompt.","group":"general","effect":"live"},
132
- "custom_providers": {"type":"dict","default":{},"doc":"OpenAI-compatible provider definitions keyed by name.","group":"general","effect":"live"},
133
- "dashboard.theme": {"type":"str","default":"default","doc":"Dashboard visual theme: \"default\", \"midnight\", \"ember\", \"mono\", \"cyberpunk\", \"rose\"","group":"dashboard","effect":"live"},
134
- "delegation.api_key": {"type":"str","default":"","doc":"API key for delegation.base_url (falls back to OPENAI_API_KEY)","group":"delegation","effect":"session"},
135
- "delegation.base_url": {"type":"str","default":"","doc":"direct OpenAI-compatible endpoint for subagents","group":"delegation","effect":"session"},
136
- "delegation.child_timeout_seconds": {"type":"int","default":600,"doc":"wall-clock timeout for each child agent (floor 30s, no ceiling). High-reasoning models on large tasks (e.g. gpt-5.5 xhigh, opus-4.6) need generous budgets; raise if children time out before producing output.","group":"delegation","effect":"session"},
137
- "delegation.inherit_mcp_toolsets": {"type":"bool","default":true,"doc":"When delegate_task narrows child toolsets explicitly, preserve any MCP toolsets the parent already has enabled. On by default so narrowing (e.g. toolsets=[\"web\",\"browser\"]) expresses \"I want these extras\" without silently stripping MCP tools the parent already has. Set to false for strict intersection.","group":"delegation","effect":"session"},
138
- "delegation.max_concurrent_children": {"type":"int","default":3,"doc":"max parallel children per batch; floor of 1 enforced, no ceiling","group":"delegation","effect":"session"},
139
- "delegation.max_iterations": {"type":"int","default":50,"doc":"per-subagent iteration cap (each subagent gets its own budget, independent of the parent's max_iterations)","group":"delegation","effect":"session"},
140
- "delegation.max_spawn_depth": {"type":"int","default":1,"doc":"Orchestrator role controls (see tools/delegate_tool.py:_get_max_spawn_depth and _get_orchestrator_enabled). Values are clamped to [1, 3] with a warning log if out of range.","group":"delegation","effect":"session"},
141
- "delegation.model": {"type":"str","default":"","doc":"e.g. \"google/gemini-3-flash-preview\" (empty = inherit parent model)","group":"delegation","effect":"session"},
142
- "delegation.orchestrator_enabled": {"type":"bool","default":true,"doc":"kill switch for role=\"orchestrator\"","group":"delegation","effect":"session"},
143
- "delegation.provider": {"type":"str","default":"","doc":"e.g. \"openrouter\" (empty = inherit parent provider + credentials)","group":"delegation","effect":"session"},
144
- "delegation.reasoning_effort": {"type":"str","default":"","doc":"reasoning effort for subagents: \"xhigh\", \"high\", \"medium\", \"low\", \"minimal\", \"none\" (empty = inherit parent's level)","group":"delegation","effect":"session"},
145
- "delegation.subagent_auto_approve": {"type":"bool","default":false,"doc":"When a subagent hits a dangerous-command approval prompt, the parent's prompt_toolkit TUI owns stdin — a thread-local input() call from the subagent worker would deadlock the parent UI. To avoid the deadlock, subagent threads ALWAYS resolve approvals non-interactively: false (default) → auto-deny with a logger.warning audit line (safe) true → auto-approve \"once\" with a logger.warning audit line Flip to true only if you trust delegated work to run dangerous cmds without human review (cron pipelines, batch automation, etc.).","group":"delegation","effect":"session"},
146
- "discord.allowed_channels": {"type":"str","default":"","doc":"If set, bot ONLY responds in these channel IDs (whitelist)","group":"discord","effect":"live"},
147
- "discord.auto_thread": {"type":"bool","default":true,"doc":"Auto-create threads on @mention in channels (like Slack)","group":"discord","effect":"live"},
148
- "discord.channel_prompts": {"type":"dict","default":{},"doc":"Per-channel ephemeral system prompts (forum parents apply to child threads)","group":"discord","effect":"live"},
149
- "discord.free_response_channels": {"type":"str","default":"","doc":"Comma-separated channel IDs where bot responds without mention","group":"discord","effect":"live"},
150
- "discord.reactions": {"type":"bool","default":true,"doc":"Add 👀/✅/❌ reactions to messages during processing","group":"discord","effect":"live"},
151
- "discord.require_mention": {"type":"bool","default":true,"doc":"Require @mention to respond in server channels","group":"discord","effect":"live"},
152
- "discord.server_actions": {"type":"str","default":"","doc":"discord / discord_admin tools: restrict which actions the agent may call. Default (empty) = all actions allowed (subject to bot privileged intents). Accepts comma-separated string (\"list_guilds,list_channels,fetch_messages\") or YAML list. Unknown names are dropped with a warning at load time. Actions: list_guilds, server_info, list_channels, channel_info, list_roles, member_info, search_members, fetch_messages, list_pins, pin_message, unpin_message, create_thread, add_role, remove_role.","group":"discord","effect":"live"},
153
- "display.bell_on_complete": {"type":"bool","default":false,"doc":"","group":"display","effect":"live"},
154
- "display.busy_input_mode": {"type":"str","default":"interrupt","doc":"interrupt | queue | steer","group":"display","effect":"live"},
155
- "display.compact": {"type":"bool","default":false,"doc":"","group":"display","effect":"live"},
156
- "display.details_mode": {"type":"str","default":"collapsed","doc":"Tool-progress section fold state: hidden | collapsed | expanded.","group":"display","effect":"live"},
157
- "display.ephemeral_system_ttl": {"type":"int","default":0,"doc":"Auto-delete system-notice replies (e.g. \"✨ New session started!\", \"♻ Restarting gateway…\", \"⚡ Stopped…\") after N seconds on platforms that support message deletion (currently Telegram; other platforms ignore and leave the message in place). Only affects slash-command replies wrapped with gateway.platforms.base.EphemeralReply — agent responses and content messages are never touched. Default 0 (disabled) preserves prior behavior.","group":"display","effect":"live"},
158
- "display.final_response_markdown": {"type":"str","default":"strip","doc":"render | strip | raw","group":"display","effect":"live"},
159
- "display.inline_diffs": {"type":"bool","default":true,"doc":"Show inline diff previews for write actions (write_file, patch, skill_manage)","group":"display","effect":"live"},
160
- "display.interim_assistant_messages": {"type":"bool","default":true,"doc":"Gateway: show natural mid-turn assistant status messages","group":"display","effect":"live"},
161
- "display.personality": {"type":"str","default":"kawaii","doc":"","group":"display","effect":"live"},
162
- "display.platforms": {"type":"dict","default":{},"doc":"Per-platform display overrides: {\"telegram\": {\"tool_progress\": \"all\"}, \"slack\": {\"tool_progress\": \"off\"}}","group":"display","effect":"live"},
163
- "display.resume_display": {"type":"str","default":"full","doc":"","group":"display","effect":"live"},
164
- "display.runtime_footer.enabled": {"type":"bool","default":false,"doc":"","group":"display","effect":"live"},
165
- "display.runtime_footer.fields": {"type":"list","default":["model","context_pct","cwd"],"doc":"Order shown; drop any to hide","group":"display","effect":"live"},
166
- "display.show_cost": {"type":"bool","default":false,"doc":"Show $ cost in the status bar (off by default)","group":"display","effect":"live"},
167
- "display.show_reasoning": {"type":"bool","default":false,"doc":"","group":"display","effect":"live"},
168
- "display.skin": {"type":"str","default":"default","doc":"","group":"display","effect":"live"},
169
- "display.streaming": {"type":"bool","default":false,"doc":"","group":"display","effect":"live"},
170
- "display.thinking_mode": {"type":"str","default":"collapsed","doc":"Reasoning display: collapsed | truncated | full.","group":"display","effect":"live"},
171
- "display.tool_preview_length": {"type":"int","default":0,"doc":"Max chars for tool call previews (0 = no limit, show full paths/commands)","group":"display","effect":"live"},
172
- "display.tool_progress": {"type":"str","default":"all","doc":"Tool-progress verbosity: off | new | all | verbose.","group":"display","effect":"live"},
173
- "display.tool_progress_command": {"type":"bool","default":false,"doc":"Enable /verbose command in messaging gateway","group":"display","effect":"live"},
174
- "display.tool_progress_overrides": {"type":"dict","default":{},"doc":"DEPRECATED — use display.platforms instead","group":"display","effect":"live"},
175
- "display.tui_auto_resume_recent": {"type":"bool","default":false,"doc":"When true, `hermes --tui` auto-resumes the most recent human- facing session on launch instead of forging a fresh one. Mirrors `hermes -c` muscle memory. Default off so existing users aren't surprised. HERMES_TUI_RESUME=<id> always wins.","group":"display","effect":"live"},
176
- "display.tui_compact": {"type":"bool","default":false,"doc":"Ink-TUI compact layout.","group":"display","effect":"live"},
177
- "display.tui_mouse": {"type":"bool","default":true,"doc":"Ink-TUI mouse support.","group":"display","effect":"live"},
178
- "display.tui_status_indicator": {"type":"str","default":"kaomoji","doc":"TUI busy indicator style: kaomoji (default), emoji, unicode (braille spinner), or ascii. Live-swappable via `/indicator <style>`.","group":"display","effect":"live"},
179
- "display.tui_statusbar": {"type":"str","default":"top","doc":"Ink-TUI statusbar placement: top | bottom | off.","group":"display","effect":"live"},
180
- "display.user_message_preview.first_lines": {"type":"int","default":2,"doc":"","group":"display","effect":"live"},
181
- "display.user_message_preview.last_lines": {"type":"int","default":2,"doc":"","group":"display","effect":"live"},
182
- "fallback_model": {"type":"dict","default":null,"doc":"Fallback model (dict) or chain (list of dicts) for provider failover.","group":"general","effect":"live"},
183
- "fallback_providers": {"type":"list","default":[],"doc":"","group":"general","effect":"live"},
184
- "file_read_max_chars": {"type":"int","default":100000,"doc":"Maximum characters returned by a single read_file call. Reads that exceed this are rejected with guidance to use offset+limit. 100K chars ≈ 25–35K tokens across typical tokenisers.","group":"general","effect":"live"},
185
- "goals.max_turns": {"type":"int","default":20,"doc":"Max continuation turns before Hermes auto-pauses the goal and asks the user to /goal resume. Protects against judge false negatives (goal actually done but judge says continue) and unbounded model spend on fuzzy / unachievable goals.","group":"goals","effect":"live"},
186
- "honcho": {"type":"dict","default":{},"doc":"Honcho AI-native memory -- reads ~/.honcho/config.json as single source of truth. This section is only needed for hermes-specific overrides; everything else (apiKey, workspace, peerName, sessions, enabled) comes from the global config.","group":"general","effect":"live"},
187
- "hooks": {"type":"dict","default":{},"doc":"Shell-script hooks — declarative bridge that invokes shell scripts on plugin-hook events (pre_tool_call, post_tool_call, pre_llm_call, subagent_stop, etc.). Each entry maps an event name to a list of {matcher, command, timeout} dicts. First registration of a new command prompts the user for consent; subsequent runs reuse the stored approval from ~/.hermes/shell-hooks-allowlist.json. See `website/docs/user-guide/features/hooks.md` for schema + examples.","group":"general","effect":"live"},
188
- "hooks_auto_accept": {"type":"bool","default":false,"doc":"Auto-accept shell-hook registrations without a TTY prompt. Also toggleable per-invocation via --accept-hooks or HERMES_ACCEPT_HOOKS=1. Gateway / cron / non-interactive runs need this (or one of the other channels) to pick up newly-added hooks.","group":"general","effect":"live"},
189
- "human_delay.max_ms": {"type":"int","default":2500,"doc":"","group":"human_delay","effect":"live"},
190
- "human_delay.min_ms": {"type":"int","default":800,"doc":"","group":"human_delay","effect":"live"},
191
- "human_delay.mode": {"type":"str","default":"off","doc":"","group":"human_delay","effect":"live"},
192
- "kanban.dispatch_in_gateway": {"type":"bool","default":true,"doc":"Run the dispatcher inside the gateway process. On by default — the cost is ~300µs every `dispatch_interval_seconds` when idle, and gateway is the supervisor users already have. Set to false only if you run the dispatcher as a separate systemd unit or don't want the gateway to spawn workers.","group":"kanban","effect":"live"},
193
- "kanban.dispatch_interval_seconds": {"type":"int","default":60,"doc":"Seconds between dispatcher ticks (idle or not). Lower = snappier pickup of newly-ready tasks; higher = less SQL pressure.","group":"kanban","effect":"live"},
194
- "logging.backup_count": {"type":"int","default":3,"doc":"Number of rotated backup files to keep","group":"logging","effect":"live"},
195
- "logging.level": {"type":"str","default":"INFO","doc":"Minimum level for agent.log: DEBUG, INFO, WARNING","group":"logging","effect":"live"},
196
- "logging.max_size_mb": {"type":"int","default":5,"doc":"Max size per log file before rotation","group":"logging","effect":"live"},
197
- "mattermost.channel_prompts": {"type":"dict","default":{},"doc":"Per-channel ephemeral system prompts","group":"mattermost","effect":"live"},
198
- "mcp_servers": {"type":"dict","default":{},"doc":"MCP server definitions keyed by name.","group":"general","effect":"restart"},
199
- "memory.memory_char_limit": {"type":"int","default":2200,"doc":"~800 tokens at 2.75 chars/token","group":"memory","effect":"session"},
200
- "memory.memory_enabled": {"type":"bool","default":true,"doc":"","group":"memory","effect":"session"},
201
- "memory.provider": {"type":"str","default":"","doc":"External memory provider plugin (empty = built-in only). Set to a provider name to activate: \"openviking\", \"mem0\", \"hindsight\", \"holographic\", \"retaindb\", \"byterover\". Only ONE external provider is allowed at a time.","group":"memory","effect":"session"},
202
- "memory.user_char_limit": {"type":"int","default":1375,"doc":"~500 tokens at 2.75 chars/token","group":"memory","effect":"session"},
203
- "memory.user_profile_enabled": {"type":"bool","default":true,"doc":"","group":"memory","effect":"session"},
204
- "model": {"type":"str","default":"","doc":"","group":"general","effect":"live"},
205
- "model_catalog.enabled": {"type":"bool","default":true,"doc":"","group":"model_catalog","effect":"live"},
206
- "model_catalog.providers": {"type":"dict","default":{},"doc":"Optional per-provider override URLs for third parties that want to self-host their own curation list using the same schema. Example: providers: openrouter: url: https://example.com/my-curation.json","group":"model_catalog","effect":"live"},
207
- "model_catalog.ttl_hours": {"type":"int","default":24,"doc":"Disk cache TTL in hours. Beyond this, the CLI refetches on the next /model or `hermes model` invocation; network failures silently fall back to the stale cache.","group":"model_catalog","effect":"live"},
208
- "model_catalog.url": {"type":"str","default":"https://hermes-agent.nousresearch.com/docs/api/model-catalog.json","doc":"","group":"model_catalog","effect":"live"},
209
- "network.force_ipv4": {"type":"bool","default":false,"doc":"Force IPv4 connections. On servers with broken or unreachable IPv6, Python tries AAAA records first and hangs for the full TCP timeout before falling back to IPv4. Set to true to skip IPv6 entirely.","group":"network","effect":"live"},
210
- "onboarding.seen": {"type":"dict","default":{},"doc":"","group":"onboarding","effect":"live"},
211
- "personalities": {"type":"dict","default":{},"doc":"Custom personalities — add your own entries here Supports string format: {\"name\": \"system prompt\"} Or dict format: {\"name\": {\"description\": \"...\", \"system_prompt\": \"...\", \"tone\": \"...\", \"style\": \"...\"}}","group":"general","effect":"live"},
212
- "prefill_messages_file": {"type":"str","default":"","doc":"Ephemeral prefill messages file — JSON list of {role, content} dicts injected at the start of every API call for few-shot priming. Never saved to sessions, logs, or trajectories.","group":"general","effect":"live"},
213
- "privacy.redact_pii": {"type":"bool","default":false,"doc":"When True, hash user IDs and strip phone numbers from LLM context","group":"privacy","effect":"live"},
214
- "prompt_caching.cache_ttl": {"type":"str","default":"5m","doc":"","group":"prompt_caching","effect":"live"},
215
- "provider": {"type":"str","default":"","doc":"Default model provider.","group":"general","effect":"live"},
216
- "providers": {"type":"dict","default":{},"doc":"","group":"general","effect":"live"},
217
- "quick_commands": {"type":"dict","default":{},"doc":"User-defined quick commands that bypass the agent loop (type: exec only)","group":"general","effect":"live"},
218
- "security.allow_private_urls": {"type":"bool","default":false,"doc":"Allow requests to private/internal IPs (for OpenWrt, proxies, VPNs)","group":"security","effect":"live"},
219
- "security.redact_secrets": {"type":"bool","default":false,"doc":"","group":"security","effect":"live"},
220
- "security.tirith_enabled": {"type":"bool","default":true,"doc":"","group":"security","effect":"live"},
221
- "security.tirith_fail_open": {"type":"bool","default":true,"doc":"","group":"security","effect":"live"},
222
- "security.tirith_path": {"type":"str","default":"tirith","doc":"","group":"security","effect":"live"},
223
- "security.tirith_timeout": {"type":"int","default":5,"doc":"","group":"security","effect":"live"},
224
- "security.website_blocklist.domains": {"type":"list","default":[],"doc":"","group":"security","effect":"live"},
225
- "security.website_blocklist.enabled": {"type":"bool","default":false,"doc":"","group":"security","effect":"live"},
226
- "security.website_blocklist.shared_files": {"type":"list","default":[],"doc":"","group":"security","effect":"live"},
227
- "sessions.auto_prune": {"type":"bool","default":false,"doc":"When true, prune ended sessions older than retention_days once per (roughly) min_interval_hours at CLI/gateway/cron startup. Only touches ended sessions — active sessions are always preserved. Default false: session history is valuable for search recall, and silently deleting it could surprise users. Opt in explicitly.","group":"sessions","effect":"live"},
228
- "sessions.min_interval_hours": {"type":"int","default":24,"doc":"Minimum hours between auto-maintenance runs (avoids repeating the sweep on every CLI invocation). Tracked via state_meta in state.db itself, so it's shared across all processes.","group":"sessions","effect":"live"},
229
- "sessions.retention_days": {"type":"int","default":90,"doc":"How many days of ended-session history to keep. Matches the default of ``hermes sessions prune``.","group":"sessions","effect":"live"},
230
- "sessions.vacuum_after_prune": {"type":"bool","default":true,"doc":"VACUUM after a prune that actually deleted rows. SQLite does not reclaim disk space on DELETE — freed pages are just reused on subsequent INSERTs — so without VACUUM the file stays bloated even after pruning. VACUUM blocks writes for a few seconds per 100MB, so it only runs at startup, and only when prune deleted ≥1 session.","group":"sessions","effect":"live"},
231
- "skills.external_dirs": {"type":"list","default":[],"doc":"e.g. [\"~/.agents/skills\", \"/shared/team-skills\"]","group":"skills","effect":"restart"},
232
- "skills.guard_agent_created": {"type":"bool","default":false,"doc":"Run the keyword/pattern security scanner on skills the agent writes via skill_manage (create/edit/patch). Off by default because the agent can already execute the same code paths via terminal() with no gate, so the scan adds friction (blocks skills that mention risky keywords in prose) without meaningful security. Turn on if you want the belt-and-suspenders — a dangerous verdict will then surface as a tool error to the agent, which can retry with the flagged content removed. External hub installs (trusted/community sources) are always scanned regardless of this setting.","group":"skills","effect":"live"},
233
- "skills.inline_shell": {"type":"bool","default":false,"doc":"Pre-execute inline shell snippets written as !`cmd` in SKILL.md body. Their stdout is inlined into the skill message before the agent reads it, so skills can inject dynamic context (dates, git state, detected tool versions, …). Off by default because any content from the skill author runs on the host without approval; only enable for skill sources you trust.","group":"skills","effect":"live"},
234
- "skills.inline_shell_timeout": {"type":"int","default":10,"doc":"Timeout (seconds) for each !`cmd` snippet when inline_shell is on.","group":"skills","effect":"live"},
235
- "skills.template_vars": {"type":"bool","default":true,"doc":"Substitute ${HERMES_SKILL_DIR} and ${HERMES_SESSION_ID} in SKILL.md content with the absolute skill directory and the active session id before the agent sees it. Lets skill authors reference bundled scripts without the agent having to join paths.","group":"skills","effect":"live"},
236
- "slack.channel_prompts": {"type":"dict","default":{},"doc":"Per-channel ephemeral system prompts","group":"slack","effect":"live"},
237
- "stt.enabled": {"type":"bool","default":true,"doc":"","group":"stt","effect":"live"},
238
- "stt.local.language": {"type":"str","default":"","doc":"auto-detect by default; set to \"en\", \"es\", \"fr\", etc. to force","group":"stt","effect":"live"},
239
- "stt.local.model": {"type":"str","default":"base","doc":"tiny, base, small, medium, large-v3","group":"stt","effect":"live"},
240
- "stt.mistral.model": {"type":"str","default":"voxtral-mini-latest","doc":"voxtral-mini-latest, voxtral-mini-2602","group":"stt","effect":"live"},
241
- "stt.openai.model": {"type":"str","default":"whisper-1","doc":"whisper-1, gpt-4o-mini-transcribe, gpt-4o-transcribe","group":"stt","effect":"live"},
242
- "stt.provider": {"type":"str","default":"local","doc":"\"local\" (free, faster-whisper) | \"groq\" | \"openai\" (Whisper API) | \"mistral\" (Voxtral Transcribe)","group":"stt","effect":"live"},
243
- "telegram.channel_prompts": {"type":"dict","default":{},"doc":"Per-chat/topic ephemeral system prompts (topics inherit from parent group)","group":"telegram","effect":"live"},
244
- "telegram.reactions": {"type":"bool","default":false,"doc":"Add 👀/✅/❌ reactions to messages during processing","group":"telegram","effect":"live"},
245
- "terminal.auto_source_bashrc": {"type":"bool","default":true,"doc":"When true (default), Hermes sources the user's shell rc files (``~/.profile``, ``~/.bash_profile``, ``~/.bashrc``) in the login shell used to build the environment snapshot. This captures PATH additions, shell functions, and aliases — which a plain ``bash -l -c`` would otherwise miss because bash skips bashrc in non-interactive login mode, and because a default Debian/Ubuntu ``~/.bashrc`` short-circuits on non-interactive sources. ``~/.profile`` and ``~/.bash_profile`` are tried first because ``n`` / ``nvm`` / ``asdf`` installers typically write their PATH exports there without an interactivity guard. Turn this off if your rc files misbehave when sourced non-interactively (e.g. one that hard-exits on TTY checks).","group":"terminal","effect":"restart"},
246
- "terminal.backend": {"type":"str","default":"local","doc":"","group":"terminal","effect":"restart"},
247
- "terminal.container_cpu": {"type":"int","default":1,"doc":"Container resource limits (docker, singularity, modal, daytona, vercel_sandbox — ignored for local/ssh)","group":"terminal","effect":"restart"},
248
- "terminal.container_disk": {"type":"int","default":51200,"doc":"MB (default 50GB)","group":"terminal","effect":"restart"},
249
- "terminal.container_memory": {"type":"int","default":5120,"doc":"MB (default 5GB)","group":"terminal","effect":"restart"},
250
- "terminal.container_persistent": {"type":"bool","default":true,"doc":"Persist filesystem across sessions","group":"terminal","effect":"restart"},
251
- "terminal.cwd": {"type":"str","default":".","doc":"Use current directory","group":"terminal","effect":"restart"},
252
- "terminal.daytona_image": {"type":"str","default":"nikolaik/python-nodejs:python3.11-nodejs20","doc":"","group":"terminal","effect":"restart"},
253
- "terminal.docker_env": {"type":"dict","default":{},"doc":"Explicit environment variables to set inside Docker containers. Unlike docker_forward_env (which reads values from the host process), docker_env lets you specify exact key-value pairs — useful when Hermes runs as a systemd service without access to the user's shell environment. Example: {\"SSH_AUTH_SOCK\": \"/run/user/1000/ssh-agent.sock\"}","group":"terminal","effect":"restart"},
254
- "terminal.docker_forward_env": {"type":"list","default":[],"doc":"","group":"terminal","effect":"restart"},
255
- "terminal.docker_image": {"type":"str","default":"nikolaik/python-nodejs:python3.11-nodejs20","doc":"","group":"terminal","effect":"restart"},
256
- "terminal.docker_mount_cwd_to_workspace": {"type":"bool","default":false,"doc":"Explicit opt-in: mount the host cwd into /workspace for Docker sessions. Default off because passing host directories into a sandbox weakens isolation.","group":"terminal","effect":"restart"},
257
- "terminal.docker_run_as_host_user": {"type":"bool","default":false,"doc":"Explicit opt-in: run the Docker container as the host user's uid:gid (via `--user`). When enabled, files written into bind-mounted dirs (docker_volumes, the persistent workspace, or the auto-mounted cwd) are owned by your host user instead of root, which avoids needing `sudo chown` after container runs. Default off to preserve behavior for images whose entrypoints expect to start as root (e.g. the bundled Hermes image, which drops to the `hermes` user via gosu). When on, SETUID/SETGID caps are omitted from the container since no privilege drop is needed.","group":"terminal","effect":"restart"},
258
- "terminal.docker_volumes": {"type":"list","default":[],"doc":"Docker volume mounts — share host directories with the container. Each entry is \"host_path:container_path\" (standard Docker -v syntax). Example: [\"/home/user/projects:/workspace/projects\", \"/home/user/.hermes/cache/documents:/output\"] For gateway MEDIA delivery, write inside Docker to /output/... and emit the host-visible path in MEDIA:, not the container path.","group":"terminal","effect":"restart"},
259
- "terminal.env_passthrough": {"type":"list","default":[],"doc":"Environment variables to pass through to sandboxed execution (terminal and execute_code). Skill-declared required_environment_variables are passed through automatically; this list is for non-skill use cases.","group":"terminal","effect":"restart"},
260
- "terminal.modal_image": {"type":"str","default":"nikolaik/python-nodejs:python3.11-nodejs20","doc":"","group":"terminal","effect":"restart"},
261
- "terminal.modal_mode": {"type":"str","default":"auto","doc":"","group":"terminal","effect":"restart"},
262
- "terminal.persistent_shell": {"type":"bool","default":true,"doc":"Persistent shell — keep a long-lived bash shell across execute() calls so cwd/env vars/shell variables survive between commands. Enabled by default for non-local backends (SSH); local is always opt-in via TERMINAL_LOCAL_PERSISTENT env var.","group":"terminal","effect":"restart"},
263
- "terminal.shell_init_files": {"type":"list","default":[],"doc":"Extra files to source in the login shell when building the per-session environment snapshot. Use this when tools like nvm, pyenv, asdf, or custom PATH entries are registered by files that a bash login shell would skip — most commonly ``~/.bashrc`` (bash doesn't source bashrc in non-interactive login mode) or zsh-specific files like ``~/.zshrc`` / ``~/.zprofile``. Paths support ``~`` / ``${VAR}``. Missing files are silently skipped. When empty, Hermes auto-sources ``~/.profile``, ``~/.bash_profile``, and ``~/.bashrc`` (in that order) if the snapshot shell is bash (this is the ``auto_source_bashrc`` behaviour — disable with that key if you want strict login-only semantics).","group":"terminal","effect":"restart"},
264
- "terminal.singularity_image": {"type":"str","default":"docker://nikolaik/python-nodejs:python3.11-nodejs20","doc":"","group":"terminal","effect":"restart"},
265
- "terminal.timeout": {"type":"int","default":180,"doc":"","group":"terminal","effect":"restart"},
266
- "terminal.vercel_runtime": {"type":"str","default":"node24","doc":"","group":"terminal","effect":"restart"},
267
- "timezone": {"type":"str","default":"","doc":"IANA timezone (e.g. \"Asia/Kolkata\", \"America/New_York\"). Empty string means use server-local time.","group":"general","effect":"live"},
268
- "tool_loop_guardrails.hard_stop_after.exact_failure": {"type":"int","default":5,"doc":"","group":"tool_loop_guardrails","effect":"live"},
269
- "tool_loop_guardrails.hard_stop_after.idempotent_no_progress": {"type":"int","default":5,"doc":"","group":"tool_loop_guardrails","effect":"live"},
270
- "tool_loop_guardrails.hard_stop_after.same_tool_failure": {"type":"int","default":8,"doc":"","group":"tool_loop_guardrails","effect":"live"},
271
- "tool_loop_guardrails.hard_stop_enabled": {"type":"bool","default":false,"doc":"","group":"tool_loop_guardrails","effect":"live"},
272
- "tool_loop_guardrails.warn_after.exact_failure": {"type":"int","default":2,"doc":"","group":"tool_loop_guardrails","effect":"live"},
273
- "tool_loop_guardrails.warn_after.idempotent_no_progress": {"type":"int","default":2,"doc":"","group":"tool_loop_guardrails","effect":"live"},
274
- "tool_loop_guardrails.warn_after.same_tool_failure": {"type":"int","default":3,"doc":"","group":"tool_loop_guardrails","effect":"live"},
275
- "tool_loop_guardrails.warnings_enabled": {"type":"bool","default":true,"doc":"","group":"tool_loop_guardrails","effect":"live"},
276
- "tool_output.max_bytes": {"type":"int","default":50000,"doc":"","group":"tool_output","effect":"live"},
277
- "tool_output.max_line_length": {"type":"int","default":2000,"doc":"","group":"tool_output","effect":"live"},
278
- "tool_output.max_lines": {"type":"int","default":2000,"doc":"","group":"tool_output","effect":"live"},
279
- "toolsets": {"type":"list","default":["hermes-cli"],"doc":"","group":"general","effect":"restart"},
280
- "tts.edge.voice": {"type":"str","default":"en-US-AriaNeural","doc":"","group":"tts","effect":"live"},
281
- "tts.elevenlabs.model_id": {"type":"str","default":"eleven_multilingual_v2","doc":"","group":"tts","effect":"live"},
282
- "tts.elevenlabs.voice_id": {"type":"str","default":"pNInz6obpgDQGcFmaJgB","doc":"Adam","group":"tts","effect":"live"},
283
- "tts.mistral.model": {"type":"str","default":"voxtral-mini-tts-2603","doc":"","group":"tts","effect":"live"},
284
- "tts.mistral.voice_id": {"type":"str","default":"c69964a6-ab8b-4f8a-9465-ec0925096ec8","doc":"Paul - Neutral","group":"tts","effect":"live"},
285
- "tts.neutts.device": {"type":"str","default":"cpu","doc":"cpu, cuda, or mps","group":"tts","effect":"live"},
286
- "tts.neutts.model": {"type":"str","default":"neuphonic/neutts-air-q4-gguf","doc":"HuggingFace model repo","group":"tts","effect":"live"},
287
- "tts.neutts.ref_audio": {"type":"str","default":"","doc":"Path to reference voice audio (empty = bundled default)","group":"tts","effect":"live"},
288
- "tts.neutts.ref_text": {"type":"str","default":"","doc":"Path to reference voice transcript (empty = bundled default)","group":"tts","effect":"live"},
289
- "tts.openai.model": {"type":"str","default":"gpt-4o-mini-tts","doc":"","group":"tts","effect":"live"},
290
- "tts.openai.voice": {"type":"str","default":"alloy","doc":"","group":"tts","effect":"live"},
291
- "tts.piper.voice": {"type":"str","default":"en_US-lessac-medium","doc":"Voice name (e.g. \"en_US-lessac-medium\") downloaded on first use, OR an absolute path to a pre-downloaded .onnx file. Full voice list: https://github.com/OHF-Voice/piper1-gpl/blob/main/docs/VOICES.md","group":"tts","effect":"live"},
292
- "tts.provider": {"type":"str","default":"edge","doc":"\"edge\" (free) | \"elevenlabs\" (premium) | \"openai\" | \"xai\" | \"minimax\" | \"mistral\" | \"gemini\" | \"neutts\" (local) | \"kittentts\" (local) | \"piper\" (local)","group":"tts","effect":"live"},
293
- "tts.xai.bit_rate": {"type":"int","default":128000,"doc":"","group":"tts","effect":"live"},
294
- "tts.xai.language": {"type":"str","default":"en","doc":"","group":"tts","effect":"live"},
295
- "tts.xai.sample_rate": {"type":"int","default":24000,"doc":"","group":"tts","effect":"live"},
296
- "tts.xai.voice_id": {"type":"str","default":"eve","doc":"","group":"tts","effect":"live"},
297
- "updates.backup_keep": {"type":"int","default":5,"doc":"How many pre-update backup zips to retain. Older ones are pruned automatically after each successful backup.","group":"updates","effect":"live"},
298
- "updates.pre_update_backup": {"type":"bool","default":false,"doc":"Run a full ``hermes backup``-style zip of HERMES_HOME before every ``hermes update``. Backups land in ``<HERMES_HOME>/backups/`` and can be restored with ``hermes import <path>``. Off by default — on large HERMES_HOME directories the zip can add minutes to every update. Set to true to re-enable, or pass ``--backup`` to opt in for a single update run.","group":"updates","effect":"live"},
299
- "voice.auto_tts": {"type":"bool","default":false,"doc":"","group":"voice","effect":"live"},
300
- "voice.beep_enabled": {"type":"bool","default":true,"doc":"Play record start/stop beeps in CLI voice mode","group":"voice","effect":"live"},
301
- "voice.max_recording_seconds": {"type":"int","default":120,"doc":"","group":"voice","effect":"live"},
302
- "voice.record_key": {"type":"str","default":"ctrl+b","doc":"","group":"voice","effect":"live"},
303
- "voice.silence_duration": {"type":"float","default":3,"doc":"Seconds of silence before auto-stop","group":"voice","effect":"live"},
304
- "voice.silence_threshold": {"type":"int","default":200,"doc":"RMS below this = silence (0-32767)","group":"voice","effect":"live"},
305
- "whatsapp": {"type":"dict","default":{},"doc":"WhatsApp platform settings (gateway mode)","group":"general","effect":"live"},
306
- }
307
-
308
- export const SCHEMA_KEYS = Object.keys(SCHEMA)
@@ -1,52 +0,0 @@
1
- // Scrollable read-only text dialog — oc ui/dialog-alert equivalent.
2
-
3
- import { useState } from "react"
4
- import { LEFT_BAR } from "../ui/borders"
5
- import { useKeyboard } from "@opentui/react"
6
- import { useKeys } from "../keys"
7
- import { useTheme } from "../theme"
8
- import type { DialogContext } from "../ui/dialog"
9
- import { copy } from "../utils/clipboard"
10
-
11
- export function openAlert(dialog: DialogContext, title: string, body: string) {
12
- dialog.replace(<Alert title={title} body={body} onClose={() => dialog.clear()} />)
13
- }
14
-
15
- const Alert = (props: { title: string; body: string; onClose: () => void }) => {
16
- const theme = useTheme().theme
17
- const keys = useKeys()
18
- const [copied, setCopied] = useState(false)
19
-
20
- const doCopy = () => {
21
- void copy(props.body)
22
- setCopied(true)
23
- setTimeout(() => setCopied(false), 900)
24
- }
25
-
26
- useKeyboard((key) => {
27
- if (keys.match("dialog.cancel", key) || keys.match("dialog.accept", key)) props.onClose()
28
- if (keys.match("dialog.copy", key)) doCopy()
29
- })
30
- return (
31
- <box flexDirection="column" width={84} maxHeight={28}
32
- border={["left"]} borderColor={theme.info}
33
- customBorderChars={LEFT_BAR}
34
- backgroundColor={theme.backgroundPanel}
35
- paddingLeft={2} paddingRight={2} paddingY={1} gap={1}>
36
- <box height={1}>
37
- <text><span fg={theme.info}>◈ </span><span fg={theme.text}>{props.title}</span></text>
38
- </box>
39
- <scrollbox scrollY flexGrow={1}>
40
- <text fg={theme.text} wrapMode="word">{props.body}</text>
41
- </scrollbox>
42
- <box height={1} flexDirection="row">
43
- <box flexShrink={0}>
44
- <text fg={theme.textMuted}>{`${keys.print("dialog.cancel")} close · ${keys.print("dialog.copy")} `}</text>
45
- </box>
46
- <box flexShrink={0} onMouseDown={(e) => { e.stopPropagation(); doCopy() }}>
47
- <text fg={copied ? theme.success : theme.textMuted}><u>{copied ? "copied" : "copy"}</u></text>
48
- </box>
49
- </box>
50
- </box>
51
- )
52
- }