@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.
- package/.env.example +31 -0
- package/HEARTBEAT.md +23 -0
- package/LICENSE +21 -0
- package/MEMORY.md +1 -0
- package/README.md +245 -0
- package/SOUL.md +13 -0
- package/USER.md +13 -0
- package/config.example.toml +221 -0
- package/dist/agent-events.js +167 -0
- package/dist/agent.js +590 -0
- package/dist/browser-tools.js +638 -0
- package/dist/chat-log.js +130 -0
- package/dist/cli.js +168 -0
- package/dist/config.js +804 -0
- package/dist/data-retention.js +54 -0
- package/dist/discord.js +1203 -0
- package/dist/generated-media.js +86 -0
- package/dist/image-derivatives.js +102 -0
- package/dist/image-gen.js +440 -0
- package/dist/inbound-attachments.js +266 -0
- package/dist/index.js +10 -0
- package/dist/media-understanding.js +120 -0
- package/dist/memory/diary/ambient-injector.js +180 -0
- package/dist/memory/diary/ambient.js +124 -0
- package/dist/memory/diary/chunks.js +231 -0
- package/dist/memory/diary/index.js +3 -0
- package/dist/memory/diary/indexer.js +93 -0
- package/dist/memory/doctor.js +250 -0
- package/dist/memory/index/chunk-indexer.js +151 -0
- package/dist/memory/index/embedding-provider.js +119 -0
- package/dist/memory/index/fts-query.js +18 -0
- package/dist/memory/index/retrieval.js +246 -0
- package/dist/memory/index/schema.js +157 -0
- package/dist/memory/index/store.js +513 -0
- package/dist/memory/index/vec.js +72 -0
- package/dist/memory/index/vector-codec.js +27 -0
- package/dist/memory/lcm/backfill.js +247 -0
- package/dist/memory/lcm/condense.js +146 -0
- package/dist/memory/lcm/context-transformer.js +662 -0
- package/dist/memory/lcm/context.js +421 -0
- package/dist/memory/lcm/eviction-score.js +38 -0
- package/dist/memory/lcm/index.js +6 -0
- package/dist/memory/lcm/indexer.js +200 -0
- package/dist/memory/lcm/normalize.js +235 -0
- package/dist/memory/lcm/schema.js +188 -0
- package/dist/memory/lcm/segment-manager.js +136 -0
- package/dist/memory/lcm/store.js +722 -0
- package/dist/memory/lcm/summarizer.js +258 -0
- package/dist/memory/lcm/types.js +1 -0
- package/dist/memory/operator.js +477 -0
- package/dist/memory/service.js +202 -0
- package/dist/memory/tools.js +205 -0
- package/dist/models.js +165 -0
- package/dist/persona.js +54 -0
- package/dist/runtime.js +493 -0
- package/dist/scheduler.js +200 -0
- package/dist/settings.js +116 -0
- package/dist/skills.js +38 -0
- package/dist/tts.js +143 -0
- package/dist/web-auth.js +105 -0
- package/dist/web-events.js +114 -0
- package/dist/web-http.js +29 -0
- package/dist/web-static.js +106 -0
- package/dist/web-tools.js +940 -0
- package/dist/web-types.js +2 -0
- package/dist/web.js +844 -0
- package/package.json +60 -0
- package/web/dist/assets/index-ClgkMgaq.css +2 -0
- package/web/dist/assets/index-Cu2QquuR.js +59 -0
- package/web/dist/favicon.svg +1 -0
- package/web/dist/icons.svg +24 -0
- 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"
|