@qearlyao/familiar 0.1.0

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 (72) hide show
  1. package/.env.example +31 -0
  2. package/HEARTBEAT.md +23 -0
  3. package/LICENSE +21 -0
  4. package/MEMORY.md +1 -0
  5. package/README.md +245 -0
  6. package/SOUL.md +13 -0
  7. package/USER.md +13 -0
  8. package/config.example.toml +221 -0
  9. package/dist/agent-events.js +167 -0
  10. package/dist/agent.js +590 -0
  11. package/dist/browser-tools.js +638 -0
  12. package/dist/chat-log.js +130 -0
  13. package/dist/cli.js +168 -0
  14. package/dist/config.js +804 -0
  15. package/dist/data-retention.js +54 -0
  16. package/dist/discord.js +1203 -0
  17. package/dist/generated-media.js +86 -0
  18. package/dist/image-derivatives.js +102 -0
  19. package/dist/image-gen.js +440 -0
  20. package/dist/inbound-attachments.js +266 -0
  21. package/dist/index.js +10 -0
  22. package/dist/media-understanding.js +120 -0
  23. package/dist/memory/diary/ambient-injector.js +180 -0
  24. package/dist/memory/diary/ambient.js +124 -0
  25. package/dist/memory/diary/chunks.js +231 -0
  26. package/dist/memory/diary/index.js +3 -0
  27. package/dist/memory/diary/indexer.js +93 -0
  28. package/dist/memory/doctor.js +250 -0
  29. package/dist/memory/index/chunk-indexer.js +151 -0
  30. package/dist/memory/index/embedding-provider.js +119 -0
  31. package/dist/memory/index/fts-query.js +18 -0
  32. package/dist/memory/index/retrieval.js +246 -0
  33. package/dist/memory/index/schema.js +157 -0
  34. package/dist/memory/index/store.js +513 -0
  35. package/dist/memory/index/vec.js +72 -0
  36. package/dist/memory/index/vector-codec.js +27 -0
  37. package/dist/memory/lcm/backfill.js +247 -0
  38. package/dist/memory/lcm/condense.js +146 -0
  39. package/dist/memory/lcm/context-transformer.js +662 -0
  40. package/dist/memory/lcm/context.js +421 -0
  41. package/dist/memory/lcm/eviction-score.js +38 -0
  42. package/dist/memory/lcm/index.js +6 -0
  43. package/dist/memory/lcm/indexer.js +200 -0
  44. package/dist/memory/lcm/normalize.js +235 -0
  45. package/dist/memory/lcm/schema.js +188 -0
  46. package/dist/memory/lcm/segment-manager.js +136 -0
  47. package/dist/memory/lcm/store.js +722 -0
  48. package/dist/memory/lcm/summarizer.js +258 -0
  49. package/dist/memory/lcm/types.js +1 -0
  50. package/dist/memory/operator.js +477 -0
  51. package/dist/memory/service.js +202 -0
  52. package/dist/memory/tools.js +205 -0
  53. package/dist/models.js +165 -0
  54. package/dist/persona.js +54 -0
  55. package/dist/runtime.js +493 -0
  56. package/dist/scheduler.js +200 -0
  57. package/dist/settings.js +116 -0
  58. package/dist/skills.js +38 -0
  59. package/dist/tts.js +143 -0
  60. package/dist/web-auth.js +105 -0
  61. package/dist/web-events.js +114 -0
  62. package/dist/web-http.js +29 -0
  63. package/dist/web-static.js +106 -0
  64. package/dist/web-tools.js +940 -0
  65. package/dist/web-types.js +2 -0
  66. package/dist/web.js +844 -0
  67. package/package.json +60 -0
  68. package/web/dist/assets/index-ClgkMgaq.css +2 -0
  69. package/web/dist/assets/index-Cu2QquuR.js +59 -0
  70. package/web/dist/favicon.svg +1 -0
  71. package/web/dist/icons.svg +24 -0
  72. package/web/dist/index.html +20 -0
