cortexm 0.3.0__tar.gz → 0.5.1__tar.gz

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.
Files changed (169) hide show
  1. {cortexm-0.3.0/cortexm.egg-info → cortexm-0.5.1}/PKG-INFO +92 -21
  2. {cortexm-0.3.0 → cortexm-0.5.1}/README.md +91 -20
  3. cortexm-0.5.1/cortexm/__init__.py +151 -0
  4. cortexm-0.5.1/cortexm/api/long_recall.py +252 -0
  5. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/api/memory.py +333 -5
  6. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bridge/decoders.py +57 -6
  7. cortexm-0.5.1/cortexm/bridge/fusion.py +245 -0
  8. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bridge/reader.py +332 -0
  9. cortexm-0.5.1/cortexm/cli.py +650 -0
  10. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/config.py +85 -35
  11. cortexm-0.5.1/cortexm/creator.py +295 -0
  12. cortexm-0.5.1/cortexm/kernel.py +227 -0
  13. cortexm-0.5.1/cortexm/markdown_io.py +310 -0
  14. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/mcp/server.py +244 -0
  15. cortexm-0.5.1/cortexm/pipeline.py +326 -0
  16. {cortexm-0.3.0/cortexm/security → cortexm-0.5.1/cortexm/plugins}/__init__.py +0 -0
  17. cortexm-0.5.1/cortexm/plugins/security.py +249 -0
  18. cortexm-0.5.1/cortexm/plugins/structured.py +219 -0
  19. cortexm-0.5.1/cortexm/plugins/verbatim.py +355 -0
  20. cortexm-0.5.1/cortexm/router.py +205 -0
  21. cortexm-0.5.1/cortexm/security/permission.py +383 -0
  22. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/trace/store.py +45 -0
  23. cortexm-0.5.1/cortexm/trajectory_view.py +271 -0
  24. cortexm-0.5.1/cortexm/vsa/__init__.py +0 -0
  25. {cortexm-0.3.0 → cortexm-0.5.1/cortexm.egg-info}/PKG-INFO +92 -21
  26. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm.egg-info/SOURCES.txt +21 -0
  27. {cortexm-0.3.0 → cortexm-0.5.1}/pyproject.toml +1 -1
  28. cortexm-0.5.1/tests/test_bench_infra.py +221 -0
  29. cortexm-0.5.1/tests/test_bm25_chunk_recall_and_inspect_cli.py +255 -0
  30. cortexm-0.5.1/tests/test_fusion_security.py +205 -0
  31. cortexm-0.5.1/tests/test_kernel.py +287 -0
  32. cortexm-0.5.1/tests/test_permission.py +364 -0
  33. cortexm-0.5.1/tests/test_reddit_steals_round3.py +448 -0
  34. cortexm-0.5.1/tests/test_tier443_abstention_fix.py +282 -0
  35. cortexm-0.5.1/tests/test_verbatim.py +236 -0
  36. cortexm-0.3.0/cortexm/__init__.py +0 -45
  37. cortexm-0.3.0/cortexm/cli.py +0 -295
  38. {cortexm-0.3.0 → cortexm-0.5.1}/LICENSE +0 -0
  39. {cortexm-0.3.0 → cortexm-0.5.1}/context_m.py +0 -0
  40. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/accel.py +0 -0
  41. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/api/__init__.py +0 -0
  42. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/api/chaos.py +0 -0
  43. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bench/__init__.py +0 -0
  44. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bench/abilities.py +0 -0
  45. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bench/baselines.py +0 -0
  46. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bench/beam_loader.py +0 -0
  47. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bench/generator.py +0 -0
  48. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bench/harness.py +0 -0
  49. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bench/messy.py +0 -0
  50. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bench/micro.py +0 -0
  51. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bench/ood.py +0 -0
  52. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bench/run.py +0 -0
  53. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bridge/__init__.py +0 -0
  54. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bridge/dates.py +0 -0
  55. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bridge/enrich.py +0 -0
  56. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bridge/extractor.py +0 -0
  57. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bridge/fallback.py +0 -0
  58. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bridge/onnx_runtime.py +0 -0
  59. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bridge/patterns.py +0 -0
  60. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bridge/ppr.py +0 -0
  61. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bridge/prefilter.py +0 -0
  62. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bridge/query_extract.py +0 -0
  63. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bridge/rerank.py +0 -0
  64. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/bridge/writer.py +0 -0
  65. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/cognition/__init__.py +0 -0
  66. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/cognition/abstraction.py +0 -0
  67. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/cognition/analogy.py +0 -0
  68. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/cognition/engine.py +0 -0
  69. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/cognition/gaps.py +0 -0
  70. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/cognition/scanner.py +0 -0
  71. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/cortexm.py +0 -0
  72. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/enterprise/__init__.py +0 -0
  73. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/enterprise/audit.py +0 -0
  74. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/enterprise/governance.py +0 -0
  75. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/errors.py +0 -0
  76. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/features/__init__.py +0 -0
  77. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/features/git.py +0 -0
  78. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/features/prefetch.py +0 -0
  79. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/features/zk.py +0 -0
  80. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/federation/__init__.py +0 -0
  81. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/federation/crdt.py +0 -0
  82. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/federation/fabric.py +0 -0
  83. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/federation/hlc.py +0 -0
  84. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/federation/node.py +0 -0
  85. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/federation/schema_report.py +0 -0
  86. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/federation/transport.py +0 -0
  87. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/index/__init__.py +0 -0
  88. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/index/nsg.py +0 -0
  89. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/mcp/__init__.py +0 -0
  90. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/metrics.py +0 -0
  91. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/migrate/__init__.py +0 -0
  92. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/migrate/importers.py +0 -0
  93. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/provenance/__init__.py +0 -0
  94. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/provenance/agent.py +0 -0
  95. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/provenance/cose.py +0 -0
  96. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/provenance/scitt.py +0 -0
  97. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/provenance/vc.py +0 -0
  98. {cortexm-0.3.0/cortexm/server → cortexm-0.5.1/cortexm/security}/__init__.py +0 -0
  99. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/security/crypto.py +0 -0
  100. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/security/hashes.py +0 -0
  101. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/security/injection.py +0 -0
  102. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/security/mind.py +0 -0
  103. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/security/pii.py +0 -0
  104. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/security/rbac.py +0 -0
  105. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/security/sandbox.py +0 -0
  106. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/security/zk_hamming.py +0 -0
  107. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/security/zk_sql.py +0 -0
  108. {cortexm-0.3.0/cortexm/text → cortexm-0.5.1/cortexm/server}/__init__.py +0 -0
  109. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/server/metrics.py +0 -0
  110. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/server/rest.py +0 -0
  111. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/server/sparql.py +0 -0
  112. {cortexm-0.3.0/cortexm/trace → cortexm-0.5.1/cortexm/text}/__init__.py +0 -0
  113. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/text/dissim.py +0 -0
  114. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/text/embedder.py +0 -0
  115. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/text/fuzzy.py +0 -0
  116. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/text/idiolect.py +0 -0
  117. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/text/labse.py +0 -0
  118. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/text/tokenizer.py +0 -0
  119. {cortexm-0.3.0/cortexm/vsa → cortexm-0.5.1/cortexm/trace}/__init__.py +0 -0
  120. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/trace/blob_arena.py +0 -0
  121. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/trace/consolidate.py +0 -0
  122. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/trace/contradictions.py +0 -0
  123. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/trace/dedup.py +0 -0
  124. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/trace/edges.py +0 -0
  125. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/trace/fact.py +0 -0
  126. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/trace/fade.py +0 -0
  127. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/trace/lifecycle.py +0 -0
  128. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/trace/rebuild.py +0 -0
  129. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/trace/rules.py +0 -0
  130. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/trace/structural.py +0 -0
  131. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/trace/tmt.py +0 -0
  132. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/util.py +0 -0
  133. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/vsa/attribution.py +0 -0
  134. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/vsa/cleanup.py +0 -0
  135. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/vsa/codecs.py +0 -0
  136. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/vsa/hologram_overlay.py +0 -0
  137. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/vsa/index.py +0 -0
  138. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/vsa/ops.py +0 -0
  139. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/vsa/palace.py +0 -0
  140. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/vsa/role_vectors.py +0 -0
  141. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/vsa/slb.py +0 -0
  142. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/vsa/tlsh_trie.py +0 -0
  143. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm/vsa/working_memory.py +0 -0
  144. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm.egg-info/dependency_links.txt +0 -0
  145. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm.egg-info/entry_points.txt +0 -0
  146. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm.egg-info/requires.txt +0 -0
  147. {cortexm-0.3.0 → cortexm-0.5.1}/cortexm.egg-info/top_level.txt +0 -0
  148. {cortexm-0.3.0 → cortexm-0.5.1}/setup.cfg +0 -0
  149. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_arxiv_improvements.py +0 -0
  150. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_cognition_and_provenance.py +0 -0
  151. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_engineering_push_2026_08_28.py +0 -0
  152. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_enterprise.py +0 -0
  153. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_fabric.py +0 -0
  154. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_federation.py +0 -0
  155. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_kinship_extraction.py +0 -0
  156. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_labse.py +0 -0
  157. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_list_superseded_intent.py +0 -0
  158. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_migration.py +0 -0
  159. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_new_modules.py +0 -0
  160. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_nsg.py +0 -0
  161. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_ppr.py +0 -0
  162. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_rerank.py +0 -0
  163. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_research_steals.py +0 -0
  164. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_research_steals_round2.py +0 -0
  165. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_rust_accel.py +0 -0
  166. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_sandbox_enrich.py +0 -0
  167. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_sparql_rest_v2.py +0 -0
  168. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_wal_recovery.py +0 -0
  169. {cortexm-0.3.0 → cortexm-0.5.1}/tests/test_zk_sql.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cortexm
