-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path.env.example
More file actions
418 lines (388 loc) · 29.2 KB
/
Copy path.env.example
File metadata and controls
418 lines (388 loc) · 29.2 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
# ═══════════════════════════════════════════════════════════════════════════
# hermes-max configuration contract. Copy to `.env` and edit.
# cp .env.example .env
#
# MINIMUM VIABLE = 2 LINES. You need EITHER a local endpoint OR one paid key:
# • Profile A (own a GPU): set VLLM_BASE_URL + OPENROUTER_API_KEY → hm up --free
# • Profile B (no GPU): set DEEPINFRA_API_KEY (or DEEPSEEK_API_KEY) → hm up --full
# Everything else below is optional — a missing key silently drops that rung.
# Full guidance: README.md · docs/profiles.md
# ═══════════════════════════════════════════════════════════════════════════
# ── DEPLOY PROFILE (the bifurcation) ─────────────────────────────────────────
# ONE codebase, two profiles. bootstrap.sh auto-detects and SUGGESTS one; this
# value (or --profile / the DEPLOY_PROFILE env var) overrides the suggestion.
# gpu_local (DEFAULT, maximalist): CUDA box; local OR cloud chat via
# $VLLM_BASE_URL; optional local Qwen3 embed/rerank (serve-*.sh);
# full hybrid+graph+rerank RAG. Nothing here is ever capped to suit
# lean — a gpu_local-only capability is one manifest `profiles:` line.
# lean_cloud (CPU / Mac-mini / VPS): NO torch/CUDA anywhere; cloud chat via
# $VLLM_BASE_URL (assumed); RAG = BM25 + AST-graph (optional cloud
# EMBED_BASE_URL); doc extract via Crawl4AI-if-present else trafilatura;
# GEPA self-evolution off by default. A graceful SUBSET, never a ceiling.
DEPLOY_PROFILE=gpu_local
# ── THE ONE PORT SWITCH ──────────────────────────────────────────────────────
# Everything reaches the model through this single variable. NEVER hardcode a
# host anywhere — flip this one line to port the whole system to the your inference host.
# Dev (this laptop, over Tailscale to the your inference host):
VLLM_BASE_URL=http://100.72.56.36:8001/v1
# Prod (running ON the your inference host): VLLM_BASE_URL=http://localhost:8001/v1
# The local model id is AUTO-DISCOVERED from GET ${VLLM_BASE_URL}/v1/models — there
# is no VLLM_MODEL_ID to set. If the endpoint is unreachable the local tier is
# silently absent (the harness keeps its own local fallback).
# ═══ INFERENCE FABRIC KEYS (lib/inference) — three tiers, minimum viable = 2 lines ═══
# ── LOCAL (required for --free / --full-local / --frontier-local / --local) ────
# VLLM_BASE_URL above is the only local var (model id auto-discovered).
# ── CLOUD GATEWAY (catch-all fallback — covers most cloud models) ──────────────
# OPENROUTER_API_KEY= # with ONLY this + VLLM_BASE_URL you get a full system.
# # Fund $10 once → 1000 free req/day on Kimi-K2.6:free,
# # DeepSeek-R1:free, Qwen3-Coder:free. The default_gateway.
# ── DIRECT PROVIDERS (optional cost/speed/limit overrides) ─────────────────────
# DEEPINFRA_API_KEY= # V4-Pro planning + V4-Flash execution (operator-funded)
# DEEPSEEK_API_KEY= # DeepSeek-direct — cheaper than DeepInfra, same models
# GROQ_API_KEY= # free high-RPM per-model buckets — research fan-out workhorse
# CEREBRAS_API_KEY= # free fast synthesis (5 RPM; single chunked-synth rung)
# ANTHROPIC_API_KEY= # Opus 4.8 — spare frontier only (triple-gated)
#
# THINKING BUDGET (caps CoT tokens so reasoning can't spiral before the model produces
# output). lib/inference roles read roles.yaml's thinking_budget map (mode-overridable);
# these env vars OVERRIDE a given role by name (HM_THINKING_BUDGET_<ROLE>), and _DEFAULT
# applies only to a role configured nowhere. For the LOCAL vLLM the budget is enforced at
# the TOKEN level via chat_template_kwargs (the vLLM server must be launched with thinking
# enabled for it to bite); other providers get the native param or a prompt hint. 0 = off.
# HM_THINKING_BUDGET_SYNTH=8192 # conductor planner/synth (matches roles.yaml)
# HM_THINKING_BUDGET_STEER=2048 # cheap nudge
# HM_THINKING_BUDGET_DRIVE=2048 # driver
# HM_THINKING_BUDGET_DEFAULT=4000 # fallback for any role not in roles.yaml
# HM_ANSWER_BUDGET=2048 # answer headroom; on LOCAL (http://) endpoints the call's
# # max_tokens is HARD-capped to role_budget + this. The local
# # vLLM ignores the soft thinking_budget field, but max_tokens
# # IS enforced, so this is the real CoT-spiral guard. Cloud
# # (https) rungs are never capped.
# HM_COT_SPIRAL_TURNS=4 # conductor plugin: nudge "write to disk now" after N
# # consecutive LLM turns with no tool call / file / verify
#
# CHEAP-INFERENCE POOL LANES (mcp-research/pool.py) — helper inference (deep_research
# plan/develop/verify/synthesize) fans out across these CLOUD lanes; the agent's MAIN
# execution driver stays on the local vLLM endpoint. pool.py reads the PLURAL names
# (comma-separated = one rate-limited org lane each). Point them at the keys above:
# GROQ_API_KEYS=${GROQ_API_KEY}
# CEREBRAS_API_KEYS=${CEREBRAS_API_KEY}
# POOL_GROQ_CONCURRENCY=4 POOL_CEREBRAS_CONCURRENCY=2 POOL_LOCAL_CONCURRENCY=2
# ═══════════════════════════════════════════════════════════════════════════════════
# ── EMBEDDINGS for mcp-codebase-rag (Stage 1.1) ──────────────────────────────
# OpenAI-compatible /embeddings endpoint enabling RAG's dense lane. On gpu_local
# the embed server auto-starts with the stack (`hm up` → serve-embed.sh on :8002),
# so this default just works. A bare host:port is fine — the RAG client normalises
# to the /v1 route (works on vLLM and the local server). Leave BLANK to force
# robust BM25(+graph)-only mode (e.g. on lean_cloud with no embed server). If left
# blank, RAG also AUTO-DETECTS a serve-embed on :8002 when it is up.
EMBED_BASE_URL=http://127.0.0.1:8002
EMBED_MODEL=Qwen3-Embedding-0.6B
# ── RERANKER for mcp-codebase-rag (Stage 1.2) ────────────────────────────────
# OpenAI/Cohere/Jina-shaped /rerank endpoint (POST {model,query,documents}). The
# fused top-pool is re-ordered by the cross-encoder before top-k — the single
# highest-precision-per-token RAG lever. On gpu_local the rerank server auto-starts
# with the stack (`hm up` → serve-rerank.sh on :8003), so this default just works
# (bare host:port is normalised to /v1). Blank ⇒ fused order unchanged (graceful);
# if blank, RAG also AUTO-DETECTS a serve-rerank on :8003 when it is up.
RERANK_BASE_URL=http://127.0.0.1:8003
RERANK_MODEL=Qwen3-Reranker-0.6B
# How many fused candidates to hand the reranker (it then picks the final top-k).
RERANK_POOL=24
# ── MUTATION TESTING for mcp-verify (OPTIONAL, Stage 2 sanctioned addition) ───
# Per-repo mutation testing (mutmut) — surfaces a WEAK TEST ORACLE (a suite that
# stays green on a deliberately-bad change). OFF by default; advisory (never flips
# a green gate red). Turn on ONLY for a repo whose eval shows the oracle is weak:
# VERIFY_MUTATION_ENABLED=1 # global toggle, or
# touch <repo>/.hermes-mutation # per-repo opt-in marker (preferred)
# When off, the mutation layer is reported as explicitly-skipped, never run.
# VERIFY_MUTATION_ENABLED=
# ── MCP SERVER PORTS ─────────────────────────────────────────────────────────
# Bound to 127.0.0.1 (local only). The four always-on capability servers are
# 9101-9104; escalation (9105) is off-by-default; checkpoint (9106) is the
# long-horizon verified-green git checkpointing server.
MCP_BIND_HOST=127.0.0.1
MCP_VERIFY_PORT=9101
MCP_RAG_PORT=9102
MCP_KG_PORT=9103
MCP_OBSERVABILITY_PORT=9104
MCP_ESCALATION_PORT=9105
MCP_CHECKPOINT_PORT=9106
# watchdog (9107): non-turn-based detection — spiral / poll-hang / progress / budget.
MCP_WATCHDOG_PORT=9107
# search (9108): verifier-guided best-of-N selection (HARD subtasks only).
MCP_SEARCH_PORT=9108
# docs (9109): sovereign documentation ingestion (SearXNG→Crawl4AI→distil→RAG/KG).
MCP_DOCS_PORT=9109
# research (9110): SOTA local deep-research (plan→develop→explore→verify→synthesize).
MCP_RESEARCH_PORT=9110
# ── DEEP RESEARCH (mcp-research; bounded, sovereign, runs on BOTH profiles) ────
# All local: SearXNG + Crawl4AI/trafilatura (via mcp-docs) + the chat model
# ($VLLM_BASE_URL) + RAG/KG. Caps are the overspawning guard — conservative.
MAX_RESEARCH_LOOPS=3
RESEARCH_MAX_SUBGOALS=5
RESEARCH_QUERIES_PER_SUBGOAL=4
RESEARCH_MAX_SOURCES_PER_QUERY=3
RESEARCH_MAX_TOTAL_SOURCES=8
RESEARCH_MIN_SOURCES=2 # independent (distinct-domain) sources to call a claim well-supported
RESEARCH_WALL_BUDGET_S=600
# RESEARCH_STATE_DIR=~/.hermes-max/research # external checkable PLAN.md state
#
# ── SCRAPE I/O SPEED (fetch-tier latency knobs) ───────────────────────────────
# The explore loop is I/O-bound on page fetches. Defaults are tuned; override to taste.
# RESEARCH_TIERED_FETCH=1 # 1 = trafilatura/fast-HTTP FIRST, Chromium only on thin pages
# # (0 = old straight-to-Crawl4AI path)
# RESEARCH_MIN_STATIC_CHARS=500 # a static fetch under this -> "thin" -> fall through to browser
RESEARCH_SCRAPE_CONCURRENCY=10 # Tier-A fetch fan-out (concurrent page fetches per batch)
RESEARCH_CRAWL4AI_CONCURRENCY=2 # Tier-B Crawl4AI/Chromium bound — keep tight (2-3); heavy browser
# RESEARCH_COVERAGE_TARGET=1.0 # per-wave early-exit: stop once this fraction of sub-goals are
# # covered by >=RESEARCH_MIN_SOURCES (lower e.g. 0.85 = faster)
# FAST_SCRAPER_URL= # optional browserless scraper service -> Tier-A.0 (fastest)
#
# Tier-B browser chain (lightest CDP browser first; each rung is a clean no-op if its
# binary is absent, so the ladder degrades B-0 -> B-1 -> B-2 Crawl4AI -> jina):
# B-0 Lightpanda (Zig, ~16x less RAM / ~9x faster than Chrome) — standalone `fetch` CLI
# B-1 Obscura (Rust/V8, CDP) — standalone `fetch` CLI, optional anti-detection stealth
# LIGHTPANDA_BIN=~/hermes-max/bin/lightpanda # B-0 binary (releases: lightpanda-io/browser)
# OBSCURA_BIN=~/hermes-max/bin/obscura # B-1 binary (releases: h4ckf0r0day/obscura)
# OBSCURA_STEALTH=1 # Obscura --stealth (anti-detect + tracker block); 0=off
# RESEARCH_BROWSER_FETCH_TIMEOUT=30 # per-URL wall cap (s) for a B-0/B-1 CLI fetch
# ── SOVEREIGN DOCS LOOP (Stage 2; all local, no external API) ─────────────────
# SearXNG (search) + Crawl4AI (extract). Both self-hosted containers:
# ./searXNG.sh (enables the JSON API) ./crawl4ai.sh (arch-aware)
SEARXNG_URL=http://localhost:8080
CRAWL4AI_URL=http://localhost:11235
# The distil step uses the chat model ($VLLM_BASE_URL). It's a reasoning model, so
# the distiller uses a generous max_tokens; override if needed.
# DOCS_DISTILL_MAX_TOKENS=6000
# mcp-docs reaches RAG/KG over MCP to store notes/entities (defaults match ports):
# RAG_MCP_URL=http://127.0.0.1:9102/mcp
# KG_MCP_URL=http://127.0.0.1:9103/mcp
# ── DEEP-RESEARCH SOURCE FAN-OUT (research_engine Stage 1; ALL keys OPTIONAL) ──
# mcp-research grows native structured-source adapters alongside the SearXNG web
# layer. NONE of these keys are required — the keyless sources (arXiv, Semantic
# Scholar unauth pool, Hacker News, Stack Exchange) work with nothing set; optional
# keys only LIFT rate limits. With every key absent the engine still answers (it
# always routes searxng as the catch-all). Source limits are volatile (Bing API
# retired Aug-2025, Brave free tier removed Feb-2026, OpenAlex key-gated Feb-2026),
# which is why degrade-to-web-only is the standing hedge.
# GITHUB_TOKEN= # free PAT -> github_search 30 req/min (absent = skipped, web covers it)
# SEMANTIC_SCHOLAR_API_KEY= # optional -> 1 RPS dedicated (absent = 5,000 req/5min shared pool)
# STACKEXCHANGE_KEY= # optional -> 10k req/day (absent = 300 req/day)
# JINA_API_KEY= # optional -> Jina Reader fallback extraction (Stage 4)
# RESEARCH_CLOUD_DISTILL=false # Distillation defaults LOCAL (Stage 7b) — the bulk
# per-source distill step runs on the already-running local model (no rate limit).
# Setting true routes DENSE-source distill to a rate-limited cloud tier (DeepSeek
# via conductor): high volume can serialize on 429 backoffs — an ARTIFICIAL
# bottleneck on the bulkiest step. Opt-in only; a warning is logged when on.
# RESEARCH_SOURCE_TIMEOUT=12 # per-adapter HTTP timeout (s); RESEARCH_RRF_K=60 (fusion constant)
# RESEARCH_CORPUS_DIR=~/.hermes-max/corpus # Stage 3 on-disk human-readable markdown corpus
# # (full untruncated docs + YAML front-matter; point at a repo path
# # to make it git-versionable). ESCALATION_MCP_URL defaults to :9107.
# ── BANYAN CONTENT-EVOLUTION (research_engine Stage 6; long-horizon autonomy) ──
# The unattended loop evolves CONTENT (namespaces/RAG/KG/skills) only, NEVER
# machinery (a Stage-6 test asserts no .py is written). All optional:
# BANYAN_STATE_DIR=~/.hermes-max/banyan # UCB1 namespace stats + surfaced.jsonl operator log
# BANYAN_SKILLS_DIR=~/.hermes-max/skills # skill library the loop may refine (point at repo skills/)
# SELF_IMPROVEMENT_ENABLED=false # runtime skill evolution OFF until mature
# # (also needs 200+ tasks / 30+ days / 50+ skills; BANYAN_MIN_* override)
# BANYAN_UCB_C=1.414 BANYAN_DRIFT_COSINE=0.95 BANYAN_GAIN_FLOOR=0.05 # tuning knobs
# ── EMERGENT-BEHAVIOR REMEDIES (Stage-6; all DEFAULT-ON, toggle-able) ─────────
# The combinatorial eval (scripts/emergent_eval.sh) found three interaction risks;
# each remedy below is wired and proven via the eval's A/B contrast. Defaults are
# the SAFE choice — flip only to reproduce the unsafe behaviour for measurement.
# RISK A — Banyan focus-thrash: UCB1 is great for research breadth, harmful for
# build-loop focus (it abandons half-finished hard subtasks). research_only scopes
# UCB1 to research; the build loop uses finish-what-you-started / dependency-order.
BANYAN_SCOPE=research_only # research_only (default) | all (UCB1 on both, thrash-prone)
BANYAN_SATURATION_MIN_HISTORY=10 # never flag a namespace saturated below this many tasks
# RISK B — research-noise contamination: drop low-authority / off-topic findings
# BEFORE they feed the synth brief (precision over recall).
RESEARCH_RELEVANCE_FILTER=true # true (default) | false (recall-max, no filter)
RESEARCH_MIN_AUTHORITY=2 # source-authority floor (peer-review/standards/official rank)
RESEARCH_MIN_RELEVANCE=0.25 # query-token containment floor
# RISK C — ladder cascade: a GLOBAL per-subtask budget stops a single subtask from
# cascading driver->steer->synth->...->escalate before any per-tier trigger fires.
CONDUCTOR_SUBTASK_USD_CAP=0.50 # per-subtask USD ceiling -> stop + surface to operator
CONDUCTOR_SUBTASK_MAX_TIERS=4 # per-subtask tier-count ceiling -> stop + surface
# Empty-base correctness: conservative cold-start when no signals are gathered.
CLASSIFIER_ESCALATE_WHEN_UNCERTAIN=true # no-signal subtask -> 'medium' (not 'easy')
# ── VERIFIER-GUIDED SEARCH (Stage 1.2; your inference host-bounded, HARD subtasks only) ──────
# The selector (candidates supplied) is always available. The GENERATION path
# uses $VLLM_BASE_URL and is bounded: default N small, hard-capped, because
# best-of-N competes for the single GPU.
SEARCH_MODEL=/model
SEARCH_DEFAULT_N=3
SEARCH_MAX_N=6
# ── LIVE OBSERVABILITY (Stage 3) ─────────────────────────────────────────────
# A live, tailable tool-call stream alongside the Phoenix spans. Run
# `scripts/watch.sh` in a side terminal to see every tool call's input/output/
# timing/heartbeat plus every routing/fallback/kill DECISION in real time.
# Verbosity: quiet (errors/kills/fallbacks) | normal (+start/finish) | verbose
# (+heartbeats, look-ahead estimates, io summaries) | debug (+full payloads).
HERMES_MAX_VERBOSITY=verbose
HERMES_MAX_LOG_DIR=~/.hermes-max/logs
# HERMES_MAX_LOG_STDOUT=0 # also echo live lines to stdout (1 to enable)
# ── WATCHDOG (Stage-0 robustness floor) ──────────────────────────────────────
# Per-tool wall-clock budget (s): a single tool call exceeding this WITHOUT a
# heartbeat is "hung" (mirrors the lowered native terminal.timeout). This is the
# GLOBAL soft budget / backstop; the PER-TOOL registry (below) refines it.
WATCHDOG_TOOL_BUDGET_S=120
WATCHDOG_STATE_DIR=~/.hermes-max/watchdog
# ── PER-TOOL ADAPTIVE BUDGETS + LOOK-AHEAD (Stage 1) ─────────────────────────
# Each variable-duration tool has a HARD ceiling (the most it may EVER run) and is
# judged by look-ahead estimate + heartbeat liveness, so legitimately-long work is
# NOT killed prematurely and genuinely-hung work IS. Kill rule: elapsed > ceiling,
# OR (elapsed > budget AND no heartbeat for > HEARTBEAT_TIMEOUT_S). Override any
# tool's ceiling with BUDGET_<TOOL>_S (TOOL upper-cased; e.g. BUDGET_FETCH_CLEAN_S).
HEARTBEAT_TIMEOUT_S=90 # kill a silent tool only this long past its budget
BUDGET_INDEX_REPO_S=1800 # index_repo hard ceiling (30 min) — file count x size
BUDGET_DEEP_RESEARCH_S=900 # deep_research hard ceiling (15 min) — queries x source
BUDGET_VERIFY_S=300 # full-test verify hard ceiling (5 min) — test count
# BUDGET_FETCH_CLEAN_S=90 # per-page Crawl4AI ceiling
# Look-ahead per-item rate priors (what's "normal"; the heartbeat is the real signal):
# EST_INDEX_PER_FILE_S=0.077 EST_RESEARCH_PER_SOURCE_S=30 EST_FETCH_PER_PAGE_S=8
# Spiral-detector thresholds (any one trips). Defaults are conservative.
WATCHDOG_SPIRAL_NGRAM=4
WATCHDOG_SPIRAL_DUP_RATIO=0.45
WATCHDOG_SPIRAL_TOP_FREQ=0.12
WATCHDOG_SPIRAL_COMPRESS=0.32
WATCHDOG_SPIRAL_SEG_SIM=0.80
# ── RAG / KG STORAGE PATHS ───────────────────────────────────────────────────
# Both start EMPTY; no seed corpus. ~ is expanded by the servers.
RAG_INDEX_PATH=~/.hermes-max/rag/index.db
KG_DB_PATH=~/.hermes-max/kg/graph.db
# ── KG BACKEND (DEFAULT embedded; Neo4j is OPTIONAL, power-user only) ─────────
# embedded (DEFAULT): one local SQLite file (KG_DB_PATH above). Zero external
# service — this is all bootstrap needs in the base case.
# neo4j: persist the SAME logical schema (entities / edges / props carrying
# provenance, temporal validity, citation edges) to a Neo4j server instead. The
# neo4j driver is NOT a base dependency — opt in with `pip install neo4j` + a
# running server. If the driver or server is absent, the store falls back to
# embedded automatically (never crashes). A backend change, not a schema change.
KG_BACKEND=embedded
# NEO4J_URI=bolt://localhost:7687
# NEO4J_USER=neo4j
# NEO4J_PASSWORD=
# NEO4J_DATABASE=neo4j
# ── OBSERVABILITY (Phoenix, OTLP gRPC) ───────────────────────────────────────
PHOENIX_COLLECTOR_ENDPOINT=http://localhost:4317
OTEL_SERVICE_NAME=hermes-max
# ── ESCALATION (OFF by default; hard daily USD cap enforced in the server) ────
ESCALATION_ENABLED=false
ESCALATION_DAILY_USD_CAP=1.00
ESCALATION_MAX_TOKENS=2048
# Cheap-frontier tier (e.g. DeepSeek V4 Flash). Leave blank while disabled.
ESCALATION_BASE_URL=
ESCALATION_API_KEY=
ESCALATION_MODEL=deepseek-v4-flash
ESCALATION_PRICE_IN=0.14
ESCALATION_PRICE_OUT=0.28
ESCALATION_STATE_PATH=~/.hermes-max/escalation/spend.json
# Optional long-horizon-hard tier (e.g. Kimi K2.6):
# ESCALATION_LONG_BASE_URL=
# ESCALATION_LONG_API_KEY=
# ESCALATION_LONG_MODEL=kimi-k2.6
# LOCAL escalation tier (Stage 3): a BIGGER LOCAL model (122B-A10B / 27B-dense)
# on a second endpoint. FREE (same box) so it is ON by default when set, and the
# hard kernel tries it BEFORE any cloud tier. No USD cap applies (it's local).
# ESCALATION_LOCAL_BASE_URL=http://localhost:8002/v1
# ESCALATION_LOCAL_API_KEY=
# ESCALATION_LOCAL_MODEL=/model-122b
# ── OPTIONAL FAST MONITOR/CRITIC MODEL (Stage 2.2; OFF by default) ────────────
# A small LFM2.5-class model on a SECOND endpoint, usable as a cheap critic.
# Default OFF: two models share the one your inference host memory bus — measure contention
# before adopting. workflow-critic targets this only when MONITOR_ENABLED=true.
MONITOR_ENABLED=false
MONITOR_BASE_URL=
MONITOR_MODEL=lfm2.5
# ── DSPY/GEPA SKILL CURATION (Stage 2.3; scheduled, off the hot path) ─────────
# Weekly evolution of the most-used skills/prompts/tool-descriptions from session
# traces. Bounded by DSPY_TIMEOUT; runs against the local model ($VLLM_BASE_URL,
# free) by default. Graceful no-op if hermes-agent-self-evolution isn't installed.
DSPY_TIMEOUT=3600
# DSPY_PYTHON=python3 # interpreter that has hermes-agent-self-evolution
# DSPY_AUTO_INSTALL=false # try `pip install` the package on first run
# DSPY_SCHEDULE=0 4 * * 0 # cron schedule (Sundays 04:00 local)
# ════════════════════════════════════════════════════════════════════════════
# CONDUCTOR — fully optional, presence-gated cloud help (additive; never required).
# Zero keys → local vLLM / default endpoint only (the bare harness). Nothing breaks.
# A role (steer/synth/escalate) is ACTIVE iff >=1 provider in its chain has a key.
# These vars ONLY ENABLE rungs (presence); ORDER lives in conductor.yaml / the
# registry defaults (mcp-escalation/conductor_registry.py). Cloud help is always a
# STATELESS TOOL — the Hermes backend model ($VLLM_BASE_URL) is NEVER swapped.
# Verified-live model IDs are baked into the registry; set only the KEYS here.
# ════════════════════════════════════════════════════════════════════════════
# ── CONDUCTOR_MODE — a HARD spend-tier cap (orthogonal to DEPLOY_PROFILE) ──────
# DEPLOY_PROFILE picks your HARDWARE lane (gpu_local / lean_cloud). CONDUCTOR_MODE
# picks your CLOUD-SPEND policy, independent of which keys are present below:
# local — NO cloud at all. Local vLLM only. Fully sovereign, $0, works offline.
# The guaranteed-correct base case (paid/free keys are IGNORED).
# free — local + FREE cloud tiers only (Cerebras steer/draft, Groq research-
# cascade + slop-draft, Gemini-Flash last-resort). No paid keys fire,
# even if present. Rate-limit-mindful (the live budget tracker gates it).
# full — adds the paid DeepSeek V4 synth/steer (DeepInfra). The recommended
# daily driver. (DEFAULT when unset.) Does NOT include Opus.
# frontier — full + the SPARING Opus 4.8 escalation tier (claude-opus-4-8),
# requires ANTHROPIC_API_KEY. Opus is THREE-gated (frontier mode+key,
# classifier=frontier-novel, V4-Pro already failed verify twice) so it
# stays rare (≤~15 calls/mo). Opt-in only via `hm up --frontier`.
# Each mode falls back THROUGH the ones below it as keys disappear:
# frontier → full → free → local. `hm up --MODE` sets this line (it is the ceiling;
# the per-subtask gating decides actual use). A documented preference, not a hard req.
CONDUCTOR_MODE=full
# ════════════════════════════════════════════════════════════════════════════
# ── INFERENCE_MODE — the POSTURE (modes.yaml): who plans, who executes ─────────
# The inference fabric (lib/inference) reads a POSTURE name that reassigns the
# CODING role chains. `hm mode <name>` sets it (persisted to ~/.hermes-max/mode,
# which takes precedence over this line); the posture also syncs CONDUCTOR_MODE
# above to its spend ceiling. The six postures, in order of appeal:
# free Kimi-K2.6-free plans, local executes. $0/mo (GPU) ← DEFAULT
# full-local V4-Pro plans, local executes. ~$1.50 (GPU)
# full V4-Pro plans, V4-Flash executes. ~$17 (no GPU)
# frontier-local Opus 4.8 plans, local executes. ~$45 (GPU)
# frontier Opus 4.8 plans, V4-Flash executes. ~$60 (no GPU)
# local pure local, no API (air-gapped floor). $0 (GPU)
# Default = free: near-frontier planning (Kimi-K2.6-free, replenishes daily) + free
# sovereign local execution. See `hm mode --list` and ARCHITECTURE.md.
INFERENCE_MODE=free
# ════════════════════════════════════════════════════════════════════════════
# --- FRONTIER tier [--frontier mode only] — SPARING Opus 4.8 escalation ---------
# ANTHROPIC_API_KEY enables the frontier escalate rung (claude-opus-4-8, $5/M in,
# $25/M out, REGULAR mode). Eligible ONLY in CONDUCTOR_MODE=frontier — never in
# --full. Fires only when all THREE gates trip (frontier mode+key, classifier=
# frontier-novel, V4-Pro already failed verify twice / opinions disagree), using
# compress-then-reason (V4-Pro writes a ~12K brief, Opus reasons ~$0.18/call).
# ANTHROPIC_API_KEY=
FRONTIER_USD_CAP_MONTHLY=10 # hard monthly cap on Opus spend; hit → fall back to V4-Pro
FRONTIER_USD_CAP_DAILY=2 # hard daily cap on Opus spend
FRONTIER_TARGET_CALLS_MONTHLY=15 # sparing target; `hm cost` warns if Opus calls exceed this
# --- SYNTHESIZE (deep) — [full mode only]. Order: DeepInfra→Fireworks→Together→DeepSeek→Kimi (NO Opus — escalation-only) ---
# inference fabric planner/driver resolution: deepinfra (FUNDED) → deepseek_direct → openrouter free → local
# DEEPINFRA_API_KEY= # the FUNDED DeepSeek provider today — V4-Pro planner / V4-Flash driver. Rotate if compromised.
DEEPINFRA_BASE_URL=https://api.deepinfra.com/v1/openai # OpenAI-compatible; POST /chat/completions → /v1/openai/chat/completions
# FIREWORKS_API_KEY= # US fallback (no-log open models)
# TOGETHER_API_KEY= # US fallback (ZDR)
# DEEPSEEK_API_KEY= # optional: deepseek-direct (api.deepseek.com) — usually CHEAPER than DeepInfra; flip order in roles.yaml
DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
# MOONSHOT_API_KEY= # opt-in: Kimi (Singapore)
# --- STEER (cheap nudges). Order: V4-Flash@DeepInfra [full] → Cerebras→Groq→Gemini-Flash [free] ---
# (V4-Flash steer reuses DEEPINFRA_API_KEY above — no extra key needed)
# --- The three CEREBRAS/GROQ/GEMINI keys below are the [free mode] tier ---
# CEREBRAS_API_KEY= # free GLM-4.7 / gpt-oss-120b @ 64K ctx; deprioritized fallback (5 RPM preview)
# GROQ_API_KEY= # free qwen3-32b / gpt-oss-120b / llama-4-scout; cheap fallback (rate-limited)
# GEMINI_API_KEY= # AI Studio; ~20 RPD on this account — last-resort tracked steer
# (OPENROUTER_API_KEY lives in the INFERENCE FABRIC KEYS block near the top — the
# fabric's catch-all default_gateway: Kimi-K2.6:free / R1:free / Qwen3-Coder:free.)
# --- PARALLEL_DRAFT POOL (verifier-selected best-of-N; fans across ALL present free/cheap above) ---
# Uses CEREBRAS_API_KEY + GROQ_API_KEY (+ optional DeepInfra V4-Flash anchor). No new keys.
# CONDUCTOR_DRAFT_MAX_N=5 # cap on concurrent draft candidates
# --- ESCALATE (rarest hardest kernel) — [full mode only] ---
# ANTHROPIC_API_KEY= # Claude Opus; only when synth fails verify twice / two opinions disagree
# --- Model + cap overrides (optional; defaults in the registry / conductor.yaml) ---
# CONDUCTOR_SYNTH_MODEL=deepseek-ai/DeepSeek-V4-Pro
# CONDUCTOR_STEER_MODEL=deepseek-ai/DeepSeek-V4-Flash
# CONDUCTOR_ESCALATE_MODEL=claude-opus-4-8
# CONDUCTOR_USD_CAP_DAILY=1 # paid rungs return the local/free signal once hit
# CONDUCTOR_USD_CAP_MONTHLY=5
# CONDUCTOR_CONFIG=./conductor.yaml # optional override file (absent = registry defaults)