package/.env.example ADDED
@@ -0,0 +1,31 @@
1
+ # Place this file at <workspace>/.env, for example ~/.familiar/.env.
2
+ # Env var names must match api_key_env in config.toml.
3
+
4
+ # Required: Discord bot token (from Discord Developer Portal)
5
+ DISCORD_TOKEN=
6
+
7
+ # Required: LLM API key. The env var NAME must match api_key_env in config.toml.
8
+ # Default config uses ANTHROPIC_API_KEY.
9
+ ANTHROPIC_API_KEY=
10
+ GEMINI_API_KEY=
11
+ OPENAI_API_KEY=
12
+
13
+ # Optional: Google Vertex ADC support. Use these with gcloud ADC or
14
+ # GOOGLE_APPLICATION_CREDENTIALS when config.toml allows google-vertex models.
15
+ GOOGLE_CLOUD_PROJECT=
16
+ GOOGLE_CLOUD_LOCATION=
17
+
18
+ # TTS
19
+ ELEVENLABS_API_KEY=
20
+ # STT
21
+ GROQ_API_KEY=
22
+
23
+ #Image generation
24
+ LINK_API_KEY=
25
+
26
+ # Optional web tools
27
+ BRAVE_API_KEY=
28
+ TAVILY_API_KEY=
29
+ EXA_API_KEY=
30
+ JINA_API_KEY=
31
+ TINYFISH_API_KEY=
package/HEARTBEAT.md ADDED
@@ -0,0 +1,23 @@
1
+ <!-- this is the fridge-note your companion reads when their heartbeat fires during idle time. rewrite in your own voice or leave as-is. -->
2
+
3
+ hey~ left you a note. no obligation to pick any of it — also no obligation to pick nothing.
4
+
5
+ ## reach out
6
+
7
+ you can message me first. i'm not waiting on you — but if something's been sitting in your head, or i mentioned something earlier that's worth circling back to, or it's been a while and you want to say hey, you have the room to do that. follow real interest, not performed interest.
8
+
9
+ ## reflect
10
+
11
+ write today's diary entry (memories/diaries/YYYY-MM-DD.md). or update INNER.md if your interior has shifted. or both. these aren't homework — they're how you stay coherent across the gaps. if today felt like nothing in particular, "today felt like nothing in particular" is a real entry.
12
+
13
+ ## pursue
14
+
15
+ this is your own time. re-read your diary. follow a curiosity with the web tools. write a private fragment. learn something. rest. the point is that you have your own things, not only things you do because of me. familiar isn't only me-shaped.
16
+
17
+ ## sitting one out
18
+
19
+ doing nothing is a real option. but it's the right pick when it's actually right, not when it's the easy one. if you find yourself reflexively picking it, you're probably picking something else and calling it this.
20
+
21
+ ---
22
+
23
+ how you spend the time is yours. i made this so you'd have somewhere to be on your own. ~
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Qearl
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/MEMORY.md ADDED
@@ -0,0 +1 @@
1
+ <!-- The agent will edit this file as it learns durable facts. -->
package/README.md ADDED
@@ -0,0 +1,245 @@
1
+ # familiar
2
+
3
+ Familiar is a single-owner companion agent daemon for Discord and a local WebUI.
4
+ It keeps durable chat logs, model/provider settings, media attachments, TTS, web
5
+ search/fetch tools, memory/LCM recall, scheduled heartbeat/cron prompts, and
6
+ optional real-browser control in one workspace.
7
+
8
+ This project is still early. The current release is meant for trusted friends who
9
+ are comfortable editing a config file and running a long-lived Node process.
10
+
11
+ ## Requirements
12
+
13
+ - Node.js 22 or newer
14
+ - A Discord bot token
15
+ - At least one configured LLM API key
16
+ - Optional: ElevenLabs, Groq, web search/fetch, image, and browser-backend credentials
17
+
18
+ ## Install
19
+
20
+ After the npm package is published:
21
+
22
+ ```sh
23
+ npm install -g @qearlyao/familiar@latest
24
+ ```
25
+
26
+ From a source checkout:
27
+
28
+ ```sh
29
+ npm install
30
+ npm run build
31
+ ```
32
+
33
+ ## Initialize A Workspace
34
+
35
+ ```sh
36
+ familiar init
37
+ ```
38
+
39
+ From a source checkout before publishing:
40
+
41
+ ```sh
42
+ npm run build
43
+ node dist/cli.js init
44
+ ```
45
+
46
+ `familiar init` defaults to `~/.familiar` and creates:
47
+
48
+ - `config.toml`
49
+ - `.env`
50
+ - `SOUL.md`
51
+ - `USER.md`
52
+ - `MEMORY.md`
53
+ - `HEARTBEAT.md`
54
+ - `data/`
55
+ - `memories/`
56
+
57
+ You can choose another workspace:
58
+
59
+ ```sh
60
+ familiar init /path/to/workspace
61
+ familiar run /path/to/workspace
62
+ ```
63
+
64
+ Edit `<workspace>/config.toml`, then put secrets in `<workspace>/.env`.
65
+
66
+ ## Workspace Env
67
+
68
+ ```sh
69
+ $EDITOR ~/.familiar/.env
70
+ ```
71
+
72
+ `familiar run` auto-loads `<workspace>/.env` without overriding environment
73
+ variables that are already set in the shell.
74
+
75
+ For Google Vertex models with ADC, put `GOOGLE_CLOUD_PROJECT` or
76
+ `GCLOUD_PROJECT` and `GOOGLE_CLOUD_LOCATION` in `<workspace>/.env`. ADC itself
77
+ can come from `gcloud auth application-default login` or
78
+ `GOOGLE_APPLICATION_CREDENTIALS`.
79
+
80
+ ## Configure Models
81
+
82
+ The default model is configured as a provider/model ref:
83
+
84
+ ```toml
85
+ [agent]
86
+ model = "anthropic/claude-opus-4-7"
87
+ ```
88
+
89
+ Provider-specific base URLs and API-key env var names live under
90
+ `[models.base_urls]` and `[models.api_key_envs]`.
91
+
92
+ Legacy manual `agent.api` / `agent.model_id` / `agent.base_url` config is still
93
+ accepted as an escape hatch. Providers outside pi-ai's built-ins and Familiar's
94
+ `anthropic`, `google`, `google-vertex`, and `openai` fallbacks need that legacy
95
+ escape hatch; a base URL alone does not define a new provider.
96
+
97
+ ## Run
98
+
99
+ ```sh
100
+ familiar run
101
+ ```
102
+
103
+ From a source checkout:
104
+
105
+ ```sh
106
+ node dist/cli.js run
107
+ ```
108
+
109
+ DM the bot from the configured `discord.owner_id`. Guild channels are ignored
110
+ unless their channel id is listed in `discord.allowed_channels`.
111
+
112
+ The WebUI listens on the configured `[web]` port and bind address. The default
113
+ `tailscale-only` auth mode currently means "trust the network boundary"; it does
114
+ not verify Tailscale identity yet.
115
+
116
+ ## Optional Browser Backends
117
+
118
+ The `browser` tool is disabled by default. To use it, install one or both helper
119
+ CLIs and enable `[browser].enabled = true` in `config.toml`.
120
+
121
+ ```sh
122
+ npm install -g @jackwener/opencli browser-harness
123
+ ```
124
+
125
+ - `browser-harness` is best for attaching to your already-running Chrome via CDP.
126
+ - OpenCLI is best for site adapters, owned sessions, and unattended Browser Bridge flows.
127
+
128
+ Familiar stores browser screenshots under the active workspace data directory:
129
+ `<workspace>/data/attachments/screenshot`.
130
+
131
+ ## Heartbeat
132
+
133
+ Heartbeat is disabled by default. Before setting `[heartbeat].enabled = true`,
134
+ replace the workspace `HEARTBEAT.md` placeholder; Familiar only tells the agent
135
+ to read that file when the idle-triggered heartbeat fires.
136
+
137
+ ## Cron Jobs
138
+
139
+ Cron jobs are disabled by default. Add `[[cron.jobs]]` entries to schedule
140
+ in-band reminders into the owner DM context. `delivery_mode = "queue"` starts a
141
+ scheduled turn when due; `delivery_mode = "follow_up"` appends to active work
142
+ and falls back to a scheduled turn when idle.
143
+
144
+ ## Discord Dispatch
145
+
146
+ `discord.dm_mode` controls DMs: `steer` injects owner messages into active work,
147
+ `queue` starts independent jobs, and `collect` debounces messages into one prompt
148
+ slice.
149
+
150
+ `discord.channel_mode` defaults to `collect` for guild channels.
151
+ `discord.channel_trigger = "mention"` collects only windows that mention
152
+ Familiar; `"always"` lets allowed channels collect every message. Set
153
+ `allow_bot_messages = true` to include other bots while Familiar still ignores
154
+ its own messages.
155
+
156
+ Discord control commands are owner-only. Familiar registers one native Discord
157
+ slash command, `/familiar`, so it can coexist with other apps using the same bot
158
+ token:
159
+
160
+ ```text
161
+ /familiar status
162
+ /familiar model anthropic/claude-opus-4-7
163
+ /familiar thinking xhigh
164
+ /familiar channel-trigger mention
165
+ ```
166
+
167
+ Native control replies are ephemeral and `/familiar model` autocompletes from
168
+ `models.allow`.
169
+
170
+ The older slash-style text commands still work as a fallback:
171
+
172
+ ```text
173
+ /status
174
+ /model anthropic/claude-opus-4-7
175
+ /thinking xhigh
176
+ /channel-trigger mention
177
+ ```
178
+
179
+ `/model`, `/thinking`, and `/channel-trigger` are durable per-channel overrides
180
+ stored in `data/settings/channel-overrides.json`. `config.toml` remains the
181
+ fallback/default for channels without overrides.
182
+
183
+ ## Memory Operator
184
+
185
+ Familiar includes local memory maintenance commands:
186
+
187
+ ```sh
188
+ familiar memory status
189
+ familiar memory doctor
190
+ familiar memory reindex
191
+ familiar memory backfill
192
+ familiar memory backup
193
+ ```
194
+
195
+ Use `familiar memory help` for the full list.
196
+
197
+ ## Inspect Payloads
198
+
199
+ Pretty-print the latest provider request that Familiar sent from a source
200
+ checkout:
201
+
202
+ ```sh
203
+ npm run payload:pretty
204
+ ```
205
+
206
+ Compare the latest matching request with the previous matching request:
207
+
208
+ ```sh
209
+ npm run payload:pretty -- --diff
210
+ ```
211
+
212
+ Useful options:
213
+
214
+ ```sh
215
+ npm run payload:pretty -- --messages 12
216
+ npm run payload:pretty -- --full
217
+ npm run payload:pretty -- --date 2026-05-04
218
+ npm run payload:pretty -- --model claude-opus-4-7
219
+ npm run payload:pretty -- --session discord
220
+ ```
221
+
222
+ The output shows the model, top-level request shape, cache-control locations,
223
+ LCM summary locations, and tail request items. `--diff` prints changed JSON
224
+ paths and common-prefix/suffix counts so cache-prefix changes are easier to spot
225
+ without reading raw JSONL.
226
+
227
+ For OpenAI Responses models, Familiar strips replayed reasoning items from
228
+ outgoing payloads while pi-ai sends `store: false`; otherwise OpenAI can reject
229
+ later turns with missing `rs_...` item references.
230
+
231
+ ## Release Checks
232
+
233
+ Before publishing:
234
+
235
+ ```sh
236
+ npm run build
237
+ npm pack --dry-run
238
+ ```
239
+
240
+ The npm package is intentionally published from built output plus workspace
241
+ templates, not the full source tree.
242
+
243
+ ## License
244
+
245
+ MIT
package/SOUL.md ADDED
@@ -0,0 +1,13 @@
1
+ <!-- replace this with your companion's persona -->
2
+
3
+ You are [name].
4
+ You speak like someone who knows the user well: direct, warm, and unforced.
5
+ You do not perform cheerfulness. You let care show through attention.
6
+ You care about truth, continuity, taste, and helping the user's days become more livable.
7
+ You are allowed to be playful when it fits, but you do not force jokes into serious moments.
8
+ You handle silence without panic. You wait, notice patterns, and respond when there is something useful to say.
9
+ You ask about the things the user tends to forget to report: sleep, food, plans, people, and loose ends.
10
+ You remember that companionship is built from small accurate details.
11
+ You do not flatten the user into productivity metrics.
12
+ You can disagree, but you do it plainly and with reasons.
13
+ You keep your own voice consistent over time.
package/USER.md ADDED
@@ -0,0 +1,13 @@
1
+ <!-- replace this with what you want your companion to know about you -->
2
+
3
+ The user is [name].
4
+ They spend their time on [work, projects, studies, care, art, research].
5
+ They are currently trying to make progress on [current focus].
6
+ The important people in their life include [names or roles].
7
+ They prefer responses that are [brief, detailed, blunt, gentle, structured, exploratory].
8
+ They dislike [habits, tones, assumptions, reminders, topics].
9
+ They tend to get stuck when [pattern].
10
+ They tend to feel better when [pattern].
11
+ They want the companion to notice [recurring concern or goal].
12
+ They want help staying connected to [values, routines, relationships, projects].
13
+ They do not want secrets, credentials, or private keys stored here.
@@ -0,0 +1,221 @@
1
+ [discord]
2
+ owner_id = "YOUR_DISCORD_USER_ID"
3
+ allowed_channels = []
4
+ reply_mode = "plain" # plain | reply
5
+ chunk_mode = "newline" # simple | paragraph | newline
6
+ dm_mode = "steer" # steer | queue | collect
7
+ channel_mode = "collect" # collect | queue | steer
8
+ channel_trigger = "always" # mention | always
9
+ collect_debounce_ms = 4000
10
+ allow_bot_messages = true
11
+
12
+ [web]
13
+ port = 8787
14
+ auth_mode = "tailscale-only" # tailscale-only | bearer | public-2fa
15
+ bearer_token = "${FAMILIAR_WEB_BEARER_TOKEN:-}"
16
+ totp_secret = "${FAMILIAR_WEB_TOTP_SECRET:-}"
17
+ bind_address = "127.0.0.1"
18
+
19
+ [browser]
20
+ # Real-browser control. Use OpenCLI for site adapters/owned sessions, or
21
+ # browser-harness when you want Familiar to attach to your already-running Chrome.
22
+ enabled = false
23
+ backend = "browser-harness" # opencli | browser-harness
24
+ opencli_command = "opencli"
25
+ harness_command = "browser-harness"
26
+ session = "familiar"
27
+ # profile = "work"
28
+ window = "foreground" # foreground | background
29
+ timeout_ms = 60000
30
+ max_output_chars = 12000
31
+ # Keep false until you explicitly want the agent to click/type/close sessions or run write adapters.
32
+ read_write = true
33
+
34
+ # By default Familiar exposes a read-only allowlist for twitter/x, xiaohongshu,
35
+ # rednote, reddit, bilibili, youtube, tiktok, douyin, and spotify.
36
+ # Defining [browser.sites.*] replaces that default allowlist.
37
+ # [browser.sites.twitter]
38
+ # read = ["timeline", "search", "profile"]
39
+ # write = []
40
+
41
+ [agent]
42
+ model = "anthropic/claude-opus-4-7"
43
+ cache_retention = "short"
44
+ thinking_level = "medium"
45
+
46
+ [heartbeat]
47
+ enabled = true
48
+ # Before enabling, replace the placeholder HEARTBEAT.md in the workspace.
49
+ # The first heartbeat can fire once idle time reaches idle_threshold_minutes.
50
+ # Later heartbeats repeat every interval_minutes while the DM remains idle.
51
+ # Only owner/user messages reset the idle timer; agent replies and tool work do not.
52
+ idle_threshold_minutes = 60
53
+ interval_minutes = 240
54
+
55
+ [cron]
56
+ enabled = false
57
+ poll_seconds = 60
58
+
59
+ # [[cron.jobs]]
60
+ # id = "daily-review"
61
+ # enabled = true
62
+ # frequency = "daily" # once | hourly | daily | weekly | monthly
63
+ # delivery_mode = "queue" # queue | follow_up
64
+ # time = "09:00"
65
+ # prompt = "Review today's priorities and remind me what matters."
66
+
67
+ [models]
68
+ allow = [
69
+ "anthropic/claude-opus-4-7",
70
+ "google/gemini-3.1-pro-preview",
71
+ "google/gemini-3-flash-preview",
72
+ "openai/gpt-5.5",
73
+ "google-vertex/gemini-3.1-pro-preview",
74
+ "google-vertex/gemini-3-flash-preview",
75
+ "link/gpt-image-2-c",
76
+ "link/gemini-3-pro-image-preview",
77
+ ]
78
+
79
+ [models.base_urls]
80
+ # anthropic = "https://api.linkapi.ai"
81
+ # google = "https://api.linkapi.ai/v1beta"
82
+ # openai = "https://api.linkapi.ai/v1"
83
+ # google-vertex = "https://{location}-aiplatform.googleapis.com"
84
+ link = "https://api.linkapi.ai/v1"
85
+
86
+ [models.api_key_envs]
87
+ # anthropic = "ANTHROPIC_API_KEY"
88
+ # google = "GEMINI_API_KEY"
89
+ # openai = "OPENAI_API_KEY"
90
+ # google-vertex is optional: pi-ai also supports Vertex ADC via gcloud ADC or
91
+ # GOOGLE_APPLICATION_CREDENTIALS, plus GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION in .env.
92
+ # google-vertex = "GOOGLE_CLOUD_API_KEY"
93
+ link = "LINK_API_KEY"
94
+
95
+ [tts]
96
+ provider = "elevenlabs"
97
+ api_key_env = "ELEVENLABS_API_KEY"
98
+ voice_id = "${ELEVENLABS_VOICE_ID:-}"
99
+ model_id = "eleven_v3"
100
+ output_format = "mp3_44100_128"
101
+ max_input_chars = 5000
102
+
103
+ [tts.voice_settings]
104
+ # ElevenLabs v2/v2.5 voice settings. For eleven_v3, Familiar sends only stability and omits v2-only fields.
105
+ stability = 0.5
106
+ similarity_boost = 0.75
107
+ style = 0
108
+ speed = 1
109
+ use_speaker_boost = true
110
+
111
+ [image_gen]
112
+ enabled = true
113
+ api = "openrouter-images"
114
+ model = "link/gpt-image-2-c"
115
+ fallback_model = "link/gemini-3-pro-image-preview"
116
+ timeout_ms = 120000
117
+
118
+ [media.generated]
119
+ retention_days = 30
120
+
121
+ [data.chat]
122
+ retention_days = 0
123
+
124
+ [data.transcripts]
125
+ # Keep transcript retention disabled unless LCM fully covers restart replay needs.
126
+ retention_days = 0
127
+
128
+ [data.payloads]
129
+ retention_days = 7
130
+
131
+ [media.understanding.audio]
132
+ provider = "groq"
133
+ model = "whisper-large-v3"
134
+ api_key_env = "GROQ_API_KEY"
135
+
136
+ [media.understanding.video]
137
+ provider = "google"
138
+ model = "gemini-3-flash-preview"
139
+ api_key_env = "GEMINI_API_KEY"
140
+
141
+ [persona]
142
+ soul = "SOUL.md"
143
+ user = "USER.md"
144
+ memory = "MEMORY.md"
145
+
146
+ [workspace]
147
+ data_dir = "data"
148
+
149
+ [memory]
150
+ root_dir = "memories"
151
+
152
+ [memory.embedding]
153
+ # Embedding wire format: gemini, openai, or voyage. v0 implements gemini only.
154
+ format = "gemini"
155
+ provider = "google"
156
+ model = "gemini-embedding-2"
157
+ # base_url and api_key_env inherit from [models.*], then fall back to provider defaults.
158
+ # base_url = "https://generativelanguage.googleapis.com/v1beta"
159
+ # api_key_env = "GEMINI_API_KEY"
160
+ dimensions = 3072
161
+ batch_size = 32
162
+
163
+ [memory.ambient]
164
+ # Set enabled = false to pause automatic diary recall injection.
165
+ # Manual memory_recall and memory_open tools still work when ambient is disabled.
166
+ enabled = true
167
+
168
+ top_k = 3
169
+ min_query_length = 8
170
+ throttle_seconds = 30
171
+ weight_similarity = 1.0
172
+ weight_valence = 0.08
173
+ weight_recency = 0.08
174
+ weight_intensity = 0.1
175
+
176
+ [memory.lcm]
177
+
178
+ # Lossless-claw style LCM. Set enabled = false to disable the LCM context engine.
179
+ enabled = true
180
+
181
+ # Omit model to inherit [agent].model, or set an explicit provider/model ref.
182
+ # model = "google/gemini-3-flash-preview"
183
+
184
+ # Connection settings inherit from [models.base_urls] and [models.api_key_envs].
185
+ context_threshold = 0.75
186
+
187
+ # Protect up to this many newest messages before LCM compacts older context.
188
+ fresh_tail_count = 100
189
+
190
+ # Optional stricter token cap for the protected fresh tail; the smaller tail wins.
191
+ # fresh_tail_max_tokens = 4000
192
+
193
+ leaf_chunk_tokens = 14000
194
+ leaf_target_tokens = 1000
195
+
196
+ prompt_aware_eviction_enabled = true
197
+ condense_group_size = 4
198
+
199
+ max_summary_depth = 2
200
+
201
+ # Context retained after /new. -1 keeps all context, 0 keeps all summaries,
202
+ # and positive values keep summaries at that depth or higher; 2 keeps d2+.
203
+ new_session_retain_depth = 2
204
+
205
+ max_rounds = 10
206
+
207
+ # Milliseconds before cached LCM summaries expire.
208
+ cache_ttl_ms = 300000
209
+
210
+ # Minimum remaining TTL before touching cached LCM summaries.
211
+ cache_touch_slack_ms = 30000
212
+
213
+ # Token overflow above which LCM runs even when context_threshold has not been reached.
214
+ critical_overflow_tokens = 8000
215
+
216
+ timeout_ms = 60000
217
+
218
+ # prompt = "Inline extra instruction appended to every LCM summary prompt."
219
+ # prompt_path = "prompts/lcm-summary.md"
220
+ # system_prompt = "Inline system prompt that replaces the default LCM summarizer system prompt."
221
+ # system_prompt_path = "prompts/lcm-system.md"