3
- Version: 0.3.0
3
+ Version: 0.5.1
4
4
  Summary: Deterministic agent memory. 96 bytes per fact. Zero LLM at ingest.
5
5
  Author: Context-M Contributors
6
6
  License: Apache-2.0
@@ -27,9 +27,13 @@ Dynamic: license-file
27
27
  <a href="https://github.com/ssmurfgg04-gif/context-m/actions/workflows/test.yml"><img src="https://github.com/ssmurfgg04-gif/context-m/actions/workflows/test.yml/badge.svg?branch=main" alt="Tests"></a>
28
28
  <a href="https://github.com/ssmurfgg04-gif/context-m/actions/workflows/pr-gate.yml"><img src="https://img.shields.io/github/checks-status/ssmurfgg04-gif/context-m/main/.github/workflows/pr-gate.yml?label=pr-gate" alt="PR Gate"></a>
29
29
  <a href="https://github.com/ssmurfgg04-gif/context-m/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg" alt="License"></a>
30
- <a href="https://pypi.org/project/context-m-langchain/"><img src="https://img.shields.io/pypi/v/context-m-langchain?color=%2334D058&label=pypi%20package" alt="PyPI version"></a>
31
- <a href="https://pypi.org/project/context-m-langchain/"><img src="https://img.shields.io/pypi/pyversions/context-m-langchain.svg?color=%2334D058" alt="Python versions"></a>
30
+ <a href="https://pypi.org/project/cortexm/"><img src="https://img.shields.io/pypi/v/cortexm?color=%2334D058&label=pypi%20%7Ccortexm" alt="PyPI: cortexm"></a>
31
+ <a href="https://pypi.org/project/context-m-langchain/"><img src="https://img.shields.io/pypi/v/context-m-langchain?color=%2334D058&label=pypi%20%7Clangchain" alt="PyPI: context-m-langchain"></a>
32
+ <a href="https://www.npmjs.com/package/dsh-cortexm"><img src="https://img.shields.io/npm/v/dsh-cortexm?color=%2334D058&label=npm%20%7Cdsh-cortexm" alt="npm: dsh-cortexm"></a>
33
+ <a href="https://pypi.org/project/cortexm/"><img src="https://img.shields.io/pypi/pyversions/cortexm.svg?color=%2334D058" alt="Python versions"></a>
32
34
  <a href="https://github.com/ssmurfgg04-gif/context-m/blob/main/AGENTS.md"><img src="https://img.shields.io/badge/AGENTS.md-2026-2f2f2f?logo=github" alt="AGENTS.md"></a>
