@cognee/cognee-openclaw 2026.6.11 → 2026.7.9

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 CHANGED
@@ -8,10 +8,12 @@ OpenClaw plugin that adds Cognee-backed memory with **multi-scope support** (com
8
8
  - **Scope-aware routing**: Memory files are automatically routed to the correct dataset based on directory structure
9
9
  - **Multi-scope recall**: Before each agent run, searches across all configured scopes and injects labeled context
10
10
  - **Session tracking**: Multi-turn conversation context via Cognee's session system
11
+ - **Agent lifecycle registration**: Registers/unregisters each agent session with the Cognee server on every prompt turn; combined with `COGNEE_AGENT_MODE=true` on the server, Cognee shuts down automatically when all agents disconnect
11
12
  - **14 search types**: From simple semantic search (CHUNKS) to chain-of-thought graph reasoning (GRAPH_COMPLETION_COT) to auto-selection (FEELING_LUCKY)
13
+ - **Lazy dataset resolution**: On first prompt, if a dataset UUID is not cached locally, the plugin queries the Cognee server by name so you can connect to any pre-existing dataset without manual configuration
12
14
  - **Health check**: Verifies Cognee API connectivity before operations
13
15
  - **Auto-index**: Syncs memory markdown files to Cognee via `/remember` (add new, update changed, forget removed, skip unchanged). The `/remember` endpoint runs ingest, graph build, and graph enrichment in one server-side call.
14
- - **In-session memory**: each recall call auto-captures the turn as a `QAEntry` in Cognee's session cache; with `AUTO_FEEDBACK=true` set on the Cognee container, follow-up messages are auto-classified as feedback and attached to the previous QA; `session_end` triggers `/improve` to bridge the session cache into the graph
16
+ - **In-session memory**: Every tool call is stored as a `TraceEntry` and every prompt/answer pair as a `QAEntry` in Cognee's session cache (`captureSession`, on by default); with `AUTO_FEEDBACK=true` set on the Cognee container, follow-up messages are auto-classified as feedback and attached to the previous QA; `session_end` triggers `/improve` to bridge the session cache into the graph
15
17
  - **One-command setup**: `openclaw cognee setup` configures Cognee as the sole memory provider
16
18
  - **CLI commands**: `openclaw cognee setup`, `openclaw cognee index`, `openclaw cognee status`, `openclaw cognee health`, `openclaw cognee scopes`, `openclaw cognee forget`, `openclaw cognee improve`
17
19
 
@@ -19,33 +21,54 @@ OpenClaw plugin that adds Cognee-backed memory with **multi-scope support** (com
19
21
 
20
22
  OpenClaw will auto-load any plugin it discovers if `plugins.allow` is not set. To restrict which plugins can load, add an explicit allowlist to your `~/.openclaw/openclaw.json`:
21
23
 
22
- ```yaml
23
- plugins:
24
- allow:
25
- - cognee-openclaw
26
- - cognee-openclaw-skills
24
+ ```json
25
+ {
26
+ "plugins": {
27
+ "allow": ["cognee-openclaw"]
28
+ }
29
+ }
27
30
  ```
28
31
 
32
+ > **Important**: `plugins.allow` must be a JSON **array**, not an object. `{"cognee-openclaw": true}` is invalid and will cause a config parse error.
33
+
29
34
  Without this, any plugin found in your environment could be loaded automatically.
30
35
 
31
36
  ## Installation
32
37
 
33
- Install the plugin locally for development:
38
+ ### Published package
39
+
40
+ ```bash
41
+ # Pin to an exact version to avoid unintended updates (supply-chain best practice)
42
+ openclaw plugins install @cognee/cognee-openclaw@2026.3.0
43
+ ```
44
+
45
+ ### Development install (symlink)
46
+
47
+ When developing or modifying the plugin, install as a symlink so that `npm run build` takes effect immediately without reinstalling:
34
48
 
35
49
  ```bash
36
50
  cd integrations/openclaw
37
51
  npm install
38
52
  npm run build
39
- openclaw plugins install -l .
53
+ openclaw plugins install --link .
40
54
  ```
41
55
 
42
- Or once published:
56
+ > **Why `--link`?** A standard install copies the built files once. Any subsequent `npm run build` updates the source but not the installed copy — so OpenClaw keeps running the stale version. With `--link`, the installed path **is** the source directory, so every build is reflected on the next gateway start.
43
57
 
44
- ```bash
45
- # Pin to an exact version to avoid unintended updates (supply-chain best practice)
46
- openclaw plugins install @cognee/cognee-openclaw@2026.3.0
58
+ After install, verify the install entry in `~/.openclaw/openclaw.json`:
59
+
60
+ ```json
61
+ "installs": {
62
+ "cognee-openclaw": {
63
+ "source": "path",
64
+ "sourcePath": "/path/to/integrations/openclaw",
65
+ "installPath": "/path/to/integrations/openclaw"
66
+ }
67
+ }
47
68
  ```
48
69
 
70
+ `sourcePath === installPath` confirms the symlink is in place.
71
+
49
72
  ## Quick Start
50
73
 
51
74
  After installing, run the setup command to configure Cognee as the memory provider:
@@ -60,81 +83,175 @@ openclaw cognee setup --hybrid
60
83
 
61
84
  **Default mode** disables built-in memory providers — all recall comes from Cognee.
62
85
 
63
- **Hybrid mode** keeps `memory-core` enabled in config, but on OpenClaw versions with exclusive memory slots only the slot winner loads at runtime.
64
- This plugin registers its own memory flush plan, so pre-compaction flush works when Cognee owns the memory slot.
86
+ **Hybrid mode** keeps `memory-core` enabled in config, but on OpenClaw versions with exclusive memory slots only the slot winner loads at runtime. This plugin registers its own memory flush plan, so pre-compaction flush works when Cognee owns the memory slot.
65
87
 
66
88
  Then configure the Cognee connection in `~/.openclaw/openclaw.json`:
67
89
 
68
- ```yaml
69
- plugins:
70
- entries:
71
- cognee-openclaw:
72
- enabled: true
73
- hooks:
74
- allowConversationAccess: true # see note below
75
- config:
76
- baseUrl: "http://localhost:8000"
77
- apiKey: "${COGNEE_API_KEY}"
78
- datasetName: "my-project"
90
+ ```json
91
+ {
92
+ "plugins": {
93
+ "allow": ["cognee-openclaw"],
94
+ "entries": {
95
+ "cognee-openclaw": {
96
+ "enabled": true,
97
+ "hooks": {
98
+ "allowPromptInjection": true
99
+ },
100
+ "config": {
101
+ "baseUrl": "http://localhost:8011",
102
+ "datasetName": "agent_sessions"
103
+ }
104
+ },
105
+ "memory-core": { "enabled": false },
106
+ "memory-lancedb": { "enabled": false }
107
+ },
108
+ "slots": {
109
+ "memory": "cognee-openclaw"
110
+ }
111
+ }
112
+ }
113
+ ```
114
+
115
+ > **`hooks.allowPromptInjection: true` is required.** Without it, OpenClaw blocks the plugin from reading the prompt content in the `before_prompt_build` hook — recall is silently skipped and no memories are injected. This key was named `allowConversationAccess` in versions before OpenClaw 2026.4.2; the old key is silently rejected, so if you copied config from an older guide, update to `allowPromptInjection`. Restart the gateway after adding or changing the flag.
116
+
117
+ ### Multi-Agent Quick Start
118
+
119
+ For a gateway with multiple named agents sharing a default dataset:
120
+
121
+ ```json
122
+ {
123
+ "plugins": {
124
+ "allow": ["cognee-openclaw"],
125
+ "entries": {
126
+ "cognee-openclaw": {
127
+ "enabled": true,
128
+ "hooks": { "allowPromptInjection": true }
129
+ },
130
+ "memory-core": { "enabled": false },
131
+ "memory-lancedb": { "enabled": false }
132
+ },
133
+ "slots": { "memory": "cognee-openclaw" }
134
+ },
135
+ "auth": {
136
+ "profiles": {
137
+ "openai:manual": { "provider": "openai", "mode": "token" }
138
+ }
139
+ },
140
+ "models": {
141
+ "providers": {
142
+ "openai": {
143
+ "baseUrl": "https://api.openai.com/v1",
144
+ "models": [{ "id": "gpt-4o-mini", "name": "GPT-4o mini" }]
145
+ }
146
+ }
147
+ },
148
+ "agents": {
149
+ "defaults": {
150
+ "model": { "primary": "openai/gpt-4o-mini" },
151
+ "models": { "openai/gpt-4o-mini": {} }
152
+ },
153
+ "list": [
154
+ { "id": "Will", "name": "Will" },
155
+ { "id": "Elizabeth", "name": "Elizabeth" }
156
+ ]
157
+ },
158
+ "gateway": {
159
+ "auth": { "mode": "token", "token": "your-gateway-token" }
160
+ }
161
+ }
79
162
  ```
80
163
 
81
- > `hooks.allowConversationAccess` -> OpenClaw 2026.4.27 blocks non-bundled plugins from registering the `agent_end` hook unless this flag is set. Without it, file sync memory operations after each agent turn is silently disabled. The gateway still loads the plugin, but file changes the agent makes won't reach Cognee until the next manual `openclaw cognee index` or gateway start. Restart the gateway after adding the flag: `openclaw gateway stop && openclaw gateway start`.
164
+ > **Required fields when adding a `models.providers.<provider>` block**: `baseUrl` is required by the config schema. Omitting it causes a validation error that prevents the gateway from starting.
165
+
166
+ #### Default: all agents share one dataset
167
+
168
+ By default — no matter how many agents are configured — every agent reads and writes the **same dataset** (`agent_sessions`), exactly like the claude-code and codex Cognee integrations. Agents stay distinguishable within it: each agent session registers separately and its conversation is keyed by its own Cognee session id, so recall and session bridging never mix sessions up. Shared memory is usually what you want: agents benefit from each other's knowledge.
169
+
170
+ #### Opt-in: per-agent isolated datasets
171
+
172
+ To give each agent its own dataset (own graph, own recall space), set **both** of these in the plugin config:
173
+
174
+ ```json
175
+ "config": {
176
+ "perAgentMemory": true,
177
+ "agentDatasetPrefix": "myorg-agent"
178
+ }
179
+ ```
180
+
181
+ With this, agent `Will` writes to dataset `myorg-agent-will`, agent `Elizabeth` to `myorg-agent-elizabeth`, and each agent's recall only searches its own dataset (plus any shared `company`/`user` scopes you configure). Use `agentDatasetTemplate` (e.g. `"{agentId}"`) instead of the prefix if you need full control over the dataset names.
182
+
183
+ > **Both settings are required.** `perAgentMemory: true` on its own does nothing — isolation only activates when an `agentDatasetPrefix` or `agentDatasetTemplate` is also set. Per-agent memory is never enabled automatically.
82
184
 
83
185
  ### Cognee Cloud
84
186
 
85
- To use Cognee Cloud instead of a local instance, set `mode` to `"cloud"`:
86
-
87
- ```yaml
88
- plugins:
89
- entries:
90
- cognee-openclaw:
91
- enabled: true
92
- config:
93
- mode: "cloud"
94
- baseUrl: "https://tenant-xxx.cloud.cognee.ai/api"
95
- apiKey: "${COGNEE_API_KEY}"
187
+ Cognee Cloud tenants (staging and production) serve the **same `/api/v1/*` API as a self-hosted server**, so connecting to the cloud is just the default configuration pointed at your tenant URL, with an API key:
188
+
189
+ ```json
190
+ {
191
+ "plugins": {
192
+ "entries": {
193
+ "cognee-openclaw": {
194
+ "enabled": true,
195
+ "config": {
196
+ "baseUrl": "https://tenant-xxx.aws.cognee.ai",
197
+ "apiKey": "${COGNEE_API_KEY}"
198
+ }
199
+ }
200
+ }
201
+ }
202
+ }
96
203
  ```
97
204
 
98
205
  Or via environment variables:
99
206
 
100
207
  ```bash
101
- export COGNEE_MODE=cloud
102
- export COGNEE_BASE_URL=https://tenant-xxx.cloud.cognee.ai/api
208
+ export COGNEE_BASE_URL=https://tenant-xxx.aws.cognee.ai
103
209
  export COGNEE_API_KEY=your-api-key
104
210
  ```
105
211
 
106
- **Cloud mode supported operations**: `remember` (new files), `recall`, per-item `forget`. The `/remember` and `/recall` endpoints are verified against self-hosted Cognee 1.0.3; cloud parity for these specific routes has not been validated yet file an issue if you hit a 404.
212
+ Do **not** set `mode: "cloud"` leave it at the default. All operations (file sync, updates, recall, session capture, agent registration, improve) work against cloud tenants through the standard paths.
213
+
214
+ > **`COGNEE_API_KEY` is mandatory for any remote/cloud server.** On a local server the plugin auto-mints a key on first use (a one-time JWT login as the default user bootstraps the mint); remote servers expose no login route, so there is nothing to mint with — every request authenticates via `X-Api-Key`. The variable must be present in the environment the **gateway process** starts from — a daemonized gateway does not see `export`s from your current shell. Set it, then `openclaw gateway stop && openclaw gateway start`.
215
+
216
+ > **Deprecated: `mode: "cloud"` / `COGNEE_MODE=cloud`.** This mode targets a legacy path scheme (`baseUrl` ending `/api`, alias routes like `/recall` without the `/api/v1` prefix) that no current Cognee Cloud deployment serves — the platform control plane exposes no data routes, and tenants use the standard `/api/v1/*` paths. The mode is kept only for backward compatibility with older deployments; on current tenants it will 404. Newer capabilities (session capture, agent registration) are not implemented for the legacy scheme and never will be.
107
217
 
108
- **Known limitation**: Updating existing data (modifying a previously synced file) is not supported in cloud mode — `PATCH /update` is self-hosted only. In cloud mode the plugin's update path is a no-op; to edit a single file in place, delete it and re-add it via the [Cognee Cloud platform](https://platform.cognee.ai) or the API directly.
218
+ ## Environment Variables
219
+
220
+ | Variable | Default | Description |
221
+ |----------|---------|-------------|
222
+ | `COGNEE_BASE_URL` | `http://localhost:8011` | Cognee API base URL |
223
+ | `COGNEE_PLUGIN_DATASET` | `agent_sessions` | Dataset name for single-scope mode. Overridden by `datasetName` in config if set. Same variable name used by the claude-code and codex Cognee integrations. |
224
+ | `COGNEE_MODE` | `local` | **Deprecated** — leave at `"local"` for self-hosted *and* cloud tenants. `"cloud"` targets a legacy path scheme no current deployment serves (see "Cognee Cloud") |
225
+ | `COGNEE_API_KEY` | — | API key (cloud mode or authenticated self-hosted) |
226
+ | `COGNEE_USERNAME` | — | Login username (self-hosted with auth) |
227
+ | `COGNEE_PASSWORD` | — | Login password (self-hosted with auth) |
228
+ | `OPENCLAW_USER_ID` | — | User identifier for user-scoped memory |
229
+ | `OPENCLAW_AGENT_ID` | `default` | Agent identifier for agent-scoped memory |
109
230
 
110
231
  ## Multi-Scope Memory
111
232
 
112
233
  For production use, enable multi-scope mode by setting any scope-specific dataset name:
113
234
 
114
- ```yaml
115
- plugins:
116
- entries:
117
- cognee-openclaw:
118
- enabled: true
119
- config:
120
- baseUrl: "http://localhost:8000"
121
- apiKey: "${COGNEE_API_KEY}"
122
-
123
- # Multi-scope datasets
124
- companyDataset: "acme-shared"
125
- userDatasetPrefix: "acme-user"
126
- agentDatasetPrefix: "acme-agent"
127
- userId: "${OPENCLAW_USER_ID}"
128
- agentId: "code-assistant"
129
-
130
- # Search all scopes during recall (in priority order)
131
- recallScopes:
132
- - agent
133
- - user
134
- - company
135
-
136
- # Default scope for files not matching any route
137
- defaultWriteScope: "agent"
235
+ ```json
236
+ {
237
+ "plugins": {
238
+ "entries": {
239
+ "cognee-openclaw": {
240
+ "enabled": true,
241
+ "config": {
242
+ "baseUrl": "http://localhost:8011",
243
+ "companyDataset": "acme-shared",
244
+ "userDatasetPrefix": "acme-user",
245
+ "agentDatasetPrefix": "acme-agent",
246
+ "userId": "${OPENCLAW_USER_ID}",
247
+ "agentId": "code-assistant",
248
+ "recallScopes": ["agent", "user", "company"],
249
+ "defaultWriteScope": "agent"
250
+ }
251
+ }
252
+ }
253
+ }
254
+ }
138
255
  ```
139
256
 
140
257
  ### Memory Scope Hierarchy
@@ -158,14 +275,14 @@ MEMORY.md -> agent scope
158
275
 
159
276
  Custom routing via config:
160
277
 
161
- ```yaml
162
- scopeRouting:
163
- - pattern: "memory/shared/**"
164
- scope: company
165
- - pattern: "memory/personal/**"
166
- scope: user
167
- - pattern: "memory/**"
168
- scope: agent
278
+ ```json
279
+ {
280
+ "scopeRouting": [
281
+ { "pattern": "memory/shared/**", "scope": "company" },
282
+ { "pattern": "memory/personal/**", "scope": "user" },
283
+ { "pattern": "memory/**", "scope": "agent" }
284
+ ]
285
+ }
169
286
  ```
170
287
 
171
288
  ### Multi-Scope Recall
@@ -188,8 +305,16 @@ This lets the agent distinguish between personal context, shared knowledge, and
188
305
 
189
306
  | Option | Type | Default | Description |
190
307
  |--------|------|---------|-------------|
191
- | `baseUrl` | string | `http://localhost:8000` | Cognee API base URL |
308
+ | `baseUrl` | string | `http://localhost:8011` | Cognee API base URL (also: `COGNEE_BASE_URL`) |
192
309
  | `apiKey` | string | `$COGNEE_API_KEY` | API key for authentication |
310
+ | `username` | string | `$COGNEE_USERNAME` | Login username |
311
+ | `password` | string | `$COGNEE_PASSWORD` | Login password |
312
+
313
+ ### Dataset
314
+
315
+ | Option | Type | Default | Description |
316
+ |--------|------|---------|-------------|
317
+ | `datasetName` | string | `agent_sessions` | Dataset name for single-scope mode (also: `COGNEE_PLUGIN_DATASET`) |
193
318
 
194
319
  ### Memory Scopes
195
320
 
@@ -198,11 +323,13 @@ This lets the agent distinguish between personal context, shared knowledge, and
198
323
  | `companyDataset` | string | — | Dataset for company-wide memory. Setting this enables multi-scope mode |
199
324
  | `userDatasetPrefix` | string | — | Prefix for user datasets (becomes `{prefix}-{userId}`) |
200
325
  | `agentDatasetPrefix` | string | — | Prefix for agent datasets (becomes `{prefix}-{agentId}`) |
326
+ | `agentDatasetTemplate` | string | — | Template for per-agent dataset with `{agentId}` placeholder; takes precedence over `agentDatasetPrefix` |
201
327
  | `userId` | string | `$OPENCLAW_USER_ID` | User identifier for user-scoped memory |
202
- | `agentId` | string | `default` | Agent identifier for agent-scoped memory |
328
+ | `agentId` | string | `default` | Agent identifier for agent-scoped memory (also: `OPENCLAW_AGENT_ID`) |
203
329
  | `recallScopes` | string[] | `["agent","user","company"]` | Scopes to search during recall, in priority order |
204
330
  | `defaultWriteScope` | string | `agent` | Default scope for files not matching any route |
205
331
  | `scopeRouting` | object[] | (see above) | Path-to-scope routing rules |
332
+ | `perAgentMemory` | boolean | `false` | Give each agent its own dataset. Strictly opt-in (never auto-enabled); requires `agentDatasetPrefix` or `agentDatasetTemplate` to also be set — see "Multi-Agent Quick Start". By default all agents share one dataset. |
206
333
 
207
334
  ### Sessions
208
335
 
@@ -210,22 +337,25 @@ This lets the agent distinguish between personal context, shared knowledge, and
210
337
  |--------|------|---------|-------------|
211
338
  | `enableSessions` | boolean | `true` | Enable session-based conversation tracking |
212
339
  | `persistSessionsAfterEnd` | boolean | `true` | Persist session Q&A into the knowledge graph |
340
+ | `captureSession` | boolean | `true` | Store each tool call as a `TraceEntry` and each prompt/answer pair as a `QAEntry` in Cognee's session cache (requires `enableSessions`) |
213
341
 
214
342
  ### Search
215
343
 
216
344
  | Option | Type | Default | Description |
217
345
  |--------|------|---------|-------------|
218
- | `searchType` | string | `GRAPH_COMPLETION` | Search strategy (see below) |
346
+ | `searchType` | string | `HYBRID_COMPLETION` | Search strategy (see below) |
219
347
  | `maxResults` | number | `3` | Max memories to inject per scope (sent as `top_k` to Cognee) |
220
348
  | `minScore` | number | `0.3` | Minimum relevance score filter |
349
+ | `maxTokens` | number | `512` | Token cap for recall per scope |
221
350
  | `searchPrompt` | string | `""` | System prompt to guide search |
222
- | ~~`maxTokens`~~ | number | `512` | **Deprecated** Cognee 1.0.3's recall payload no longer accepts a token cap; use `maxResults` instead. Setting this is silently ignored. |
351
+ | `recallInjectionPosition` | string | `prependContext` | Where recalled memories are injected: `prependSystemContext`, `appendSystemContext`, or `prependContext` |
223
352
 
224
353
  ### Search Types
225
354
 
226
355
  | Type | Description |
227
356
  |------|-------------|
228
- | `GRAPH_COMPLETION` | **Default** — graph traversal + LLM reasoning |
357
+ | `HYBRID_COMPLETION` | **Default** — combined vector + graph retrieval |
358
+ | `GRAPH_COMPLETION` | Graph traversal + LLM reasoning; slower but deeper — best for offline/CLI queries rather than the per-prompt recall path |
229
359
  | `CHUNKS` | Semantic vector search, returns raw stored text (no generation) |
230
360
  | `FEELING_LUCKY` | Auto-selects a strategy per query (may pick generative modes) |
231
361
  | `GRAPH_COMPLETION_COT` | Chain-of-thought reasoning over graph (iterative) |
@@ -233,7 +363,6 @@ This lets the agent distinguish between personal context, shared knowledge, and
233
363
  | `GRAPH_SUMMARY_COMPLETION` | Graph with pre-computed summaries |
234
364
  | `RAG_COMPLETION` | Traditional RAG with document chunks |
235
365
  | `TRIPLET_COMPLETION` | Subject-predicate-object search |
236
- | `CHUNKS` | Pure semantic vector search |
237
366
  | `CHUNKS_LEXICAL` | Keyword/lexical search |
238
367
  | `SUMMARIES` | Pre-computed hierarchical summaries |
239
368
  | `TEMPORAL` | Time-aware graph search |
@@ -248,9 +377,9 @@ This lets the agent distinguish between personal context, shared knowledge, and
248
377
  | `autoRecall` | boolean | `true` | Inject memories before agent runs |
249
378
  | `autoIndex` | boolean | `true` | Sync memory files on startup, after agent runs, and on session end |
250
379
  | `improveOnSessionEnd` | boolean | `true` | On `session_end`, call `/improve` with the session id to bridge session-cache QAs into the graph |
251
- | ~~`autoCognify`~~ | boolean | `true` | **Deprecated** — `/remember` runs the cognify step server-side. Setting this is silently ignored. |
252
- | ~~`autoMemify`~~ | boolean | `false` | **Deprecated** — graph enrichment now runs server-side via `/remember`'s `self_improvement` default. Setting this is silently ignored. |
253
- | ~~`deleteMode`~~ | string | `soft` | **Deprecated** — `/forget` always runs the equivalent of `soft`; the legacy `hard` mode is gone (cognee's source explicitly warns against it). Setting this is silently ignored. |
380
+ | ~~`autoCognify`~~ | boolean | `true` | **Deprecated** — `/remember` runs the cognify step server-side |
381
+ | ~~`autoMemify`~~ | boolean | `false` | **Deprecated** — graph enrichment now runs server-side via `/remember` |
382
+ | ~~`deleteMode`~~ | string | `soft` | **Deprecated** — `/forget` always runs soft delete |
254
383
 
255
384
  ### Timeouts
256
385
 
@@ -259,6 +388,17 @@ This lets the agent distinguish between personal context, shared knowledge, and
259
388
  | `requestTimeoutMs` | number | `60000` | HTTP timeout for Cognee requests |
260
389
  | `ingestionTimeoutMs` | number | `300000` | HTTP timeout for add/update requests |
261
390
 
391
+ ### Recall budget & circuit breaker
392
+
393
+ Recall runs on the prompt hot path, so it is bounded: each recall call gets a short timeout, the whole recall step gets a wall-clock budget, and repeated failures open a circuit breaker that skips recall until the server recovers. Memories missed under the budget are dropped for that turn only — writes (traces, QA, file sync, improve) are never budgeted. The breaker state is shared with the claude-code and codex integrations via `~/.cognee-plugin/recall-breaker.json`, so all plugins using one Cognee server back off together.
394
+
395
+ | Option | Type | Default | Description |
396
+ |--------|------|---------|-------------|
397
+ | `recallTimeoutMs` | number | `2500` | Per recall HTTP call timeout (no retries) |
398
+ | `recallBudgetMs` | number | `4000` | Overall wall-clock budget for the recall step per prompt |
399
+ | `recallBreakerThreshold` | number | `5` | Consecutive failures (network/timeout/5xx) before the breaker opens |
400
+ | `recallBreakerCooldownMs` | number | `120000` | How long recall is skipped once the breaker opens |
401
+
262
402
  Note: Files are stored in Cognee using sanitized relative paths as filenames (e.g., `MEMORY.md.txt` for `MEMORY.md`, `memory.tools.md.txt` for `memory/tools.md`) for easy identification and to avoid path separator issues.
263
403
 
264
404
  ## CLI Commands
@@ -266,7 +406,7 @@ Note: Files are stored in Cognee using sanitized relative paths as filenames (e.
266
406
  ```bash
267
407
  # Configure Cognee as the memory provider (run once after install)
268
408
  openclaw cognee setup # Cognee only
269
- openclaw cognee setup --hybrid # Keep built-ins enabled in config (runtime co-load depends on slot rules)
409
+ openclaw cognee setup --hybrid # Keep built-ins enabled in config
270
410
 
271
411
  # Manually sync memory files to Cognee
272
412
  openclaw cognee index
@@ -289,26 +429,13 @@ openclaw cognee improve # current dataset, all sessions
289
429
  openclaw cognee improve --session-id <id> # scope to one session
290
430
  ```
291
431
 
292
- ## How It Works
293
-
294
- 1. **On startup**: Health check, then scan `memory/` directory and call `/api/v1/remember` (one batched multipart upload per scope). Cognee runs add + cognify + improve server-side.
295
- 2. **Before each prompt**: Call `/api/v1/recall` for each configured scope in parallel, merge results with scope labels, inject as `<cognee_memories>` context. The openclaw session id is passed through; Cognee uses it to auto-capture the turn as a session QA and (with `AUTO_FEEDBACK=true`) auto-attach feedback to the prior QA when one is detected.
296
- 3. **After each agent run**: Re-scan memory files; new files batch into `/remember`, changed files go through `PATCH /update` (self-hosted) with fallback to `/remember`, removed files are dropped via `/forget`.
297
- 4. **On session end**: Final sync sweep. With `improveOnSessionEnd` on, also dispatches `/improve` for the just-ended session id to bridge session QAs into the permanent graph.
298
- 5. **State tracking**:
299
- - `~/.openclaw/memory/cognee/datasets.json` — dataset ID mapping
300
- - `~/.openclaw/memory/cognee/scoped-sync-indexes.json` — per-scope file hashes and data IDs
301
- - `~/.openclaw/memory/cognee/sync-index.json` — legacy single-scope index
302
-
303
- Memory files detected at: `MEMORY.md` and `memory/**/*.md` (recursive)
304
-
305
432
  ## Development
306
433
 
307
434
  ```bash
308
435
  cd integrations/openclaw
309
436
  npm install
310
437
  npm run build
311
- openclaw plugins install -l .
438
+ openclaw plugins install --link .
312
439
  ```
313
440
 
314
441
  For live rebuilds during development:
@@ -317,6 +444,8 @@ For live rebuilds during development:
317
444
  npm run dev
318
445
  ```
319
446
 
447
+ After each build, restart the OpenClaw gateway to pick up the new code.
448
+
320
449
  ## Testing
321
450
 
322
451
  ```bash
@@ -0,0 +1,20 @@
1
+ export declare const DEFAULT_BREAKER_PATH: string;
2
+ /**
3
+ * A failure should trip the breaker only when it signals an unavailable or
4
+ * overloaded server: network errors, timeouts/aborts, and 5xx responses.
5
+ * 4xx (auth, stale dataset ids) are the caller's problem and must NOT trip —
6
+ * mirrors the claude/codex `_cognee_client.py` rules.
7
+ */
8
+ export declare function isBreakerError(error: unknown): boolean;
9
+ export declare class RecallBreaker {
10
+ private readonly threshold;
11
+ private readonly cooldownMs;
12
+ private readonly path;
13
+ constructor(threshold: number, cooldownMs: number, path?: string);
14
+ private load;
15
+ private save;
16
+ /** Seconds until the breaker closes again; 0 when recall may proceed. */
17
+ openForSeconds(): Promise<number>;
18
+ recordFailure(message: string): Promise<void>;
19
+ recordSuccess(): Promise<void>;
20
+ }
@@ -0,0 +1,80 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { dirname, join } from "node:path";
3
+ import { homedir } from "node:os";
4
+ // ---------------------------------------------------------------------------
5
+ // Recall circuit breaker — same design and state file as the claude-code and
6
+ // codex integrations (~/.cognee-plugin/recall-breaker.json), so all Cognee
7
+ // plugins sharing one server trip and recover together. Shape:
8
+ // { failures: number, cooldown_until: epoch-seconds, last_error?: string }
9
+ // Opens after `threshold` consecutive breaker-eligible failures; stays open
10
+ // for `cooldownMs`, then half-opens (next recall attempt runs).
11
+ // ---------------------------------------------------------------------------
12
+ export const DEFAULT_BREAKER_PATH = join(homedir(), ".cognee-plugin", "recall-breaker.json");
13
+ /**
14
+ * A failure should trip the breaker only when it signals an unavailable or
15
+ * overloaded server: network errors, timeouts/aborts, and 5xx responses.
16
+ * 4xx (auth, stale dataset ids) are the caller's problem and must NOT trip —
17
+ * mirrors the claude/codex `_cognee_client.py` rules.
18
+ */
19
+ export function isBreakerError(error) {
20
+ const msg = error instanceof Error ? error.message : String(error);
21
+ const status = /\((\d{3})\)/.exec(msg)?.[1];
22
+ if (status)
23
+ return status.startsWith("5");
24
+ return true; // no HTTP status → network error, timeout, or abort
25
+ }
26
+ export class RecallBreaker {
27
+ threshold;
28
+ cooldownMs;
29
+ path;
30
+ constructor(threshold, cooldownMs, path = DEFAULT_BREAKER_PATH) {
31
+ this.threshold = threshold;
32
+ this.cooldownMs = cooldownMs;
33
+ this.path = path;
34
+ }
35
+ async load() {
36
+ try {
37
+ const raw = JSON.parse(await readFile(this.path, "utf-8"));
38
+ return {
39
+ failures: typeof raw.failures === "number" ? raw.failures : 0,
40
+ cooldown_until: typeof raw.cooldown_until === "number" ? raw.cooldown_until : 0,
41
+ last_error: typeof raw.last_error === "string" ? raw.last_error : undefined,
42
+ };
43
+ }
44
+ catch {
45
+ return { failures: 0, cooldown_until: 0 };
46
+ }
47
+ }
48
+ async save(state) {
49
+ try {
50
+ await mkdir(dirname(this.path), { recursive: true });
51
+ await writeFile(this.path, JSON.stringify(state), "utf-8");
52
+ }
53
+ catch { /* best-effort */ }
54
+ }
55
+ /** Seconds until the breaker closes again; 0 when recall may proceed. */
56
+ async openForSeconds() {
57
+ const state = await this.load();
58
+ const remaining = state.cooldown_until - Date.now() / 1000;
59
+ return remaining > 0 ? remaining : 0;
60
+ }
61
+ async recordFailure(message) {
62
+ const state = await this.load();
63
+ state.failures += 1;
64
+ state.last_error = message.slice(0, 300);
65
+ if (state.failures >= this.threshold) {
66
+ // Failures are NOT reset on trip (same as claude/codex): after the
67
+ // cooldown the breaker half-opens, and a single failed probe re-trips
68
+ // immediately instead of paying `threshold` slow attempts again.
69
+ state.cooldown_until = Date.now() / 1000 + this.cooldownMs / 1000;
70
+ }
71
+ await this.save(state);
72
+ }
73
+ async recordSuccess() {
74
+ const state = await this.load();
75
+ if (state.failures === 0 && state.cooldown_until === 0)
76
+ return; // avoid write churn on the happy path
77
+ await this.save({ failures: 0, cooldown_until: 0 });
78
+ }
79
+ }
80
+ //# sourceMappingURL=breaker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"breaker.js","sourceRoot":"","sources":["../../src/breaker.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import type { CogneeDeleteMode, CogneeMode, CogneeSearchResult, CogneeSearchType } from "./types.js";
2
2
  export declare class CogneeHttpClient {
3
3
  readonly baseUrl: string;
4
- private readonly apiKey?;
4
+ private apiKey?;
5
5
  private readonly username?;
6
6
  private readonly password?;
7
7
  private readonly timeoutMs;
@@ -11,6 +11,15 @@ export declare class CogneeHttpClient {
11
11
  private loginPromise;
12
12
  constructor(baseUrl: string, apiKey?: string, username?: string, password?: string, timeoutMs?: number, ingestionTimeoutMs?: number, mode?: CogneeMode);
13
13
  private get isCloud();
14
+ /**
15
+ * Inject an API key resolved/minted after construction (resolveOrMintApiKey).
16
+ * From then on every request authenticates with X-Api-Key and the JWT login
17
+ * fallback is never used again — the key is the principal identity, matching
18
+ * the claude-code/codex integrations. JWT login remains only as the one-time
19
+ * bootstrap that mints a key on a fresh LOCAL server (cloud has no login
20
+ * route, which is why COGNEE_API_KEY is mandatory there).
21
+ */
22
+ setApiKey(key: string): void;
14
23
  login(): Promise<void>;
15
24
  ensureAuth(): Promise<void>;
16
25
  private buildHeaders;
@@ -121,7 +130,39 @@ export declare class CogneeHttpClient {
121
130
  topK?: number;
122
131
  sessionId?: string;
123
132
  scope?: string | string[];
133
+ onlyContext?: boolean;
134
+ /** Per-call timeout for the prompt hot path. When set, retries are
135
+ * disabled so a slow server fails fast instead of eating the budget. */
136
+ timeoutMs?: number;
124
137
  }): Promise<CogneeSearchResult[]>;
138
+ rememberEntry(params: {
139
+ datasetName: string;
140
+ sessionId: string;
141
+ entry: Record<string, unknown>;
142
+ }): Promise<{
143
+ entryId?: string;
144
+ }>;
145
+ registerAgent(params: {
146
+ agentSessionName: string;
147
+ sessionId?: string;
148
+ datasetNames?: string[];
149
+ }): Promise<{
150
+ ok: boolean;
151
+ connectionId?: string;
152
+ }>;
153
+ unregisterAgent(params: {
154
+ agentSessionName: string;
155
+ }): Promise<{
156
+ ok: boolean;
157
+ activeAgents: number;
158
+ }>;
159
+ listApiKeys(): Promise<{
160
+ key: string;
161
+ name?: string;
162
+ }[]>;
163
+ createApiKey(name: string): Promise<{
164
+ key: string;
165
+ }>;
125
166
  listDatasets(): Promise<{
126
167
  id: string;
127
168
  name: string;