Repository navigation
Expand file tree
/
Copy pathconfig.example.yaml
More file actions
213 lines (195 loc) · 9.48 KB
/
Copy pathconfig.example.yaml
File metadata and controls
213 lines (195 loc) · 9.48 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
vault:
path: ~/Documents/Obsidian/MyVault
# `Agent` is the folder the writeback jobs own; exclude it from ingest so
# the daemon doesn't read its own memory files back in.
exclude_dirs: [".obsidian", ".trash", "templates", "Agent"]
# Frontmatter keys consulted for a note's episodic date, in order.
date_frontmatter_keys: ["occurred_at", "date", "created", "created_at"]
# Optional. Set to your vault's earliest bulk-import date to let otherwise
# undated notes take their date from mtime. Run
# `daemon migrate backfill-dates --dry-run` to see the detected import dates.
# mtime_trusted_before: 2026-06-21
chunking:
max_tokens: 512
overlap_tokens: 50
split_on_headers: ["#", "##", "###"]
embeddings:
model: BAAI/bge-small-en-v1.5
batch_size: 32
device: auto # auto | cpu | cuda | mps
cache_folder: ./data/models # model files live here; first run downloads, later runs are offline
# Hybrid retrieval: fuse a BM25-style sparse signal with the dense one server-side in Qdrant.
# Flip to false to A/B against dense-only. Switching modes requires `daemon ingest --full`.
hybrid: false
sparse_model: Qdrant/bm42-all-minilm-l6-v2-attentions
vector_store:
backend: qdrant
qdrant:
# Embedded mode (the default): qdrant runs *inside* the daemon process
# against this folder. No Docker, no server to start — just a directory
# that persists across restarts. Back it up with the rest of ./data/.
# (Deliberately *not* ./data/qdrant — that folder is the docker server's
# storage mount, and the two on-disk layouts are not interchangeable.)
path: ./data/qdrant-local
# Embedded mode is single-process: exactly one daemon may hold the folder
# at a time, so the CLI and the GUI can't both be open against it. Switch
# to the server below if you hit either wall:
# * concurrent access (GUI + CLI + Hermes at once, or a shared machine)
# * a large vault — the server has real payload indexes and a much
# faster filtered search; embedded filters in Python.
# To switch: comment out `path` above, uncomment `url` below, and run
# `docker-compose up -d qdrant`. Setting both is a config error, on
# purpose — silently preferring one would hide which store your vectors
# actually landed in. Your existing index does not move between modes;
# re-run `daemon ingest --full` after switching.
# url: http://localhost:6333
collection: chunks
graph:
path: ./data/graph.gpickle
manifest_path: ./data/manifest.json
expansion_depth: 2
distance_decay: 0.5
retrieval:
seed_top_k: 8
context_token_budget: 6000
candidate_pool: 3 # always surface at least N candidates to the user
# Build the candidate pool by team draft between the seed ranking and the
# graph-expansion ranking, instead of by raw score. An expanded chunk scores
# its seed's score decayed by graph distance, so under a score sort expansion
# can never outrank its own seed and the expansion policy is never examined —
# which is why picks used to teach the graph nothing. `daemon policy` shows
# which ranking your picks actually favour. Set false for the old score order.
interleave: true
# Rerank the candidate pool with a local cross-encoder and enter that
# ordering as a third drafting team (§IV.18), so `daemon policy` can report
# whether reranking actually earns picks on this vault. Off by default —
# enabling it without the weights cached would download on first query — so
# run `daemon models download` before flipping this on.
# rerank: true
# rerank_model: cross-encoder/ms-marco-MiniLM-L-6-v2
# rerank_max_candidates: 100
llm:
provider: anthropic
# Sonnet 4.6 is the cost/quality sweet spot for personal RAG synthesis.
# Alternatives: claude-opus-4-7 (highest fidelity, ~5x cost), claude-haiku-4-5 (fastest, lowest cost).
model: claude-sonnet-4-6
max_tokens: 2048
# Opus 4.7 and other reasoning-capable models reject `temperature`. Leave it
# unset (null) for those; set a float (e.g. 0.3) for Sonnet/Haiku if desired.
temperature: null
# Background-agent jobs (extract / link / reflect) use this cheaper model.
# Leave null to reuse `model` above; default Haiku 4.5 is ~15x cheaper than Opus.
batch_model: claude-haiku-4-5
agent:
# Master switch. Start in dry-run mode (daemon link --dry-run, daemon extract --note <one>)
# to verify thresholds against your vault, then flip to true.
enabled: true
folder_name: Agent
# Linker thresholds. The auto-apply gate is intentionally strict: cosine >= 0.85
# AND the target's title must appear verbatim (case-insensitive) in the source body.
# Everything between suggest and apply thresholds lands in Agent/link-suggestions-*.md.
link_apply_cosine: 0.85
link_apply_requires_title_substring: true
link_suggest_cosine: 0.78
link_max_per_note: 5
tag_apply_min_neighbor_count: 4
# Extractor.
extract_min_word_count: 80
extract_skip_if_processed_within_hours: 18
# Reflection: which themes to maintain in Agent/memory-*.md.
reflect_themes: [personality, projects, relationships, themes]
reflect_lookback_days: 7
# Don't touch a note that was saved within this many minutes (avoid collisions).
write_grace_minutes: 30
# --- Observer (M4) -----------------------------------------------------
# The observer reads structural reports from M3 and writes a markdown
# letter into <vault>/Agent/observer-<date>.md. Gated separately from
# `enabled` so you can opt in after watching reflect/extract/link first.
observer_enabled: false
observer_lookback_days: 7
observer_max_communities: 8
# Opus 4.7 is the recommended model for the observer — interpreting
# structural patterns into prose is the highest-quality lift in this
# project. Set null to fall back to `llm.batch_model`.
observer_model: claude-opus-4-7
# How many prior letters to feed in for continuity, and how many to
# surface in the rolling `observer.md` index.
observer_prior_letters: 4
observer_index_window: 8
# Retention for snapshots auto-created by `daemon consolidate`.
observer_snapshot_retention_days: 14
hermes:
# My Daemon as the memory & dream layer for the Hermes agent (PLAN-HERMES.md).
# Everything defaults off — the provider only activates when Hermes loads it
# AND provider_enabled is true, and nothing is written unless allow_write_back.
# --- Memory-provider plugin (Path A, primary) ---
provider_enabled: false
# Conversation captures land here: a *normal* (ingest-visible) folder, NOT the
# daemon-owned Agent/, so captures become recallable in later sessions.
capture_folder: Conversations/hermes
capture_requires_confirmation: true
# Skip capturing turns shorter than this (combined user+assistant chars).
capture_min_chars: 120
prefetch_budget_chars: 4000
dream_block_budget_chars: 3000
# One-paragraph identity framing injected above last night's letter at session
# start. Leave blank for the built-in default.
identity: ""
# --- Shared retrieval defaults handed to the agent ---
# Recall is retrieval-only by default: Hermes has its own model and wants
# grounded, cited context, not an answer composed for it.
recall_synthesize_default: false
recall_top_k: 8
# Master write-back gate (endorse + remember). Read-only until you flip this.
allow_write_back: false
# --- MCP server (Path B, optional portability) ---
mcp_enabled: false
mcp_transport: stdio # stdio | http
mcp_host: 127.0.0.1
mcp_port: 8077
# HTTP bearer token comes from this env var only — never from yaml.
mcp_auth_token_env: MY_DAEMON_MCP_TOKEN
feedback:
db_path: ./data/feedback.db
snapshot:
# Bundles produced by `daemon snapshot create` land here. Each bundle freezes
# the vector + graph + feedback state so the M3 analyzer and M4 observer LLM
# can read a stable copy without contaminating live retrieval.
dir: ./data/snapshots
# `daemon snapshot prune` deletes bundles older than this; uncalled snapshots
# never expire on their own.
retention_days: 14
consolidation:
# `daemon analyze <snapshot_id>` writes structural.json + weight_evolution.json
# into <out_dir>/<snapshot_id>/. The M4 observer reads from the same place.
out_dir: ./data/consolidation
# Default lookback window for the hypothetical-weight-evolution replay.
simulate_lookback_days: 7
# Caps on the size of each ranked-list section of the report.
max_communities: 8
max_bridging_notes: 10
max_bridge_edges: 20
max_orphans: 20
max_dangling: 20
max_warm_edges: 20
# Sampling for betweenness centrality. Full BC is O(VE), so we sample for
# large graphs; 200 is a sensible default for personal vaults.
betweenness_sample_k: 200
run:
# `daemon run` — the foreground supervisor. Watches the vault, ingests after
# things go quiet, and runs `daemon consolidate` overnight. Install it as a
# background service with `daemon schedule install` (systemd --user on Linux,
# a schtasks command on Windows).
# Seconds of *quiet* before an incremental ingest fires. The timer restarts on
# every new change, so a sync client rewriting a hundred notes produces one
# ingest after it settles rather than one in the middle of it.
debounce_seconds: 5
# Local wall-clock time for the nightly consolidation, 24-hour "HH:MM".
# Set to null to turn it off. It still obeys both writeback gates above
# (agent.enabled AND agent.observer_enabled); with either closed the
# supervisor logs why once and stops mentioning it.
consolidate_at: "03:00"
# Cadence of the "still alive" log line, in minutes. 0 silences it.
heartbeat_minutes: 15
logging:
level: INFO