agmem 0.1.2__py3-none-any.whl → 0.1.3__py3-none-any.whl
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.
- {agmem-0.1.2.dist-info → agmem-0.1.3.dist-info}/METADATA +138 -14
- {agmem-0.1.2.dist-info → agmem-0.1.3.dist-info}/RECORD +45 -26
- memvcs/cli.py +10 -0
- memvcs/commands/add.py +6 -0
- memvcs/commands/audit.py +59 -0
- memvcs/commands/clone.py +7 -0
- memvcs/commands/daemon.py +28 -0
- memvcs/commands/distill.py +16 -0
- memvcs/commands/federated.py +53 -0
- memvcs/commands/fsck.py +31 -0
- memvcs/commands/garden.py +14 -0
- memvcs/commands/gc.py +51 -0
- memvcs/commands/merge.py +55 -1
- memvcs/commands/prove.py +66 -0
- memvcs/commands/pull.py +27 -0
- memvcs/commands/resolve.py +130 -0
- memvcs/commands/verify.py +74 -23
- memvcs/core/audit.py +124 -0
- memvcs/core/consistency.py +9 -9
- memvcs/core/crypto_verify.py +280 -0
- memvcs/core/distiller.py +25 -25
- memvcs/core/encryption.py +169 -0
- memvcs/core/federated.py +86 -0
- memvcs/core/gardener.py +23 -24
- memvcs/core/ipfs_remote.py +39 -0
- memvcs/core/knowledge_graph.py +1 -0
- memvcs/core/llm/__init__.py +10 -0
- memvcs/core/llm/anthropic_provider.py +50 -0
- memvcs/core/llm/base.py +27 -0
- memvcs/core/llm/factory.py +30 -0
- memvcs/core/llm/openai_provider.py +36 -0
- memvcs/core/merge.py +36 -23
- memvcs/core/objects.py +16 -6
- memvcs/core/pack.py +92 -0
- memvcs/core/privacy_budget.py +63 -0
- memvcs/core/remote.py +38 -0
- memvcs/core/repository.py +82 -2
- memvcs/core/temporal_index.py +9 -0
- memvcs/core/trust.py +103 -0
- memvcs/core/vector_store.py +15 -1
- memvcs/core/zk_proofs.py +26 -0
- {agmem-0.1.2.dist-info → agmem-0.1.3.dist-info}/WHEEL +0 -0
- {agmem-0.1.2.dist-info → agmem-0.1.3.dist-info}/entry_points.txt +0 -0
- {agmem-0.1.2.dist-info → agmem-0.1.3.dist-info}/licenses/LICENSE +0 -0
- {agmem-0.1.2.dist-info → agmem-0.1.3.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agmem
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Agentic Memory Version Control System - Git for AI agent memories
|
|
5
5
|
Home-page: https://github.com/vivek-tiwari-vt/agmem
|
|
6
6
|
Author: agmem Team
|
|
@@ -10,7 +10,7 @@ Project-URL: Homepage, https://github.com/vivek-tiwari-vt/agmem
|
|
|
10
10
|
Project-URL: Documentation, https://github.com/vivek-tiwari-vt/agmem#readme
|
|
11
11
|
Project-URL: Repository, https://github.com/vivek-tiwari-vt/agmem
|
|
12
12
|
Project-URL: Bug Tracker, https://github.com/vivek-tiwari-vt/agmem/issues
|
|
13
|
-
Keywords: ai,agent,memory,version-control,git,vcs,llm
|
|
13
|
+
Keywords: ai,agent,memory,version-control,git,vcs,llm,merkle,audit,encryption,differential-privacy,trust,multi-agent
|
|
14
14
|
Classifier: Development Status :: 3 - Alpha
|
|
15
15
|
Classifier: Intended Audience :: Developers
|
|
16
16
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -22,6 +22,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
23
|
Classifier: Topic :: Software Development :: Version Control
|
|
24
24
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
25
|
+
Classifier: Topic :: Security :: Cryptography
|
|
25
26
|
Requires-Python: >=3.8
|
|
26
27
|
Description-Content-Type: text/markdown
|
|
27
28
|
License-File: LICENSE
|
|
@@ -32,6 +33,9 @@ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
|
32
33
|
Requires-Dist: black==24.10.0; extra == "dev"
|
|
33
34
|
Requires-Dist: flake8>=5.0.0; extra == "dev"
|
|
34
35
|
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
36
|
+
Provides-Extra: llm
|
|
37
|
+
Requires-Dist: openai>=1.0.0; extra == "llm"
|
|
38
|
+
Requires-Dist: anthropic>=0.18.0; extra == "llm"
|
|
35
39
|
Provides-Extra: mcp
|
|
36
40
|
Requires-Dist: mcp>=1.0.0; extra == "mcp"
|
|
37
41
|
Provides-Extra: vector
|
|
@@ -46,6 +50,8 @@ Requires-Dist: google-cloud-storage>=2.0.0; extra == "cloud"
|
|
|
46
50
|
Provides-Extra: gardener
|
|
47
51
|
Requires-Dist: scikit-learn>=1.3.0; extra == "gardener"
|
|
48
52
|
Requires-Dist: openai>=1.0.0; extra == "gardener"
|
|
53
|
+
Provides-Extra: anthropic
|
|
54
|
+
Requires-Dist: anthropic>=0.18.0; extra == "anthropic"
|
|
49
55
|
Provides-Extra: pii
|
|
50
56
|
Requires-Dist: presidio-analyzer>=2.2.0; extra == "pii"
|
|
51
57
|
Provides-Extra: daemon
|
|
@@ -58,8 +64,13 @@ Provides-Extra: distill
|
|
|
58
64
|
Requires-Dist: openai>=1.0.0; extra == "distill"
|
|
59
65
|
Provides-Extra: verify
|
|
60
66
|
Requires-Dist: openai>=1.0.0; extra == "verify"
|
|
67
|
+
Provides-Extra: crypto
|
|
68
|
+
Requires-Dist: cryptography>=41.0.0; extra == "crypto"
|
|
69
|
+
Provides-Extra: ipfs
|
|
70
|
+
Requires-Dist: requests>=2.28.0; extra == "ipfs"
|
|
61
71
|
Provides-Extra: all
|
|
62
72
|
Requires-Dist: mcp>=1.0.0; extra == "all"
|
|
73
|
+
Requires-Dist: cryptography>=41.0.0; extra == "all"
|
|
63
74
|
Requires-Dist: sqlite-vec>=0.1.0; extra == "all"
|
|
64
75
|
Requires-Dist: sentence-transformers>=2.0.0; extra == "all"
|
|
65
76
|
Requires-Dist: fastapi>=0.100.0; extra == "all"
|
|
@@ -68,8 +79,12 @@ Requires-Dist: boto3>=1.34.0; extra == "all"
|
|
|
68
79
|
Requires-Dist: google-cloud-storage>=2.0.0; extra == "all"
|
|
69
80
|
Requires-Dist: scikit-learn>=1.3.0; extra == "all"
|
|
70
81
|
Requires-Dist: openai>=1.0.0; extra == "all"
|
|
82
|
+
Requires-Dist: anthropic>=0.18.0; extra == "all"
|
|
71
83
|
Requires-Dist: watchdog>=3.0.0; extra == "all"
|
|
72
84
|
Requires-Dist: networkx>=3.0; extra == "all"
|
|
85
|
+
Requires-Dist: tiktoken>=0.5.0; extra == "all"
|
|
86
|
+
Requires-Dist: presidio-analyzer>=2.2.0; extra == "all"
|
|
87
|
+
Requires-Dist: requests>=2.28.0; extra == "all"
|
|
73
88
|
Dynamic: author
|
|
74
89
|
Dynamic: home-page
|
|
75
90
|
Dynamic: license-file
|
|
@@ -105,10 +120,23 @@ agmem solves all of these problems with a familiar Git-like interface.
|
|
|
105
120
|
- ✅ **Branch/tag names with `/`** — Git-style refs: `feature/test`, `releases/v1` (path-validated)
|
|
106
121
|
- ✅ **Content-addressable storage** — SHA-256 deduplication like Git
|
|
107
122
|
- ✅ **Memory-type-aware merging** — Episodic append, semantic consolidate, procedural prefer-new
|
|
108
|
-
- ✅ **Remote (file://)** — `clone`, `push`, `pull`, `remote`; pull merges into current branch
|
|
123
|
+
- ✅ **Remote (file://)** — `clone`, `push`, `pull`, `remote`; pull merges into current branch; push conflict detection (non–fast-forward reject)
|
|
109
124
|
- ✅ **Search** — Semantic with `agmem[vector]`, or plain text over `current/` when vector deps missing
|
|
110
125
|
- ✅ **Knowledge graph** — `agmem graph` from wikilinks/tags; `--no-similarity`, `--format d3`, `--serve` (optional `agmem[web]`)
|
|
111
|
-
- ✅ **Integrity** — `agmem fsck`; path/ref/hash validation
|
|
126
|
+
- ✅ **Integrity** — `agmem fsck` (objects, refs, vector store, Merkle/signature); `agmem verify --crypto`; path/ref/hash validation (no path traversal)
|
|
127
|
+
- ✅ **Cryptographic commit verification** — Merkle tree over blobs; Ed25519 signing of root; verify on checkout, pull, `verify`, `fsck`; Merkle proofs for single-blob verification
|
|
128
|
+
- ✅ **Encryption at rest** — Optional AES-256-GCM with Argon2id key derivation; hash-then-encrypt preserves deduplication
|
|
129
|
+
- ✅ **Tamper-evident audit trail** — Append-only hash-chained log (init, add, commit, checkout, merge, push, pull, config); `agmem audit` and `agmem audit --verify`
|
|
130
|
+
- ✅ **Multi-agent trust** — Trust store (full / conditional / untrusted) per public key; applied on pull/merge; clone copies remote keys
|
|
131
|
+
- ✅ **Conflict resolution** — `agmem resolve` with ours/theirs/both; conflicts persisted in `.mem/merge/`; path-safe
|
|
132
|
+
- ✅ **Differential privacy** — Epsilon/delta budget in `.mem/privacy_budget.json`; `--private` on `agmem distill` and `agmem garden` when enabled
|
|
133
|
+
- ✅ **Pack files & GC** — `agmem gc` (reachable from refs, prune loose, optional repack); pack format and index in core
|
|
134
|
+
- ✅ **Multi-provider LLM** — OpenAI and Anthropic via `memvcs.core.llm`; config/repo or env; used by gardener, distiller, consistency, merge
|
|
135
|
+
- ✅ **Temporal querying** — Point-in-time and range queries in temporal index; frontmatter timestamps
|
|
136
|
+
- ✅ **Federated collaboration** — `agmem federated push|pull` (stub) for coordinator-based summary sharing
|
|
137
|
+
- ✅ **Zero-knowledge proofs** — `agmem prove` (stub) for keyword containment and memory freshness
|
|
138
|
+
- ✅ **Daemon health** — Periodic Merkle verification in daemon loop; safe auto-remediation hooks
|
|
139
|
+
- ✅ **GPU acceleration** — Vector store detects GPU for embedding model when available
|
|
112
140
|
- ✅ **Optional** — `serve`, `daemon` (watch + auto-commit), `garden` (episode archival), MCP server; install extras as needed
|
|
113
141
|
|
|
114
142
|
## Quick Start
|
|
@@ -227,12 +255,18 @@ All commands are listed below. Highlights: **`agmem blame <file>`** (who changed
|
|
|
227
255
|
|
|
228
256
|
| Command | Description |
|
|
229
257
|
|---------|-------------|
|
|
230
|
-
| `agmem clone <url> [dir]` | Clone repo (file:// URLs); path-validated |
|
|
258
|
+
| `agmem clone <url> [dir]` | Clone repo (file:// URLs); path-validated; copies remote public keys |
|
|
231
259
|
| `agmem remote add <name> <url>` | Add remote |
|
|
232
260
|
| `agmem remote show` | List remotes |
|
|
233
|
-
| `agmem push <remote> <branch>` | Push branch (refs validated) |
|
|
234
|
-
| `agmem pull [--remote <name>] [--branch <b>]` | Fetch and merge into current branch |
|
|
235
|
-
| `agmem fsck` | Check objects, refs, optional vector store |
|
|
261
|
+
| `agmem push <remote> <branch>` | Push branch (refs validated); rejects non–fast-forward |
|
|
262
|
+
| `agmem pull [--remote <name>] [--branch <b>]` | Fetch and merge into current branch; optional crypto/trust checks |
|
|
263
|
+
| `agmem fsck` | Check objects, refs, optional vector store, Merkle roots and signatures |
|
|
264
|
+
| `agmem verify [ref]` | Belief consistency (contradictions); use `--crypto` to verify commit Merkle/signature |
|
|
265
|
+
| `agmem audit [--verify] [--max n]` | Show tamper-evident audit log; `--verify` checks hash chain |
|
|
266
|
+
| `agmem resolve [path]` | Resolve merge conflicts (ours/theirs/both); path under `current/` |
|
|
267
|
+
| `agmem gc [--dry-run] [--prune-days n]` | Garbage collection: delete unreachable loose objects; optional repack |
|
|
268
|
+
| `agmem prove --memory <path> --property keyword\|freshness --value <v> [-o out]` | Generate ZK proofs (stub) |
|
|
269
|
+
| `agmem federated push\|pull` | Federated collaboration (stub; requires coordinator in config) |
|
|
236
270
|
|
|
237
271
|
### Optional (install extras)
|
|
238
272
|
|
|
@@ -301,7 +335,81 @@ Configure in `.mem/config.json` (e.g. `archive_dir`, consolidation thresholds).
|
|
|
301
335
|
agmem fsck
|
|
302
336
|
```
|
|
303
337
|
|
|
304
|
-
Verifies objects, refs, and (if installed) the vector store. Run after cloning or if something looks wrong.
|
|
338
|
+
Verifies objects, refs, and (if installed) the vector store. When commit metadata includes `merkle_root` and optionally `signature`, fsck also runs cryptographic verification. Run after cloning or if something looks wrong.
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## Security, trust & advanced features
|
|
343
|
+
|
|
344
|
+
The following 18 capabilities are implemented (or stubbed) per the agmem features implementation plan. They are grouped by tier.
|
|
345
|
+
|
|
346
|
+
### Tier 1 — Security and trust
|
|
347
|
+
|
|
348
|
+
| # | Feature | Description |
|
|
349
|
+
|---|---------|-------------|
|
|
350
|
+
| **1** | **Cryptographic commit verification** | Merkle tree over commit blobs; Ed25519 signing of Merkle root; verification on checkout, pull, `agmem verify --crypto`, and `agmem fsck`. Merkle proofs for single-blob verification. Keys: `.mem/keys/`; private key from env `AGMEM_SIGNING_PRIVATE_KEY` or `AGMEM_SIGNING_PRIVATE_KEY_FILE`. Old commits without `merkle_root` are unverified. |
|
|
351
|
+
| **2** | **Encryption at rest** | Optional AES-256-GCM for object contents; key from passphrase via Argon2id; hash-then-encrypt preserves deduplication. Config in `.mem/encryption.json` or repo config; opt-in. |
|
|
352
|
+
| **3** | **Tamper-evident audit trail** | Append-only, hash-chained log in `.mem/audit/` for init, add, commit, checkout, merge, push, pull, config. **Commands:** `agmem audit` (show entries), `agmem audit --verify` (verify chain). |
|
|
353
|
+
|
|
354
|
+
### Tier 2 — Multi-agent collaboration
|
|
355
|
+
|
|
356
|
+
| # | Feature | Description |
|
|
357
|
+
|---|---------|-------------|
|
|
358
|
+
| **4** | **Multi-agent trust and identity** | Trust store (full / conditional / untrusted) per public key; applied on pull and merge. Clone copies remote public keys; user adds them to trust store. Identity = keypair (same as commit signing). |
|
|
359
|
+
| **5** | **Federated memory collaboration** | Agents share summaries or aggregated updates via a coordinator. **Command:** `agmem federated push` / `agmem federated pull` (stub). Config: `federated.enabled`, `coordinator_url`. |
|
|
360
|
+
| **6** | **Conflict resolution interface** | Structured resolution: ours / theirs / both per path. **Command:** `agmem resolve [path]`. Conflicts persisted in `.mem/merge/conflicts.json`; path traversal protected. |
|
|
361
|
+
|
|
362
|
+
### Tier 3 — Privacy
|
|
363
|
+
|
|
364
|
+
| # | Feature | Description |
|
|
365
|
+
|---|---------|-------------|
|
|
366
|
+
| **7** | **Differential privacy** | Epsilon/delta budget per repo in `.mem/privacy_budget.json`. **Usage:** `agmem distill --private`, `agmem garden --private`; blocks when budget exceeded. Config: `differential_privacy.max_epsilon`, `delta`. |
|
|
367
|
+
| **8** | **Zero-knowledge proofs** | zk-SNARK-style proofs for keyword containment and memory freshness. **Command:** `agmem prove --memory <path> --property keyword|freshness --value <v> [-o out]` (stub). |
|
|
368
|
+
|
|
369
|
+
### Tier 4 — Storage and distribution
|
|
370
|
+
|
|
371
|
+
| # | Feature | Description |
|
|
372
|
+
|---|---------|-------------|
|
|
373
|
+
| **9** | **Decentralized storage (IPFS)** | Push/pull via IPFS CIDs; pinning and gateway fallback. Stub in `memvcs.core.ipfs_remote`; optional dependency. |
|
|
374
|
+
| **10** | **Pack files and garbage collection** | Pack loose objects into pack file + index; GC deletes unreachable objects. **Command:** `agmem gc [--dry-run] [--prune-days n]`. Config: `gc_prune_days` (default 90). |
|
|
375
|
+
| **11** | **Enhanced cloud remote operations** | Push conflict detection: non–fast-forward push rejected with a clear message. S3/GCS remotes and distributed locking in storage layer. |
|
|
376
|
+
|
|
377
|
+
### Tier 5 — Intelligence and retrieval
|
|
378
|
+
|
|
379
|
+
| # | Feature | Description |
|
|
380
|
+
|---|---------|-------------|
|
|
381
|
+
| **12** | **Multi-provider LLM** | `memvcs.core.llm`: OpenAI and Anthropic; factory by config or env. Used by gardener, distiller, consistency checker, merge. Credentials via env (e.g. `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`). |
|
|
382
|
+
| **13** | **Enhanced semantic compression** | Multi-stage pipeline (chunk → fact extraction → dedup → embed → tiered storage); hybrid retrieval. Docstrings and design in distiller/vector store. |
|
|
383
|
+
| **14** | **Temporal querying and time-travel** | Point-in-time and range queries in `memvcs.core.temporal_index`; frontmatter timestamps; “state at T” resolution. |
|
|
384
|
+
| **15** | **Cross-memory relationship graph** | Knowledge graph extended with co-occurrence, semantic similarity, causal and entity edges; incremental updates. Docstrings in `knowledge_graph.py`. |
|
|
385
|
+
|
|
386
|
+
### Tier 6 — Operations and maintenance
|
|
387
|
+
|
|
388
|
+
| # | Feature | Description |
|
|
389
|
+
|---|---------|-------------|
|
|
390
|
+
| **16** | **Automated memory health monitoring** | Daemon runs periodic Merkle verification; safe auto-remediation hooks; unsafe actions alert only. |
|
|
391
|
+
| **17** | **GPU-accelerated operations** | Vector store detects GPU for embedding model (e.g. sentence-transformers with CUDA/Metal); transparent CPU fallback. |
|
|
392
|
+
| **18** | **Test suite and quality** | Broad tests: object store, merge, crypto (Merkle, proofs, verify), trust, privacy budget, pack/GC, resolve helpers, encryption, LLM provider; CI with coverage. |
|
|
393
|
+
|
|
394
|
+
### New files and config (summary)
|
|
395
|
+
|
|
396
|
+
| Addition | Purpose |
|
|
397
|
+
|----------|---------|
|
|
398
|
+
| `memvcs/core/crypto_verify.py` | Merkle build/verify, Ed25519 sign/verify, Merkle proofs |
|
|
399
|
+
| `memvcs/core/audit.py` | Tamper-evident audit append and verify |
|
|
400
|
+
| `memvcs/core/trust.py` | Trust store (key → level) |
|
|
401
|
+
| `memvcs/core/privacy_budget.py` | Epsilon/delta budget for DP |
|
|
402
|
+
| `memvcs/core/pack.py` | Pack format, index, GC |
|
|
403
|
+
| `memvcs/core/encryption.py` | AES-256-GCM, Argon2id, config |
|
|
404
|
+
| `memvcs/core/llm/` | LLM provider interface and OpenAI/Anthropic |
|
|
405
|
+
| `memvcs/core/zk_proofs.py` | ZK proof stubs |
|
|
406
|
+
| `memvcs/core/federated.py` | Federated push/pull stubs |
|
|
407
|
+
| `.mem/audit/` | Audit log |
|
|
408
|
+
| `.mem/keys/` | Public (and optional private) keys |
|
|
409
|
+
| `.mem/trust/` or config | Trust store |
|
|
410
|
+
| `.mem/privacy_budget.json` | DP budget state |
|
|
411
|
+
| `.mem/merge/conflicts.json` | Unresolved merge conflicts |
|
|
412
|
+
| Commit `metadata` | `merkle_root`, `signature` |
|
|
305
413
|
|
|
306
414
|
---
|
|
307
415
|
|
|
@@ -450,10 +558,20 @@ Repository configuration is stored in `.mem/config.json`:
|
|
|
450
558
|
"summarizer_model": "default",
|
|
451
559
|
"max_episode_size": 1048576,
|
|
452
560
|
"consolidation_threshold": 100
|
|
561
|
+
},
|
|
562
|
+
"differential_privacy": {
|
|
563
|
+
"max_epsilon": 1.0,
|
|
564
|
+
"delta": 1e-5
|
|
565
|
+
},
|
|
566
|
+
"federated": {
|
|
567
|
+
"enabled": false,
|
|
568
|
+
"coordinator_url": ""
|
|
453
569
|
}
|
|
454
570
|
}
|
|
455
571
|
```
|
|
456
572
|
|
|
573
|
+
Optional sections: **`differential_privacy`** (for `--private` on distill/garden); **`federated`** (for `agmem federated`); **`signing`** (public key for commit verification); trust store under `.mem/trust/` or config; encryption in `.mem/encryption.json` when enabled.
|
|
574
|
+
|
|
457
575
|
### agmem config (cloud and PII)
|
|
458
576
|
|
|
459
577
|
Optional user/repo config for S3/GCS and PII hooks:
|
|
@@ -515,13 +633,17 @@ mypy memvcs/
|
|
|
515
633
|
- [x] Basic commands (init, add, commit, status, log, diff, show, reset, tag, stash, reflog, blame, tree, clean)
|
|
516
634
|
- [x] HEAD~n resolution; branch/tag names with `/` (Git-style)
|
|
517
635
|
- [x] Branching and checkout; merging with memory-type-aware strategies
|
|
518
|
-
- [x] Remote operations (clone, push, pull, remote) — file:// URLs; pull merges into current branch
|
|
636
|
+
- [x] Remote operations (clone, push, pull, remote) — file:// URLs; pull merges into current branch; push conflict detection
|
|
519
637
|
- [x] Search — semantic with `agmem[vector]`, plain text fallback
|
|
520
638
|
- [x] Knowledge graph (`agmem graph`) — wikilinks, tags, optional similarity; `--no-similarity`, `--serve`
|
|
521
|
-
- [x] Integrity (`agmem fsck`); path/ref/hash validation
|
|
639
|
+
- [x] Integrity (`agmem fsck`); path/ref/hash validation; Merkle/signature verification
|
|
522
640
|
- [x] Web UI (`agmem serve`); MCP server (`agmem mcp`); daemon (`agmem daemon`); garden (`agmem garden`)
|
|
523
|
-
- [
|
|
524
|
-
- [
|
|
641
|
+
- [x] Cryptographic commit verification (Merkle tree, Ed25519 signing, verify on checkout/pull/fsck)
|
|
642
|
+
- [x] Tamper-evident audit trail (`agmem audit`); multi-agent trust store; conflict resolution (`agmem resolve`)
|
|
643
|
+
- [x] Encryption at rest (optional AES-256-GCM); differential privacy budget (`--private` on distill/garden)
|
|
644
|
+
- [x] Pack files and garbage collection (`agmem gc`); ZK proofs and federated stubs (`agmem prove`, `agmem federated`)
|
|
645
|
+
- [x] Multi-provider LLM (OpenAI, Anthropic); temporal range queries; daemon health checks; GPU detection; test suite and CI
|
|
646
|
+
- [ ] IPFS remote (stub in place); full ZK circuits and federated coordinator
|
|
525
647
|
|
|
526
648
|
## Integrations
|
|
527
649
|
|
|
@@ -614,8 +736,10 @@ agmem graph --serve # Serve knowledge graph UI (same extra)
|
|
|
614
736
|
|
|
615
737
|
- **Full history:** `agmem log`, `agmem reflog`
|
|
616
738
|
- **Line-level attribution:** `agmem blame <file>` — see which commit and author last changed each line (e.g. `agmem blame current/semantic/user-preferences.md`)
|
|
739
|
+
- **Tamper-evident audit:** `agmem audit` and `agmem audit --verify` for hash-chained operation log
|
|
740
|
+
- **Cryptographic verification:** `agmem verify --crypto` and `agmem fsck` for Merkle roots and Ed25519 signatures
|
|
617
741
|
- **Visual audit:** `agmem serve` for browser-based history and diff viewer
|
|
618
|
-
- **Integrity:** `agmem fsck` to verify objects and
|
|
742
|
+
- **Integrity:** `agmem fsck` to verify objects, refs, and commit signatures
|
|
619
743
|
|
|
620
744
|
## Ecosystem Plugin Patterns
|
|
621
745
|
|
|
@@ -1,34 +1,39 @@
|
|
|
1
|
-
agmem-0.1.
|
|
1
|
+
agmem-0.1.3.dist-info/licenses/LICENSE,sha256=X_S6RBErW-F0IDbM3FAEoDB-zxExFnl2m8640rTXphM,1067
|
|
2
2
|
memvcs/__init__.py,sha256=mXwHTSlUPWo4ERqJLGJnxmxtGQQHPSbXb4IpO61l04M,193
|
|
3
|
-
memvcs/cli.py,sha256=
|
|
3
|
+
memvcs/cli.py,sha256=YF06oMNjKWUmiNahILmfjrIXgoXzU-5BJFmbunSb8Sc,6075
|
|
4
4
|
memvcs/commands/__init__.py,sha256=A2D6xWaO6epU7iV4QSvqvF5TspnwRyDN7NojmGatPrE,510
|
|
5
|
-
memvcs/commands/add.py,sha256=
|
|
5
|
+
memvcs/commands/add.py,sha256=k9eM7qf2NFvneiJkFQNiAYFB2GgKmyPw_NXmkCxblQE,8736
|
|
6
|
+
memvcs/commands/audit.py,sha256=E6m54B726tqDQR3rrgRXWrjE-seu2UocqrFxN1aHkY4,1680
|
|
6
7
|
memvcs/commands/base.py,sha256=yWvIYuofRxbHXvChlSd_DL_hJMaQdbZwa2XBDWj5Bio,634
|
|
7
8
|
memvcs/commands/blame.py,sha256=2tEXyXpAebm_zQFAyw-6d3K09Lnh1GVLYGp6htlEmI0,5605
|
|
8
9
|
memvcs/commands/branch.py,sha256=ghsK4tnGe7XApxQSgou7V0BASBC8PL8nQs_yBt0notQ,3150
|
|
9
10
|
memvcs/commands/checkout.py,sha256=xaYZSbCQ-MyLWPtwA2FdH6WqGMI3oF3R2JmCufGBVFg,3182
|
|
10
11
|
memvcs/commands/clean.py,sha256=e0OhSQdHfFnOPTRbyKbM8IcX4yJD5n_kaBKjIeoaRBo,1973
|
|
11
|
-
memvcs/commands/clone.py,sha256=
|
|
12
|
+
memvcs/commands/clone.py,sha256=aB0LcugIWJE9IEez6y70KlpZu4eIF2EdXZxE24jXyac,3260
|
|
12
13
|
memvcs/commands/commit.py,sha256=W4ulVZuEETJh1SHpscaQfNjyQMqeIE0AYZIbMbTrsq4,6801
|
|
13
|
-
memvcs/commands/daemon.py,sha256=
|
|
14
|
+
memvcs/commands/daemon.py,sha256=dD20IPjwebtmMCO8vE5hVQoTDzLomxPiCoDwkrST7OU,9895
|
|
14
15
|
memvcs/commands/decay.py,sha256=QcgOTMJZxrfw_AOz94YHA3LGoNXRMDn69TxWlUrpSw4,2421
|
|
15
16
|
memvcs/commands/diff.py,sha256=KcgD57_fae4uvQ8G9ZbXmLpAYYIDiWiBuVcjsDtyE1U,5480
|
|
16
|
-
memvcs/commands/distill.py,sha256=
|
|
17
|
-
memvcs/commands/
|
|
18
|
-
memvcs/commands/
|
|
17
|
+
memvcs/commands/distill.py,sha256=YbPU1_os8GBFMjznNoOsevdqJa_MtiGO8B5vFxIjE9g,2858
|
|
18
|
+
memvcs/commands/federated.py,sha256=D4UiRFZWnQrW7kM4KqY0s2ttAqM2t-xeJN5-b_WKSHE,1633
|
|
19
|
+
memvcs/commands/fsck.py,sha256=AdJBMLA2myQ0cJJcjUgsYptsE3qvX4JQc9UAwVmSHlA,7772
|
|
20
|
+
memvcs/commands/garden.py,sha256=vSmI6XPpxK3EkLHCVpjWRg7eJPszHHzbcH8B14csueI,3820
|
|
21
|
+
memvcs/commands/gc.py,sha256=fHQl99HckZ8CcF2iI-PSH46aN-RmbPk6cRrC0WEE_94,1360
|
|
19
22
|
memvcs/commands/graph.py,sha256=MDi6bK2w0OrpK5VOE8XXw5gQX7BuD7VzUyqJ5Ra9Bsg,4746
|
|
20
23
|
memvcs/commands/init.py,sha256=TsrLFLXwkDFT0opsYJTfwu0NIxLrNiiba5SpzRtxjDI,1614
|
|
21
24
|
memvcs/commands/log.py,sha256=eNlLs0-PS2nF0pMAMI8izKGUiEb2m3S0RB4Zh6cUQpE,2859
|
|
22
25
|
memvcs/commands/mcp.py,sha256=PMfwVD6uHltN58Jh7IOiS1w7oND42tg14QKRCJNudmY,1740
|
|
23
|
-
memvcs/commands/merge.py,sha256=
|
|
26
|
+
memvcs/commands/merge.py,sha256=s3QLZp-_I6OvhllLhL9yFZAQ8d4M4FbvxkXV7gUgw5M,4877
|
|
24
27
|
memvcs/commands/pack.py,sha256=rIDjMpxJG0oxrWnB3vCGHqviCITIeIbdy3nhuHVHzM8,3629
|
|
25
|
-
memvcs/commands/
|
|
28
|
+
memvcs/commands/prove.py,sha256=o_RPvSK061WiaM4YfNIGlTC357s5_AfY4iOx4-hwFyE,2094
|
|
29
|
+
memvcs/commands/pull.py,sha256=hn9FIlNc3KUr5EUDo4_66KQSK0BSSXjOn32xaDNxf0Q,3621
|
|
26
30
|
memvcs/commands/push.py,sha256=0abEdHkCMfHpH_Nmlw3OaU7Hzi0-RXF-cTVHpiSPw6k,5086
|
|
27
31
|
memvcs/commands/recall.py,sha256=7nwC4mFYpdjKWG-Cs3cpDLr5_SgYJ6HkVSXDOkFke5A,4592
|
|
28
32
|
memvcs/commands/reflog.py,sha256=j8Rxw_4jZuldS1k1g3wF2EItmPxBEmogWcbccOZrGkw,1117
|
|
29
33
|
memvcs/commands/remote.py,sha256=4PXDZjoU4YA4IbGrn_1KbFVCSVxVB_pVdI2nIn1NSbw,1761
|
|
30
34
|
memvcs/commands/repair.py,sha256=OBVa30Zc9rOjUw2GoiSAC6iZrnuCZN_J8nHpCnk5BzM,2312
|
|
31
35
|
memvcs/commands/reset.py,sha256=3TG7qOu2k1uji-TdSyXsdZ6LV2wqc2MB8aSJ6q71IGk,2778
|
|
36
|
+
memvcs/commands/resolve.py,sha256=SFjCCYlcBqP9pjykWIPrDivtk_714VhsWl1Vt7gjyfM,4093
|
|
32
37
|
memvcs/commands/resurrect.py,sha256=zi4ErN1jWVCn8I5rV4g_Dlbg1YadGEU6Xhc7srzlwfg,2503
|
|
33
38
|
memvcs/commands/search.py,sha256=NOMbkQmVurQ-_d7bZVf9vjOH6OgVPeErqpLZiSxsvBA,5322
|
|
34
39
|
memvcs/commands/serve.py,sha256=n8DroVRIQVm5UO2-o-9JU17pQYF-HYOMIJKycdRcBMs,1408
|
|
@@ -39,30 +44,44 @@ memvcs/commands/tag.py,sha256=CaCnA3JifVrdr8DfX4g0bp-_oRvagJkQFcI4bJbW1uM,3004
|
|
|
39
44
|
memvcs/commands/test.py,sha256=HZrpGZQhu9HnGZLjiq8TXi8jfOZqP-wc3bW6mgpP2yk,3926
|
|
40
45
|
memvcs/commands/timeline.py,sha256=xdOr2jz-_ArSPY-GxwXBloiwhfBzIfz4MAi-JEhP8H0,3666
|
|
41
46
|
memvcs/commands/tree.py,sha256=vdULq4vIXA_4gNfMnHn_Y78BwE0sJoeTBOnFJR3WsZ4,4927
|
|
42
|
-
memvcs/commands/verify.py,sha256=
|
|
47
|
+
memvcs/commands/verify.py,sha256=04CVW5NYWkUlPJ5z1Kci6dfQFM6UmPTGZh9ZextFLMc,3887
|
|
43
48
|
memvcs/commands/when.py,sha256=MMQ15PFXFCTmjIq7dr0tC0XvGAdndMvckVnnWehc60Y,3692
|
|
44
49
|
memvcs/core/__init__.py,sha256=dkIC-4tS0GhwV2mZIbofEe8xR8uiFwrxslGf1aXwhYg,493
|
|
45
50
|
memvcs/core/access_index.py,sha256=HhacnzSUASzRV2jhDHkwRFoPS3rtqh9n9yE1VV7JXpk,5596
|
|
51
|
+
memvcs/core/audit.py,sha256=8APkm9Spl_-1rIdyRQz1elyxOeK3nlpwm0CLkpLlhTE,3732
|
|
46
52
|
memvcs/core/config_loader.py,sha256=j-jgLDp2TRzWN9ZEZebfWSfatevBNYs0FEb3ud1SIR8,8277
|
|
47
|
-
memvcs/core/consistency.py,sha256=
|
|
53
|
+
memvcs/core/consistency.py,sha256=YOG8xhqZLKZCLbai2rdcP0KxYPNGFv5RRMwrQ6qCeyc,7462
|
|
48
54
|
memvcs/core/constants.py,sha256=WUjAb50BFcF0mbFi_GNteDLCxLihmViBm9Fb-JMPmbM,220
|
|
55
|
+
memvcs/core/crypto_verify.py,sha256=WrOgDtIEwpjcPfDj2uqwdyg3sIM3j1hUSVPEFvptWnc,9936
|
|
49
56
|
memvcs/core/decay.py,sha256=ROGwnqngs7eJNkbKmwyOdij607m73vpmoJqzrIDLBzk,6581
|
|
50
57
|
memvcs/core/diff.py,sha256=koEHTLciIUxYKVJVuvmY0GDXMgDgGZP_qg5RayhF-iE,13226
|
|
51
|
-
memvcs/core/distiller.py,sha256=
|
|
52
|
-
memvcs/core/
|
|
58
|
+
memvcs/core/distiller.py,sha256=fsZqOHxHTro0yy7rrMW3j5oUMibsVOShlikn2UjOieQ,10440
|
|
59
|
+
memvcs/core/encryption.py,sha256=epny_nlW6ylllv1qxs1mAcFq-PrLIisgfot4llOoAqw,5289
|
|
60
|
+
memvcs/core/federated.py,sha256=H9U5-TgiY_OjQ6Adn85Pw6hV1FYtlXgjjQYMTor35EY,2828
|
|
61
|
+
memvcs/core/gardener.py,sha256=_io40S0OQzPz3euKpS0M6QqEApxxkaX1UXs8uYttQag,16193
|
|
53
62
|
memvcs/core/hooks.py,sha256=XF9z8J5sWjAcuOyWQ2nuvEzK0UV8s4ThrcltaBZttzw,5448
|
|
54
|
-
memvcs/core/
|
|
55
|
-
memvcs/core/
|
|
56
|
-
memvcs/core/
|
|
63
|
+
memvcs/core/ipfs_remote.py,sha256=985xAtSw4P9yxxw-WXtQvNSY8b2hOpFp9TNBbHpIDBk,1062
|
|
64
|
+
memvcs/core/knowledge_graph.py,sha256=sa2jw9AwJIaKs8obHHXdnExxHx-CebtVrgjJaa2qo14,12939
|
|
65
|
+
memvcs/core/merge.py,sha256=x2eSaxr4f63Eq00FCJ6DDe2TZU8H5yHQpzKzMhYsaFw,19871
|
|
66
|
+
memvcs/core/objects.py,sha256=I4UlqQoBPuzyPHKWboZbZP6cy5hL1Dz18IfBm6lInNk,10455
|
|
67
|
+
memvcs/core/pack.py,sha256=zXwsRWSzfup6KrkxX6_jIw6gwxmRbmEnFCoVvhNZXHQ,2999
|
|
57
68
|
memvcs/core/pii_scanner.py,sha256=T6gQ1APFrSDk980fjnv4ZMF-UztbJgmUFSwGrwWixEw,10802
|
|
69
|
+
memvcs/core/privacy_budget.py,sha256=fOPlxoKEAmsKtda-OJCrSaKjTyw7ekcqdN7KfRBw1CY,2113
|
|
58
70
|
memvcs/core/refs.py,sha256=4Nx2ZVRa_DzfUZ4O1AwzOHEjoGAEICJKqSd9GxaiD_g,16754
|
|
59
|
-
memvcs/core/remote.py,sha256=
|
|
60
|
-
memvcs/core/repository.py,sha256=
|
|
71
|
+
memvcs/core/remote.py,sha256=a-Nwr7m4fUK86K-dxG1CawMID7JX2MZ6V94RHkGjkeI,11625
|
|
72
|
+
memvcs/core/repository.py,sha256=NzC2UFPv6ePxi5lfiSKyZFLclH4bJpWJz88pY7tDiv4,20605
|
|
61
73
|
memvcs/core/schema.py,sha256=_CrEWCdArc0yDJ04GT7fyvjHqkal7gegdFSsFOjVpBc,15287
|
|
62
74
|
memvcs/core/staging.py,sha256=dptdGi_74lhDkcGqGVU39ZyTkb25j-Rnkz0GWi83W1k,7221
|
|
63
|
-
memvcs/core/temporal_index.py,sha256=
|
|
75
|
+
memvcs/core/temporal_index.py,sha256=81hZHlVElp2UpXjseFVCdDUwxGM45zIU-y1dDlOhFHI,4012
|
|
64
76
|
memvcs/core/test_runner.py,sha256=7-0jCvji63JRbVfy3LNQWIQ7VL5weulOoG7SY1-YJbw,11496
|
|
65
|
-
memvcs/core/
|
|
77
|
+
memvcs/core/trust.py,sha256=msx80Cl3bxyQTY8mFUKWY9P6l3zb1s8FafympgHwtpo,3494
|
|
78
|
+
memvcs/core/vector_store.py,sha256=yUAp5BlaAtjkrtsdY1I-vmAp_YIFgJykBoNlp5hcg0I,11063
|
|
79
|
+
memvcs/core/zk_proofs.py,sha256=xo0uB6sbufz9OcnZLJK2iH3CXtuVAMopGNp0S1ne_Wo,967
|
|
80
|
+
memvcs/core/llm/__init__.py,sha256=vnjtE9Xlv9a2pZV88DMT9JaINkZ30hC9VLPL5lJRlps,236
|
|
81
|
+
memvcs/core/llm/anthropic_provider.py,sha256=O1eaCb9r464ajLJz-Gy8lGxBie5ojRUZ_5HdgRXO5KY,1540
|
|
82
|
+
memvcs/core/llm/base.py,sha256=qPzg3KPAMeoyWGc_2JoVR4-plpdft5Rc2g9uO-Z4fJQ,623
|
|
83
|
+
memvcs/core/llm/factory.py,sha256=sRl4XiAHs1eReXjCdwYLvbjUaIxdfQZV93hiME-i8j8,912
|
|
84
|
+
memvcs/core/llm/openai_provider.py,sha256=hGOdEPWf96zP7PqC5FzwISXoNDvLSOXCHJjbRj2HgI8,885
|
|
66
85
|
memvcs/core/storage/__init__.py,sha256=yJE7bm5G7VlFLpSVFrrTkP4eOyQlWRPfBvEP9T5PW44,1901
|
|
67
86
|
memvcs/core/storage/base.py,sha256=IK4To8Cb-LHv5ltlaQLdB6LE-69euFK3hNqBtMCe7-g,9956
|
|
68
87
|
memvcs/core/storage/gcs.py,sha256=-cWuGw1jkFh-Xig-Abmwr9HGwjW5lWQJuF2xcAR1l78,10632
|
|
@@ -79,8 +98,8 @@ memvcs/retrieval/recaller.py,sha256=8KY-XjMUz5_vcKf46zI64uk1DEM__u7wM92ShukOtsY,
|
|
|
79
98
|
memvcs/retrieval/strategies.py,sha256=26yxQQubQfjxWQXknfVMxuzPHf2EcZxJg_B99BEdl5c,11458
|
|
80
99
|
memvcs/utils/__init__.py,sha256=8psUzz4Ntv2GzbRebkeVsoyC6Ck-FIwi0_lfYdj5oho,185
|
|
81
100
|
memvcs/utils/helpers.py,sha256=37zg_DcQ2y99b9NSLqxFkglHe13rJXKhFDpEbQ7iLhM,4121
|
|
82
|
-
agmem-0.1.
|
|
83
|
-
agmem-0.1.
|
|
84
|
-
agmem-0.1.
|
|
85
|
-
agmem-0.1.
|
|
86
|
-
agmem-0.1.
|
|
101
|
+
agmem-0.1.3.dist-info/METADATA,sha256=gtN5tU3wSR8trf5kKJIBP6KgAGQrjm66dCs8NRvu_ao,36834
|
|
102
|
+
agmem-0.1.3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
103
|
+
agmem-0.1.3.dist-info/entry_points.txt,sha256=at7eWycgjqOo1wbUMECnXUsNo3gpCkJTU71OzrGLHu0,42
|
|
104
|
+
agmem-0.1.3.dist-info/top_level.txt,sha256=HtMMsKuwLKLOdgF1GxqQztqFM54tTJctVdJuOec6B-4,7
|
|
105
|
+
agmem-0.1.3.dist-info/RECORD,,
|
memvcs/cli.py
CHANGED
|
@@ -58,6 +58,11 @@ from .commands.decay import DecayCommand
|
|
|
58
58
|
from .commands.resurrect import ResurrectCommand
|
|
59
59
|
from .commands.verify import VerifyCommand
|
|
60
60
|
from .commands.repair import RepairCommand
|
|
61
|
+
from .commands.audit import AuditCommand
|
|
62
|
+
from .commands.federated import FederatedCommand
|
|
63
|
+
from .commands.resolve import ResolveCommand
|
|
64
|
+
from .commands.prove import ProveCommand
|
|
65
|
+
from .commands.gc import GcCommand
|
|
61
66
|
|
|
62
67
|
|
|
63
68
|
# List of available commands
|
|
@@ -100,6 +105,11 @@ COMMANDS = [
|
|
|
100
105
|
ResurrectCommand,
|
|
101
106
|
VerifyCommand,
|
|
102
107
|
RepairCommand,
|
|
108
|
+
AuditCommand,
|
|
109
|
+
FederatedCommand,
|
|
110
|
+
ResolveCommand,
|
|
111
|
+
ProveCommand,
|
|
112
|
+
GcCommand,
|
|
103
113
|
]
|
|
104
114
|
|
|
105
115
|
|
memvcs/commands/add.py
CHANGED
|
@@ -198,6 +198,12 @@ class AddCommand:
|
|
|
198
198
|
print(f"Rejected {rejected_count} file(s) - use --force to override")
|
|
199
199
|
if staged_count > 0:
|
|
200
200
|
print("Run 'agmem commit -m \"message\"' to save snapshot")
|
|
201
|
+
try:
|
|
202
|
+
from ..core.audit import append_audit
|
|
203
|
+
|
|
204
|
+
append_audit(repo.mem_dir, "add", {"staged_count": staged_count})
|
|
205
|
+
except Exception:
|
|
206
|
+
pass
|
|
201
207
|
else:
|
|
202
208
|
print("No files staged")
|
|
203
209
|
|
memvcs/commands/audit.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agmem audit - Tamper-evident audit trail.
|
|
3
|
+
|
|
4
|
+
Read and verify the append-only audit log.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
|
|
9
|
+
from ..commands.base import require_repo
|
|
10
|
+
from ..core.audit import read_audit, verify_audit
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AuditCommand:
|
|
14
|
+
"""Show and verify the tamper-evident audit log."""
|
|
15
|
+
|
|
16
|
+
name = "audit"
|
|
17
|
+
help = "Show and verify the tamper-evident audit log"
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def add_arguments(parser: argparse.ArgumentParser):
|
|
21
|
+
parser.add_argument(
|
|
22
|
+
"-n",
|
|
23
|
+
"--max",
|
|
24
|
+
type=int,
|
|
25
|
+
default=50,
|
|
26
|
+
metavar="N",
|
|
27
|
+
help="Show at most N entries (default 50)",
|
|
28
|
+
)
|
|
29
|
+
parser.add_argument(
|
|
30
|
+
"--verify",
|
|
31
|
+
action="store_true",
|
|
32
|
+
help="Verify the audit chain and report first tampering point",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def execute(args) -> int:
|
|
37
|
+
repo, code = require_repo()
|
|
38
|
+
if code != 0:
|
|
39
|
+
return code
|
|
40
|
+
|
|
41
|
+
if args.verify:
|
|
42
|
+
valid, first_bad = verify_audit(repo.mem_dir)
|
|
43
|
+
if valid:
|
|
44
|
+
print("Audit log chain is valid.")
|
|
45
|
+
return 0
|
|
46
|
+
print(f"Audit log chain invalid at entry index {first_bad}.")
|
|
47
|
+
return 1
|
|
48
|
+
|
|
49
|
+
entries = read_audit(repo.mem_dir, max_entries=args.max)
|
|
50
|
+
if not entries:
|
|
51
|
+
print("No audit entries.")
|
|
52
|
+
return 0
|
|
53
|
+
for e in entries:
|
|
54
|
+
ts = e.get("timestamp", "")
|
|
55
|
+
op = e.get("operation", "")
|
|
56
|
+
details = e.get("details", {})
|
|
57
|
+
detail_str = " ".join(f"{k}={v}" for k, v in sorted(details.items()) if v is not None)
|
|
58
|
+
print(f"{ts} {op} {detail_str}")
|
|
59
|
+
return 0
|
memvcs/commands/clone.py
CHANGED
|
@@ -90,5 +90,12 @@ class CloneCommand:
|
|
|
90
90
|
}
|
|
91
91
|
config_file.write_text(json.dumps(config, indent=2))
|
|
92
92
|
|
|
93
|
+
# Copy remote's public key to .mem/keys/remotes/origin.pub for trust store
|
|
94
|
+
remote_keys = remote_mem / "keys" / "public.pem"
|
|
95
|
+
if remote_keys.exists():
|
|
96
|
+
keys_remotes = target / ".mem" / "keys" / "remotes"
|
|
97
|
+
keys_remotes.mkdir(parents=True, exist_ok=True)
|
|
98
|
+
shutil.copy2(remote_keys, keys_remotes / "origin.pub")
|
|
99
|
+
|
|
93
100
|
print(f"Cloned into {target}")
|
|
94
101
|
return 0
|
memvcs/commands/daemon.py
CHANGED
|
@@ -203,10 +203,38 @@ class DaemonCommand:
|
|
|
203
203
|
signal.signal(signal.SIGTERM, signal_handler)
|
|
204
204
|
signal.signal(signal.SIGINT, signal_handler)
|
|
205
205
|
|
|
206
|
+
# Health monitoring: periodic integrity check (configurable interval)
|
|
207
|
+
last_health_check = 0
|
|
208
|
+
health_check_interval = 3600 # 1 hour
|
|
209
|
+
|
|
206
210
|
try:
|
|
207
211
|
while running:
|
|
208
212
|
time.sleep(1)
|
|
209
213
|
|
|
214
|
+
# Periodic health check (Merkle/signature, optional)
|
|
215
|
+
if (
|
|
216
|
+
health_check_interval
|
|
217
|
+
and (time.time() - last_health_check) >= health_check_interval
|
|
218
|
+
):
|
|
219
|
+
try:
|
|
220
|
+
from ..core.crypto_verify import verify_commit, load_public_key
|
|
221
|
+
|
|
222
|
+
head = repo.refs.get_branch_commit(
|
|
223
|
+
repo.refs.get_current_branch() or "main"
|
|
224
|
+
) or (repo.refs.get_head() or {}).get("value")
|
|
225
|
+
if head:
|
|
226
|
+
ok, err = verify_commit(
|
|
227
|
+
repo.object_store,
|
|
228
|
+
head,
|
|
229
|
+
load_public_key(repo.mem_dir),
|
|
230
|
+
mem_dir=repo.mem_dir,
|
|
231
|
+
)
|
|
232
|
+
if not ok and err and "tampered" in (err or "").lower():
|
|
233
|
+
sys.stderr.write(f"Health check: {err}\n")
|
|
234
|
+
except Exception:
|
|
235
|
+
pass
|
|
236
|
+
last_health_check = time.time()
|
|
237
|
+
|
|
210
238
|
if handler.pending:
|
|
211
239
|
elapsed = time.time() - handler.last_change
|
|
212
240
|
if elapsed >= debounce:
|
memvcs/commands/distill.py
CHANGED
|
@@ -41,6 +41,11 @@ class DistillCommand:
|
|
|
41
41
|
action="store_true",
|
|
42
42
|
help="Do not create safety branch",
|
|
43
43
|
)
|
|
44
|
+
parser.add_argument(
|
|
45
|
+
"--private",
|
|
46
|
+
action="store_true",
|
|
47
|
+
help="Use differential privacy (spend epsilon from budget)",
|
|
48
|
+
)
|
|
44
49
|
|
|
45
50
|
@staticmethod
|
|
46
51
|
def execute(args) -> int:
|
|
@@ -48,6 +53,17 @@ class DistillCommand:
|
|
|
48
53
|
if code != 0:
|
|
49
54
|
return code
|
|
50
55
|
|
|
56
|
+
if getattr(args, "private", False):
|
|
57
|
+
from ..core.privacy_budget import load_budget, spend_epsilon
|
|
58
|
+
|
|
59
|
+
spent, max_eps, _ = load_budget(repo.mem_dir)
|
|
60
|
+
epsilon_cost = 0.1
|
|
61
|
+
if not spend_epsilon(repo.mem_dir, epsilon_cost):
|
|
62
|
+
print(f"Privacy budget exceeded (spent {spent:.2f}, max {max_eps}).")
|
|
63
|
+
return 1
|
|
64
|
+
if spent + epsilon_cost > max_eps * 0.8:
|
|
65
|
+
print(f"Privacy budget low: {spent + epsilon_cost:.2f}/{max_eps}")
|
|
66
|
+
|
|
51
67
|
config = DistillerConfig(
|
|
52
68
|
source_dir=args.source,
|
|
53
69
|
target_dir=args.target,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agmem federated - Federated memory collaboration.
|
|
3
|
+
|
|
4
|
+
Push local summaries to coordinator; pull merged summaries.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
|
|
9
|
+
from ..commands.base import require_repo
|
|
10
|
+
from ..core.federated import get_federated_config, produce_local_summary, push_updates, pull_merged
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class FederatedCommand:
|
|
14
|
+
"""Federated memory collaboration with coordinator."""
|
|
15
|
+
|
|
16
|
+
name = "federated"
|
|
17
|
+
help = "Push/pull federated summaries (coordinator must be configured)"
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def add_arguments(parser: argparse.ArgumentParser):
|
|
21
|
+
parser.add_argument(
|
|
22
|
+
"action",
|
|
23
|
+
choices=["push", "pull"],
|
|
24
|
+
help="Push local summary or pull merged from coordinator",
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def execute(args) -> int:
|
|
29
|
+
repo, code = require_repo()
|
|
30
|
+
if code != 0:
|
|
31
|
+
return code
|
|
32
|
+
|
|
33
|
+
cfg = get_federated_config(repo.root)
|
|
34
|
+
if not cfg:
|
|
35
|
+
print(
|
|
36
|
+
"Federated collaboration not enabled. Set federated.enabled and coordinator_url in config."
|
|
37
|
+
)
|
|
38
|
+
return 1
|
|
39
|
+
|
|
40
|
+
if args.action == "push":
|
|
41
|
+
summary = produce_local_summary(repo.root, cfg["memory_types"])
|
|
42
|
+
msg = push_updates(repo.root, summary)
|
|
43
|
+
print(msg)
|
|
44
|
+
return 0 if "Pushed" in msg else 1
|
|
45
|
+
else:
|
|
46
|
+
data = pull_merged(repo.root)
|
|
47
|
+
if data is None:
|
|
48
|
+
print("Pull failed or coordinator unavailable.")
|
|
49
|
+
return 1
|
|
50
|
+
print("Merged summary from coordinator:")
|
|
51
|
+
for k, v in (data or {}).items():
|
|
52
|
+
print(f" {k}: {v}")
|
|
53
|
+
return 0
|