memorix 1.9.4 → 1.9.5
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/CHANGELOG.md +33 -1
- package/README.md +6 -5
- package/README.zh-CN.md +6 -5
- package/dist/cli/index.js +890 -325
- package/dist/index.d.ts +3 -1
- package/dist/index.js +251 -104
- package/dist/maintenance-runner.js +144 -113
- package/dist/media-audio-runner.js +57 -26
- package/dist/media-video-runner.js +57 -26
- package/dist/memcode-runtime/CHANGELOG.md +33 -1
- package/dist/sdk.d.ts +1 -0
- package/dist/sdk.js +1012 -842
- package/dist/types.d.ts +1 -1
- package/dist/vector-backfill-runner.js +57 -26
- package/docs/AGENT_OPERATOR_PLAYBOOK.md +47 -3
- package/docs/API_REFERENCE.md +3 -1
- package/docs/CONFIGURATION.md +15 -1
- package/docs/DOCKER.md +23 -3
- package/docs/INTEGRATIONS.md +1 -1
- package/docs/KNOWN_ISSUES_AND_ROADMAP.md +26 -1
- package/docs/MULTI-DEVICE-SYNC-RESEARCH.md +4 -0
- package/docs/SETUP.md +55 -0
- package/package.json +2 -2
- package/plugins/antigravity/memorix/plugin.json +1 -1
- package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
- package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/copilot/memorix/plugin.json +1 -1
- package/plugins/gemini/memorix/gemini-extension.json +1 -1
- package/plugins/hermes/memorix/plugin.yaml +1 -1
- package/plugins/omp/memorix/package.json +1 -1
- package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/pi/memorix/package.json +1 -1
- package/server.json +2 -2
- package/src/cli/command-guide.ts +2 -2
- package/src/cli/commands/agent-integrations.ts +57 -0
- package/src/cli/commands/background.ts +11 -2
- package/src/cli/commands/serve-http.ts +193 -42
- package/src/cli/commands/setup.ts +77 -10
- package/src/cli/commands/sync-store.ts +47 -12
- package/src/cli/commands/sync.ts +26 -0
- package/src/dashboard/server.ts +10 -12
- package/src/integrations/registry.ts +1 -1
- package/src/memory/graph.ts +10 -8
- package/src/memory/session.ts +1 -1
- package/src/sdk.ts +24 -0
- package/src/server/mcp-binding-store.ts +14 -3
- package/src/server.ts +2 -2
- package/src/store/file-lock.ts +28 -3
- package/src/store/graph-store.ts +178 -46
- package/src/store/persistence.ts +14 -9
- package/src/store/sqlite-db.ts +6 -3
- package/src/store/sqlite-store.ts +32 -27
- package/src/sync/engine.ts +9 -7
- package/src/sync/namespace.ts +23 -0
- package/src/sync/policy.ts +19 -4
- package/src/sync/store-port.ts +43 -13
- package/src/sync/types.ts +2 -0
- package/src/types.ts +1 -1
- package/src/workspace/mcp-adapters/grok.ts +32 -0
package/dist/types.d.ts
CHANGED
|
@@ -608,7 +608,7 @@ interface MemoryRef {
|
|
|
608
608
|
/** MCP config format adapter interface */
|
|
609
609
|
interface MCPConfigAdapter {
|
|
610
610
|
/** Setup-only adapters may support a host that does not participate in workspace sync. */
|
|
611
|
-
readonly source: AgentTarget | 'codebuddy' | 'dsh' | 'workbuddy';
|
|
611
|
+
readonly source: AgentTarget | 'codebuddy' | 'dsh' | 'workbuddy' | 'grok';
|
|
612
612
|
/** Parse MCP server entries from a config file */
|
|
613
613
|
parse(content: string): MCPServerEntry[];
|
|
614
614
|
/** Generate config file content from MCP server entries */
|
|
@@ -835,18 +835,21 @@ CREATE TABLE IF NOT EXISTS chat_transcript (
|
|
|
835
835
|
`;
|
|
836
836
|
CREATE_GRAPH_ENTITIES_TABLE = `
|
|
837
837
|
CREATE TABLE IF NOT EXISTS graph_entities (
|
|
838
|
-
|
|
838
|
+
projectId TEXT NOT NULL,
|
|
839
|
+
name TEXT NOT NULL,
|
|
839
840
|
entityType TEXT NOT NULL DEFAULT '',
|
|
840
|
-
observations TEXT NOT NULL DEFAULT '[]'
|
|
841
|
+
observations TEXT NOT NULL DEFAULT '[]',
|
|
842
|
+
PRIMARY KEY (projectId, name)
|
|
841
843
|
);
|
|
842
844
|
`;
|
|
843
845
|
CREATE_GRAPH_RELATIONS_TABLE = `
|
|
844
846
|
CREATE TABLE IF NOT EXISTS graph_relations (
|
|
845
847
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
848
|
+
projectId TEXT NOT NULL,
|
|
846
849
|
from_entity TEXT NOT NULL,
|
|
847
850
|
to_entity TEXT NOT NULL,
|
|
848
851
|
relationType TEXT NOT NULL DEFAULT '',
|
|
849
|
-
UNIQUE(from_entity, to_entity, relationType)
|
|
852
|
+
UNIQUE(projectId, from_entity, to_entity, relationType)
|
|
850
853
|
);
|
|
851
854
|
`;
|
|
852
855
|
CREATE_CODE_FILES_TABLE = `
|
|
@@ -1714,6 +1717,21 @@ var init_sqlite_reliability = __esm({
|
|
|
1714
1717
|
import { promises as fs2 } from "fs";
|
|
1715
1718
|
import { randomUUID } from "crypto";
|
|
1716
1719
|
import path4 from "path";
|
|
1720
|
+
function canReclaimStaleLock(raw) {
|
|
1721
|
+
try {
|
|
1722
|
+
const parsed = JSON.parse(raw);
|
|
1723
|
+
const pid = Number(parsed.pid);
|
|
1724
|
+
if (!Number.isSafeInteger(pid) || pid < 1) return true;
|
|
1725
|
+
try {
|
|
1726
|
+
process.kill(pid, 0);
|
|
1727
|
+
return false;
|
|
1728
|
+
} catch (error) {
|
|
1729
|
+
return error.code !== "EPERM";
|
|
1730
|
+
}
|
|
1731
|
+
} catch {
|
|
1732
|
+
return true;
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1717
1735
|
async function acquireLock(lockPath) {
|
|
1718
1736
|
for (let i2 = 0; i2 < MAX_RETRIES; i2++) {
|
|
1719
1737
|
try {
|
|
@@ -1727,9 +1745,12 @@ async function acquireLock(lockPath) {
|
|
|
1727
1745
|
try {
|
|
1728
1746
|
const stat5 = await fs2.stat(lockPath);
|
|
1729
1747
|
if (Date.now() - stat5.mtimeMs > LOCK_STALE_MS) {
|
|
1730
|
-
await fs2.
|
|
1731
|
-
|
|
1732
|
-
|
|
1748
|
+
const raw2 = await fs2.readFile(lockPath, "utf8").catch(() => "");
|
|
1749
|
+
if (canReclaimStaleLock(raw2)) {
|
|
1750
|
+
await fs2.unlink(lockPath).catch(() => {
|
|
1751
|
+
});
|
|
1752
|
+
continue;
|
|
1753
|
+
}
|
|
1733
1754
|
}
|
|
1734
1755
|
} catch {
|
|
1735
1756
|
continue;
|
|
@@ -1740,6 +1761,10 @@ async function acquireLock(lockPath) {
|
|
|
1740
1761
|
}
|
|
1741
1762
|
}
|
|
1742
1763
|
}
|
|
1764
|
+
const raw = await fs2.readFile(lockPath, "utf8").catch(() => "");
|
|
1765
|
+
if (!canReclaimStaleLock(raw)) {
|
|
1766
|
+
throw new Error(`Failed to acquire lock: ${lockPath} (owner is still running)`);
|
|
1767
|
+
}
|
|
1743
1768
|
await fs2.unlink(lockPath).catch(() => {
|
|
1744
1769
|
});
|
|
1745
1770
|
try {
|
|
@@ -5670,6 +5695,7 @@ var init_sqlite_store = __esm({
|
|
|
5670
5695
|
init_sqlite_db();
|
|
5671
5696
|
init_sqlite_reliability();
|
|
5672
5697
|
init_sqlite_fts();
|
|
5698
|
+
init_file_lock();
|
|
5673
5699
|
SqliteBackend = class {
|
|
5674
5700
|
db = null;
|
|
5675
5701
|
dataDir = "";
|
|
@@ -5833,38 +5859,43 @@ var init_sqlite_store = __esm({
|
|
|
5833
5859
|
}
|
|
5834
5860
|
// ── Migration ────────────────────────────────────────────────────
|
|
5835
5861
|
async migrateFromJsonIfNeeded() {
|
|
5836
|
-
const count2 = this.db.prepare(`SELECT COUNT(*) AS cnt FROM observations`).get();
|
|
5837
|
-
if (count2.cnt > 0) return;
|
|
5838
5862
|
const jsonPath = path7.join(this.dataDir, "observations.json");
|
|
5839
5863
|
if (!fs4.existsSync(jsonPath)) return;
|
|
5840
|
-
|
|
5864
|
+
await withFileLock(this.dataDir, async () => {
|
|
5865
|
+
const count2 = this.db.prepare(`SELECT COUNT(*) AS cnt FROM observations`).get();
|
|
5866
|
+
if (count2.cnt > 0) return;
|
|
5841
5867
|
const raw = fs4.readFileSync(jsonPath, "utf-8");
|
|
5842
|
-
const
|
|
5868
|
+
const parsed = JSON.parse(raw);
|
|
5869
|
+
if (!Array.isArray(parsed)) {
|
|
5870
|
+
throw new Error("[memorix] observations.json migration refused: expected a JSON array");
|
|
5871
|
+
}
|
|
5872
|
+
const observations2 = parsed;
|
|
5843
5873
|
if (observations2.length === 0) return;
|
|
5874
|
+
if (observations2.some((obs) => !obs || !Number.isSafeInteger(obs.id) || obs.id < 1 || typeof obs.projectId !== "string")) {
|
|
5875
|
+
throw new Error("[memorix] observations.json migration refused: invalid observation record");
|
|
5876
|
+
}
|
|
5844
5877
|
console.error(`[memorix] Migrating ${observations2.length} observations from JSON to SQLite...`);
|
|
5845
5878
|
const insertMany = this.db.transaction((obsList) => {
|
|
5846
5879
|
for (const obs of obsList) {
|
|
5847
5880
|
this.stmtInsert.run(obsToRow(obs));
|
|
5848
5881
|
}
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
if (fs4.existsSync(counterPath)) {
|
|
5853
|
-
try {
|
|
5882
|
+
const counterPath = path7.join(this.dataDir, "counter.json");
|
|
5883
|
+
let counterNextId;
|
|
5884
|
+
if (fs4.existsSync(counterPath)) {
|
|
5854
5885
|
const counterData = JSON.parse(fs4.readFileSync(counterPath, "utf-8"));
|
|
5855
|
-
const
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5886
|
+
const candidate = counterData.nextId ?? counterData.next_id;
|
|
5887
|
+
if (candidate !== void 0 && (!Number.isSafeInteger(candidate) || Number(candidate) < 1)) {
|
|
5888
|
+
throw new Error("[memorix] counter.json migration refused: nextId must be a positive integer");
|
|
5889
|
+
}
|
|
5890
|
+
counterNextId = candidate === void 0 ? void 0 : Number(candidate);
|
|
5859
5891
|
}
|
|
5860
|
-
|
|
5861
|
-
this.rawSaveIdCounter(Math.max(
|
|
5862
|
-
|
|
5863
|
-
|
|
5892
|
+
const maxId = Math.max(...obsList.map((obs) => obs.id));
|
|
5893
|
+
this.rawSaveIdCounter(Math.max(counterNextId ?? 1, maxId + 1));
|
|
5894
|
+
this.bumpGeneration();
|
|
5895
|
+
});
|
|
5896
|
+
insertMany(observations2);
|
|
5864
5897
|
console.error(`[memorix] Migration complete. ${observations2.length} observations now in SQLite.`);
|
|
5865
|
-
}
|
|
5866
|
-
console.error(`[memorix] JSON\u2192SQLite migration failed (non-fatal, data preserved in JSON): ${err}`);
|
|
5867
|
-
}
|
|
5898
|
+
});
|
|
5868
5899
|
}
|
|
5869
5900
|
// ── Public read ──────────────────────────────────────────────────
|
|
5870
5901
|
async loadAll() {
|
|
@@ -41,7 +41,7 @@ For the 1.4 release line, the visible product shape is:
|
|
|
41
41
|
- `memorix_project_context` / `memorix context "..."` is the normal black-box entry for non-trivial coding work: it assembles a bounded task Workset instead of injecting a generic memory dump; `memorix resume "..."` is the explicit CLI continuation projection
|
|
42
42
|
- Code State keeps local snapshots and freshness links; a healthy pre-existing local CodeGraph index can add a bounded semantic outline, but Memorix never initializes or synchronizes that external index itself
|
|
43
43
|
- `memorix knowledge` is an explicit review path for source-backed Markdown knowledge and canonical workflows. Do not initialize a versioned workspace or apply a proposal unless the user asks for that managed artifact
|
|
44
|
-
- integration surfaces are agent-specific: Claude Code, Codex, GitHub Copilot CLI, Antigravity, and Hermes receive plugin packages; OpenClaw receives a compatible bundle; Pi and Oh-my-Pi receive package entries; Gemini CLI receives an extension package; OpenCode receives a plugin file and skill; Grok Build receives native hooks and `AGENTS.md` guidance while keeping MCP host-owned; DeepSeek Harness receives an MCP patch row, AGENTS.md guidance, and skills; Cursor and other agents receive MCP/rules/hooks where supported
|
|
44
|
+
- integration surfaces are agent-specific: Claude Code, Codex, GitHub Copilot CLI, Antigravity, and Hermes receive plugin packages; OpenClaw receives a compatible bundle; Pi and Oh-my-Pi receive package entries; Gemini CLI receives an extension package; OpenCode receives a plugin file and skill; Grok Build receives native hooks and `AGENTS.md` guidance while keeping MCP host-owned by default (`--mcp http` writes Grok `config.toml`); DeepSeek Harness receives an MCP patch row, AGENTS.md guidance, and skills; Cursor and other agents receive MCP/rules/hooks where supported
|
|
45
45
|
- privacy-safe diagnostics and receipts avoid raw chat, memory text, query text, tool payloads, and local file paths
|
|
46
46
|
|
|
47
47
|
---
|
|
@@ -257,7 +257,7 @@ What this installs depends on the target agent:
|
|
|
257
257
|
- Pi: user Pi package with extension-based hook capture and a Memorix skill, registered through `pi install <path> --approve`; project-local setup uses `-l`.
|
|
258
258
|
- Gemini CLI: local extension package under `~/.gemini/extensions/memorix`, extension-bundled stdio MCP, `GEMINI.md` context, hooks, commands, and skills. Antigravity CLI has an official Gemini CLI migration path, but Gemini CLI remains a separate target.
|
|
259
259
|
- OpenCode: local plugin file, `opencode.json` MCP config, OpenCode skill, plus `AGENTS.md` guidance.
|
|
260
|
-
- Grok Build: native hooks in `~/.grok/hooks/memorix.json` and guidance in `~/.grok/AGENTS.md`. Global hooks are trusted; project hooks require Grok `/hooks-trust` or `--trust`.
|
|
260
|
+
- Grok Build: native hooks in `~/.grok/hooks/memorix.json` and guidance in `~/.grok/AGENTS.md`. Global hooks are trusted; project hooks require Grok `/hooks-trust` or `--trust`. MCP stays host-owned unless you pass `--mcp http`, which writes `[mcp_servers.memorix]` in Grok `config.toml`.
|
|
261
261
|
- Antigravity: native plugin under `~/.gemini/config/plugins/memorix` or `.agents/plugins/memorix`, with `plugin.json`, `mcp_config.json`, `hooks.json`, rules, and skills.
|
|
262
262
|
- OpenClaw: OpenClaw-compatible bundle under `~/.openclaw/extensions/memorix`, bundled `.mcp.json`, skills, and OpenClaw `HOOK.md`/`handler.ts` hook pack.
|
|
263
263
|
- Hermes Agent: Hermes plugin under Hermes home (`%LOCALAPPDATA%\hermes` on native Windows, `~/.hermes` elsewhere, or `HERMES_HOME`), enabled in `config.yaml`, with plugin hooks, slash command, CLI command, skills, and MCP config.
|
|
@@ -404,7 +404,51 @@ memorix background ensure
|
|
|
404
404
|
memorix background ensure 2>/dev/null
|
|
405
405
|
```
|
|
406
406
|
|
|
407
|
-
Or
|
|
407
|
+
Or supervise `memorix serve-http` directly so a crash or reboot restarts the control plane.
|
|
408
|
+
|
|
409
|
+
Linux systemd user unit (`~/.config/systemd/user/memorix-http.service`):
|
|
410
|
+
|
|
411
|
+
```ini
|
|
412
|
+
[Unit]
|
|
413
|
+
Description=Memorix HTTP MCP control plane
|
|
414
|
+
After=default.target
|
|
415
|
+
|
|
416
|
+
[Service]
|
|
417
|
+
Type=simple
|
|
418
|
+
ExecStart=/usr/bin/env memorix serve-http --host 127.0.0.1 --port 3211
|
|
419
|
+
Environment=PATH=%h/.local/bin:/usr/local/bin:/usr/bin
|
|
420
|
+
Restart=on-failure
|
|
421
|
+
RestartSec=3
|
|
422
|
+
|
|
423
|
+
[Install]
|
|
424
|
+
WantedBy=default.target
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
macOS LaunchAgent (`~/Library/LaunchAgents/com.memorix.http.plist`). Point `ProgramArguments` at `which memorix`:
|
|
428
|
+
|
|
429
|
+
```xml
|
|
430
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
431
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
432
|
+
<plist version="1.0">
|
|
433
|
+
<dict>
|
|
434
|
+
<key>Label</key>
|
|
435
|
+
<string>com.memorix.http</string>
|
|
436
|
+
<key>ProgramArguments</key>
|
|
437
|
+
<array>
|
|
438
|
+
<string>/usr/local/bin/memorix</string>
|
|
439
|
+
<string>serve-http</string>
|
|
440
|
+
<string>--host</string>
|
|
441
|
+
<string>127.0.0.1</string>
|
|
442
|
+
<string>--port</string>
|
|
443
|
+
<string>3211</string>
|
|
444
|
+
</array>
|
|
445
|
+
<key>KeepAlive</key>
|
|
446
|
+
<true/>
|
|
447
|
+
<key>RunAtLoad</key>
|
|
448
|
+
<true/>
|
|
449
|
+
</dict>
|
|
450
|
+
</plist>
|
|
451
|
+
```
|
|
408
452
|
|
|
409
453
|
**Why this matters:** IDEs that use `serverUrl` (Windsurf, Cursor HTTP mode) connect to `http://localhost:3211/mcp` but cannot start the server. If the service is down, the IDE shows an MCP error with no recovery path. The user must run `memorix background start` or `ensure` manually.
|
|
410
454
|
|
package/docs/API_REFERENCE.md
CHANGED
|
@@ -81,6 +81,7 @@ memorix sync workspace --action scan
|
|
|
81
81
|
memorix sync store status --json
|
|
82
82
|
memorix sync store push
|
|
83
83
|
memorix sync store pull
|
|
84
|
+
memorix sync store push --scope user
|
|
84
85
|
memorix sync store device rotate
|
|
85
86
|
memorix ingest image --path ./diagram.png
|
|
86
87
|
memorix media import --path ./architecture.png
|
|
@@ -92,7 +93,8 @@ memorix receipt --json --probe "release blocker"
|
|
|
92
93
|
The CLI is for direct terminal use, not a 1:1 mirror of MCP tool names. It does not require an MCP connection. `--cwd` selects a Git project from any shell; an unbound terminal has project-visible access only, including transfer exports. `memorix identity join|use|clear` makes personal/team access and coordination explicit, while `--as <agent-id>` is the one-command equivalent for scripts. The only MCP-only area is the optional graph-compatibility tools (`create_entities`, `read_graph`, and related tools) for workflows that expect the official memory-server style graph API.
|
|
93
94
|
|
|
94
95
|
`memorix sync store` is an explicit, opt-in multi-device observation relay. It
|
|
95
|
-
uses the current Git project as its namespace
|
|
96
|
+
uses the current Git project as its namespace by default (`--scope project`),
|
|
97
|
+
or every local project with `--scope user`. It excludes personal/agent-targeted
|
|
96
98
|
and unqualified records, keeps a local retry outbox, and stores cursors locally.
|
|
97
99
|
The default `status` action is preview-only. GitHub stores immutable JSONL event
|
|
98
100
|
blobs; it does not receive `memorix.db`, `memorix.db-wal`, or `memorix.db-shm`.
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -102,6 +102,15 @@ Memorix resolves configuration in this order:
|
|
|
102
102
|
Environment variables stay available for CI, MCP launchers, and temporary shell
|
|
103
103
|
overrides. They are not the default user-facing setup path.
|
|
104
104
|
|
|
105
|
+
For the HTTP control plane, `MEMORIX_HTTP_MAX_BODY_BYTES` bounds JSON request
|
|
106
|
+
bodies at 10 MiB by default and accepts values up to 64 MiB. Keep the default
|
|
107
|
+
unless a trusted local client needs larger payloads; this limit is not an
|
|
108
|
+
authentication boundary. `MEMORIX_HTTP_AUTH_TOKEN` enables Bearer-token
|
|
109
|
+
authentication for every endpoint except `/health`. Non-loopback binds are
|
|
110
|
+
refused unless this token is set or the operator explicitly sets
|
|
111
|
+
`MEMORIX_HTTP_ALLOW_UNAUTHENTICATED_BIND=1` behind a private network or
|
|
112
|
+
authenticated reverse proxy.
|
|
113
|
+
|
|
105
114
|
If you want the simplest setup, configure `~/.memorix/config.toml` once and stop
|
|
106
115
|
there. Add `<git-root>/memorix.toml` only when a repository needs different
|
|
107
116
|
models, memory behavior, or server defaults.
|
|
@@ -397,10 +406,15 @@ Common keys:
|
|
|
397
406
|
Store sync is disabled unless `MEMORIX_SYNC_PROVIDER` is explicitly set. It
|
|
398
407
|
replicates approved project-visible observation events, never the live SQLite
|
|
399
408
|
file or its `-wal` / `-shm` companions. The local SQLite store remains the
|
|
400
|
-
canonical read/write store.
|
|
409
|
+
canonical read/write store. Default scope is the current Git project. Pass
|
|
410
|
+
`--scope user` to relay every local project through a separate `user-global`
|
|
411
|
+
named per-user namespace. Set the same stable value on that user's devices;
|
|
412
|
+
the value is required so operators sharing one remote cannot silently share a
|
|
413
|
+
default namespace.
|
|
401
414
|
|
|
402
415
|
```text
|
|
403
416
|
MEMORIX_SYNC_PROVIDER=fs|github|s3|postgres
|
|
417
|
+
MEMORIX_SYNC_USER_NAMESPACE=your-stable-user-id # required with --scope user
|
|
404
418
|
```
|
|
405
419
|
|
|
406
420
|
The filesystem relay needs `MEMORIX_SYNC_FS_ROOT`. The GitHub relay needs a
|
package/docs/DOCKER.md
CHANGED
|
@@ -29,6 +29,22 @@ Then open:
|
|
|
29
29
|
- MCP endpoint: `http://localhost:3211/mcp`
|
|
30
30
|
- health: `http://localhost:3211/health`
|
|
31
31
|
|
|
32
|
+
The compose port is bound to `127.0.0.1` by default. Do not expose this
|
|
33
|
+
unauthenticated control plane directly to the public internet. For a hosted
|
|
34
|
+
deployment, put it behind an authenticated reverse proxy or a private network
|
|
35
|
+
boundary before allowing remote clients to connect.
|
|
36
|
+
|
|
37
|
+
Set `MEMORIX_HTTP_AUTH_TOKEN` in the service environment when the control plane
|
|
38
|
+
must accept remote clients. Send it as `Authorization: Bearer <token>`; the
|
|
39
|
+
`/health` endpoint remains unauthenticated for readiness checks. The supplied
|
|
40
|
+
compose file uses an explicit unauthenticated-bind opt-in because its published
|
|
41
|
+
host port is loopback-only.
|
|
42
|
+
|
|
43
|
+
HTTP JSON bodies are limited to 10 MiB by default (dashboard maintenance
|
|
44
|
+
requests use a 1 MiB sub-limit). Operators can set
|
|
45
|
+
`MEMORIX_HTTP_MAX_BODY_BYTES`, up to 64 MiB, when a trusted local client needs
|
|
46
|
+
larger media or tool payloads.
|
|
47
|
+
|
|
32
48
|
Stop it with:
|
|
33
49
|
|
|
34
50
|
```bash
|
|
@@ -50,7 +66,9 @@ If you prefer `docker run`:
|
|
|
50
66
|
|
|
51
67
|
```bash
|
|
52
68
|
docker build -t memorix:local .
|
|
53
|
-
docker run --rm -p 3211:3211
|
|
69
|
+
docker run --rm -p 127.0.0.1:3211:3211 \
|
|
70
|
+
-e MEMORIX_HTTP_ALLOW_UNAUTHENTICATED_BIND=1 \
|
|
71
|
+
-v memorix-data:/data memorix:local
|
|
54
72
|
```
|
|
55
73
|
|
|
56
74
|
---
|
|
@@ -60,9 +78,11 @@ docker run --rm -p 3211:3211 -v memorix-data:/data memorix:local
|
|
|
60
78
|
`memorix serve-http` accepts a `--host` flag:
|
|
61
79
|
|
|
62
80
|
- **Local** (default): binds to `127.0.0.1` — only accessible from the host machine
|
|
63
|
-
- **Docker**: the Dockerfile sets `--host 0.0.0.0` — accessible from outside the container, which is required for port mapping (`-p 3211:3211`) to work
|
|
81
|
+
- **Docker**: the Dockerfile sets `--host 0.0.0.0` — accessible from outside the container, which is required for port mapping (`-p 3211:3211`) to work. Set `MEMORIX_HTTP_AUTH_TOKEN`, or explicitly opt into an unauthenticated private-network bind with `MEMORIX_HTTP_ALLOW_UNAUTHENTICATED_BIND=1`.
|
|
64
82
|
|
|
65
|
-
If you run `serve-http` manually inside a container, make sure to pass
|
|
83
|
+
If you run `serve-http` manually inside a container, make sure to pass
|
|
84
|
+
`--host 0.0.0.0` plus one of those explicit security settings, or the server
|
|
85
|
+
will refuse to start.
|
|
66
86
|
|
|
67
87
|
---
|
|
68
88
|
|
package/docs/INTEGRATIONS.md
CHANGED
|
@@ -53,7 +53,7 @@ Generated guidance also has scope:
|
|
|
53
53
|
| CodeBuddy Code | `memorix setup --agent codebuddy --global` | CodeBuddy local marketplace plugin | `~/.codebuddy/memorix-local` marketplace with `.codebuddy-plugin`, bundled stdio MCP, skills, and hooks | Setup attempts `codebuddy plugin marketplace add` then user-scope install. It does not alter existing CodeBuddy settings, permissions, or model configuration; review third-party hooks in CodeBuddy's `/hooks` flow before enabling them. |
|
|
54
54
|
| GitHub Copilot CLI | `memorix setup --agent copilot --global` | Copilot CLI plugin package | Local plugin under `~/.copilot/plugins/local/memorix` with MCP, skills, and hooks | Setup attempts `copilot plugin install <local-path>` when Copilot CLI is available. |
|
|
55
55
|
| Cursor | `memorix setup --agent cursor --global` | Cursor MCP and rules config | Cursor MCP config, `.cursor/rules/memorix.mdc`, skills, and hook guidance | Reload Cursor after setup so it can pick up project config changes. |
|
|
56
|
-
| Grok Build | `memorix setup --agent grok --global` | `~/.grok/hooks/memorix.json` + `~/.grok/AGENTS.md` | Lifecycle hooks on SessionStart, SessionEnd, UserPromptSubmit, PostToolUse, PostToolUseFailure, PreCompact, PostCompact, Stop, and StopFailure, plus Grok project/global guidance | Uses Grok's own JSON hook directory
|
|
56
|
+
| Grok Build | `memorix setup --agent grok --global` | `~/.grok/hooks/memorix.json` + `~/.grok/AGENTS.md` | Lifecycle hooks on SessionStart, SessionEnd, UserPromptSubmit, PostToolUse, PostToolUseFailure, PreCompact, PostCompact, Stop, and StopFailure, plus Grok project/global guidance | Uses Grok's own JSON hook directory. MCP stays host-owned unless you pass `--mcp http`, which writes `[mcp_servers.memorix]` with `url = "http://localhost:3211/mcp"` in Grok `config.toml`. Global hooks are trusted; project hooks require Grok `/hooks-trust`. Set `GROK_HOME` to use a custom Grok home. The command is `memorix hook --agent grok`. |
|
|
57
57
|
| Gemini CLI | `memorix setup --agent gemini-cli --global` | Gemini CLI extension | Extension under `~/.gemini/extensions/memorix` with MCP, `GEMINI.md` context, hooks, commands, and skills | Antigravity CLI has an official Gemini CLI migration path, but Gemini CLI remains an active standalone Google CLI target. |
|
|
58
58
|
| OpenCode | `memorix setup --agent opencode --global` | OpenCode local plugin file | Global setup writes `~/.config/opencode/plugins/memorix.js`, `~/.config/opencode/opencode.json`, skills, and `AGENTS.md` guidance; repo-local setup writes the `.opencode/` equivalents. | OpenCode loads local plugin and skill files from its config scope. |
|
|
59
59
|
| OpenClaw | `memorix setup --agent openclaw --global` | OpenClaw compatible bundle | `~/.openclaw/extensions/memorix` with `.mcp.json`, skills, and OpenClaw `HOOK.md`/`handler.ts` hook pack | Setup attempts `openclaw plugins install <path> --force` and `openclaw hooks enable memorix` when OpenClaw is available. |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Memorix 已知边界与路线图
|
|
2
2
|
|
|
3
|
-
> 最后审阅:2026-
|
|
3
|
+
> 最后审阅:2026-09-18(对照 v1.9.4,准备 1.9.5)
|
|
4
4
|
|
|
5
5
|
这份文档说明仍然成立的产品边界、风险和方向;它不是发布流水账。
|
|
6
6
|
|
|
@@ -10,6 +10,31 @@
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
+
## 1.9.5 剩余必须纳入项
|
|
14
|
+
|
|
15
|
+
> 基线是 `v1.9.4` / `main` `f7ed621`。本节是发布门槛与必须做出的
|
|
16
|
+
> 明确决策,不等同于“所有 open issue 都要合并”。
|
|
17
|
+
|
|
18
|
+
### 发布门槛
|
|
19
|
+
|
|
20
|
+
| 优先级 | 项目 | 当前结论 | 1.9.5 完成标准 |
|
|
21
|
+
|---|---|---|---|
|
|
22
|
+
| P1 | HTTP 控制面安全与生命周期 | 本地分支已加入请求体上限和 Compose 回环绑定;显式绑定非回环地址时仍没有认证。端口冲突、后台假存活、优雅关闭也需要补齐。 | 默认只监听回环;非回环暴露必须认证或被明确拒绝;监听失败可观测且启动失败不留假状态;后台重启/停止和 HTTP、SQLite 资源关闭有测试。 |
|
|
23
|
+
| P1 | 项目隔离 | 图谱表缺少项目归属,替换/删除可能影响其他项目。旧 JSON 迁移的去重条件也没有真正按项目隔离。 | 图谱实体、边和迁移路径都有项目边界;两个项目之间的读、写、替换、删除、迁移测试全部通过。 |
|
|
24
|
+
| P1 | 迁移失败语义 | legacy JSON 迁移没有跨进程锁和完整原子恢复;解析失败继续启动为空库,会把“数据损坏”伪装成“没有数据”。 | 迁移具备锁、原子提交、备份/恢复和可诊断失败;源数据不完整时 fail-closed,不覆盖或隐藏旧数据。 |
|
|
25
|
+
| P1 | Store / SQLite 生命周期 | SDK、HTTP 和 Orama 存在进程级共享状态;关闭一个实例可能影响另一个,缓存中的 SQLite handle 也没有始终释放。普通写入重试、事务内异步回调和 ID/代数更新仍需审计。 | 明确实例所有权或引用计数;关闭路径真正释放数据库和索引;并发写入有有界重试;写锁内不等待不受控异步工作;增加多实例和崩溃恢复测试。 |
|
|
26
|
+
| P2 | 内存与容量边界 | 请求体已在本地分支设上限;会话、stateless binding、Dashboard/团队查询、失败任务、embedding 缓存和项目目录缓存仍有无界路径。 | 每条路径有上限、TTL 或保留策略;大输入、长时间运行和重复初始化的内存/延迟回归测试通过。 |
|
|
27
|
+
| P1 | 发布契约 | 本地分支已加入 tag/version/commit 校验、npm 可见性等待和 check-only 发布前置检查,但尚未进入主线。 | 远程 workflow 使用这些保护;模拟“npm 已发布但 registry 尚未传播”和错误 tag 时会安全停止或可重试。 |
|
|
28
|
+
|
|
29
|
+
### 新 issue / PR 处置
|
|
30
|
+
|
|
31
|
+
- [#301](https://github.com/AVIDS2/memorix/issues/301) / [#303](https://github.com/AVIDS2/memorix/pull/303):纳入 1.9.5。它修复显式 `--mcp http` 被 Grok 忽略、插件仍各自启动 stdio MCP 的已发布行为,并补充系统服务示例。当前 CI 全绿但没有人工 review;合并前必须验证 Grok、Claude/Codex/Copilot/CodeBuddy/Gemini/OpenClaw/Antigravity 的真实安装结果,以及 systemd/LaunchAgent 重启和有效数据目录。系统服务示例保持未绑定项目,由客户端显式提供项目根目录。
|
|
32
|
+
- [#302](https://github.com/AVIDS2/memorix/issues/302) / [#304](https://github.com/AVIDS2/memorix/pull/304):列入 1.9.5 决策窗口,但不接受“CI 绿就直接合并”。当前实现已补用户范围 tombstone 的源项目校验、跨项目整数 observation ID remap 和显式 per-user namespace;还必须补混合项目 compaction、隐私过滤审计,以及无 Git checkout 的 CLI 测试后才能发布。
|
|
33
|
+
- [#300](https://github.com/AVIDS2/memorix/pull/300):暂缓。Atlas Cloud 是可选 provider,当前没有 checks 或人工 review,不应挤占 1.9.5 基础设施门槛。
|
|
34
|
+
- [#297](https://github.com/AVIDS2/memorix/issues/297) / [#283](https://github.com/AVIDS2/memorix/issues/283):保留为生态/文档跟进,不是 1.9.5 阻塞项;[#49](https://github.com/AVIDS2/memorix/issues/49) 与 [#3](https://github.com/AVIDS2/memorix/issues/3) 继续独立排期。
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
13
38
|
## 当前产品边界
|
|
14
39
|
|
|
15
40
|
Memorix 是本地优先、可插拔的 Agent Memory 系统。它给不同 Agent 或同一 Agent 的新会话提供同一个项目记忆层,并把 CLI 作为最完整、最稳定的控制面;MCP 是面向 Agent 的受控入口,而不是唯一入口。
|
|
@@ -89,6 +89,10 @@ backup is not a merge input.
|
|
|
89
89
|
version/audit record.
|
|
90
90
|
- [x] Personal, agent-targeted, candidate, ephemeral, and other-project rows
|
|
91
91
|
are excluded by default.
|
|
92
|
+
- [x] `--scope user` is an explicit opt-in that relays every local project's
|
|
93
|
+
eligible rows through a separate `user-global` namespace. Privacy
|
|
94
|
+
filters still drop personal, agent-targeted, candidate, and ephemeral
|
|
95
|
+
rows. The live SQLite file is still never copied.
|
|
92
96
|
- [x] Copying a data directory produces a clear device-clone error and a
|
|
93
97
|
documented `device rotate` recovery path.
|
|
94
98
|
- [x] GitHub relay protocol smoke proves only JSONL/snapshot artifacts are uploaded;
|
package/docs/SETUP.md
CHANGED
|
@@ -237,6 +237,61 @@ Use foreground HTTP mode for debugging or custom launch supervision:
|
|
|
237
237
|
memorix serve-http --port 3211
|
|
238
238
|
```
|
|
239
239
|
|
|
240
|
+
`memorix background start` survives the terminal but not logout or reboot. For a supervised control plane that only execs `memorix serve-http`, use an OS unit. Keep the bind address loopback-only.
|
|
241
|
+
|
|
242
|
+
Linux systemd user unit (`~/.config/systemd/user/memorix-http.service`):
|
|
243
|
+
|
|
244
|
+
```ini
|
|
245
|
+
[Unit]
|
|
246
|
+
Description=Memorix HTTP MCP control plane
|
|
247
|
+
After=default.target
|
|
248
|
+
|
|
249
|
+
[Service]
|
|
250
|
+
Type=simple
|
|
251
|
+
ExecStart=/usr/bin/env memorix serve-http --host 127.0.0.1 --port 3211
|
|
252
|
+
Environment=PATH=%h/.local/bin:/usr/local/bin:/usr/bin
|
|
253
|
+
Restart=on-failure
|
|
254
|
+
RestartSec=3
|
|
255
|
+
|
|
256
|
+
[Install]
|
|
257
|
+
WantedBy=default.target
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
systemctl --user daemon-reload
|
|
262
|
+
systemctl --user enable --now memorix-http.service
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
macOS LaunchAgent (`~/Library/LaunchAgents/com.memorix.http.plist`). Replace the `memorix` path with the output of `which memorix`:
|
|
266
|
+
|
|
267
|
+
```xml
|
|
268
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
269
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
270
|
+
<plist version="1.0">
|
|
271
|
+
<dict>
|
|
272
|
+
<key>Label</key>
|
|
273
|
+
<string>com.memorix.http</string>
|
|
274
|
+
<key>ProgramArguments</key>
|
|
275
|
+
<array>
|
|
276
|
+
<string>/usr/local/bin/memorix</string>
|
|
277
|
+
<string>serve-http</string>
|
|
278
|
+
<string>--host</string>
|
|
279
|
+
<string>127.0.0.1</string>
|
|
280
|
+
<string>--port</string>
|
|
281
|
+
<string>3211</string>
|
|
282
|
+
</array>
|
|
283
|
+
<key>KeepAlive</key>
|
|
284
|
+
<true/>
|
|
285
|
+
<key>RunAtLoad</key>
|
|
286
|
+
<true/>
|
|
287
|
+
</dict>
|
|
288
|
+
</plist>
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.memorix.http.plist
|
|
293
|
+
```
|
|
294
|
+
|
|
240
295
|
Generic HTTP MCP config:
|
|
241
296
|
|
|
242
297
|
```json
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memorix",
|
|
3
3
|
"mcpName": "io.github.AVIDS2/memorix",
|
|
4
|
-
"version": "1.9.
|
|
4
|
+
"version": "1.9.5",
|
|
5
5
|
"description": "Local-first shared memory layer for AI coding agents across MCP clients, Git history, reasoning context, and project sessions.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"sideEffects": false,
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"check:plugin-release": "node scripts/sync-plugin-release-manifests.mjs --check",
|
|
84
84
|
"audit:pi-upstream": "node scripts/pi-upstream-audit.mjs",
|
|
85
85
|
"lint": "tsc --noEmit",
|
|
86
|
-
"prepublishOnly": "npm run
|
|
86
|
+
"prepublishOnly": "npm run check:mcp-registry && npm run check:plugin-release && npm run build && npm test"
|
|
87
87
|
},
|
|
88
88
|
"keywords": [
|
|
89
89
|
"mcp",
|
package/server.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"url": "https://github.com/AVIDS2/memorix",
|
|
8
8
|
"source": "github"
|
|
9
9
|
},
|
|
10
|
-
"version": "1.9.
|
|
10
|
+
"version": "1.9.5",
|
|
11
11
|
"websiteUrl": "https://mem.rglens.com",
|
|
12
12
|
"icons": [
|
|
13
13
|
{
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
{
|
|
23
23
|
"registryType": "npm",
|
|
24
24
|
"identifier": "memorix",
|
|
25
|
-
"version": "1.9.
|
|
25
|
+
"version": "1.9.5",
|
|
26
26
|
"runtimeHint": "npx",
|
|
27
27
|
"packageArguments": [
|
|
28
28
|
{
|
package/src/cli/command-guide.ts
CHANGED
|
@@ -213,11 +213,11 @@ const GUIDES: Record<string, CliCommandGuide> = {
|
|
|
213
213
|
'memorix sync rules --action status',
|
|
214
214
|
'memorix sync workspace --action scan',
|
|
215
215
|
'memorix sync store status --json',
|
|
216
|
-
'memorix sync store push|pull [--dry] [--json]',
|
|
216
|
+
'memorix sync store push|pull [--dry] [--json] [--scope project|user]',
|
|
217
217
|
'memorix sync store compact --dry --through device=sequence',
|
|
218
218
|
'memorix sync store device rotate',
|
|
219
219
|
],
|
|
220
|
-
notes: ['Store sync is opt-in
|
|
220
|
+
notes: ['Store sync is opt-in and never copies the live SQLite database. Default scope is the current Git project; `--scope user` relays every local project.'],
|
|
221
221
|
},
|
|
222
222
|
ingest: {
|
|
223
223
|
summary: 'Ingest Git and image evidence into project memory.',
|