@joshuaswarren/openclaw-engram 9.0.89 → 9.0.92

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
@@ -134,7 +134,24 @@ Run the stdio MCP server:
134
134
  openclaw engram access mcp-serve
135
135
  ```
136
136
 
137
- Point your MCP client's command at `openclaw engram access mcp-serve`. Works with Claude Code, and any other MCP-compatible client. The server exposes the same 8 tools as the HTTP endpoint.
137
+ Point your MCP client's command at `openclaw engram access mcp-serve`. Works with Claude Code, and any other MCP-compatible client. The server exposes the same tools as the HTTP endpoint.
138
+
139
+ **Claude Code (MCP over HTTP):** Start the Engram HTTP server, then add to `~/.claude.json`:
140
+
141
+ ```json
142
+ {
143
+ "mcpServers": {
144
+ "engram": {
145
+ "url": "http://localhost:4318/mcp",
146
+ "headers": {
147
+ "Authorization": "Bearer ${ENGRAM_TOKEN}"
148
+ }
149
+ }
150
+ }
151
+ }
152
+ ```
153
+
154
+ See the [Standalone Server Guide](docs/guides/standalone-server.md) for multi-tenant setups and connecting multiple agent harnesses.
138
155
 
139
156
  ## How It Works
140
157
 
@@ -202,6 +219,10 @@ Use a preset to jump to a recommended level: `conservative`, `balanced`, `resear
202
219
  - **Scripts & automation** — Authenticated REST API for custom integrations
203
220
  - **Local LLMs** — Run extraction and reranking with local models (Ollama, LM Studio, etc.)
204
221
 
222
+ ### Standalone Multi-Tenant Server
223
+
224
+ Run Engram as a standalone HTTP server that multiple agent harnesses share. Isolate tenants with namespace policies, feed conversations from any client via the observe endpoint, and search archived history with LCM full-text search. Works with OpenClaw, Codex CLI, Claude Code, and custom HTTP agents. See the [Standalone Server Guide](docs/guides/standalone-server.md).
225
+
205
226
  ### Built for production
206
227
 
207
228
  - **672 tests** with CI enforcement
@@ -215,6 +236,7 @@ Use a preset to jump to a recommended level: `conservative`, `balanced`, `resear
215
236
  ### Core
216
237
 
217
238
  - **Automatic memory extraction** — Facts, decisions, preferences, corrections extracted from conversations
239
+ - **Observe endpoint** — Feed conversation messages from any agent into the extraction pipeline via HTTP or MCP
218
240
  - **Recall injection** — Relevant memories injected before each agent turn
219
241
  - **Entity tracking** — People, projects, tools, companies tracked as structured entities
220
242
  - **Lifecycle management** — Memories age through active, validated, stale, archived states
@@ -320,6 +342,8 @@ Available via both stdio and HTTP transports:
320
342
  | `engram.suggestion_submit` | Queue a memory for review |
321
343
  | `engram.entity_get` | Look up a known entity |
322
344
  | `engram.review_queue_list` | View the governance review queue |
345
+ | `engram.observe` | Feed conversation messages into memory pipeline (LCM + extraction) |
346
+ | `engram.lcm_search` | Full-text search over LCM-archived conversations |
323
347
  | `engram_context_search` | Full-text search across all archived conversation history (LCM) |
324
348
  | `engram_context_describe` | Get a compressed summary of a turn range (LCM) |
325
349
  | `engram_context_expand` | Retrieve raw lossless messages for a turn range (LCM) |
@@ -395,6 +419,7 @@ All settings live in `openclaw.json` under `plugins.entries.openclaw-engram.conf
395
419
  - [Writing a Search Backend](docs/writing-a-search-backend.md) — Build your own adapter
396
420
  - [API Reference](docs/api.md) — HTTP, MCP, and CLI documentation
397
421
  - [Codex CLI Integration](docs/guides/codex-cli.md) — Setup Engram with OpenAI's Codex
422
+ - [Standalone Server Guide](docs/guides/standalone-server.md) — Multi-tenant HTTP server for multiple agent harnesses
398
423
  - [Local LLM Guide](docs/guides/local-llm.md) — Local-first extraction and reranking
