@reconcrap/people-network-memory 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/README.md +476 -0
- package/docs/mcp_tools.md +138 -0
- package/harness_adapters/openclaw/mcp.managed.unix.template.json +25 -0
- package/harness_adapters/openclaw/mcp.managed.windows.template.json +26 -0
- package/harness_adapters/openclaw/mcp.template.json +14 -0
- package/harness_adapters/openclaw/ppl/SKILL.md +114 -0
- package/package.json +30 -0
- package/pyproject.toml +26 -0
- package/scripts/install_windows.ps1 +92 -0
- package/scripts/npm/people-memory.js +276 -0
- package/scripts/people_memory_bootstrap.py +247 -0
- package/scripts/run_graphiti_live_from_liepin.ps1 +87 -0
- package/scripts/run_tests_with_artifacts.ps1 +307 -0
- package/src/people_network_memory/__init__.py +6 -0
- package/src/people_network_memory/application/__init__.py +16 -0
- package/src/people_network_memory/application/normalization.py +1441 -0
- package/src/people_network_memory/application/services.py +921 -0
- package/src/people_network_memory/cli.py +1212 -0
- package/src/people_network_memory/config.py +268 -0
- package/src/people_network_memory/domain/__init__.py +55 -0
- package/src/people_network_memory/domain/identity.py +77 -0
- package/src/people_network_memory/domain/models.py +355 -0
- package/src/people_network_memory/fixtures/__init__.py +6 -0
- package/src/people_network_memory/fixtures/eval.py +398 -0
- package/src/people_network_memory/fixtures/extractor_eval.py +364 -0
- package/src/people_network_memory/fixtures/generator.py +290 -0
- package/src/people_network_memory/fixtures/report.py +252 -0
- package/src/people_network_memory/graphiti_adapter/__init__.py +9 -0
- package/src/people_network_memory/graphiti_adapter/episode_formatter.py +70 -0
- package/src/people_network_memory/graphiti_adapter/graphiti_store.py +655 -0
- package/src/people_network_memory/graphiti_adapter/indexer.py +194 -0
- package/src/people_network_memory/graphiti_adapter/ontology.py +68 -0
- package/src/people_network_memory/harness_adapters/__init__.py +2 -0
- package/src/people_network_memory/harness_adapters/openclaw/__init__.py +9 -0
- package/src/people_network_memory/harness_adapters/openclaw/installer.py +577 -0
- package/src/people_network_memory/harness_adapters/openclaw/integration_eval.py +508 -0
- package/src/people_network_memory/harness_adapters/openclaw/smoke.py +292 -0
- package/src/people_network_memory/infrastructure/__init__.py +2 -0
- package/src/people_network_memory/infrastructure/archive_backup.py +171 -0
- package/src/people_network_memory/infrastructure/diagnostics.py +171 -0
- package/src/people_network_memory/infrastructure/embeddings.py +155 -0
- package/src/people_network_memory/infrastructure/file_store.py +129 -0
- package/src/people_network_memory/infrastructure/graphiti_promotion.py +212 -0
- package/src/people_network_memory/infrastructure/id_generator.py +40 -0
- package/src/people_network_memory/infrastructure/in_memory_store.py +1008 -0
- package/src/people_network_memory/infrastructure/llm_extractor.py +476 -0
- package/src/people_network_memory/infrastructure/llm_identity_advisor.py +200 -0
- package/src/people_network_memory/infrastructure/llm_judge.py +162 -0
- package/src/people_network_memory/infrastructure/redaction.py +21 -0
- package/src/people_network_memory/infrastructure/release_check.py +186 -0
- package/src/people_network_memory/infrastructure/retrieval_intent.py +98 -0
- package/src/people_network_memory/infrastructure/semantic_index.py +262 -0
- package/src/people_network_memory/mcp_server/__init__.py +2 -0
- package/src/people_network_memory/mcp_server/contracts.py +85 -0
- package/src/people_network_memory/mcp_server/runtime.py +133 -0
- package/src/people_network_memory/mcp_server/tools.py +588 -0
- package/src/people_network_memory/ports/__init__.py +2 -0
- package/src/people_network_memory/ports/errors.py +25 -0
- package/src/people_network_memory/ports/interfaces.py +103 -0
- package/src/people_network_memory/projection/__init__.py +6 -0
- package/src/people_network_memory/projection/builders.py +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
# People Network Memory MCP
|
|
2
|
+
|
|
3
|
+
Local-first V1 scaffold for a personal social-memory MCP. The implementation keeps the product logic independent from Graphiti/MCP/OpenClaw so the core can be tested without external services.
|
|
4
|
+
|
|
5
|
+
## Quick Commands
|
|
6
|
+
|
|
7
|
+
```powershell
|
|
8
|
+
python -m pip install -e .
|
|
9
|
+
python -m unittest discover -s tests -v
|
|
10
|
+
people-memory start --test-mode --once
|
|
11
|
+
people-memory doctor --test-mode
|
|
12
|
+
people-memory load-fixtures --summary
|
|
13
|
+
people-memory eval-fixtures
|
|
14
|
+
people-memory eval-fixtures --failures-only --output .people-network-memory/eval-report.json
|
|
15
|
+
people-memory spike-graphiti
|
|
16
|
+
people-memory check-embedding
|
|
17
|
+
people-memory tool-schemas
|
|
18
|
+
people-memory smoke-graphiti --isolated
|
|
19
|
+
people-memory graphiti-gate --isolated --output .people-network-memory/graphiti-gate.json
|
|
20
|
+
people-memory index-graphiti --resume --limit 10 --output .people-network-memory/index-graphiti.json
|
|
21
|
+
people-memory graphiti-ladder --steps 1,3,10 --cumulative --output-dir .people-network-memory/test-artifacts/graphiti-ladder
|
|
22
|
+
people-memory smoke-openclaw
|
|
23
|
+
people-memory eval-harness-integration
|
|
24
|
+
people-memory release-check
|
|
25
|
+
people-memory eval-graphiti --isolated --max-interactions 3 --max-queries 3
|
|
26
|
+
people-memory install-openclaw --dry-run
|
|
27
|
+
people-memory list-reviews
|
|
28
|
+
people-memory backup --output .people-network-memory/backup.json
|
|
29
|
+
people-memory backup-archive --output .people-network-memory/backup.zip
|
|
30
|
+
people-memory restore --input .people-network-memory/backup.json
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The base test suite uses `unittest` and does not require Graphiti, Docker, or a graph
|
|
34
|
+
database:
|
|
35
|
+
|
|
36
|
+
```powershell
|
|
37
|
+
python -m unittest discover -s tests -v
|
|
38
|
+
python -m people_network_memory.cli release-check
|
|
39
|
+
powershell -ExecutionPolicy Bypass -File .\scripts\run_tests_with_artifacts.ps1
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The artifact runner writes command output, JSON reports, and a manifest with
|
|
43
|
+
exit codes to `.people-network-memory/test-artifacts/latest/` by default. That
|
|
44
|
+
directory is ignored by git so local verification reports do not leak into the
|
|
45
|
+
package.
|
|
46
|
+
|
|
47
|
+
## Local Install
|
|
48
|
+
|
|
49
|
+
### npm Install
|
|
50
|
+
|
|
51
|
+
The recommended end-user distribution path is the npm wrapper. It keeps the
|
|
52
|
+
product code in Python, but gives OpenClaw users a familiar install/update
|
|
53
|
+
surface:
|
|
54
|
+
|
|
55
|
+
```powershell
|
|
56
|
+
npm install -g @reconcrap/people-network-memory
|
|
57
|
+
people-memory doctor --test-mode
|
|
58
|
+
people-memory install-openclaw --backend local_json
|
|
59
|
+
people-memory doctor --agent openclaw
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The npm `people-memory` command lazily creates a private Python 3.11+ venv and
|
|
63
|
+
installs this package into it. The default venv locations are:
|
|
64
|
+
|
|
65
|
+
- Windows: `%LOCALAPPDATA%\people-network-memory\npm-venv`
|
|
66
|
+
- macOS: `~/Library/Application Support/people-network-memory/npm-venv`
|
|
67
|
+
- Linux: `${XDG_DATA_HOME:-~/.local/share}/people-network-memory/npm-venv`
|
|
68
|
+
|
|
69
|
+
Set `PEOPLE_MEMORY_NPM_VENV` to override that location, or
|
|
70
|
+
`PEOPLE_MEMORY_PYTHON` to choose a specific Python command. For Graphiti extras,
|
|
71
|
+
either run with `--backend graphiti` or set
|
|
72
|
+
`PEOPLE_MEMORY_NPM_EXTRAS=graphiti`.
|
|
73
|
+
|
|
74
|
+
When `install-openclaw` is run through the npm command, the installer writes
|
|
75
|
+
OpenClaw to launch the absolute Node executable plus the npm wrapper script.
|
|
76
|
+
That keeps the MCP server independent of shell PATH differences between visible
|
|
77
|
+
terminals and hidden OpenClaw gateway sessions on Windows and macOS.
|
|
78
|
+
|
|
79
|
+
Update flow:
|
|
80
|
+
|
|
81
|
+
```powershell
|
|
82
|
+
npm update -g @reconcrap/people-network-memory
|
|
83
|
+
people-memory install-openclaw --backend local_json
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Source Checkout Install
|
|
87
|
+
|
|
88
|
+
For a clean Windows checkout, use the bootstrap script. It creates `.venv`,
|
|
89
|
+
installs the package, runs the test suite, runs `doctor`, and starts the MCP
|
|
90
|
+
server once in test mode:
|
|
91
|
+
|
|
92
|
+
```powershell
|
|
93
|
+
powershell -ExecutionPolicy Bypass -File .\scripts\install_windows.ps1
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Install optional Graphiti/Kuzu dependencies as part of the same flow:
|
|
97
|
+
|
|
98
|
+
```powershell
|
|
99
|
+
powershell -ExecutionPolicy Bypass -File .\scripts\install_windows.ps1 -Graphiti
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
To also wire OpenClaw to a managed bootstrap command:
|
|
103
|
+
|
|
104
|
+
```powershell
|
|
105
|
+
powershell -ExecutionPolicy Bypass -File .\scripts\install_windows.ps1 -OpenClaw
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The managed OpenClaw entry starts `scripts/people_memory_bootstrap.py`. On each
|
|
109
|
+
server start, that bootstrapper checks for a local `.venv`, creates it if
|
|
110
|
+
missing, installs or updates dependencies when `pyproject.toml` changes, then
|
|
111
|
+
launches the MCP server from the venv. This lets an AI harness repair missing
|
|
112
|
+
Python package dependencies without the user manually running pip.
|
|
113
|
+
|
|
114
|
+
For a trusted git checkout, add `-AutoUpdate` to let the bootstrapper run
|
|
115
|
+
`git pull --ff-only` before dependency checks:
|
|
116
|
+
|
|
117
|
+
```powershell
|
|
118
|
+
powershell -ExecutionPolicy Bypass -File .\scripts\install_windows.ps1 -OpenClaw -AutoUpdate
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
This still requires a system Python 3.11+ command to exist. On Windows the
|
|
122
|
+
managed entry uses `py -3.11`; on macOS/Linux it uses `python3`.
|
|
123
|
+
|
|
124
|
+
For Graphiti-backed OpenClaw, first configure the embedding and LLM environment
|
|
125
|
+
variables in OpenClaw or the launching shell, then run:
|
|
126
|
+
|
|
127
|
+
```powershell
|
|
128
|
+
powershell -ExecutionPolicy Bypass -File .\scripts\install_windows.ps1 -Graphiti -OpenClaw -Backend graphiti
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
The bootstrap script does not write API keys or model credentials.
|
|
132
|
+
|
|
133
|
+
For the current Windows development setup, the live Graphiti artifact run can
|
|
134
|
+
reuse Volcengine/Doubao embeddings and the LLM values from the Liepin screening
|
|
135
|
+
config:
|
|
136
|
+
|
|
137
|
+
```powershell
|
|
138
|
+
$env:VOLCENGINE_API_KEY="<secret>"
|
|
139
|
+
powershell -ExecutionPolicy Bypass -File .\scripts\run_graphiti_live_from_liepin.ps1
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
That wrapper maps the embedding endpoint/model to Volcengine, reads
|
|
143
|
+
`baseUrl`/`model`/credential from `~/.liepin-recommend-mcp/screening-config.json`
|
|
144
|
+
for the LLM provider, disables Graphiti telemetry, and stores verification
|
|
145
|
+
artifacts under `.people-network-memory/test-artifacts/graphiti-live/`.
|
|
146
|
+
|
|
147
|
+
`spike-graphiti` is the prerequisite gate. `graphiti-gate` is the promotion
|
|
148
|
+
gate: it keeps `local_json` as the default, runs live embedding plus a full
|
|
149
|
+
Graphiti/Kuzu fixture eval when providers are configured, and reports whether
|
|
150
|
+
Graphiti/Kuzu is ready to become the recommended recall backend.
|
|
151
|
+
|
|
152
|
+
## Backends
|
|
153
|
+
|
|
154
|
+
- `local_json` is the default non-test backend and persists to
|
|
155
|
+
`~/.people-network-memory/people-memory.json`.
|
|
156
|
+
- `inmemory` is used for tests and quick smoke checks.
|
|
157
|
+
- `graphiti` is gated behind `people-memory graphiti-gate`; do not treat it as
|
|
158
|
+
the recommended recall backend until that command passes with live providers.
|
|
159
|
+
- For local Graphiti, prefer embedded Kuzu first. It avoids Docker and server setup.
|
|
160
|
+
|
|
161
|
+
Python 3.11 venv setup for Graphiti + Kuzu:
|
|
162
|
+
|
|
163
|
+
```powershell
|
|
164
|
+
py -3.11 -m venv .venv
|
|
165
|
+
.\.venv\Scripts\python.exe -m pip install --upgrade pip
|
|
166
|
+
.\.venv\Scripts\python.exe -m pip install -e ".[graphiti]"
|
|
167
|
+
.\.venv\Scripts\python.exe -m people_network_memory.cli spike-graphiti
|
|
168
|
+
.\.venv\Scripts\python.exe -m people_network_memory.cli smoke-graphiti --isolated
|
|
169
|
+
.\.venv\Scripts\python.exe -m people_network_memory.cli eval-graphiti --isolated --max-interactions 3 --max-queries 3 --output .people-network-memory/graphiti-eval.json
|
|
170
|
+
.\.venv\Scripts\python.exe -m people_network_memory.cli graphiti-gate --isolated --output .people-network-memory/graphiti-gate.json
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Eval reports include Recall@3, Recall@5, per-category breakdowns, evidence
|
|
174
|
+
coverage, no-result counts, sensitive-leak counts, and optional case-level
|
|
175
|
+
diagnostics. When `--max-interactions` is used, evals default to queries whose
|
|
176
|
+
source fixture interactions were ingested. Add `--all-queries` only when you
|
|
177
|
+
intentionally want to test missing/unanswerable targets.
|
|
178
|
+
|
|
179
|
+
Case-level diagnostics include the query, expected people/terms, matched and
|
|
180
|
+
missed expected values, and the actual top retrieval results with evidence
|
|
181
|
+
source text/date. The artifact runner saves these full case diagnostics by
|
|
182
|
+
default in `eval-fixtures.json`; Graphiti live artifacts save them in
|
|
183
|
+
`graphiti-gate.json` and `graphiti-eval.json`.
|
|
184
|
+
|
|
185
|
+
`eval-graphiti` without `--max-*` runs the full fixture set. The small bounded
|
|
186
|
+
form above is only a quick smoke check. `graphiti-gate` uses the full fixture
|
|
187
|
+
set by default and requires Recall@3 >= 70%, Recall@5 >= 85%, complete returned
|
|
188
|
+
evidence, zero sensitive leaks, at least 40 checked queries, and at least 60
|
|
189
|
+
ingested interactions unless you intentionally bound the run.
|
|
190
|
+
|
|
191
|
+
Graphiti indexing should be treated as resumable background work. Local JSON is
|
|
192
|
+
the canonical capture store; `index-graphiti` reads saved local interactions and
|
|
193
|
+
adds compact text episodes into Graphiti/Kuzu one by one, saving progress after
|
|
194
|
+
each successful episode:
|
|
195
|
+
|
|
196
|
+
```powershell
|
|
197
|
+
people-memory index-graphiti --resume --limit 10 --output .people-network-memory/index-graphiti.json
|
|
198
|
+
people-memory index-graphiti --resume --limit 10
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Use the ingestion ladder to find the point where the live Graphiti/LLM path
|
|
202
|
+
slows down or fails. Each step writes a separate JSON artifact:
|
|
203
|
+
|
|
204
|
+
```powershell
|
|
205
|
+
people-memory graphiti-ladder --steps 1,3,10,20,40,90 --output-dir .people-network-memory/test-artifacts/graphiti-ladder
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Add `--cumulative` when testing larger rungs. It reuses one artifact-local
|
|
209
|
+
Graphiti/Kuzu store plus one state file, so a `20,40,90` run indexes only the
|
|
210
|
+
additional interactions at each step and leaves the test database under the
|
|
211
|
+
artifact directory:
|
|
212
|
+
|
|
213
|
+
```powershell
|
|
214
|
+
people-memory graphiti-ladder --steps 20,40,90 --cumulative --output-dir .people-network-memory/test-artifacts/graphiti-ladder-cumulative
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
If that command is interrupted, rerun it with `--resume-cumulative` against the
|
|
218
|
+
same output directory to keep the existing state file:
|
|
219
|
+
|
|
220
|
+
```powershell
|
|
221
|
+
people-memory graphiti-ladder --steps 20,40,90 --cumulative --resume-cumulative --output-dir .people-network-memory/test-artifacts/graphiti-ladder-cumulative
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
For slow live providers, raise the per-episode timeout without changing code:
|
|
225
|
+
|
|
226
|
+
```powershell
|
|
227
|
+
$env:PEOPLE_MEMORY_GRAPHITI_ADD_TIMEOUT_SECONDS="600"
|
|
228
|
+
$env:PEOPLE_MEMORY_GRAPHITI_RETRY_ATTEMPTS="4"
|
|
229
|
+
people-memory graphiti-ladder --steps 20,40,90 --cumulative --resume-cumulative --output-dir .people-network-memory/test-artifacts/graphiti-ladder-cumulative
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Bounded ladder runs are diagnostics only; they cannot promote Graphiti/Kuzu to
|
|
233
|
+
the recommended backend.
|
|
234
|
+
|
|
235
|
+
After an existing Graphiti/Kuzu fixture graph has been indexed, evaluate search
|
|
236
|
+
quality without re-ingesting episodes:
|
|
237
|
+
|
|
238
|
+
```powershell
|
|
239
|
+
people-memory eval-graphiti-search --data-path .people-network-memory/test-artifacts/graphiti-ladder-cumulative/cumulative-store/projection --graphiti-kuzu-path .people-network-memory/test-artifacts/graphiti-ladder-cumulative/cumulative-store/graphiti.kuzu --indexed-interactions 90 --output .people-network-memory/test-artifacts/graphiti-search/eval.json
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
If the graph was populated by the fixture ladder before the projection cache was
|
|
243
|
+
hydrated, rebuild that local cache without calling Graphiti again:
|
|
244
|
+
|
|
245
|
+
```powershell
|
|
246
|
+
people-memory hydrate-graphiti-cache --data-path .people-network-memory/test-artifacts/graphiti-ladder-cumulative/cumulative-store/projection --fixture-seed 42 --limit 90 --output .people-network-memory/test-artifacts/graphiti-search/cache-hydration.json
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Build the optional local semantic sidecar over the hydrated projection cache:
|
|
250
|
+
|
|
251
|
+
```powershell
|
|
252
|
+
people-memory build-semantic-cache --data-path .people-network-memory/test-artifacts/graphiti-ladder-cumulative/cumulative-store/projection --limit 90 --reset --output .people-network-memory/test-artifacts/graphiti-search/semantic-cache.json
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
With that sidecar present, Graphiti retrieval merges three sources: Graphiti
|
|
256
|
+
graph search, local semantic interaction search, and local token/event search.
|
|
257
|
+
The strict eval report checks intent-aware matches, not just loose token
|
|
258
|
+
overlap: `who mentioned X` must return the speaker, promise queries must return
|
|
259
|
+
follow-up items, and profile queries must combine the requested terms in one
|
|
260
|
+
returned result. For intentionally broad fixture queries, the report also keeps
|
|
261
|
+
`expected_person_rank` as a diagnostic because several mock people may satisfy
|
|
262
|
+
the same place/topic or company/topic query.
|
|
263
|
+
|
|
264
|
+
## Optional LLM Retrieval Judge
|
|
265
|
+
|
|
266
|
+
The default retrieval path is deterministic and fully testable. For a final
|
|
267
|
+
quality pass, enable the optional OpenAI-compatible LLM judge:
|
|
268
|
+
|
|
269
|
+
```powershell
|
|
270
|
+
$env:PEOPLE_MEMORY_RETRIEVAL_JUDGE="llm"
|
|
271
|
+
$env:PEOPLE_MEMORY_RETRIEVAL_JUDGE_TIMEOUT_SECONDS="30"
|
|
272
|
+
$env:PEOPLE_MEMORY_LLM_BASE_URL="<base-url>"
|
|
273
|
+
$env:PEOPLE_MEMORY_LLM_MODEL="<model>"
|
|
274
|
+
$env:PEOPLE_MEMORY_LLM_API_KEY="<secret>"
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
When enabled, `retrieve_network_context` fetches a broader candidate set, asks
|
|
278
|
+
the judge to rank only candidates that directly answer the query, and falls back
|
|
279
|
+
to deterministic ranking if the judge fails or returns invalid JSON.
|
|
280
|
+
|
|
281
|
+
The intended harness split is hybrid:
|
|
282
|
+
|
|
283
|
+
- This tool owns social-memory retrieval quality: query expansion, graph/semantic
|
|
284
|
+
search, deterministic social-intent checks, optional LLM reranking, evidence,
|
|
285
|
+
sensitivity policy, and stable person IDs.
|
|
286
|
+
- The AI harness owns user-aware synthesis: applying its memory of the user's
|
|
287
|
+
goals, style, preferences, and current constraints to the retrieved social
|
|
288
|
+
evidence.
|
|
289
|
+
- The OpenClaw skill instructs the harness to retrieve from this MCP first,
|
|
290
|
+
treat returned people/network facts as source-backed evidence, then combine
|
|
291
|
+
them with the harness's own user memory for final recommendations, briefs,
|
|
292
|
+
drafts, or plans.
|
|
293
|
+
|
|
294
|
+
Run the deterministic harness integration eval to check that contract without
|
|
295
|
+
needing a live AI harness:
|
|
296
|
+
|
|
297
|
+
```powershell
|
|
298
|
+
people-memory eval-harness-integration --output .people-network-memory/harness-integration-eval.json
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
The eval seeds a small social graph and verifies planning, intro drafting,
|
|
302
|
+
conflict resolution, missing-person evidence, and follow-up cases. Each case
|
|
303
|
+
records the prompt, simulated harness memory, MCP tool calls, actual retrieval
|
|
304
|
+
results, hydrated person cards when needed, and pass/fail checks for source
|
|
305
|
+
boundaries.
|
|
306
|
+
|
|
307
|
+
## LLM Ingestion Extractor
|
|
308
|
+
|
|
309
|
+
The capture path defaults to the OpenAI-compatible LLM extractor when usable,
|
|
310
|
+
then falls back to deterministic normalization. This improves messier Chinese,
|
|
311
|
+
alias, and bilingual social notes without making a fresh install depend on LLM
|
|
312
|
+
credentials. To provide an LLM, set:
|
|
313
|
+
|
|
314
|
+
```powershell
|
|
315
|
+
$env:PEOPLE_MEMORY_INGESTION_EXTRACTOR="llm"
|
|
316
|
+
$env:PEOPLE_MEMORY_INGESTION_EXTRACTOR_TIMEOUT_SECONDS="30"
|
|
317
|
+
$env:PEOPLE_MEMORY_LLM_BASE_URL="<base-url>"
|
|
318
|
+
$env:PEOPLE_MEMORY_LLM_MODEL="<model>"
|
|
319
|
+
$env:PEOPLE_MEMORY_LLM_API_KEY="<secret>"
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
The extractor proposes participants, aliases, topics, claims, relationships,
|
|
323
|
+
and follow-ups from `source_text`. The application layer still preserves the
|
|
324
|
+
original note as evidence, strips model-invented `person_id` values, applies the
|
|
325
|
+
deterministic normalizer, and sends identity ambiguity to review instead of
|
|
326
|
+
silently merging cards. If the extractor fails or returns invalid JSON, capture
|
|
327
|
+
falls back to the deterministic rules.
|
|
328
|
+
|
|
329
|
+
To force deterministic-only capture:
|
|
330
|
+
|
|
331
|
+
```powershell
|
|
332
|
+
$env:PEOPLE_MEMORY_INGESTION_EXTRACTOR="off"
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
OpenClaw installs default to `PEOPLE_MEMORY_INGESTION_EXTRACTOR=llm`. Use
|
|
336
|
+
`people-memory install-openclaw --ingestion-extractor off` only when you want to
|
|
337
|
+
disable the LLM extraction pass for that harness.
|
|
338
|
+
|
|
339
|
+
## Embeddings
|
|
340
|
+
|
|
341
|
+
Local-first default recommendation:
|
|
342
|
+
|
|
343
|
+
```powershell
|
|
344
|
+
$env:PEOPLE_MEMORY_EMBEDDING_PROVIDER="ollama"
|
|
345
|
+
$env:PEOPLE_MEMORY_EMBEDDING_BASE_URL="http://localhost:11434/v1"
|
|
346
|
+
$env:PEOPLE_MEMORY_EMBEDDING_MODEL="nomic-embed-text"
|
|
347
|
+
people-memory check-embedding
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
OpenAI-compatible cloud endpoints use the same command with:
|
|
351
|
+
|
|
352
|
+
```powershell
|
|
353
|
+
$env:PEOPLE_MEMORY_EMBEDDING_PROVIDER="openai_compatible"
|
|
354
|
+
$env:PEOPLE_MEMORY_EMBEDDING_BASE_URL="https://ark.cn-beijing.volces.com/api/coding/v3"
|
|
355
|
+
$env:PEOPLE_MEMORY_EMBEDDING_MODEL="doubao-embedding-vision-251215"
|
|
356
|
+
$env:PEOPLE_MEMORY_EMBEDDING_API_KEY="<secret>"
|
|
357
|
+
people-memory check-embedding
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
Do not commit API keys or write them into config files.
|
|
361
|
+
|
|
362
|
+
## Sensitivity Policy
|
|
363
|
+
|
|
364
|
+
Sensitivity labels such as `sensitive` and `do_not_surface_unprompted` are kept
|
|
365
|
+
as metadata, but V1 defaults to `personal` surfacing because this is a private
|
|
366
|
+
single-user memory tool.
|
|
367
|
+
|
|
368
|
+
```powershell
|
|
369
|
+
$env:PEOPLE_MEMORY_SENSITIVITY_POLICY="personal" # private recall includes sensitive context
|
|
370
|
+
$env:PEOPLE_MEMORY_SENSITIVITY_POLICY="strict" # hide sensitive context unless explicitly requested
|
|
371
|
+
$env:PEOPLE_MEMORY_SENSITIVITY_POLICY="task_aware" # include for private recall, hide for shareable output
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
The MCP retrieval tool also accepts `sensitivity_policy`, `output_context`, and
|
|
375
|
+
the explicit `include_sensitive` override per request.
|
|
376
|
+
|
|
377
|
+
Graphiti also needs an LLM provider for episode extraction. Embeddings alone are
|
|
378
|
+
enough for vector smoke checks, but not enough for live Graphiti ingestion.
|
|
379
|
+
Some OpenAI-compatible gateways do not support `response_format`; leave
|
|
380
|
+
`PEOPLE_MEMORY_LLM_RESPONSE_FORMAT` unset or set it to `none` for those
|
|
381
|
+
providers. Use `json_object` or `json_schema` only when the provider explicitly
|
|
382
|
+
supports that mode.
|
|
383
|
+
|
|
384
|
+
```powershell
|
|
385
|
+
$env:PEOPLE_MEMORY_BACKEND="graphiti"
|
|
386
|
+
$env:PEOPLE_MEMORY_GRAPH_BACKEND="kuzu"
|
|
387
|
+
$env:PEOPLE_MEMORY_LLM_PROVIDER="openai_compatible"
|
|
388
|
+
$env:PEOPLE_MEMORY_LLM_BASE_URL="<base-url>"
|
|
389
|
+
$env:PEOPLE_MEMORY_LLM_MODEL="<model>"
|
|
390
|
+
$env:PEOPLE_MEMORY_LLM_API_KEY="<secret>"
|
|
391
|
+
$env:PEOPLE_MEMORY_LLM_RESPONSE_FORMAT="none"
|
|
392
|
+
.\.venv\Scripts\python.exe -m people_network_memory.cli smoke-graphiti --isolated
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
`reset` is intentionally guarded:
|
|
396
|
+
|
|
397
|
+
```powershell
|
|
398
|
+
people-memory reset --confirm DELETE
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
It deletes only the configured local JSON data file for `local_json`.
|
|
402
|
+
|
|
403
|
+
## Backup
|
|
404
|
+
|
|
405
|
+
Use JSON backup for portable person-card projection data:
|
|
406
|
+
|
|
407
|
+
```powershell
|
|
408
|
+
people-memory backup --output .people-network-memory/backup.json
|
|
409
|
+
people-memory restore --input .people-network-memory/backup.json
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
Use archive backup when the backend has local storage beyond the projection
|
|
413
|
+
cache. For `graphiti` + Kuzu, the archive includes `projection.json` and the
|
|
414
|
+
configured Kuzu database directory:
|
|
415
|
+
|
|
416
|
+
```powershell
|
|
417
|
+
people-memory backup-archive --backend graphiti --output .people-network-memory/graphiti-backup.zip
|
|
418
|
+
people-memory restore-archive --backend graphiti --input .people-network-memory/graphiti-backup.zip --confirm OVERWRITE
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
`restore-archive` requires explicit confirmation and rejects unsafe archive
|
|
422
|
+
member paths.
|
|
423
|
+
|
|
424
|
+
## Low-Friction Capture
|
|
425
|
+
|
|
426
|
+
The MCP tool accepts raw `source_text` first. If the harness can confidently
|
|
427
|
+
extract structure, it should include it. If not, it can still send the original
|
|
428
|
+
note and the server will conservatively normalize obvious people, places,
|
|
429
|
+
topics, mentions, work/school facts, contacts, interests, and follow-ups.
|
|
430
|
+
|
|
431
|
+
## Review Queue
|
|
432
|
+
|
|
433
|
+
Ambiguous identity matches are captured without blocking the original note. Use
|
|
434
|
+
the review commands to clean them up later:
|
|
435
|
+
|
|
436
|
+
```powershell
|
|
437
|
+
people-memory list-reviews
|
|
438
|
+
people-memory resolve-review --review-id review_0001 --source-person-id person_0003 --target-person-id alice
|
|
439
|
+
people-memory dismiss-review --review-id review_0002 --note "not enough information"
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
Resolving an identity review merges the source person into the target person,
|
|
443
|
+
preserves aliases, interactions, facts, claims, follow-ups, relationships, and
|
|
444
|
+
evidence, then marks the review item as resolved.
|
|
445
|
+
|
|
446
|
+
## OpenClaw
|
|
447
|
+
|
|
448
|
+
Install or preview the OpenClaw adapter:
|
|
449
|
+
|
|
450
|
+
```powershell
|
|
451
|
+
people-memory install-openclaw --dry-run
|
|
452
|
+
people-memory install-openclaw
|
|
453
|
+
people-memory install-openclaw --managed-bootstrap
|
|
454
|
+
people-memory doctor --agent openclaw
|
|
455
|
+
people-memory smoke-openclaw
|
|
456
|
+
people-memory eval-harness-integration
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
The installer updates only the `people-network-memory` MCP server entry in the
|
|
460
|
+
active OpenClaw config. Current OpenClaw builds use `~/.openclaw/openclaw.json`
|
|
461
|
+
under `mcp.servers`; when that file exists the installer updates it, and also
|
|
462
|
+
maintains the legacy/generic `~/.openclaw/mcp.json` shape for older MCP
|
|
463
|
+
harnesses. It preserves unrelated MCP servers and writes the mirrored skill to
|
|
464
|
+
`~/.openclaw/skills/ppl/SKILL.md`. The MCP server namespace remains
|
|
465
|
+
`people-network-memory` for tool compatibility, but the user-facing OpenClaw
|
|
466
|
+
slash trigger is `/ppl`; `/people_network_memory` and `/people-network-memory`
|
|
467
|
+
remain accepted aliases for existing prompts.
|
|
468
|
+
By default it uses the active Python executable with
|
|
469
|
+
`-m people_network_memory.cli start`, so it does not require the `people-memory`
|
|
470
|
+
console script to be on PATH. For end-user harness installs, prefer
|
|
471
|
+
`--managed-bootstrap`: that stores a tiny stdlib launcher in the MCP command so
|
|
472
|
+
the harness can recreate the venv and refresh Python dependencies automatically.
|
|
473
|
+
|
|
474
|
+
`smoke-openclaw` installs into a temporary OpenClaw home by default, checks the
|
|
475
|
+
adapter config and skill text, verifies prompt-routing examples, and exercises
|
|
476
|
+
the three public MCP workflows with the test backend.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# MCP Tool Contract
|
|
2
|
+
|
|
3
|
+
V1 exposes exactly three public tools. The machine-readable source of truth is:
|
|
4
|
+
|
|
5
|
+
```powershell
|
|
6
|
+
people-memory tool-schemas
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Adapters should treat the schema as stable within contract version `v1`.
|
|
10
|
+
|
|
11
|
+
## record_interaction
|
|
12
|
+
|
|
13
|
+
Use for a meeting, coffee, dinner, call, message, intro, event, or loose memory
|
|
14
|
+
note. The required field is `source_text`; all structured fields are optional so
|
|
15
|
+
the harness can preserve the user's original wording and add structure only when
|
|
16
|
+
it can do so confidently.
|
|
17
|
+
|
|
18
|
+
The server performs conservative normalization for obvious raw notes. By
|
|
19
|
+
default, `PEOPLE_MEMORY_INGESTION_EXTRACTOR=llm` lets an OpenAI-compatible LLM
|
|
20
|
+
propose structure first when LLM provider settings are available; without those
|
|
21
|
+
settings, capture starts directly with deterministic normalization. Either way,
|
|
22
|
+
the same identity policy, evidence preservation, and review rules still run.
|
|
23
|
+
For example, `source_text` alone can capture simple patterns such as:
|
|
24
|
+
|
|
25
|
+
- `Met Alice Zhang at Blue Bottle. We discussed robotics hiring. Alice mentioned Bob.`
|
|
26
|
+
- `Remember Alice Zhang. Alice works at Tencent Robotics as product lead. Alice studied at Tsinghua. Email alice@example.com.`
|
|
27
|
+
- `在Blue Bottle见了Alice Zhang,聊了robotics hiring,Alice Zhang提到Henry Guo。`
|
|
28
|
+
- `今天在潘家园见了胡八一(胖子),聊了北京的项目。胖子提到王凯。`
|
|
29
|
+
|
|
30
|
+
The harness should still pass structured fields when it has them, but it does
|
|
31
|
+
not need to interrupt the user just to fill a form.
|
|
32
|
+
|
|
33
|
+
Important modeling rules:
|
|
34
|
+
|
|
35
|
+
- Put people who were present in `participants`.
|
|
36
|
+
- Put people discussed but not present in `mentioned_people`.
|
|
37
|
+
- Store "A said B ..." in `attributed_claims`, not as a direct fact about B.
|
|
38
|
+
- Store relationship phrases such as "A knows B", "A works with B", or
|
|
39
|
+
"A introduced me to B" in `relationships`. If B is not already known, the
|
|
40
|
+
service creates a provisional second-degree card and returns a non-blocking
|
|
41
|
+
enrichment item.
|
|
42
|
+
- Preserve Chinese names and aliases exactly. Explicit alias forms such as
|
|
43
|
+
`胡八一(胖子)`, `胡八一又叫胖子`, and `胡八一绰号胖子` are modeled as one
|
|
44
|
+
canonical person with `胖子` as an alias unless the server returns an identity
|
|
45
|
+
review because the alias already points to a different card.
|
|
46
|
+
- Store promises and next actions in `follow_ups`.
|
|
47
|
+
- Preserve sensitivity labels when the user marks something private, sensitive,
|
|
48
|
+
secondhand, unverified, or not to surface unprompted.
|
|
49
|
+
|
|
50
|
+
Output fields that matter for harness autonomy:
|
|
51
|
+
|
|
52
|
+
- `capture_summary`: a short structured checkpoint the harness should show the
|
|
53
|
+
user after saving, including people created/updated, key details, follow-ups,
|
|
54
|
+
review items, and a correction hint.
|
|
55
|
+
- `captured_follow_ups`: follow-ups preserved from the capture.
|
|
56
|
+
- `post_capture_opportunities`: a structured list of useful next actions the
|
|
57
|
+
harness may take after capture.
|
|
58
|
+
- `harness_context_requests`: suggested ways for the harness to use its own
|
|
59
|
+
memory or available tools to enrich the result.
|
|
60
|
+
- `needs_review`: ambiguity or data-quality items that should be handled
|
|
61
|
+
carefully rather than silently auto-merged.
|
|
62
|
+
|
|
63
|
+
`post_capture_opportunities` include `recommended_default`, `risk_level`,
|
|
64
|
+
`reversibility`, `external_visibility`, `requires_confirmation`, `undo_hint`,
|
|
65
|
+
related people, and evidence. A harness should proactively execute low-risk,
|
|
66
|
+
private/local, easily reversible opportunities when supported, then report what
|
|
67
|
+
it did and how to undo it. It should ask first before externally visible,
|
|
68
|
+
costly, destructive, privacy-sensitive, or hard-to-reverse actions such as
|
|
69
|
+
sending messages, inviting other people to calendar events, merging ambiguous
|
|
70
|
+
identities, deleting data, or publishing information.
|
|
71
|
+
|
|
72
|
+
The harness should show the `capture_summary` every time because it is the
|
|
73
|
+
fastest way for the user to catch mistakes immediately, such as "this was a
|
|
74
|
+
different Alice", "that follow-up is wrong", or "remove that sensitive note".
|
|
75
|
+
|
|
76
|
+
## retrieve_network_context
|
|
77
|
+
|
|
78
|
+
Use for vague recall, relationship questions, and pre-meeting briefs.
|
|
79
|
+
|
|
80
|
+
Input:
|
|
81
|
+
|
|
82
|
+
- `query`: required natural-language query.
|
|
83
|
+
- `limit`: optional result limit from 1 to 50, default 10.
|
|
84
|
+
- `include_sensitive`: optional override. Use `true` to force sensitive facts
|
|
85
|
+
into the response, `false` to force-hide them, or omit it to use policy.
|
|
86
|
+
- `sensitivity_policy`: optional `personal`, `strict`, or `task_aware`.
|
|
87
|
+
The default app policy is `personal` because this V1 is a single-user private
|
|
88
|
+
memory tool.
|
|
89
|
+
- `output_context`: `private` or `shareable`, default `private`. In
|
|
90
|
+
`task_aware` mode, sensitive facts are included only for private recall and
|
|
91
|
+
hidden for shareable drafts or messages.
|
|
92
|
+
- `mode`: `recall` or `brief`.
|
|
93
|
+
|
|
94
|
+
Every result should include evidence, confidence-bearing source notes, and
|
|
95
|
+
`why_matched`.
|
|
96
|
+
|
|
97
|
+
Sensitivity labels are still preserved as metadata. They control surfacing
|
|
98
|
+
policy; they do not delete or weaken the underlying memory.
|
|
99
|
+
|
|
100
|
+
Harness integration guidance:
|
|
101
|
+
|
|
102
|
+
- Treat this tool as the source of truth for people/network memory: social
|
|
103
|
+
notes, relationships, claims, follow-ups, and person-card facts.
|
|
104
|
+
- Treat the AI harness's own memory as the source of truth for user-level
|
|
105
|
+
preferences, work style, current projects, and prior instructions.
|
|
106
|
+
- Retrieve from this tool first, then let the harness combine the returned
|
|
107
|
+
evidence with its own user memory to curate the final answer.
|
|
108
|
+
- If tool evidence and harness memory conflict about a person or interaction,
|
|
109
|
+
prefer the tool evidence for social facts and mention uncertainty only when it
|
|
110
|
+
affects the answer.
|
|
111
|
+
- If the tool has no matching evidence, the harness may still use its own user
|
|
112
|
+
memory, but it should clearly separate that inference from social-graph
|
|
113
|
+
recall.
|
|
114
|
+
- For task curation, such as dinner planning or intro drafting, retrieve with
|
|
115
|
+
the user's full task constraints, optionally call `get_person` for shortlisted
|
|
116
|
+
candidates, then explain recommendations using both source-backed social
|
|
117
|
+
evidence and user-preference context.
|
|
118
|
+
|
|
119
|
+
The deterministic harness integration eval checks this behavior without
|
|
120
|
+
requiring a live AI harness:
|
|
121
|
+
|
|
122
|
+
```powershell
|
|
123
|
+
people-memory eval-harness-integration --output .people-network-memory/harness-integration-eval.json
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The eval report includes the prompt, simulated harness memory, MCP tool calls,
|
|
127
|
+
actual retrieval results, hydrated person cards, and source-boundary checks for
|
|
128
|
+
each case.
|
|
129
|
+
|
|
130
|
+
## get_person
|
|
131
|
+
|
|
132
|
+
Use when the caller already has a stable `person_id`, usually after retrieval.
|
|
133
|
+
The tool also accepts `name` as a best-effort harness fallback because some AI
|
|
134
|
+
harnesses may ask for a card by visible person name after capture or recall.
|
|
135
|
+
When both are available, prefer `person_id`.
|
|
136
|
+
|
|
137
|
+
The response returns either a full person card with `found: true`, or a small
|
|
138
|
+
missing response with `found: false` and `missing_info`.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mcpServers": {
|
|
3
|
+
"people-network-memory": {
|
|
4
|
+
"command": "python3",
|
|
5
|
+
"args": [
|
|
6
|
+
"__REPO_ROOT__/scripts/people_memory_bootstrap.py",
|
|
7
|
+
"run",
|
|
8
|
+
"--repo",
|
|
9
|
+
"__REPO_ROOT__",
|
|
10
|
+
"--venv",
|
|
11
|
+
"__REPO_ROOT__/.venv",
|
|
12
|
+
"--backend",
|
|
13
|
+
"local_json",
|
|
14
|
+
"--extra",
|
|
15
|
+
"base"
|
|
16
|
+
],
|
|
17
|
+
"env": {
|
|
18
|
+
"PEOPLE_MEMORY_BACKEND": "local_json",
|
|
19
|
+
"PEOPLE_MEMORY_INGESTION_EXTRACTOR": "llm",
|
|
20
|
+
"PEOPLE_MEMORY_SENSITIVITY_POLICY": "personal",
|
|
21
|
+
"GRAPHITI_TELEMETRY_ENABLED": "false"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mcpServers": {
|
|
3
|
+
"people-network-memory": {
|
|
4
|
+
"command": "py",
|
|
5
|
+
"args": [
|
|
6
|
+
"-3.11",
|
|
7
|
+
"__REPO_ROOT__\\scripts\\people_memory_bootstrap.py",
|
|
8
|
+
"run",
|
|
9
|
+
"--repo",
|
|
10
|
+
"__REPO_ROOT__",
|
|
11
|
+
"--venv",
|
|
12
|
+
"__REPO_ROOT__\\.venv",
|
|
13
|
+
"--backend",
|
|
14
|
+
"local_json",
|
|
15
|
+
"--extra",
|
|
16
|
+
"base"
|
|
17
|
+
],
|
|
18
|
+
"env": {
|
|
19
|
+
"PEOPLE_MEMORY_BACKEND": "local_json",
|
|
20
|
+
"PEOPLE_MEMORY_INGESTION_EXTRACTOR": "llm",
|
|
21
|
+
"PEOPLE_MEMORY_SENSITIVITY_POLICY": "personal",
|
|
22
|
+
"GRAPHITI_TELEMETRY_ENABLED": "false"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mcpServers": {
|
|
3
|
+
"people-network-memory": {
|
|
4
|
+
"command": "python",
|
|
5
|
+
"args": ["scripts/people_memory_bootstrap.py", "run", "--repo", ".", "--venv", ".venv"],
|
|
6
|
+
"env": {
|
|
7
|
+
"PEOPLE_MEMORY_BACKEND": "local_json",
|
|
8
|
+
"PEOPLE_MEMORY_INGESTION_EXTRACTOR": "llm",
|
|
9
|
+
"PEOPLE_MEMORY_SENSITIVITY_POLICY": "personal",
|
|
10
|
+
"GRAPHITI_TELEMETRY_ENABLED": "false"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|