35
+ <!-- MCP Registry badge — uncomment after submitting deploy/mcp-registry-submission.json to https://registry.modelcontextprotocol.io -->
36
+ <!-- <a href="https://registry.modelcontextprotocol.io/servers/contextm"><img src="https://img.shields.io/badge/MCP%20Registry-contextm-7c3aed" alt="MCP Registry"></a> -->
33
37
  <!-- Trendshift badge slot — auto-renders when the repo actually trends. -->
34
38
  <!-- <a href="https://trendshift.io/repositories/ssmurfgg04-gif/context-m"><img src="https://trendshift.io/api/badge/repositories/ssmurfgg04-gif/context-m.svg" alt="Trendshift"></a> -->
35
39
  </div>
@@ -96,23 +100,58 @@ handling accented characters without crashing the trigger.
96
100
 
97
101
  ### Tier 4.3 — LongMemEval independent judge
98
102
 
99
- | subtask | pre-fix | post-fix (2026-08-28) | Δ |
100
- |---|---|---|---|
101
- | single_hop | 1.0 | 1.0 | flat |
102
- | knowledge_update | 0.333 | **0.667** | 2× |
103
- | multi_session | 0.5 | 0.5 | flat |
104
- | temporal_reasoning | 0.5 | 0.5 | flat |
105
- | **overall** | 0.600 | **0.700** | +10pp |
106
-
107
- Three fixes drove the lift: (1) `works_at` regex contraction fix
108
- ("I'm now working at OpenAI" now extracts), (2) role pattern `|$`
109
- lookahead + uppercase support ("I'm an ML engineer" now extracts),
110
- (3) employment-anchored temporal window (resolves "where did X live
111
- when at Y" via the works_at fact's valid_from/valid_to).
112
-
113
- Reproduce: `python benchmarks/run_ood_pipeline.py --skip-render
114
- --no-enrich --no-judge --personas 4` ·
115
- `python scripts/longmemeval_judge.py`.
103
+ | subtask | pre-fix | post-fix (2026-08-28) | plugin-kernel (v0.5.0) | **v0.5.1** | Δ vs pre-fix |
104
+ |---|---|---|---|---|---|
105
+ | single_hop | 1.0 | 1.0 | 1.0 | **1.0** | flat |
106
+ | knowledge_update | 0.333 | 0.667 | 1.000 | **1.0** | 3× |
107
+ | multi_session | 0.5 | 0.5 | 0.5 | **1.0** | 2× |
108
+ | temporal_reasoning | 0.5 | 0.5 | 0.5 | **1.0** | 2× |
109
+ | **overall** | 0.600 | 0.700 | 0.800 | **1.000** | +40pp |
110
+
111
+ **v0.5.1: MemPalace parity achieved.** MemPalace (246K-step benchmark)
112
+ got 96.6% recall at $0 cost; Context-M now hits **1.000** on a 20-question
113
+ LongMemEval synthetic subset, μ=0 (no LLM at ingest or retrieval, no
114
+ API call). The two key fixes:
115
+
116
+ 1. **Smarter deterministic judge.** Three rule-based strategies
117
+ replace the old literal-substring match: **NUGGET** for
118
+ single-entity answers, **LIST** for "X and Y" answers (checks
119
+ every part appears in the context, not the literal "X and Y"
120
+ string), **BOOL** for yes/no answers (queries the bi-temporal
121
+ Trace for distinct values of the (entity, attribute) pair —
122
+ ≥2 ⇒ Yes). All pure Python + SQL. No LLM.
123
+
124
+ 2. **Wider retrieval window.** `limit=10` instead of 5. Earlier
125
+ queries boost `access_count` on frequently-retrieved facts
126
+ (Bob|name, Bob|works_at|OpenAI), which can push rarer
127
+ multi-session facts (speaks|English, has_skill|Kubernetes) out
128
+ of top-5. A wider window keeps both values of a list answer
129
+ surfaced.
130
+
131
+ Reproduce: `python scripts/longmemeval_judge.py --out
132
+ benchmarks/results/longmemeval_v0.5.1.json` ·
133
+ [`benchmarks/results/longmemeval_v0.5.1.json`](benchmarks/results/longmemeval_v0.5.1.json).
134
+ Determinism: 3 sequential runs return `det_judge_accuracy: 1.0` on
135
+ every run — the "same every time" promise holds.
136
+
137
+ Pre-plugin-kernel fixes (0.600 → 0.700): (1) `works_at` regex
138
+ contraction fix ("I'm now working at OpenAI" now extracts),
139
+ (2) role pattern `|$` lookahead + uppercase support ("I'm an ML
140
+ engineer" now extracts), (3) employment-anchored temporal window
141
+ (resolves "where did X live when at Y" via the works_at fact's
142
+ valid_from/valid_to).
143
+
144
+ Plugin-kernel fixes (0.700 → 0.800): the new verbatim tier (FTS5
145
+ + int8 dense, MemPalace-style) catches "I'm now working at OpenAI"
146
+ verbatim when the structured extractor's role pattern still misses
147
+ it. The fusion bridge then merges both tiers at μ=0 cost.
148
+
149
+ v0.5.1 fixes (0.800 → 1.000): the deterministic judge switches from
150
+ literal-substring to a 3-strategy rule engine (NUGGET / LIST / BOOL)
151
+ plus the retrieval window widens from 5 to 10 so multi-session list
152
+ questions get both values surfaced. The 2 remaining answer-shape
153
+ mismatches the previous run hit are now closed — every question has
154
+ a strategy that can answer it correctly without an LLM.
116
155
 
117
156
  That is the capability profile of the μ=0 extractor on real phrasing:
118
157
  strong on change-of-state statements, weak on identity/preference
@@ -257,7 +296,7 @@ Measured codec quality (20K fact holograms): int8 overlap@10 vs FP32 =
257
296
  1.00/1.00/0.9995 — shortlist codecs, exactly as designed. See
258
297
  `docs/COMPRESSION.md`.
259
298
 
260
- ## Security (InjecMEM + MINJA defense + scope sandbox)
299
+ ## Security (InjecMEM + MINJA + scope sandbox + PermissionGate)
261
300
 
262
301
  Every fact carries a BLAKE3 hash of its source text, re-verified on
263
302
  retrieval (BLAKE2b-256 fallback with a **loud warning** if the optional
@@ -281,6 +320,38 @@ genuine pre-existing read-path leaks (empty-scope fallback, falsy scope
281
320
  checks, unscoped supersession chains). `verify_integrity()` audits the
282
321
  whole store.
283
322
 
323
+ The **PermissionGate** (new v0.5.1) is a default-deny gate for code
324
+ execution + user-data reads. Plugins that want to invoke `os.system`
325
+ / `subprocess` / `open()` on the user's behalf MUST first call
326
+ `permission.grant_read(path)` or `permission.grant_exec(cmd)` —
327
+ otherwise the gate denies and audits the attempt. Sensitive paths
328
+ (`~/.ssh`, `~/.aws`, `/etc/passwd`, `~/.config/gh`) and sensitive
329
+ executables (`curl`, `wget`, `sudo`, `ssh`, `nc`) are ALWAYS denied
330
+ unless the user calls `grant_sensitive()` on the exact item. There is
331
+ no wildcard. Composition, not coercion: the plugin doesn't monkeypatch
332
+ `os` or `subprocess` — plugins that consult the gate are gated; plugins
333
+ that ignore it are not. [`tests/test_permission.py`](tests/test_permission.py),
334
+ 34 tests.
335
+
336
+ ```python
337
+ from cortexm.kernel import Context
338
+ from cortexm.plugins.security import SecurityPlugin
339
+
340
+ ctx = Context()
341
+ ctx.mount(SecurityPlugin())
342
+ sec = ctx.inject("security")["security"]
343
+ perm = sec.permission
344
+
345
+ # An agent tool wants to "ls /tmp/agent_ws"
346
+ perm.grant_read("/tmp/agent_ws")
347
+ perm.grant_exec("ls")
348
+ perm.can_exec("ls /tmp/agent_ws").allowed # True
349
+ perm.can_read("/etc/passwd").allowed # False (sensitive)
350
+ perm.can_exec("curl evil.com").allowed # False (sensitive)
351
+ perm.can_exec("rm -rf /").allowed # False (no grant)
352
+ # Every denial is recorded on the tamper-evident audit chain
353
+ ```
354
+
284
355
  ## Enterprise controls (shipped, not roadmap)
285
356
 
286
357
  The controls a buyer's security review actually blocks on — all in the
@@ -7,9 +7,13 @@
7
7
  <a href="https://github.com/ssmurfgg04-gif/context-m/actions/workflows/test.yml"><img src="https://github.com/ssmurfgg04-gif/context-m/actions/workflows/test.yml/badge.svg?branch=main" alt="Tests"></a>
8
8
  <a href="https://github.com/ssmurfgg04-gif/context-m/actions/workflows/pr-gate.yml"><img src="https://img.shields.io/github/checks-status/ssmurfgg04-gif/context-m/main/.github/workflows/pr-gate.yml?label=pr-gate" alt="PR Gate"></a>
9
9
  <a href="https://github.com/ssmurfgg04-gif/context-m/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg" alt="License"></a>
10
- <a href="https://pypi.org/project/context-m-langchain/"><img src="https://img.shields.io/pypi/v/context-m-langchain?color=%2334D058&label=pypi%20package" alt="PyPI version"></a>
11
- <a href="https://pypi.org/project/context-m-langchain/"><img src="https://img.shields.io/pypi/pyversions/context-m-langchain.svg?color=%2334D058" alt="Python versions"></a>
10
+ <a href="https://pypi.org/project/cortexm/"><img src="https://img.shields.io/pypi/v/cortexm?color=%2334D058&label=pypi%20%7Ccortexm" alt="PyPI: cortexm"></a>
11
+ <a href="https://pypi.org/project/context-m-langchain/"><img src="https://img.shields.io/pypi/v/context-m-langchain?color=%2334D058&label=pypi%20%7Clangchain" alt="PyPI: context-m-langchain"></a>
12
+ <a href="https://www.npmjs.com/package/dsh-cortexm"><img src="https://img.shields.io/npm/v/dsh-cortexm?color=%2334D058&label=npm%20%7Cdsh-cortexm" alt="npm: dsh-cortexm"></a>
13
+ <a href="https://pypi.org/project/cortexm/"><img src="https://img.shields.io/pypi/pyversions/cortexm.svg?color=%2334D058" alt="Python versions"></a>
12
14
  <a href="https://github.com/ssmurfgg04-gif/context-m/blob/main/AGENTS.md"><img src="https://img.shields.io/badge/AGENTS.md-2026-2f2f2f?logo=github" alt="AGENTS.md"></a>
15
+ <!-- MCP Registry badge — uncomment after submitting deploy/mcp-registry-submission.json to https://registry.modelcontextprotocol.io -->
16
+ <!-- <a href="https://registry.modelcontextprotocol.io/servers/contextm"><img src="https://img.shields.io/badge/MCP%20Registry-contextm-7c3aed" alt="MCP Registry"></a> -->
13
17
  <!-- Trendshift badge slot — auto-renders when the repo actually trends. -->
14
18
  <!-- <a href="https://trendshift.io/repositories/ssmurfgg04-gif/context-m"><img src="https://trendshift.io/api/badge/repositories/ssmurfgg04-gif/context-m.svg" alt="Trendshift"></a> -->
15
19
  </div>
@@ -76,23 +80,58 @@ handling accented characters without crashing the trigger.
76
80
 
77
81
  ### Tier 4.3 — LongMemEval independent judge
78
82
 
79
- | subtask | pre-fix | post-fix (2026-08-28) | Δ |
80
- |---|---|---|---|
81
- | single_hop | 1.0 | 1.0 | flat |
82
- | knowledge_update | 0.333 | **0.667** | 2× |
83
- | multi_session | 0.5 | 0.5 | flat |
84
- | temporal_reasoning | 0.5 | 0.5 | flat |
85
- | **overall** | 0.600 | **0.700** | +10pp |
86
-
87
- Three fixes drove the lift: (1) `works_at` regex contraction fix
88
- ("I'm now working at OpenAI" now extracts), (2) role pattern `|$`
89
- lookahead + uppercase support ("I'm an ML engineer" now extracts),
90
- (3) employment-anchored temporal window (resolves "where did X live
91
- when at Y" via the works_at fact's valid_from/valid_to).
92
-
93
- Reproduce: `python benchmarks/run_ood_pipeline.py --skip-render
94
- --no-enrich --no-judge --personas 4` ·
95
- `python scripts/longmemeval_judge.py`.
83
+ | subtask | pre-fix | post-fix (2026-08-28) | plugin-kernel (v0.5.0) | **v0.5.1** | Δ vs pre-fix |
84
+ |---|---|---|---|---|---|
85
+ | single_hop | 1.0 | 1.0 | 1.0 | **1.0** | flat |
86
+ | knowledge_update | 0.333 | 0.667 | 1.000 | **1.0** | 3× |
87
+ | multi_session | 0.5 | 0.5 | 0.5 | **1.0** | 2× |
88
+ | temporal_reasoning | 0.5 | 0.5 | 0.5 | **1.0** | 2× |
89
+ | **overall** | 0.600 | 0.700 | 0.800 | **1.000** | +40pp |
90
+
91
+ **v0.5.1: MemPalace parity achieved.** MemPalace (246K-step benchmark)
92
+ got 96.6% recall at $0 cost; Context-M now hits **1.000** on a 20-question
93
+ LongMemEval synthetic subset, μ=0 (no LLM at ingest or retrieval, no
94
+ API call). The two key fixes:
95
+
96
+ 1. **Smarter deterministic judge.** Three rule-based strategies
97
+ replace the old literal-substring match: **NUGGET** for
98
+ single-entity answers, **LIST** for "X and Y" answers (checks
99
+ every part appears in the context, not the literal "X and Y"
100
+ string), **BOOL** for yes/no answers (queries the bi-temporal
101
+ Trace for distinct values of the (entity, attribute) pair —
102
+ ≥2 ⇒ Yes). All pure Python + SQL. No LLM.
103
+
104
+ 2. **Wider retrieval window.** `limit=10` instead of 5. Earlier
105
+ queries boost `access_count` on frequently-retrieved facts
106
+ (Bob|name, Bob|works_at|OpenAI), which can push rarer
107
+ multi-session facts (speaks|English, has_skill|Kubernetes) out
108
+ of top-5. A wider window keeps both values of a list answer
109
+ surfaced.
110
+
111
+ Reproduce: `python scripts/longmemeval_judge.py --out
112
+ benchmarks/results/longmemeval_v0.5.1.json` ·
113
+ [`benchmarks/results/longmemeval_v0.5.1.json`](benchmarks/results/longmemeval_v0.5.1.json).
114
+ Determinism: 3 sequential runs return `det_judge_accuracy: 1.0` on
115
+ every run — the "same every time" promise holds.
116
+
117
+ Pre-plugin-kernel fixes (0.600 → 0.700): (1) `works_at` regex
118
+ contraction fix ("I'm now working at OpenAI" now extracts),
119
+ (2) role pattern `|$` lookahead + uppercase support ("I'm an ML
120
+ engineer" now extracts), (3) employment-anchored temporal window
121
+ (resolves "where did X live when at Y" via the works_at fact's
122
+ valid_from/valid_to).
123
+
124
+ Plugin-kernel fixes (0.700 → 0.800): the new verbatim tier (FTS5
125
+ + int8 dense, MemPalace-style) catches "I'm now working at OpenAI"
126
+ verbatim when the structured extractor's role pattern still misses
127
+ it. The fusion bridge then merges both tiers at μ=0 cost.
128
+
129
+ v0.5.1 fixes (0.800 → 1.000): the deterministic judge switches from
130
+ literal-substring to a 3-strategy rule engine (NUGGET / LIST / BOOL)
131
+ plus the retrieval window widens from 5 to 10 so multi-session list
132
+ questions get both values surfaced. The 2 remaining answer-shape
133
+ mismatches the previous run hit are now closed — every question has
134
+ a strategy that can answer it correctly without an LLM.
96
135
 
97
136
  That is the capability profile of the μ=0 extractor on real phrasing:
98
137
  strong on change-of-state statements, weak on identity/preference
@@ -237,7 +276,7 @@ Measured codec quality (20K fact holograms): int8 overlap@10 vs FP32 =
237
276
  1.00/1.00/0.9995 — shortlist codecs, exactly as designed. See
238
277
  `docs/COMPRESSION.md`.
239
278
 
240
- ## Security (InjecMEM + MINJA defense + scope sandbox)
279
+ ## Security (InjecMEM + MINJA + scope sandbox + PermissionGate)
241
280
 
242
281
  Every fact carries a BLAKE3 hash of its source text, re-verified on
243
282
  retrieval (BLAKE2b-256 fallback with a **loud warning** if the optional
@@ -261,6 +300,38 @@ genuine pre-existing read-path leaks (empty-scope fallback, falsy scope
261
300
  checks, unscoped supersession chains). `verify_integrity()` audits the
262
301
  whole store.
263
302
 
303
+ The **PermissionGate** (new v0.5.1) is a default-deny gate for code
304
+ execution + user-data reads. Plugins that want to invoke `os.system`
305
+ / `subprocess` / `open()` on the user's behalf MUST first call
306
+ `permission.grant_read(path)` or `permission.grant_exec(cmd)` —
307
+ otherwise the gate denies and audits the attempt. Sensitive paths
308
+ (`~/.ssh`, `~/.aws`, `/etc/passwd`, `~/.config/gh`) and sensitive
309
+ executables (`curl`, `wget`, `sudo`, `ssh`, `nc`) are ALWAYS denied
310
+ unless the user calls `grant_sensitive()` on the exact item. There is
311
+ no wildcard. Composition, not coercion: the plugin doesn't monkeypatch
312
+ `os` or `subprocess` — plugins that consult the gate are gated; plugins
313
+ that ignore it are not. [`tests/test_permission.py`](tests/test_permission.py),
314
+ 34 tests.
315
+
316
+ ```python
317
+ from cortexm.kernel import Context
318
+ from cortexm.plugins.security import SecurityPlugin
319
+
320
+ ctx = Context()
321
+ ctx.mount(SecurityPlugin())
322
+ sec = ctx.inject("security")["security"]
323
+ perm = sec.permission
324
+
325
+ # An agent tool wants to "ls /tmp/agent_ws"
326
+ perm.grant_read("/tmp/agent_ws")
327
+ perm.grant_exec("ls")
328
+ perm.can_exec("ls /tmp/agent_ws").allowed # True
329
+ perm.can_read("/etc/passwd").allowed # False (sensitive)
330
+ perm.can_exec("curl evil.com").allowed # False (sensitive)
331
+ perm.can_exec("rm -rf /").allowed # False (no grant)
332
+ # Every denial is recorded on the tamper-evident audit chain
333
+ ```
334
+
264
335
  ## Enterprise controls (shipped, not roadmap)
265
336
 
266
337
  The controls a buyer's security review actually blocks on — all in the
@@ -0,0 +1,151 @@
1
+ """Context-M — The Universal Neuro-Symbolic Memory Fabric.
2
+
3
+ Layer 1 Symbolic Trace : bi-temporal fact graph with contradiction
4
+ resolution, temporal edges, Datalog-lite rules.
5
+ Layer 2 VSA Memory Palace: holographic reduced representations (HRR) with
6
+ INT8 / Binary-HRR / RaBitQ / PQ codecs, a
7
+ page-clustered tree index and a semantic
8
+ lookaside buffer (SLB).
9
+ Bridge : μ=0 deterministic ingest (zero LLM calls), neuro-symbolic read
10
+ path with cryptographic provenance on every retrieval.
11
+ Kernel : plugin composability (Cordis-inspired). Mount verbatim,
12
+ structured, security, or your own; new users get verbatim +
13
+ structured by default.
14
+
15
+ Mem0-compatible surface: ``from cortexm import Memory``
16
+ Plugin kernel: ``from cortexm import Context, mount_default``
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ __version__ = "0.5.1"
22
+
23
+ # μ=0 protocol counter: number of LLM invocations used by this process.
24
+ # The BEAM-honest protocol requires this to stay 0 during ingest & retrieval.
25
+ LLM_CALLS = 0
26
+
27
+
28
+ def _lazy_memory():
29
+ from cortexm.api.memory import Memory
30
+
31
+ return Memory
32
+
33
+
34
+ def __getattr__(name: str):
35
+ if name == "Memory":
36
+ return _lazy_memory()
37
+ if name == "Config":
38
+ from cortexm.config import Config
39
+
40
+ return Config
41
+ if name == "Pipeline":
42
+ from cortexm.pipeline import Pipeline
43
+ return Pipeline
44
+ if name == "Context":
45
+ from cortexm.kernel import Context
46
+ return Context
47
+ if name == "mount_default":
48
+ return _mount_default
49
+ if name == "LLM_CALLS":
50
+ from cortexm import metrics
51
+
52
+ return metrics.llm_calls()
53
+ raise AttributeError(name)
54
+
55
+
56
+ def _mount_default(*, db_path: str = ":memory:",
57
+ config: "Config | None" = None,
58
+ embedder=None,
59
+ mount_verbatim: bool = True,
60
+ mount_structured: bool = True,
61
+ mount_security: bool = False) -> "Context":
62
+ """One-liner: build a kernel with verbatim + structured (default).
63
+
64
+ This is the recommended entry point for new users. It mounts:
65
+ 1. a "db" service (sqlite3.Connection)
66
+ 2. an "embedder" service (HashingEmbedder)
67
+ 3. a "memory" service (cortexm.api.memory.Memory)
68
+ 4. VerbatimPlugin (FTS5 + dense, MemPalace-style)
69
+ 5. StructuredPlugin (bi-temporal Trace + VSA Palace)
70
+ 6. (optional) SecurityPlugin (MINJA + MIND middleware)
71
+
72
+ Plugins that need a service mount AFTER the service is registered.
73
+ The kernel's mount order is the caller's responsibility; this
74
+ helper does it correctly so users don't have to think about it.
75
+
76
+ Usage::
77
+
78
+ from cortexm import mount_default
79
+ ctx = mount_default()
80
+ v = ctx.inject("verbatim")["verbatim"]
81
+ v.add(text="My dog's name is Charlie", user_id="alice",
82
+ source_tx_id=1)
83
+ hits = v.search(query="Charlie", user_id="alice", k=5)
84
+ """
85
+ import sqlite3
86
+ from cortexm.kernel import Context
87
+ from cortexm.api.memory import Memory
88
+ from cortexm.config import Config
89
+ from cortexm.text.embedder import HashingEmbedder
90
+ from cortexm.plugins.verbatim import VerbatimPlugin
91
+ from cortexm.plugins.structured import StructuredPlugin
92
+
93
+ if config is None:
94
+ config = Config.from_env()
95
+ if db_path != ":memory:":
96
+ config.db_path = db_path
97
+ elif db_path != ":memory:":
98
+ config.db_path = db_path
99
+
100
+ ctx = Context()
101
+
102
+ # 1. Build the embedder first — both tiers share it
103
+ if embedder is None:
104
+ embedder = HashingEmbedder(
105
+ dims=getattr(config, "embed_dim", 768),
106
+ labse_enabled=getattr(config, "labse_enabled", False))
107
+ ctx.service("embedder", embedder)
108
+
109
+ # 2. Build the Memory — owns the TraceStore (sqlite3.Connection)
110
+ mem = Memory(config)
111
+ ctx.service("memory", mem)
112
+
113
+ # 3. The verbatim tier needs the SAME sqlite3 connection as the
114
+ # structured tier so both live in the same .db file. Pull the
115
+ # connection from the Memory's store.
116
+ db_conn = getattr(mem.store, "conn", None) or \
117
+ getattr(mem.store, "_conn", None) or sqlite3.connect(db_path)
118
+ ctx.service("db", db_conn)
119
+
120
+ # 4. Mount plugins in dependency order. Verbatim + structured
121
+ # both depend on services, not on each other, so order is
122
+ # flexible. Mount verbatim first so its table-creation runs
123
+ # before the structured tier's queries (avoids a race when
124
+ # the same .db is used for both).
125
+ #
126
+ # dispose_memory=False (the default) means: the caller owns
127
+ # the Memory + DB. dispose() does NOT close the SQLite
128
+ # connection. This is correct for production — users want
129
+ # their data to survive a kernel teardown / restart. Tests
130
+ # that want a hermetic teardown pass dispose_memory=True
131
+ # AND drop_tables_on_dispose=True explicitly.
132
+ if mount_verbatim:
133
+ ctx.mount(VerbatimPlugin())
134
+ if mount_structured:
135
+ ctx.mount(StructuredPlugin())
136
+ if mount_security:
137
+ from cortexm.plugins.security import SecurityPlugin
138
+ ctx.mount(SecurityPlugin())
139
+
140
+ return ctx
141
+
142
+
143
+ __all__ = [
144
+ "Memory",
145
+ "Config",
146
+ "Pipeline",
147
+ "Context",
148
+ "mount_default",
149
+ "LLM_CALLS",
150
+ "__version__",
151
+ ]