enigma-memory 0.1.1 → 0.1.3
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/apps/browser-extension/manifest.json +41 -0
- package/apps/browser-extension/src/background.js +88 -0
- package/apps/browser-extension/src/content-script.js +602 -0
- package/apps/browser-extension/src/native-bridge.js +289 -0
- package/apps/cli/bin/enigma.mjs +209 -2
- package/apps/desktop/src/tray.js +231 -0
- package/docs/benchmark-reproducibility.md +113 -0
- package/docs/browser-extension-install.md +169 -0
- package/docs/developer-ecosystem.md +76 -0
- package/docs/hosted-cloud-product.md +68 -0
- package/docs/installers-and-desktop.md +76 -0
- package/docs/memory-benchmarks.md +82 -0
- package/docs/sdk-api.md +181 -0
- package/examples/ci/github-actions.yml +91 -0
- package/examples/node-basic-memory.mjs +84 -0
- package/package.json +21 -1
- package/packages/connectors/src/index.js +274 -39
- package/packages/hosted-cloud/src/index.js +538 -0
- package/packages/mcp-server/src/index.js +1 -1
- package/scripts/build-installer-assets.mjs +273 -0
- package/scripts/package-browser-extension.mjs +473 -0
- package/scripts/run-memory-benchmarks.mjs +897 -0
- package/scripts/verify-registry-install.mjs +6 -1
- package/templates/mcp-client-config.json +10 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
export const TRAY_MODEL_SCHEMA = 'enigma.desktop.tray_model.v1';
|
|
2
|
+
export const TRAY_MENU_SCHEMA = 'enigma.desktop.tray_menu.v1';
|
|
3
|
+
|
|
4
|
+
export const TRAY_ACTION_TYPES = Object.freeze({
|
|
5
|
+
STATUS: 'tray/status',
|
|
6
|
+
QUICKSTART: 'tray/quickstart',
|
|
7
|
+
CONNECT_CLIENTS: 'tray/connect-clients',
|
|
8
|
+
OPEN_DOCS: 'tray/open-docs',
|
|
9
|
+
RUN_DIAGNOSTICS: 'tray/run-diagnostics',
|
|
10
|
+
QUIT: 'tray/quit',
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const DEFAULT_DOCS_URL = 'https://docs.enigmaprotocol.net/docs/install';
|
|
14
|
+
const STATUS_VALUES = Object.freeze(new Set(['not-installed', 'ready', 'needs-setup', 'running', 'degraded', 'offline']));
|
|
15
|
+
const DIAGNOSTIC_VALUES = Object.freeze(new Set(['idle', 'queued', 'running', 'passed', 'failed']));
|
|
16
|
+
const CLIENTS = Object.freeze([
|
|
17
|
+
Object.freeze({ id: 'claude-desktop', label: 'Claude Desktop', kind: 'mcp-client' }),
|
|
18
|
+
Object.freeze({ id: 'cursor', label: 'Cursor', kind: 'mcp-client' }),
|
|
19
|
+
Object.freeze({ id: 'vscode', label: 'VS Code', kind: 'mcp-client' }),
|
|
20
|
+
Object.freeze({ id: 'browser-bridge', label: 'Browser bridge', kind: 'extension' }),
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
function cleanString(value) {
|
|
24
|
+
return String(value ?? '').trim();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function normalizeStatus(value) {
|
|
28
|
+
const status = cleanString(value);
|
|
29
|
+
return STATUS_VALUES.has(status) ? status : 'needs-setup';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function normalizeDiagnostics(value) {
|
|
33
|
+
const status = cleanString(value);
|
|
34
|
+
return DIAGNOSTIC_VALUES.has(status) ? status : 'idle';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function normalizeClients(value) {
|
|
38
|
+
const requested = Array.isArray(value) ? value : [];
|
|
39
|
+
const seen = new Set();
|
|
40
|
+
const known = new Map(CLIENTS.map((client) => [client.id, client]));
|
|
41
|
+
const clients = [];
|
|
42
|
+
for (const item of requested) {
|
|
43
|
+
const id = cleanString(typeof item === 'string' ? item : item?.id);
|
|
44
|
+
const connected = typeof item === 'string' || item?.connected === true;
|
|
45
|
+
if (!known.has(id) || seen.has(id) || !connected) continue;
|
|
46
|
+
seen.add(id);
|
|
47
|
+
clients.push({ ...known.get(id), connected: true });
|
|
48
|
+
}
|
|
49
|
+
for (const client of CLIENTS) {
|
|
50
|
+
if (!seen.has(client.id)) clients.push({ ...client, connected: false });
|
|
51
|
+
}
|
|
52
|
+
return clients;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function menuItem(id, label, action, options = {}) {
|
|
56
|
+
return Object.freeze({
|
|
57
|
+
id,
|
|
58
|
+
label,
|
|
59
|
+
action,
|
|
60
|
+
enabled: options.enabled !== false,
|
|
61
|
+
checked: options.checked === true,
|
|
62
|
+
role: cleanString(options.role) || 'item',
|
|
63
|
+
honest_boundary: cleanString(options.honest_boundary),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function action(type, payload = {}) {
|
|
68
|
+
return Object.freeze({ type, ...payload });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function createTrayState(options = {}) {
|
|
72
|
+
const status = normalizeStatus(options.status);
|
|
73
|
+
const clients = normalizeClients(options.connectedClients ?? options.clients);
|
|
74
|
+
const connectedCount = clients.filter((client) => client.connected).length;
|
|
75
|
+
return Object.freeze({
|
|
76
|
+
schema: TRAY_MODEL_SCHEMA,
|
|
77
|
+
model_only: true,
|
|
78
|
+
native_tray_started: false,
|
|
79
|
+
status,
|
|
80
|
+
status_label: statusLabel(status),
|
|
81
|
+
quickstart_available: options.quickstartAvailable !== false,
|
|
82
|
+
clients: Object.freeze(clients.map((client) => Object.freeze({ ...client }))),
|
|
83
|
+
connected_client_count: connectedCount,
|
|
84
|
+
docs_url: cleanString(options.docsUrl) || DEFAULT_DOCS_URL,
|
|
85
|
+
diagnostics: Object.freeze({
|
|
86
|
+
status: normalizeDiagnostics(options.diagnosticsStatus),
|
|
87
|
+
last_result: cleanString(options.diagnosticsResult),
|
|
88
|
+
}),
|
|
89
|
+
quit_requested: options.quitRequested === true,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function statusLabel(status) {
|
|
94
|
+
switch (normalizeStatus(status)) {
|
|
95
|
+
case 'ready':
|
|
96
|
+
return 'Ready';
|
|
97
|
+
case 'running':
|
|
98
|
+
return 'Running';
|
|
99
|
+
case 'degraded':
|
|
100
|
+
return 'Needs attention';
|
|
101
|
+
case 'offline':
|
|
102
|
+
return 'Offline';
|
|
103
|
+
case 'not-installed':
|
|
104
|
+
return 'Not installed';
|
|
105
|
+
default:
|
|
106
|
+
return 'Needs setup';
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function createTrayMenu(state = createTrayState()) {
|
|
111
|
+
const model = state?.schema === TRAY_MODEL_SCHEMA ? state : createTrayState(state);
|
|
112
|
+
return Object.freeze({
|
|
113
|
+
schema: TRAY_MENU_SCHEMA,
|
|
114
|
+
model_only: true,
|
|
115
|
+
native_tray_started: false,
|
|
116
|
+
status: model.status,
|
|
117
|
+
items: Object.freeze([
|
|
118
|
+
menuItem('status', `Status: ${model.status_label}`, TRAY_ACTION_TYPES.STATUS, {
|
|
119
|
+
enabled: false,
|
|
120
|
+
honest_boundary: 'Local tray status is an application model snapshot, not cryptographic proof.',
|
|
121
|
+
}),
|
|
122
|
+
menuItem('quickstart', 'Run quickstart', TRAY_ACTION_TYPES.QUICKSTART, {
|
|
123
|
+
enabled: model.quickstart_available && model.status !== 'running',
|
|
124
|
+
honest_boundary: 'Emits an intent to run the existing quickstart command; this module does not execute commands.',
|
|
125
|
+
}),
|
|
126
|
+
menuItem('connect-clients', `Connect clients (${model.connected_client_count})`, TRAY_ACTION_TYPES.CONNECT_CLIENTS, {
|
|
127
|
+
honest_boundary: 'Opens client-connection intent only; no MCP client is configured by this pure model.',
|
|
128
|
+
}),
|
|
129
|
+
menuItem('open-docs', 'Open install docs', TRAY_ACTION_TYPES.OPEN_DOCS, {
|
|
130
|
+
honest_boundary: 'Emits a docs URL intent only; this module does not launch a browser.',
|
|
131
|
+
}),
|
|
132
|
+
menuItem('run-diagnostics', diagnosticsLabel(model.diagnostics.status), TRAY_ACTION_TYPES.RUN_DIAGNOSTICS, {
|
|
133
|
+
enabled: model.diagnostics.status !== 'running',
|
|
134
|
+
honest_boundary: 'Emits diagnostics intent only; the caller owns command execution and evidence capture.',
|
|
135
|
+
}),
|
|
136
|
+
menuItem('separator-before-quit', '—', '', { enabled: false, role: 'separator' }),
|
|
137
|
+
menuItem('quit', 'Quit Enigma tray', TRAY_ACTION_TYPES.QUIT, {
|
|
138
|
+
honest_boundary: 'Emits quit intent only; host application owns process shutdown.',
|
|
139
|
+
}),
|
|
140
|
+
]),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function diagnosticsLabel(status) {
|
|
145
|
+
switch (normalizeDiagnostics(status)) {
|
|
146
|
+
case 'queued':
|
|
147
|
+
return 'Diagnostics queued';
|
|
148
|
+
case 'running':
|
|
149
|
+
return 'Diagnostics running';
|
|
150
|
+
case 'passed':
|
|
151
|
+
return 'Run diagnostics (last passed)';
|
|
152
|
+
case 'failed':
|
|
153
|
+
return 'Run diagnostics (last failed)';
|
|
154
|
+
default:
|
|
155
|
+
return 'Run diagnostics';
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function trayStatus(status) {
|
|
160
|
+
return action(TRAY_ACTION_TYPES.STATUS, { status: normalizeStatus(status) });
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function runQuickstart(options = {}) {
|
|
164
|
+
return action(TRAY_ACTION_TYPES.QUICKSTART, { bundle: cleanString(options.bundle) || '<bundle-path>', overwrite: options.overwrite !== false });
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function connectClients(clientIds = []) {
|
|
168
|
+
return action(TRAY_ACTION_TYPES.CONNECT_CLIENTS, { clients: normalizeClients(clientIds).filter((client) => client.connected).map((client) => client.id) });
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export function openDocs(url = DEFAULT_DOCS_URL) {
|
|
172
|
+
return action(TRAY_ACTION_TYPES.OPEN_DOCS, { url: cleanString(url) || DEFAULT_DOCS_URL });
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export function runDiagnostics(scope = 'local') {
|
|
176
|
+
return action(TRAY_ACTION_TYPES.RUN_DIAGNOSTICS, { scope: cleanString(scope) || 'local' });
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function quitTray() {
|
|
180
|
+
return action(TRAY_ACTION_TYPES.QUIT, { quit_requested: true });
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function reduceTrayState(state = createTrayState(), requestedAction = {}) {
|
|
184
|
+
const model = state?.schema === TRAY_MODEL_SCHEMA ? state : createTrayState(state);
|
|
185
|
+
const type = cleanString(requestedAction.type);
|
|
186
|
+
switch (type) {
|
|
187
|
+
case TRAY_ACTION_TYPES.STATUS:
|
|
188
|
+
return createTrayState({ ...model, status: requestedAction.status });
|
|
189
|
+
case TRAY_ACTION_TYPES.QUICKSTART:
|
|
190
|
+
return createTrayState({ ...model, status: 'running', diagnosticsStatus: model.diagnostics.status });
|
|
191
|
+
case TRAY_ACTION_TYPES.CONNECT_CLIENTS:
|
|
192
|
+
return createTrayState({ ...model, connectedClients: requestedAction.clients });
|
|
193
|
+
case TRAY_ACTION_TYPES.OPEN_DOCS:
|
|
194
|
+
return createTrayState({ ...model, docsUrl: requestedAction.url });
|
|
195
|
+
case TRAY_ACTION_TYPES.RUN_DIAGNOSTICS:
|
|
196
|
+
return createTrayState({ ...model, diagnosticsStatus: 'queued' });
|
|
197
|
+
case TRAY_ACTION_TYPES.QUIT:
|
|
198
|
+
return createTrayState({ ...model, quitRequested: true });
|
|
199
|
+
default:
|
|
200
|
+
return model;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function trayActionIntent(requestedAction = {}) {
|
|
205
|
+
const type = cleanString(requestedAction.type);
|
|
206
|
+
switch (type) {
|
|
207
|
+
case TRAY_ACTION_TYPES.STATUS:
|
|
208
|
+
return Object.freeze({ kind: 'status', status: normalizeStatus(requestedAction.status), side_effect: false });
|
|
209
|
+
case TRAY_ACTION_TYPES.QUICKSTART:
|
|
210
|
+
return Object.freeze({ kind: 'quickstart', command: 'enigma', args: ['quickstart', '--bundle', '<bundle-path>', '--overwrite'], side_effect: 'caller-owned' });
|
|
211
|
+
case TRAY_ACTION_TYPES.CONNECT_CLIENTS:
|
|
212
|
+
return Object.freeze({ kind: 'connect_clients', clients: normalizeClients(requestedAction.clients).filter((client) => client.connected).map((client) => client.id), side_effect: 'caller-owned' });
|
|
213
|
+
case TRAY_ACTION_TYPES.OPEN_DOCS:
|
|
214
|
+
return Object.freeze({ kind: 'open_docs', url: cleanString(requestedAction.url) || DEFAULT_DOCS_URL, side_effect: 'caller-owned' });
|
|
215
|
+
case TRAY_ACTION_TYPES.RUN_DIAGNOSTICS:
|
|
216
|
+
return Object.freeze({ kind: 'run_diagnostics', command: 'enigma', args: ['doctor'], side_effect: 'caller-owned' });
|
|
217
|
+
case TRAY_ACTION_TYPES.QUIT:
|
|
218
|
+
return Object.freeze({ kind: 'quit', side_effect: 'caller-owned' });
|
|
219
|
+
default:
|
|
220
|
+
return Object.freeze({ kind: 'unknown', side_effect: false });
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export const trayActions = Object.freeze({
|
|
225
|
+
trayStatus,
|
|
226
|
+
runQuickstart,
|
|
227
|
+
connectClients,
|
|
228
|
+
openDocs,
|
|
229
|
+
runDiagnostics,
|
|
230
|
+
quitTray,
|
|
231
|
+
});
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Benchmark reproducibility
|
|
2
|
+
|
|
3
|
+
This guide explains how to reproduce the current local Enigma memory benchmark, save the public-safe JSON report, cite the external benchmark standards it is modeled after, and understand what is still required before publishing live third-party comparisons.
|
|
4
|
+
|
|
5
|
+
## What is reproducible today
|
|
6
|
+
|
|
7
|
+
The current package is `enigma-memory@0.1.3`. The local benchmark is available through the package script and the script file it wraps:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
cd enigma
|
|
11
|
+
npm run benchmark:memory-suite
|
|
12
|
+
npm run benchmark:memory-suite -- --out benchmark-report.json
|
|
13
|
+
node scripts/run-memory-benchmarks.mjs --out benchmark-report.json
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The `--out` form writes the report to the requested path and prints only a small status object. Without `--out`, the command writes the full JSON report to stdout.
|
|
17
|
+
|
|
18
|
+
The report schema is `enigma.memory_benchmark_suite.v1`. It is designed to be public-safe: it contains aggregate metrics, commitments, citations, cross-provider profile labels, and claim boundaries. It does not include raw fixture memory, private question text, private answer text, provider transcripts, credentials, account ids, or local absolute paths.
|
|
19
|
+
|
|
20
|
+
## Reproduce and save JSON
|
|
21
|
+
|
|
22
|
+
1. Use a clean checkout containing `enigma-memory@0.1.3`.
|
|
23
|
+
2. From a repository root that contains `enigma/package.json`, enter the package directory:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
cd enigma
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
If your checkout already has `package.json` for `enigma-memory` at the current directory, skip this `cd`.
|
|
30
|
+
|
|
31
|
+
3. Install the package dependencies with the reviewed package command:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
npm install
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
4. Run the benchmark and save the public-safe JSON report:
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
npm run benchmark:memory-suite -- --out benchmark-report.json
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
5. Preserve the JSON file with the command, package version, operating system/runtime, and review context that produced it.
|
|
44
|
+
6. When sharing the result publicly, share the generated JSON report only after confirming it still has `public_safe: true` and `schema: "enigma.memory_benchmark_suite.v1"`.
|
|
45
|
+
|
|
46
|
+
The local fixture measures Enigma-controlled operations only: vault remember/update, vault export/import, passport context-pack retrieval, optimizer token estimates and duplicate removal, bundle/context-pack verification, abstention behavior, exact-answer recall over the deterministic fixture, and p50/p95 operation latency from `performance.now`.
|
|
47
|
+
|
|
48
|
+
## Local baseline rows in the report
|
|
49
|
+
|
|
50
|
+
The report now includes `metrics.local_baseline_comparisons`, which compares deterministic local baselines over the same private fixture questions. These rows are local package evidence only: they do not call hosted providers, use provider APIs, or support invoice savings, ROI, compliance, model-forgetting, or benchmark-leadership claims.
|
|
51
|
+
|
|
52
|
+
| Row | Local boundary |
|
|
53
|
+
| --- | --- |
|
|
54
|
+
| `full_context` | Supplies every active fixture memory without optimization or deduplication. |
|
|
55
|
+
| `recency_last_n` | Supplies the three most recently updated active fixture memories. |
|
|
56
|
+
| `keyword_filter` | Supplies active fixture memories whose content or tags match deterministic query terms. |
|
|
57
|
+
| `enigma_context_pack` | Uses the Enigma passport context-pack compiler and optimizer boundary. |
|
|
58
|
+
|
|
59
|
+
The report also includes `public_claims_allowed`; keep public copy within those local-fixture boundaries unless separate reviewed external evidence exists.
|
|
60
|
+
|
|
61
|
+
## How to cite external benchmark standards
|
|
62
|
+
|
|
63
|
+
Use these standards as citations and task-category references, not as claimed Enigma results unless the exact external benchmark has been run and reviewed:
|
|
64
|
+
|
|
65
|
+
- LoCoMo: https://snap-research.github.io/locomo/ — cite for long-term conversational-memory QA, event summarization, and multimodal generation over long conversations.
|
|
66
|
+
- LongMemEval: https://arxiv.org/abs/2410.10813 — cite for information extraction, multi-session reasoning, temporal reasoning, knowledge updates, and abstention.
|
|
67
|
+
|
|
68
|
+
The current local report mirrors some task categories from those benchmarks, but it does not download LoCoMo or LongMemEval data, run their official evaluation pipelines, or claim leaderboard-equivalent results.
|
|
69
|
+
|
|
70
|
+
## Why live third-party comparisons are not claimed yet
|
|
71
|
+
|
|
72
|
+
The current benchmark does not call external provider APIs, external SDKs, hosted memory services, ChatGPT native memory, Claude memory tooling, or third-party agent loops. Cross-provider rows in the report are profile labels that reuse the same Enigma context-pack boundary; they do not call or compare live provider models and are not live provider rankings.
|
|
73
|
+
|
|
74
|
+
Real comparisons require fixed adapters, fixed datasets, fixed agent/tool loops, explicit provider terms review, and reviewed handling of secrets and raw benchmark data. Memory quality can change with the surrounding agent framework and tool loop, so a fair comparison must document more than the memory store.
|
|
75
|
+
|
|
76
|
+
The current report must not be used as evidence of provider-side deletion, model forgetting, compliance certification, token ROI, provider invoice savings, benchmark leadership, hosted-cloud readiness, or “best in world” superiority.
|
|
77
|
+
|
|
78
|
+
## External comparison requirements
|
|
79
|
+
|
|
80
|
+
Use placeholder environment names only. Do not commit real tokens, API keys, account ids, provider transcripts, raw benchmark conversations, or private memory.
|
|
81
|
+
|
|
82
|
+
The report field `external_competitor_adapters` is a requirements matrix, not a score table. External rows are expected to remain requirements-only until credentials, runtimes, and datasets are supplied and reviewed: `can_run_in_this_harness: false`, `scores_included: false`, and no recall, abstention, token, latency, or ranking scores.
|
|
83
|
+
|
|
84
|
+
| Target | Runtime or SDK needed | Placeholder secrets and local inputs | Dataset requirement | Adapter boundary before results can be claimed |
|
|
85
|
+
| --- | --- | --- | --- | --- |
|
|
86
|
+
| Letta | Letta SDK/runtime; documented SDK packages include `@letta-ai/letta-client` and `letta-client`; API-key-backed service access may be required. | `LETTA_API_KEY`, `LETTA_BASE_URL`, `LETTA_PROJECT_ID`, `BENCHMARK_DATASET_PATH` | Local reviewed LoCoMo/LongMemEval split or another reviewed local dataset file with license, version, split, and checksum metadata. | Build a Letta adapter that fixes the agent loop, memory write/read policy, model settings, and scoring path. Results may describe that configured Letta run only, not generic provider deletion or model forgetting. |
|
|
87
|
+
| LangGraph memory | LangGraph runtime with short-term checkpointer memory and long-term namespaced store. | `LANGGRAPH_CHECKPOINTER_URI`, `LANGGRAPH_STORE_URI`, `BENCHMARK_DATASET_PATH` | Same local dataset file and split used for Enigma and every competitor. | Fix graph topology, checkpoint scope, namespace policy, retrieval policy, model/tool loop, and scorer. Do not attribute graph/tool behavior solely to the memory store. |
|
|
88
|
+
| Zep | Zep service/runtime positioned around temporal Context Graph and Context Lake retrieval. | `ZEP_API_KEY`, `ZEP_PROJECT_ID`, `ZEP_BASE_URL`, `BENCHMARK_DATASET_PATH` | Same local dataset file and split; include source checksum and whether any provider-side graph state is reused or reset. | Build a Zep adapter that records ingest, session, retrieval, reset, and scoring policy. Zep’s sub-200ms retrieval positioning is a vendor/source fact, not an Enigma-measured claim until measured in the same harness. |
|
|
89
|
+
| Mem0 | Mem0 platform or open-source stack; positioned as a universal self-improving memory layer. | `MEM0_API_KEY`, `MEM0_BASE_URL`, `MEM0_PROJECT_ID`, `BENCHMARK_DATASET_PATH` | Same local dataset file and split; record Mem0 deployment flavor/version. | Build a Mem0 adapter with fixed extraction, update, retrieval, reset, and scorer behavior. Self-improving or platform behavior must be bounded to the configured run. |
|
|
90
|
+
| OpenAI native ChatGPT memory | ChatGPT consumer-app/native memory environment. It is not directly available through a public API in this harness. | No usable harness secret; `OPENAI_API_KEY` alone is not sufficient to exercise ChatGPT native memory. | No fair automated dataset run until an approved interface can load/reset/query native memory reproducibly. | Do not claim live native ChatGPT memory comparison from this repository. A future adapter would need an approved public interface, reproducible memory reset/load semantics, and provider-policy review. |
|
|
91
|
+
| Claude memory tool | Client-side/provider-specific memory tool environment. | `CLAUDE_MEMORY_TOOL_CONFIG`, `ANTHROPIC_API_KEY`, `BENCHMARK_DATASET_PATH` | Same local dataset file and split, plus reviewed tool-state reset/export rules. | Build an adapter around the exact client/tool environment, not generic Claude model behavior. Results can only cover that configured memory-tool setup. |
|
|
92
|
+
|
|
93
|
+
## Source references for adapter planning
|
|
94
|
+
|
|
95
|
+
- Letta MemGPT concepts: https://docs.letta.com/concepts/memgpt/
|
|
96
|
+
- Zep documentation: https://help.getzep.com/
|
|
97
|
+
- Mem0 documentation: https://docs.mem0.ai/
|
|
98
|
+
- LangGraph memory documentation: https://docs.langchain.com/oss/python/langgraph/memory
|
|
99
|
+
- OpenAI ChatGPT memory FAQ: https://help.openai.com/en/articles/8590148-memory-faq
|
|
100
|
+
- Claude memory tool support article: https://support.anthropic.com/en/articles/11145838-using-claude-memory
|
|
101
|
+
|
|
102
|
+
## Minimum evidence for a future live comparison
|
|
103
|
+
|
|
104
|
+
Before publishing external comparison language, capture all of the following in the benchmark report or an adjacent reviewed evidence file:
|
|
105
|
+
|
|
106
|
+
1. Package version, benchmark schema, command, timestamp, OS/runtime, and adapter version.
|
|
107
|
+
2. Dataset name, source URL, license review status, local file checksum, split, and record count.
|
|
108
|
+
3. Secret names used as placeholders, with confirmation that no secret values are printed or persisted.
|
|
109
|
+
4. Adapter configuration: SDK/runtime version, model where applicable, memory write/read policy, reset policy, context limits, retry policy, and scoring code.
|
|
110
|
+
5. Per-target raw scoring inputs retained privately when license permits, with public reports limited to safe aggregates.
|
|
111
|
+
6. Explicit boundaries separating memory-store behavior, agent-loop behavior, model behavior, provider-hosted state, and Enigma receipt verification.
|
|
112
|
+
|
|
113
|
+
Until that evidence exists, use only the local benchmark claim: Enigma can reproduce deterministic local memory-fixture operations and emit a public-safe `enigma.memory_benchmark_suite.v1` JSON report.
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Browser extension local install
|
|
2
|
+
|
|
3
|
+
This guide is for local developer installation only. It does not submit Enigma to Chrome Web Store, Microsoft Edge Add-ons, Mozilla Add-ons, or any external account.
|
|
4
|
+
|
|
5
|
+
## Boundaries
|
|
6
|
+
|
|
7
|
+
- The extension is loaded by the user as an unpacked or temporary local extension.
|
|
8
|
+
- The native host is installed by the user and runs on the local machine as `com.enigma.native_host`.
|
|
9
|
+
- Context insertion requires two user clicks: request context, then approve insertion.
|
|
10
|
+
- The extension must not auto-inject context into a provider page.
|
|
11
|
+
- The extension does not use browser sync storage and must not store raw memory in browser storage.
|
|
12
|
+
- Provider-native memory is cache only. The local Enigma bundle/native host remains canonical.
|
|
13
|
+
|
|
14
|
+
## Package preflight
|
|
15
|
+
|
|
16
|
+
From the package root, validate the extension before loading or zipping it:
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
node scripts/package-browser-extension.mjs
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The command emits public-safe JSON with a deterministic file list, SHA-256 checksums, and safety fields. To also write a deterministic local ZIP for manual inspection or enterprise review:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
node scripts/package-browser-extension.mjs --zip ./dist/enigma-browser-extension.zip
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The ZIP command does not publish, sign, upload, or submit the extension.
|
|
29
|
+
|
|
30
|
+
## Install the native host first
|
|
31
|
+
|
|
32
|
+
Install the npm package so both `enigma` and `enigma-native-host` are available:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
npm install -g enigma-memory
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Create or select a local bundle:
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
enigma init --bundle <absolute-bundle-path> --subject local-user --display-name "Local user"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Set `ENIGMA_BUNDLE` for the browser-launched host process, or point the native-host manifest at a small local wrapper that sets `ENIGMA_BUNDLE=<absolute-bundle-path>` before launching `enigma-native-host`. Native messaging manifests require an absolute executable path; they do not expand shell aliases, `~`, `$HOME`, `%USERPROFILE%`, or command arguments.
|
|
45
|
+
|
|
46
|
+
Resolve the absolute host executable path:
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
command -v enigma-native-host
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Windows PowerShell:
|
|
53
|
+
|
|
54
|
+
```powershell
|
|
55
|
+
(Get-Command enigma-native-host.cmd).Source
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Load the extension locally
|
|
59
|
+
|
|
60
|
+
### Chrome
|
|
61
|
+
|
|
62
|
+
1. Open `chrome://extensions`.
|
|
63
|
+
2. Enable **Developer mode**.
|
|
64
|
+
3. Select **Load unpacked**.
|
|
65
|
+
4. Choose `enigma/apps/browser-extension`.
|
|
66
|
+
5. Open the Enigma extension details and copy the 32-character extension ID.
|
|
67
|
+
|
|
68
|
+
### Microsoft Edge
|
|
69
|
+
|
|
70
|
+
1. Open `edge://extensions`.
|
|
71
|
+
2. Enable **Developer mode**.
|
|
72
|
+
3. Select **Load unpacked**.
|
|
73
|
+
4. Choose `enigma/apps/browser-extension`.
|
|
74
|
+
5. Open the Enigma extension details and copy the 32-character extension ID.
|
|
75
|
+
|
|
76
|
+
### Firefox
|
|
77
|
+
|
|
78
|
+
1. Open `about:debugging#/runtime/this-firefox`.
|
|
79
|
+
2. Select **Load Temporary Add-on**.
|
|
80
|
+
3. Choose `enigma/apps/browser-extension/manifest.json`.
|
|
81
|
+
4. Copy the temporary extension ID shown by Firefox. For repeatable development, use a stable development add-on ID and pass the same value to the native-host manifest generator.
|
|
82
|
+
|
|
83
|
+
## Generate the browser native-host manifest
|
|
84
|
+
|
|
85
|
+
Generate a manifest after you know the extension ID and absolute host path.
|
|
86
|
+
|
|
87
|
+
Chrome:
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
enigma native-host manifest \
|
|
91
|
+
--browser chrome \
|
|
92
|
+
--host-path <absolute-enigma-native-host-path> \
|
|
93
|
+
--extension-id <chrome-extension-id> \
|
|
94
|
+
--out ./com.enigma.native_host.json
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Edge:
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
enigma native-host manifest \
|
|
101
|
+
--browser edge \
|
|
102
|
+
--host-path <absolute-enigma-native-host-path> \
|
|
103
|
+
--extension-id <edge-extension-id> \
|
|
104
|
+
--out ./com.enigma.native_host.json
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Firefox:
|
|
108
|
+
|
|
109
|
+
```sh
|
|
110
|
+
enigma native-host manifest \
|
|
111
|
+
--browser firefox \
|
|
112
|
+
--host-path <absolute-enigma-native-host-path> \
|
|
113
|
+
--extension-id <firefox-extension-id> \
|
|
114
|
+
--out ./com.enigma.native_host.json
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Preview browser-specific install locations without mutating registry or profile state:
|
|
118
|
+
|
|
119
|
+
```sh
|
|
120
|
+
enigma native-host install-plan \
|
|
121
|
+
--browser chrome \
|
|
122
|
+
--manifest <absolute-path-to-com.enigma.native_host.json>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Use `--browser edge` or `--browser firefox` for the other browsers. The install plan is a checklist: it does not copy manifests, write registry keys, or change browser profiles. Copy the generated manifest to the listed native messaging host location yourself, and on Windows review and run the listed registry command only when you are ready to register `com.enigma.native_host`.
|
|
126
|
+
|
|
127
|
+
## Register the native-host manifest locally
|
|
128
|
+
|
|
129
|
+
Use the paths from `enigma native-host install-plan` as the source of truth. These are the common manual targets:
|
|
130
|
+
|
|
131
|
+
### Chrome native host
|
|
132
|
+
|
|
133
|
+
- macOS per-user: `<home>/Library/Application Support/Google/Chrome/NativeMessagingHosts/com.enigma.native_host.json`
|
|
134
|
+
- Linux per-user: `<home>/.config/google-chrome/NativeMessagingHosts/com.enigma.native_host.json`
|
|
135
|
+
- Windows per-user: copy the manifest to an operator-chosen local file, then set `HKCU\Software\Google\Chrome\NativeMessagingHosts\com.enigma.native_host` to that manifest path.
|
|
136
|
+
|
|
137
|
+
### Microsoft Edge native host
|
|
138
|
+
|
|
139
|
+
- macOS per-user: `<home>/Library/Application Support/Microsoft Edge/NativeMessagingHosts/com.enigma.native_host.json`
|
|
140
|
+
- Linux per-user: `<home>/.config/microsoft-edge/NativeMessagingHosts/com.enigma.native_host.json`
|
|
141
|
+
- Windows per-user: copy the manifest to an operator-chosen local file, then set `HKCU\Software\Microsoft\Edge\NativeMessagingHosts\com.enigma.native_host` to that manifest path.
|
|
142
|
+
|
|
143
|
+
### Firefox native host
|
|
144
|
+
|
|
145
|
+
- macOS per-user: `<home>/Library/Application Support/Mozilla/NativeMessagingHosts/com.enigma.native_host.json`
|
|
146
|
+
- Linux per-user: `<home>/.mozilla/native-messaging-hosts/com.enigma.native_host.json`
|
|
147
|
+
- Windows per-user: copy the manifest to an operator-chosen local file, then set `HKCU\Software\Mozilla\NativeMessagingHosts\com.enigma.native_host` to that manifest path.
|
|
148
|
+
|
|
149
|
+
All-users locations and registry hives are operator-managed deployment choices. Local developer install should prefer per-user targets unless an enterprise policy requires otherwise.
|
|
150
|
+
|
|
151
|
+
## Local insertion demo flow
|
|
152
|
+
|
|
153
|
+
1. Confirm the native-host manifest allowlist uses the extension ID from the local browser profile.
|
|
154
|
+
2. Restart the browser after native-host registration so it can discover `com.enigma.native_host`.
|
|
155
|
+
3. Visit a supported HTTPS provider page: ChatGPT, Claude, Kimi, or Perplexity.
|
|
156
|
+
4. Open the Enigma control shown by the content script.
|
|
157
|
+
5. Click **Request context**. The extension asks the local native host for a transient context pack; selected page text is included only if the user explicitly enables it for that request.
|
|
158
|
+
6. Review the returned context in the panel.
|
|
159
|
+
7. Click **Approve and insert** to insert plain text into the active prompt surface.
|
|
160
|
+
8. Submit to the provider only if you choose to. Enigma does not submit prompts for you.
|
|
161
|
+
|
|
162
|
+
After insertion, the extension records only target metadata, insertion timestamp, receipt metadata, and insertion counts. It must not write raw memory, context plaintext, or receipt plaintext into browser sync storage or public artifacts.
|
|
163
|
+
|
|
164
|
+
## Troubleshooting
|
|
165
|
+
|
|
166
|
+
- **Host not found**: confirm the manifest filename is `com.enigma.native_host.json`, the manifest `name` is `com.enigma.native_host`, and the browser-specific install location or registry key points to the manifest.
|
|
167
|
+
- **Host exits immediately**: confirm `ENIGMA_BUNDLE` is visible to the browser-launched process or use a local wrapper that sets it before launching `enigma-native-host`.
|
|
168
|
+
- **Extension cannot connect**: confirm the extension ID in the native-host manifest matches the locally loaded extension.
|
|
169
|
+
- **No insertion happens**: confirm you clicked both **Request context** and **Approve and insert**. The extension intentionally does not auto-inject.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Developer ecosystem
|
|
2
|
+
|
|
3
|
+
Enigma Memory is a local-first SDK, CLI, MCP server, and service-contract package. The developer surfaces are designed to be copied without secrets, cloud credentials, hidden local paths, or account identifiers.
|
|
4
|
+
|
|
5
|
+
## Copyable starting points
|
|
6
|
+
|
|
7
|
+
- SDK/API guide: [`docs/sdk-api.md`](./sdk-api.md)
|
|
8
|
+
- Node example app: [`examples/node-basic-memory.mjs`](../examples/node-basic-memory.mjs)
|
|
9
|
+
- GitHub Actions example: [`examples/ci/github-actions.yml`](../examples/ci/github-actions.yml)
|
|
10
|
+
- Benchmark reproducibility guide: [`docs/benchmark-reproducibility.md`](./benchmark-reproducibility.md)
|
|
11
|
+
- Generic MCP client template: [`templates/mcp-client-config.json`](../templates/mcp-client-config.json)
|
|
12
|
+
|
|
13
|
+
## Local SDK loop
|
|
14
|
+
|
|
15
|
+
Use the SDK when you want an app-owned vault and receipt-backed proof loop:
|
|
16
|
+
|
|
17
|
+
1. Create a local vault with `createVault`.
|
|
18
|
+
2. Add a generic, non-private memory with `remember`.
|
|
19
|
+
3. Create a passport with `createPassport`.
|
|
20
|
+
4. Compile a receipt-backed context pack with `compileContextPack`.
|
|
21
|
+
5. Export a proof-carrying bundle with `exportBundle`; keep full bundles private unless local import key material has been reviewed and removed.
|
|
22
|
+
6. Verify receipts with `verifyReceiptChain`, `enigma verify`, `enigma-verify`, or MCP `enigma_verify_receipts`.
|
|
23
|
+
|
|
24
|
+
The example app prints ids, counts, roots, and verification status only. It does not print raw memory text, generated key material, credentials, provider transcripts, or local absolute paths.
|
|
25
|
+
|
|
26
|
+
## CLI and CI loop
|
|
27
|
+
|
|
28
|
+
The CI example installs Node 24, installs the published `enigma-memory@0.1.3` package, runs:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
npx enigma quickstart --overwrite
|
|
32
|
+
npx enigma doctor
|
|
33
|
+
npm run benchmark:memory-suite -- --out benchmark-report.json
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
and then runs a small ESM import smoke. It does not require GitHub secrets, cloud provider credentials, npm tokens, private bundles, or local path assumptions. The benchmark step writes a public-safe local JSON report using schema `enigma.memory_benchmark_suite.v1`; see the benchmark reproducibility guide for claim boundaries and the requirements for any future live third-party comparison.
|
|
37
|
+
|
|
38
|
+
Use the workflow as a template in a consumer repository. It is intentionally limited to install/import/doctor smoke coverage, local proof generation, and deterministic local benchmark evidence; it does not publish packages, deploy infrastructure, contact hosted Enigma cloud, or call external memory providers.
|
|
39
|
+
|
|
40
|
+
## MCP client loop
|
|
41
|
+
|
|
42
|
+
The generic MCP template uses the installed `enigma-mcp` command and exactly one environment placeholder:
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"mcpServers": {
|
|
47
|
+
"enigma": {
|
|
48
|
+
"command": "enigma-mcp",
|
|
49
|
+
"env": {
|
|
50
|
+
"ENIGMA_BUNDLE": "<ENIGMA_BUNDLE>"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Replace `<ENIGMA_BUNDLE>` with the bundle file you control, or with the client-specific environment expansion syntax if your MCP client supports it. Do not commit private bundle paths if they reveal local usernames, workspace names, account ids, or other personal details.
|
|
58
|
+
|
|
59
|
+
## Claim boundaries for developers
|
|
60
|
+
|
|
61
|
+
Enigma proof artifacts cover Enigma-controlled or Enigma-mediated state: local vault events, receipts, active/tombstoned memory addresses, context-pack retrieval/injection receipts, relay/gateway records, usage events, and settlement receipts.
|
|
62
|
+
|
|
63
|
+
They do not prove:
|
|
64
|
+
|
|
65
|
+
- provider-side deletion;
|
|
66
|
+
- model forgetting;
|
|
67
|
+
- compliance certification;
|
|
68
|
+
- token ROI, investment outcome, or provider invoice savings;
|
|
69
|
+
- hosted-cloud readiness from a local demo;
|
|
70
|
+
- benchmark leadership from SDK mechanics alone.
|
|
71
|
+
|
|
72
|
+
Benchmark claims require benchmark-specific evidence. LoCoMo covers long-term conversational memory QA, event summarization, and multimodal generation across long conversations. LongMemEval covers extraction, multi-session reasoning, temporal reasoning, knowledge updates, and abstention. Agent-memory benchmark results can depend heavily on the agent/framework/tool loop, not only on the memory store. Keep those distinctions when writing integrations or public copy.
|
|
73
|
+
|
|
74
|
+
## What to keep out of examples
|
|
75
|
+
|
|
76
|
+
Do not add secrets, tokens, 2FA codes, cloud account ids, personal data, provider transcripts, raw private memory, absolute local paths, or unreviewed hosted endpoints to examples/templates. Public-safe examples should use generic ids, relative paths, placeholders, hashes, commitments, counts, receipt ids, and roots.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Hosted cloud product contract
|
|
2
|
+
|
|
3
|
+
This document separates the hosted-cloud product contract surface from the external systems still required before Enigma can sell or operate a hosted cloud service.
|
|
4
|
+
|
|
5
|
+
## Production contract-ready now
|
|
6
|
+
|
|
7
|
+
The source package now has pure contract builders and validators in `packages/hosted-cloud/src/index.js` for:
|
|
8
|
+
|
|
9
|
+
- user account records;
|
|
10
|
+
- tenant records;
|
|
11
|
+
- hosted vault records;
|
|
12
|
+
- API key metadata records;
|
|
13
|
+
- usage billing records;
|
|
14
|
+
- dashboard summaries;
|
|
15
|
+
- backup drill records;
|
|
16
|
+
- incident and SLA reference records.
|
|
17
|
+
|
|
18
|
+
These functions are contract and validation code only. They do not call an auth provider, billing provider, cloud deployment, KMS, backup target, support desk, status page, SIEM, or model provider. They are safe to import as package code because they do not start servers, read user files, mutate deployment state, publish packages, or contact external accounts.
|
|
19
|
+
|
|
20
|
+
The validators enforce hosted-cloud boundaries:
|
|
21
|
+
|
|
22
|
+
- contract artifacts must include `operator_evidence_refs` for auth provider, billing provider, legal docs, data processing terms, support ownership, and external security review;
|
|
23
|
+
- missing operator evidence references are rejected;
|
|
24
|
+
- raw memory, plaintext prompts, provider responses, transcripts, credential-looking values, token values, private keys, and API key secret material are rejected;
|
|
25
|
+
- financial outcome claims, token ROI/profit claims, provider-side deletion claims, and model-forgetting claims are rejected;
|
|
26
|
+
- API key contracts store identifiers, fingerprints, scopes, rotation refs, and timestamps only, not key material;
|
|
27
|
+
- hosted vault contracts are opaque-record and plaintext-minimized contracts only;
|
|
28
|
+
- billing records remain contract records until an external billing provider invoice flow is wired.
|
|
29
|
+
|
|
30
|
+
Every builder emits `readiness.contract_ready: true` and `readiness.integration_kind: "contract_validator_only"`. It also emits `readiness.hosted_cloud_sellable: false` because contract readiness is not provider wiring, legal approval, security review, or operator go-live approval.
|
|
31
|
+
|
|
32
|
+
## Externally blocked before hosted cloud can be sold
|
|
33
|
+
|
|
34
|
+
Hosted cloud remains blocked until an operator wires and records evidence for all of the following:
|
|
35
|
+
|
|
36
|
+
| Blocker | Required before selling hosted cloud |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| Auth provider | A real auth provider, tenant/user lifecycle, access-control rules, session/token handling, rotation, revocation, and audit evidence. |
|
|
39
|
+
| Billing provider | A real billing provider, customer/subscription mapping, invoice lifecycle, tax/legal handling, dunning/refund policy, and reconciliation evidence. |
|
|
40
|
+
| Legal docs | Approved hosted terms, privacy notice, service descriptions, acceptable-use terms, retention/deletion language, and claim review. |
|
|
41
|
+
| Data processing terms | Approved DPA or equivalent data-processing terms, subprocessors, data residency, retention, deletion, legal hold, and customer notice process. |
|
|
42
|
+
| Support ownership | Named support owner, escalation policy, incident owner, response process, status communication process, and support tooling. |
|
|
43
|
+
| External security review | External security review or audit scope, remediation tracking, approval record, and release sign-off. |
|
|
44
|
+
|
|
45
|
+
A `provided` operator evidence ref means the contract can point to external evidence. It still does not by itself make hosted cloud sellable; an operator must complete the release checklist and issue go-live approval. A `blocked_external_dependency` ref is an explicit blocker, not fake evidence.
|
|
46
|
+
|
|
47
|
+
## Non-claims
|
|
48
|
+
|
|
49
|
+
Hosted cloud collateral must not say or imply:
|
|
50
|
+
|
|
51
|
+
- Enigma has live hosted cloud tenants before provider wiring and operator acceptance exist;
|
|
52
|
+
- Enigma has made any model or provider forget data;
|
|
53
|
+
- Enigma has provider-side deletion proof;
|
|
54
|
+
- Enigma guarantees ROI, profit, investment return, token price movement, or invoice savings;
|
|
55
|
+
- Enigma has SOC 2, HIPAA, GDPR, or other compliance certification unless separately audited and approved;
|
|
56
|
+
- local/package evidence, contract validation, static docs, or dashboard summaries are live service evidence.
|
|
57
|
+
|
|
58
|
+
Safe wording:
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
Enigma has hosted-cloud contract builders and validators for account, tenant, vault, API key, billing, dashboard, backup drill, and incident/SLA records. Hosted cloud remains blocked until auth, billing, legal/data-processing terms, support ownership, external security review, and operator go-live evidence are complete.
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Avoid wording:
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
Enigma hosted cloud is ready to sell because the contracts exist.
|
|
68
|
+
```
|