399
424
  - [Cost Control Guide](docs/guides/cost-control.md) — Budget mappings and presets
400
425
  - [Namespaces](docs/namespaces.md) — Multi-agent memory isolation
@@ -1216,9 +1216,29 @@ function serializeFrontmatter(fm) {
1216
1216
  if (fm.sourceMemoryId) lines.push(`sourceMemoryId: ${fm.sourceMemoryId}`);
1217
1217
  if (fm.sourceTurnId) lines.push(`sourceTurnId: ${fm.sourceTurnId}`);
1218
1218
  if (fm.memoryKind) lines.push(`memoryKind: ${fm.memoryKind}`);
1219
+ if (fm.structuredAttributes && Object.keys(fm.structuredAttributes).length > 0) {
1220
+ lines.push(`structuredAttributes: ${JSON.stringify(fm.structuredAttributes)}`);
1221
+ }
1219
1222
  lines.push("---");
1220
1223
  return lines.join("\n");
1221
1224
  }
1225
+ function parseStructuredAttributes(raw) {
1226
+ if (!raw || !raw.trim()) return void 0;
1227
+ try {
1228
+ const parsed = JSON.parse(raw);
1229
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
1230
+ const result = {};
1231
+ for (const [k, v] of Object.entries(parsed)) {
1232
+ if (typeof k === "string" && typeof v === "string") {
1233
+ result[k] = v;
1234
+ }
1235
+ }
1236
+ return Object.keys(result).length > 0 ? result : void 0;
1237
+ }
1238
+ } catch {
1239
+ }
1240
+ return void 0;
1241
+ }
1222
1242
  function parseLinkReasonValue(rawValue) {
1223
1243
  const legacyValue = rawValue.replace(/\\"/g, '"');
1224
1244
  const looksLikeLegacyPath = !rawValue.includes("\\\\") && (/[A-Za-z]:\\[A-Za-z0-9._ -]+(?:\\[A-Za-z0-9._ -]+)*/.test(rawValue) || /\\[A-Za-z0-9._ -]+\\[A-Za-z0-9._ -]+/.test(rawValue));
@@ -1331,7 +1351,9 @@ function parseFrontmatter2(raw) {
1331
1351
  sourceMemoryId: fm.sourceMemoryId || void 0,
1332
1352
  sourceTurnId: fm.sourceTurnId || void 0,
1333
1353
  // v8.0 Phase 2B: HiMem episode/note classification
1334
- memoryKind: fm.memoryKind || void 0
1354
+ memoryKind: fm.memoryKind || void 0,
1355
+ // Structured attributes (JSON on a single line)
1356
+ structuredAttributes: parseStructuredAttributes(fm.structuredAttributes)
1335
1357
  },
1336
1358
  content
1337
1359
  };
@@ -1812,9 +1834,16 @@ var StorageManager = class _StorageManager {
1812
1834
  artifactType: options.artifactType,
1813
1835
  sourceMemoryId: options.sourceMemoryId,
1814
1836
  sourceTurnId: options.sourceTurnId,
1815
- memoryKind: options.memoryKind
1837
+ memoryKind: options.memoryKind,
1838
+ structuredAttributes: options.structuredAttributes
1816
1839
  };
1817
- const sanitized = sanitizeMemoryContent(content);
1840
+ let enrichedContent = content;
1841
+ if (options.structuredAttributes && Object.keys(options.structuredAttributes).length > 0) {
1842
+ const attrLines = Object.entries(options.structuredAttributes).map(([k, v]) => `${k}: ${v}`).join("; ");
1843
+ enrichedContent = `${content}
1844
+ [Attributes: ${attrLines}]`;
1845
+ }
1846
+ const sanitized = sanitizeMemoryContent(enrichedContent);
1818
1847
  if (!sanitized.clean) {
1819
1848
  log.warn(`memory content sanitized for ${id}; violations=${sanitized.violations.join(", ")}`);
1820
1849
  }
@@ -3859,4 +3888,4 @@ export {
3859
3888
  serializeEntityFile,
3860
3889
  StorageManager
3861
3890
  };
3862
- //# sourceMappingURL=chunk-O4KLNIZ3.js.map
3891
+ //# sourceMappingURL=chunk-DDJJSZIV.js.map