@nxuss/lemma 1.37.0 → 1.39.0

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 (284) hide show
  1. package/README.md +9 -6
  2. package/bin/brain-ingest.js +86 -27
  3. package/bin/doctor.js +31 -4
  4. package/bin/init.js +98 -60
  5. package/dashboard/dist/assets/index-DNTQXLER.css +1 -0
  6. package/dashboard/dist/assets/index-DzL_Zu3m.js +452 -0
  7. package/dashboard/dist/index.html +2 -2
  8. package/dist/cjs/cli/gitHooks.d.ts +9 -2
  9. package/dist/cjs/cli/gitHooks.d.ts.map +1 -1
  10. package/dist/cjs/cli/gitHooks.js +31 -4
  11. package/dist/cjs/cli/gitHooks.js.map +1 -1
  12. package/dist/cjs/cli/hostHooks.d.ts +13 -1
  13. package/dist/cjs/cli/hostHooks.d.ts.map +1 -1
  14. package/dist/cjs/cli/hostHooks.js +34 -4
  15. package/dist/cjs/cli/hostHooks.js.map +1 -1
  16. package/dist/cjs/cli/lemma-proxy.d.ts.map +1 -1
  17. package/dist/cjs/cli/lemma-proxy.js +42 -5
  18. package/dist/cjs/cli/lemma-proxy.js.map +1 -1
  19. package/dist/cjs/infra/analyzers/index.d.ts +0 -2
  20. package/dist/cjs/infra/analyzers/index.d.ts.map +1 -1
  21. package/dist/cjs/infra/analyzers/index.js +1 -6
  22. package/dist/cjs/infra/analyzers/index.js.map +1 -1
  23. package/dist/cjs/infra/cli.d.ts +4 -0
  24. package/dist/cjs/infra/cli.d.ts.map +1 -1
  25. package/dist/cjs/infra/cli.js +6 -199
  26. package/dist/cjs/infra/cli.js.map +1 -1
  27. package/dist/cjs/infra/index.d.ts +1 -3
  28. package/dist/cjs/infra/index.d.ts.map +1 -1
  29. package/dist/cjs/infra/index.js +1 -16
  30. package/dist/cjs/infra/index.js.map +1 -1
  31. package/dist/cjs/infra/mcp-tools.d.ts.map +1 -1
  32. package/dist/cjs/infra/mcp-tools.js +8 -453
  33. package/dist/cjs/infra/mcp-tools.js.map +1 -1
  34. package/dist/cjs/infra/types.d.ts +0 -101
  35. package/dist/cjs/infra/types.d.ts.map +1 -1
  36. package/dist/cjs/infra/types.js +2 -1
  37. package/dist/cjs/infra/types.js.map +1 -1
  38. package/dist/cjs/mcp/index.js +33 -10
  39. package/dist/cjs/mcp/index.js.map +1 -1
  40. package/dist/cjs/mcp/prompts.d.ts +1 -1
  41. package/dist/cjs/mcp/prompts.d.ts.map +1 -1
  42. package/dist/cjs/mcp/prompts.js +8 -21
  43. package/dist/cjs/mcp/prompts.js.map +1 -1
  44. package/dist/cjs/mcp/tool-profiles.d.ts +8 -3
  45. package/dist/cjs/mcp/tool-profiles.d.ts.map +1 -1
  46. package/dist/cjs/mcp/tool-profiles.js +25 -54
  47. package/dist/cjs/mcp/tool-profiles.js.map +1 -1
  48. package/dist/cjs/mcp/tools/memory.d.ts +8 -0
  49. package/dist/cjs/mcp/tools/memory.d.ts.map +1 -1
  50. package/dist/cjs/mcp/tools/memory.js +154 -125
  51. package/dist/cjs/mcp/tools/memory.js.map +1 -1
  52. package/dist/cjs/mcp/tools.d.ts.map +1 -1
  53. package/dist/cjs/mcp/tools.js +11 -6
  54. package/dist/cjs/mcp/tools.js.map +1 -1
  55. package/dist/cjs/mcp/workspaceShared.d.ts.map +1 -1
  56. package/dist/cjs/mcp/workspaceShared.js +13 -12
  57. package/dist/cjs/mcp/workspaceShared.js.map +1 -1
  58. package/dist/cjs/proxy/ProjectRegistry.d.ts +44 -0
  59. package/dist/cjs/proxy/ProjectRegistry.d.ts.map +1 -1
  60. package/dist/cjs/proxy/ProjectRegistry.js +92 -3
  61. package/dist/cjs/proxy/ProjectRegistry.js.map +1 -1
  62. package/dist/cjs/subconscious/HostRecall.d.ts +36 -3
  63. package/dist/cjs/subconscious/HostRecall.d.ts.map +1 -1
  64. package/dist/cjs/subconscious/HostRecall.js +164 -37
  65. package/dist/cjs/subconscious/HostRecall.js.map +1 -1
  66. package/dist/cjs/subconscious/NarrowEvidence.d.ts +47 -0
  67. package/dist/cjs/subconscious/NarrowEvidence.d.ts.map +1 -0
  68. package/dist/cjs/subconscious/NarrowEvidence.js +252 -0
  69. package/dist/cjs/subconscious/NarrowEvidence.js.map +1 -0
  70. package/dist/cjs/subconscious/TheBrainV2.d.ts +37 -0
  71. package/dist/cjs/subconscious/TheBrainV2.d.ts.map +1 -1
  72. package/dist/cjs/subconscious/TheBrainV2.js +147 -15
  73. package/dist/cjs/subconscious/TheBrainV2.js.map +1 -1
  74. package/dist/cjs/subconscious/freshness/LocalFsResolver.d.ts.map +1 -1
  75. package/dist/cjs/subconscious/freshness/LocalFsResolver.js +17 -0
  76. package/dist/cjs/subconscious/freshness/LocalFsResolver.js.map +1 -1
  77. package/dist/cjs/subconscious/recallDigest.d.ts +42 -0
  78. package/dist/cjs/subconscious/recallDigest.d.ts.map +1 -0
  79. package/dist/cjs/subconscious/recallDigest.js +94 -0
  80. package/dist/cjs/subconscious/recallDigest.js.map +1 -0
  81. package/dist/cjs/utils/OtherLanguageSymbols.d.ts +31 -0
  82. package/dist/cjs/utils/OtherLanguageSymbols.d.ts.map +1 -0
  83. package/dist/cjs/utils/OtherLanguageSymbols.js +283 -0
  84. package/dist/cjs/utils/OtherLanguageSymbols.js.map +1 -0
  85. package/dist/cjs/utils/SavingsLedger.d.ts +27 -0
  86. package/dist/cjs/utils/SavingsLedger.d.ts.map +1 -1
  87. package/dist/cjs/utils/SavingsLedger.js +51 -0
  88. package/dist/cjs/utils/SavingsLedger.js.map +1 -1
  89. package/dist/cjs/utils/StoreDraft.d.ts +12 -0
  90. package/dist/cjs/utils/StoreDraft.d.ts.map +1 -1
  91. package/dist/cjs/utils/StoreDraft.js +53 -1
  92. package/dist/cjs/utils/StoreDraft.js.map +1 -1
  93. package/dist/cjs/utils/SymbolSurgicalContext.d.ts +2 -0
  94. package/dist/cjs/utils/SymbolSurgicalContext.d.ts.map +1 -1
  95. package/dist/cjs/utils/SymbolSurgicalContext.js +1 -0
  96. package/dist/cjs/utils/SymbolSurgicalContext.js.map +1 -1
  97. package/dist/cjs/utils/reportSavings.d.ts +17 -4
  98. package/dist/cjs/utils/reportSavings.d.ts.map +1 -1
  99. package/dist/cjs/utils/reportSavings.js +67 -22
  100. package/dist/cjs/utils/reportSavings.js.map +1 -1
  101. package/dist/esm/cli/gitHooks.d.ts +9 -2
  102. package/dist/esm/cli/gitHooks.d.ts.map +1 -1
  103. package/dist/esm/cli/gitHooks.js +31 -4
  104. package/dist/esm/cli/gitHooks.js.map +1 -1
  105. package/dist/esm/cli/hostHooks.d.ts +13 -1
  106. package/dist/esm/cli/hostHooks.d.ts.map +1 -1
  107. package/dist/esm/cli/hostHooks.js +32 -3
  108. package/dist/esm/cli/hostHooks.js.map +1 -1
  109. package/dist/esm/cli/lemma-proxy.d.ts.map +1 -1
  110. package/dist/esm/cli/lemma-proxy.js +42 -5
  111. package/dist/esm/cli/lemma-proxy.js.map +1 -1
  112. package/dist/esm/infra/analyzers/index.d.ts +0 -2
  113. package/dist/esm/infra/analyzers/index.d.ts.map +1 -1
  114. package/dist/esm/infra/analyzers/index.js +0 -2
  115. package/dist/esm/infra/analyzers/index.js.map +1 -1
  116. package/dist/esm/infra/cli.d.ts +4 -0
  117. package/dist/esm/infra/cli.d.ts.map +1 -1
  118. package/dist/esm/infra/cli.js +6 -199
  119. package/dist/esm/infra/cli.js.map +1 -1
  120. package/dist/esm/infra/index.d.ts +1 -3
  121. package/dist/esm/infra/index.d.ts.map +1 -1
  122. package/dist/esm/infra/index.js +1 -3
  123. package/dist/esm/infra/index.js.map +1 -1
  124. package/dist/esm/infra/mcp-tools.d.ts.map +1 -1
  125. package/dist/esm/infra/mcp-tools.js +9 -454
  126. package/dist/esm/infra/mcp-tools.js.map +1 -1
  127. package/dist/esm/infra/types.d.ts +0 -101
  128. package/dist/esm/infra/types.d.ts.map +1 -1
  129. package/dist/esm/infra/types.js +2 -1
  130. package/dist/esm/infra/types.js.map +1 -1
  131. package/dist/esm/mcp/index.js +33 -10
  132. package/dist/esm/mcp/index.js.map +1 -1
  133. package/dist/esm/mcp/prompts.d.ts +1 -1
  134. package/dist/esm/mcp/prompts.d.ts.map +1 -1
  135. package/dist/esm/mcp/prompts.js +8 -21
  136. package/dist/esm/mcp/prompts.js.map +1 -1
  137. package/dist/esm/mcp/tool-profiles.d.ts +8 -3
  138. package/dist/esm/mcp/tool-profiles.d.ts.map +1 -1
  139. package/dist/esm/mcp/tool-profiles.js +25 -54
  140. package/dist/esm/mcp/tool-profiles.js.map +1 -1
  141. package/dist/esm/mcp/tools/memory.d.ts +8 -0
  142. package/dist/esm/mcp/tools/memory.d.ts.map +1 -1
  143. package/dist/esm/mcp/tools/memory.js +156 -128
  144. package/dist/esm/mcp/tools/memory.js.map +1 -1
  145. package/dist/esm/mcp/tools.d.ts.map +1 -1
  146. package/dist/esm/mcp/tools.js +12 -7
  147. package/dist/esm/mcp/tools.js.map +1 -1
  148. package/dist/esm/mcp/workspaceShared.d.ts.map +1 -1
  149. package/dist/esm/mcp/workspaceShared.js +13 -12
  150. package/dist/esm/mcp/workspaceShared.js.map +1 -1
  151. package/dist/esm/proxy/ProjectRegistry.d.ts +44 -0
  152. package/dist/esm/proxy/ProjectRegistry.d.ts.map +1 -1
  153. package/dist/esm/proxy/ProjectRegistry.js +91 -2
  154. package/dist/esm/proxy/ProjectRegistry.js.map +1 -1
  155. package/dist/esm/subconscious/HostRecall.d.ts +36 -3
  156. package/dist/esm/subconscious/HostRecall.d.ts.map +1 -1
  157. package/dist/esm/subconscious/HostRecall.js +159 -36
  158. package/dist/esm/subconscious/HostRecall.js.map +1 -1
  159. package/dist/esm/subconscious/NarrowEvidence.d.ts +47 -0
  160. package/dist/esm/subconscious/NarrowEvidence.d.ts.map +1 -0
  161. package/dist/esm/subconscious/NarrowEvidence.js +211 -0
  162. package/dist/esm/subconscious/NarrowEvidence.js.map +1 -0
  163. package/dist/esm/subconscious/TheBrainV2.d.ts +37 -0
  164. package/dist/esm/subconscious/TheBrainV2.d.ts.map +1 -1
  165. package/dist/esm/subconscious/TheBrainV2.js +146 -14
  166. package/dist/esm/subconscious/TheBrainV2.js.map +1 -1
  167. package/dist/esm/subconscious/freshness/LocalFsResolver.d.ts.map +1 -1
  168. package/dist/esm/subconscious/freshness/LocalFsResolver.js +17 -0
  169. package/dist/esm/subconscious/freshness/LocalFsResolver.js.map +1 -1
  170. package/dist/esm/subconscious/recallDigest.d.ts +42 -0
  171. package/dist/esm/subconscious/recallDigest.d.ts.map +1 -0
  172. package/dist/esm/subconscious/recallDigest.js +87 -0
  173. package/dist/esm/subconscious/recallDigest.js.map +1 -0
  174. package/dist/esm/utils/OtherLanguageSymbols.d.ts +31 -0
  175. package/dist/esm/utils/OtherLanguageSymbols.d.ts.map +1 -0
  176. package/dist/esm/utils/OtherLanguageSymbols.js +275 -0
  177. package/dist/esm/utils/OtherLanguageSymbols.js.map +1 -0
  178. package/dist/esm/utils/SavingsLedger.d.ts +27 -0
  179. package/dist/esm/utils/SavingsLedger.d.ts.map +1 -1
  180. package/dist/esm/utils/SavingsLedger.js +51 -0
  181. package/dist/esm/utils/SavingsLedger.js.map +1 -1
  182. package/dist/esm/utils/StoreDraft.d.ts +12 -0
  183. package/dist/esm/utils/StoreDraft.d.ts.map +1 -1
  184. package/dist/esm/utils/StoreDraft.js +52 -1
  185. package/dist/esm/utils/StoreDraft.js.map +1 -1
  186. package/dist/esm/utils/SymbolSurgicalContext.d.ts +2 -0
  187. package/dist/esm/utils/SymbolSurgicalContext.d.ts.map +1 -1
  188. package/dist/esm/utils/SymbolSurgicalContext.js +1 -1
  189. package/dist/esm/utils/SymbolSurgicalContext.js.map +1 -1
  190. package/dist/esm/utils/reportSavings.d.ts +17 -4
  191. package/dist/esm/utils/reportSavings.d.ts.map +1 -1
  192. package/dist/esm/utils/reportSavings.js +65 -22
  193. package/dist/esm/utils/reportSavings.js.map +1 -1
  194. package/package.json +2 -1
  195. package/dashboard/dist/assets/index-BoeQau6n.css +0 -1
  196. package/dashboard/dist/assets/index-Clf3qR64.js +0 -451
  197. package/dist/cjs/infra/analyzers/DriftDetector.d.ts +0 -4
  198. package/dist/cjs/infra/analyzers/DriftDetector.d.ts.map +0 -1
  199. package/dist/cjs/infra/analyzers/DriftDetector.js +0 -88
  200. package/dist/cjs/infra/analyzers/DriftDetector.js.map +0 -1
  201. package/dist/cjs/infra/analyzers/InfraAnalyzer.d.ts +0 -3
  202. package/dist/cjs/infra/analyzers/InfraAnalyzer.d.ts.map +0 -1
  203. package/dist/cjs/infra/analyzers/InfraAnalyzer.js +0 -73
  204. package/dist/cjs/infra/analyzers/InfraAnalyzer.js.map +0 -1
  205. package/dist/cjs/infra/config.d.ts +0 -17
  206. package/dist/cjs/infra/config.d.ts.map +0 -1
  207. package/dist/cjs/infra/config.js +0 -111
  208. package/dist/cjs/infra/config.js.map +0 -1
  209. package/dist/cjs/infra/errorCause.d.ts +0 -36
  210. package/dist/cjs/infra/errorCause.d.ts.map +0 -1
  211. package/dist/cjs/infra/errorCause.js +0 -143
  212. package/dist/cjs/infra/errorCause.js.map +0 -1
  213. package/dist/cjs/infra/providers/InfraProvider.d.ts +0 -9
  214. package/dist/cjs/infra/providers/InfraProvider.d.ts.map +0 -1
  215. package/dist/cjs/infra/providers/InfraProvider.js +0 -3
  216. package/dist/cjs/infra/providers/InfraProvider.js.map +0 -1
  217. package/dist/cjs/infra/providers/JenkinsProvider.d.ts +0 -16
  218. package/dist/cjs/infra/providers/JenkinsProvider.d.ts.map +0 -1
  219. package/dist/cjs/infra/providers/JenkinsProvider.js +0 -193
  220. package/dist/cjs/infra/providers/JenkinsProvider.js.map +0 -1
  221. package/dist/cjs/infra/providers/OKDProvider.d.ts +0 -24
  222. package/dist/cjs/infra/providers/OKDProvider.d.ts.map +0 -1
  223. package/dist/cjs/infra/providers/OKDProvider.js +0 -296
  224. package/dist/cjs/infra/providers/OKDProvider.js.map +0 -1
  225. package/dist/cjs/infra/providers/TerraformProvider.d.ts +0 -17
  226. package/dist/cjs/infra/providers/TerraformProvider.d.ts.map +0 -1
  227. package/dist/cjs/infra/providers/TerraformProvider.js +0 -111
  228. package/dist/cjs/infra/providers/TerraformProvider.js.map +0 -1
  229. package/dist/cjs/infra/providers/index.d.ts +0 -9
  230. package/dist/cjs/infra/providers/index.d.ts.map +0 -1
  231. package/dist/cjs/infra/providers/index.js +0 -34
  232. package/dist/cjs/infra/providers/index.js.map +0 -1
  233. package/dist/cjs/infra/templates/jenkins/index.d.ts +0 -15
  234. package/dist/cjs/infra/templates/jenkins/index.d.ts.map +0 -1
  235. package/dist/cjs/infra/templates/jenkins/index.js +0 -128
  236. package/dist/cjs/infra/templates/jenkins/index.js.map +0 -1
  237. package/dist/cjs/infra/templates/okd/index.d.ts +0 -31
  238. package/dist/cjs/infra/templates/okd/index.d.ts.map +0 -1
  239. package/dist/cjs/infra/templates/okd/index.js +0 -149
  240. package/dist/cjs/infra/templates/okd/index.js.map +0 -1
  241. package/dist/esm/infra/analyzers/DriftDetector.d.ts +0 -4
  242. package/dist/esm/infra/analyzers/DriftDetector.d.ts.map +0 -1
  243. package/dist/esm/infra/analyzers/DriftDetector.js +0 -84
  244. package/dist/esm/infra/analyzers/DriftDetector.js.map +0 -1
  245. package/dist/esm/infra/analyzers/InfraAnalyzer.d.ts +0 -3
  246. package/dist/esm/infra/analyzers/InfraAnalyzer.d.ts.map +0 -1
  247. package/dist/esm/infra/analyzers/InfraAnalyzer.js +0 -70
  248. package/dist/esm/infra/analyzers/InfraAnalyzer.js.map +0 -1
  249. package/dist/esm/infra/config.d.ts +0 -17
  250. package/dist/esm/infra/config.d.ts.map +0 -1
  251. package/dist/esm/infra/config.js +0 -101
  252. package/dist/esm/infra/config.js.map +0 -1
  253. package/dist/esm/infra/errorCause.d.ts +0 -36
  254. package/dist/esm/infra/errorCause.d.ts.map +0 -1
  255. package/dist/esm/infra/errorCause.js +0 -138
  256. package/dist/esm/infra/errorCause.js.map +0 -1
  257. package/dist/esm/infra/providers/InfraProvider.d.ts +0 -9
  258. package/dist/esm/infra/providers/InfraProvider.d.ts.map +0 -1
  259. package/dist/esm/infra/providers/InfraProvider.js +0 -2
  260. package/dist/esm/infra/providers/InfraProvider.js.map +0 -1
  261. package/dist/esm/infra/providers/JenkinsProvider.d.ts +0 -16
  262. package/dist/esm/infra/providers/JenkinsProvider.d.ts.map +0 -1
  263. package/dist/esm/infra/providers/JenkinsProvider.js +0 -186
  264. package/dist/esm/infra/providers/JenkinsProvider.js.map +0 -1
  265. package/dist/esm/infra/providers/OKDProvider.d.ts +0 -24
  266. package/dist/esm/infra/providers/OKDProvider.d.ts.map +0 -1
  267. package/dist/esm/infra/providers/OKDProvider.js +0 -292
  268. package/dist/esm/infra/providers/OKDProvider.js.map +0 -1
  269. package/dist/esm/infra/providers/TerraformProvider.d.ts +0 -17
  270. package/dist/esm/infra/providers/TerraformProvider.d.ts.map +0 -1
  271. package/dist/esm/infra/providers/TerraformProvider.js +0 -107
  272. package/dist/esm/infra/providers/TerraformProvider.js.map +0 -1
  273. package/dist/esm/infra/providers/index.d.ts +0 -9
  274. package/dist/esm/infra/providers/index.d.ts.map +0 -1
  275. package/dist/esm/infra/providers/index.js +0 -27
  276. package/dist/esm/infra/providers/index.js.map +0 -1
  277. package/dist/esm/infra/templates/jenkins/index.d.ts +0 -15
  278. package/dist/esm/infra/templates/jenkins/index.d.ts.map +0 -1
  279. package/dist/esm/infra/templates/jenkins/index.js +0 -124
  280. package/dist/esm/infra/templates/jenkins/index.js.map +0 -1
  281. package/dist/esm/infra/templates/okd/index.d.ts +0 -31
  282. package/dist/esm/infra/templates/okd/index.d.ts.map +0 -1
  283. package/dist/esm/infra/templates/okd/index.js +0 -142
  284. package/dist/esm/infra/templates/okd/index.js.map +0 -1
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@nxuss/lemma.svg?color=orange&style=flat-square)](https://www.npmjs.com/package/@nxuss/lemma)
4
4
  [![License](https://img.shields.io/npm/l/@nxuss/lemma.svg?color=blue&style=flat-square)](https://github.com/Nxusbets/lemma/blob/main/LICENSE)
5
- [![MCP](https://img.shields.io/badge/MCP-111%20tools-ff69b4?style=flat-square)](https://github.com/Nxusbets/lemma)
5
+ [![MCP](https://img.shields.io/badge/MCP-91%20tools-ff69b4?style=flat-square)](https://github.com/Nxusbets/lemma)
6
6
  [![Local-first](https://img.shields.io/badge/local--first-no%20cloud%20required-success?style=flat-square)](https://github.com/Nxusbets/lemma)
7
7
 
8
8
  **A memory your AI agent can verify, and a context window that only holds what matters.**
@@ -60,8 +60,7 @@ pretending (`capability_matrix`).
60
60
 
61
61
  ## Free vs Pro
62
62
 
63
- 61 of the 111 tools are free, including all memory, upkeep and export tools and the 22
64
- infrastructure tools (Jenkins, OKD/OpenShift, Terraform). Pro adds writing and patching,
63
+ 41 of the 91 tools are free, including all memory, upkeep and export tools. Pro adds writing and patching,
65
64
  `search_workspace`, `run_workspace_command`, static analysis, PR review and auto-heal.
66
65
 
67
66
  | | Free | Pro |
@@ -70,7 +69,7 @@ infrastructure tools (Jenkins, OKD/OpenShift, Terraform). Pro adds writing and p
70
69
  | Context | `read_workspace_file`, `scrub_privacy`, `token_budget`, `token_receipt`, `auto_context_bundle` | `get_ast_hologram`, `smart_file_slice`, `get_symbol_surgical_context` |
71
70
  | Workspace | — | `apply_workspace_patch`, `write_workspace_file`, `run_workspace_command`, `validate_patch_sandbox`, `surgical_ast_insert` |
72
71
  | Analysis & review | `type_coverage_report`, `git_blame_heat` | `depgraph`, `entropy_score`, `refactor`, `review_diff`, `review_pr`, `test_oracle` |
73
- | Infrastructure | all 22 `infra_*`, `jenkins_*`, `okd_*`, `terraform_*` | — |
72
+ | Monolith analysis | `infra_analyze_monolith`, `infra_suggest_split` (not advertised; via `lemma_toolbox`) | — |
74
73
 
75
74
  Without a license, Pro tools aren't advertised to the model at all. Full list:
76
75
  `lemma_toolbox { "action": "list" }`. Get Pro: `lemma activate <key>` →
@@ -87,8 +86,12 @@ Without a license, Pro tools aren't advertised to the model at all. Full list:
87
86
  | Claude Desktop / any MCP client | `{ "command": "npx", "args": ["-y", "@nxuss/lemma", "mcp"] }` |
88
87
 
89
88
  `lemma init` also installs the hooks that feed the Brain (git `post-commit` / `post-merge` /
90
- `post-checkout`, and post-tool hooks for Claude Code, Codex, Cursor and OpenCode). Existing hooks
91
- are kept; `--no-hooks` skips them. Health check: `lemma doctor`.
89
+ `post-checkout`, and post-tool hooks for Claude Code, Codex, Cursor and OpenCode). In Claude Code
90
+ it adds a `SessionStart` briefing and a prompt-time recall too, and pre-approves the read and
91
+ memory tools so using them never costs a permission prompt. Existing hooks are kept; `--no-hooks`
92
+ skips them. An install from an older version gets the missing Claude Code hooks the next time the
93
+ MCP server starts; re-run `lemma init` after upgrading to refresh the agent rules. Health check:
94
+ `lemma doctor`.
92
95
 
93
96
  ### CLI
94
97
 
@@ -4,16 +4,16 @@
4
4
  /**
5
5
  * Feeds The Brain from sources the model never has to remember to store manually.
6
6
  *
7
- * Meant to be wired to a git post-commit hook so every commit becomes a searchable memory
8
- * without depending on the assistant calling `store_memory`:
7
+ * Commit ingestion is opt-in (`--commits`). It used to run on every commit from a post-commit
8
+ * hook, and on Lemma's own repo it made 295 of 339 memories — a copy of `git log`, recalled
9
+ * twice in total, that crowded out the memories written on purpose. Hooks an older `lemma init`
10
+ * installed still call this with no flags; that is now a no-op for commits.
9
11
  *
10
- * echo 'lemma-brain-ingest "$(git rev-parse --show-toplevel)" &' >> .git/hooks/post-commit
12
+ * With `--commits` it's an incremental catch-up: a marker file under .lemma/session/ tracks the
13
+ * last commit ingested, so repeated runs never double-store. `--max N` only matters the first
14
+ * time there is no marker yet. `--no-commits` is accepted and ignored (older hooks pass it).
11
15
  *
12
- * With no flags it's an incremental catch-up: a marker file under .lemma/session/ tracks the
13
- * last commit ingested, so running this after every commit or by hand both take the same path
14
- * and never double-store. `--max N` only matters the first time there is no marker yet.
15
- *
16
- * Usage: lemma-brain-ingest [projectRoot] [--max N] [--changelog] [--no-commits] [--team-pull]
16
+ * Usage: lemma-brain-ingest [projectRoot] [--commits [--max N]] [--changelog] [--team-pull]
17
17
  * lemma-brain-ingest --hook-result [--host=claude|codex|cursor|opencode] < payload.json
18
18
  * lemma-brain-ingest --prompt-submit < payload.json
19
19
  *
@@ -49,12 +49,27 @@ function readStdin() {
49
49
  }
50
50
  }
51
51
 
52
- function hookResult(args) {
52
+ // Tell the dashboard which memories a note offered (see reportRecall). Awaited: this process
53
+ // exits as soon as it has answered the host, and an unfinished request would die with it.
54
+ async function reportOffered(dist, root, notes) {
55
+ try {
56
+ const { reportRecall } = require(path.join(dist, 'utils', 'reportSavings.js'));
57
+ const { repoRoot } = require(path.join(dist, 'subconscious', 'TeamBrain.js'));
58
+ const projectPath = repoRoot(root || process.cwd());
59
+ await Promise.all(
60
+ notes.filter((n) => n && n.offered.length > 0).map((n) => reportRecall({ projectPath, trigger: n.trigger, memoryIds: n.offered }))
61
+ );
62
+ } catch {
63
+ // Reporting is bookkeeping; the note itself already went to the host.
64
+ }
65
+ }
66
+
67
+ async function hookResult(args) {
53
68
  const dist = path.join(__dirname, '..', 'dist', 'cjs');
54
- let recordHookPayload, recallForHookPayload, normalizeHostPayload, formatHostOutput, parseHost;
69
+ let recordHookPayload, hookRecall, normalizeHostPayload, formatHostOutput, parseHost;
55
70
  try {
56
71
  ({ recordHookPayload } = require(path.join(dist, 'utils', 'FixCapture.js')));
57
- ({ recallForHookPayload } = require(path.join(dist, 'subconscious', 'HostRecall.js')));
72
+ ({ hookRecall } = require(path.join(dist, 'subconscious', 'HostRecall.js')));
58
73
  ({ normalizeHostPayload, formatHostOutput, parseHost } = require(path.join(dist, 'subconscious', 'HostAdapters.js')));
59
74
  } catch {
60
75
  return; // no build — a hook must stay silent and harmless
@@ -68,23 +83,30 @@ function hookResult(args) {
68
83
  return;
69
84
  }
70
85
  const notes = [];
86
+ const recalled = [];
87
+ let root;
71
88
  for (const payload of normalizeHostPayload(host, raw)) {
72
89
  try {
73
90
  const res = recordHookPayload(payload, payload.cwd);
74
91
  if (res && res.captured) console.error(res.note.trim());
75
92
  } catch { /* capture failing must not cost the recall below */ }
76
- const note = recallForHookPayload(payload, payload.cwd);
77
- if (note && !notes.includes(note)) notes.push(note);
93
+ const recall = hookRecall(payload, payload.cwd);
94
+ if (recall && !notes.includes(recall.text)) {
95
+ notes.push(recall.text);
96
+ recalled.push(recall);
97
+ root = root || payload.cwd;
98
+ }
78
99
  }
79
100
  const out = formatHostOutput(host, notes.join('\n'));
80
101
  if (out) process.stdout.write(out);
102
+ await reportOffered(dist, root, recalled);
81
103
  }
82
104
 
83
- function promptSubmit() {
105
+ async function promptSubmit() {
84
106
  const dist = path.join(__dirname, '..', 'dist', 'cjs');
85
- let recallForPrompt, formatHostOutput;
107
+ let promptRecall, formatHostOutput;
86
108
  try {
87
- ({ recallForPrompt } = require(path.join(dist, 'subconscious', 'HostRecall.js')));
109
+ ({ promptRecall } = require(path.join(dist, 'subconscious', 'HostRecall.js')));
88
110
  ({ formatHostOutput } = require(path.join(dist, 'subconscious', 'HostAdapters.js')));
89
111
  } catch {
90
112
  return; // no build — a hook must stay silent and harmless
@@ -95,18 +117,53 @@ function promptSubmit() {
95
117
  } catch {
96
118
  return;
97
119
  }
98
- const out = formatHostOutput('claude', recallForPrompt(payload, payload && payload.cwd, undefined, { mcpEntry: path.join(dist, 'mcp', 'index.js') }), 'UserPromptSubmit');
120
+ const recall = promptRecall(payload, payload && payload.cwd, undefined, { mcpEntry: path.join(dist, 'mcp', 'index.js') });
121
+ const out = formatHostOutput('claude', recall ? recall.text : '', 'UserPromptSubmit');
122
+ if (out) process.stdout.write(out);
123
+ await reportOffered(dist, payload && payload.cwd, [recall]);
124
+ }
125
+
126
+ // SessionStart hook (Claude Code): the Brain's briefing and the Lemma playbook, in context
127
+ // before the first prompt — no tool call for the agent to remember or skip.
128
+ async function sessionStart() {
129
+ const dist = path.join(__dirname, '..', 'dist', 'cjs');
130
+ let sessionRecall, formatHostOutput;
131
+ try {
132
+ ({ sessionRecall } = require(path.join(dist, 'subconscious', 'HostRecall.js')));
133
+ ({ formatHostOutput } = require(path.join(dist, 'subconscious', 'HostAdapters.js')));
134
+ } catch {
135
+ return;
136
+ }
137
+ let payload = {};
138
+ try {
139
+ payload = JSON.parse(readStdin()) || {};
140
+ } catch {
141
+ // No payload is fine: the briefing only needs a directory.
142
+ }
143
+ // Work that landed since the last session began becomes a "store what you learned" reminder
144
+ // for the first prompt — no SessionEnd hook needed, which no installer wires up.
145
+ try {
146
+ const { draftSinceLastSession } = require(path.join(dist, 'utils', 'StoreDraft.js'));
147
+ const { repoRoot } = require(path.join(dist, 'subconscious', 'TeamBrain.js'));
148
+ draftSinceLastSession(repoRoot(payload.cwd || process.cwd()));
149
+ } catch {
150
+ // the reminder is a courtesy; the briefing must still go out
151
+ }
152
+ const recall = sessionRecall(payload, payload.cwd);
153
+ const out = formatHostOutput('claude', recall ? recall.text : '', 'SessionStart');
99
154
  if (out) process.stdout.write(out);
155
+ await reportOffered(dist, payload.cwd, [recall]);
100
156
  }
101
157
 
102
- function main() {
158
+ async function main() {
103
159
  const args = process.argv.slice(2);
160
+ if (args.includes('--session-start')) return sessionStart();
104
161
  if (args.includes('--prompt-submit')) return promptSubmit();
105
162
  if (args.includes('--hook-result')) return hookResult(args);
106
163
  const maxIndex = args.indexOf('--max');
107
164
  const maxCommits = maxIndex >= 0 ? parseInt(args[maxIndex + 1], 10) : undefined;
108
165
  const includeChangelog = args.includes('--changelog');
109
- const includeCommits = !args.includes('--no-commits');
166
+ const includeCommits = args.includes('--commits');
110
167
  const teamPull = args.includes('--team-pull');
111
168
  const positional = args.filter((a, i) => !a.startsWith("--") && (maxIndex < 0 || i !== maxIndex + 1));
112
169
  const projectRoot = path.resolve(positional[0] || process.cwd());
@@ -156,11 +213,13 @@ function flushBrain() {
156
213
  }
157
214
  }
158
215
 
159
- try {
160
- main();
161
- } catch (err) {
162
- // A hook that fails must never be the reason a commit or session goes bad.
163
- console.error('[lemma-brain-ingest] Skipped:', err && err.message);
164
- }
165
- flushBrain();
166
- process.exit(0);
216
+ (async () => {
217
+ try {
218
+ await main();
219
+ } catch (err) {
220
+ // A hook that fails must never be the reason a commit or session goes bad.
221
+ console.error('[lemma-brain-ingest] Skipped:', err && err.message);
222
+ }
223
+ flushBrain();
224
+ process.exit(0);
225
+ })();
package/bin/doctor.js CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  /**
5
5
  * Lemma doctor — verifies the Lemma wiring on this machine / project:
6
- * wrapper, project skill, user skill (muse), and AGENTS.md block.
6
+ * wrapper, project skill, user skill (muse), AGENTS.md block, and Claude Code hooks/permissions.
7
7
  *
8
8
  * Usage: `lemma doctor` (exit 0 = usable, exit 1 = wrapper broken).
9
9
  */
@@ -111,10 +111,37 @@ async function main() {
111
111
  const agentsPath = path.join(cwd, 'AGENTS.md');
112
112
  if (!fs.existsSync(agentsPath) || !fs.readFileSync(agentsPath, 'utf8').includes('@nxuss/lemma')) {
113
113
  warn('no Lemma block in ./AGENTS.md — run `lemma init`');
114
- } else if (fs.readFileSync(agentsPath, 'utf8').includes('At session')) {
115
- ok('AGENTS.md block current (session-start guard)');
114
+ } else if (fs.readFileSync(agentsPath, 'utf8').includes('## Triggers')) {
115
+ ok('AGENTS.md block current (trigger-based rules)');
116
116
  } else {
117
- warn('AGENTS.md block is stale (pre Muse guard) — re-run `lemma init`');
117
+ warn('AGENTS.md block is stale (pre trigger rules) — re-run `lemma init`');
118
+ }
119
+
120
+ // 5. Claude Code hooks + permissions — what makes the Brain speak without being asked.
121
+ const claudeLocal = path.join(cwd, '.claude', 'settings.local.json');
122
+ let claudeSettings = null;
123
+ try {
124
+ claudeSettings = JSON.parse(fs.readFileSync(claudeLocal, 'utf8'));
125
+ } catch {
126
+ // missing or unreadable — reported below
127
+ }
128
+ if (!claudeSettings) {
129
+ warn('no .claude/settings.local.json — run `lemma init` for Claude Code hooks');
130
+ } else {
131
+ const hooksText = JSON.stringify(claudeSettings.hooks || {});
132
+ const missing = [
133
+ ['PostToolUse', 'lemma-brain-ingest --hook-result'],
134
+ ['UserPromptSubmit', 'lemma-brain-ingest --prompt-submit'],
135
+ ['SessionStart', 'lemma-brain-ingest --session-start'],
136
+ ].filter(([, mark]) => !hooksText.includes(mark)).map(([event]) => event);
137
+ if (missing.length === 0) ok('Claude Code hooks current (PostToolUse, UserPromptSubmit, SessionStart)');
138
+ else warn(`Claude Code hooks missing: ${missing.join(', ')} — re-run \`lemma init\` (or restart the MCP server: it repairs an existing install)`);
139
+
140
+ const allow = (claudeSettings.permissions && claudeSettings.permissions.allow) || [];
141
+ const core = ['search_memory', 'get_memory', 'verify_memory', 'store_memory', 'update_memory', 'read_workspace_file', 'search_workspace'];
142
+ const unallowed = core.filter((t) => !allow.includes(`mcp__lemma__${t}`) && !allow.includes('mcp__lemma'));
143
+ if (unallowed.length === 0) ok('core Lemma tools pre-approved (no permission prompt)');
144
+ else warn(`core Lemma tools still prompt for permission: ${unallowed.join(', ')} — re-run \`lemma init\``);
118
145
  }
119
146
 
120
147
  process.stdout.write(`\n ${DIM}Brain: ~/.lemma-cache/lemma_brain.json · proxy: lemma-proxy.cjs status${RESET}\n\n`);
package/bin/init.js CHANGED
@@ -260,17 +260,41 @@ function loadLemmaToolNames() {
260
260
  }
261
261
 
262
262
  const LEMMA_TOOL_NAMES = loadLemmaToolNames();
263
- const LEMMA_MCP_TOOLS = LEMMA_TOOL_NAMES.map((name) => `mcp__lemma__${name}`);
263
+ // Pre-approved in Claude Code: reading, searching and the Brain's lifecycle — local, and nothing
264
+ // a native Read/Grep couldn't already do. Tools that write code (apply_workspace_patch,
265
+ // surgical_ast_insert), run commands (run_workspace_command), delete (forget_memory) or
266
+ // dispatch arbitrary tools (lemma_toolbox) still ask.
267
+ const LEMMA_PREAPPROVED_TOOLS = [
268
+ 'search_memory', 'get_memory', 'verify_memory', 'store_memory', 'update_memory', 'refresh_memory',
269
+ 'downvote_memory', 'read_workspace_file', 'list_workspace_dir', 'search_workspace', 'smart_file_slice',
270
+ 'get_ast_hologram', 'get_symbol_surgical_context', 'output_region', 'get_project_onboarding',
271
+ 'state_hash_cache', 'smarter_cache', 'token_receipt', 'get_routing_advice',
272
+ ].map((name) => `mcp__lemma__${name}`);
264
273
 
265
274
  const CLAUDE_MD_CONTENT = `# Lemma MCP — Cómo usar las herramientas de este proyecto
266
275
 
267
- Tienes conectado el servidor MCP \`lemma\`. Úsalo cuando aporte algo real — caché verificable,
268
- scrubbing de secretos, contexto de proyecto ya indexado — no como sustituto automático de tus
269
- herramientas nativas en cada caso. Si una tool de Lemma no encaja con lo que necesitas hacer,
270
- usa la herramienta nativa; una regla que te obliga a usar la tool equivocada para ahorrar
271
- tokens sale más cara que los tokens que ahorra.
276
+ Tienes conectado el servidor MCP \`lemma\`. Lo que hace que las herramientas nativas no pueden
277
+ es **recordar entre sesiones**: el Brain guarda fixes y decisiones verificadas, y avisa cuando el
278
+ código del que dependen cambió. Ese valor solo existe si se consulta y se alimenta, así que estos
279
+ momentos no son opcionales:
272
280
 
273
- ## Por defecto, para esto sí conviene usar Lemma
281
+ ## Disparadores — haz esto siempre
282
+
283
+ | Cuando… | Llama | Por qué no basta lo nativo |
284
+ |---|---|---|
285
+ | Vas a investigar un bug, un error o un "¿por qué X?" | \`mcp__lemma__search_memory\` con el texto del error o la pregunta | Puede que ya esté resuelto; \`grep\` no encuentra lo que se aprendió en otra sesión |
286
+ | Un aviso 🧠 de Lemma nombra memorias | \`mcp__lemma__get_memory\` de la primera | El aviso trae solo el titular; el cuerpo tiene los archivos y el porqué |
287
+ | Un fix quedó verificado (tests pasan, build ok, el usuario confirmó) | \`mcp__lemma__store_memory\` con \`filePaths\`: la causa raíz, la trampa o lo que no funcionó — no un resumen de qué cambió | Si no se guarda, la próxima sesión lo vuelve a investigar desde cero; un resumen de cambios ya está en git log y nadie lo vuelve a buscar |
288
+ | Una memoria resultó desactualizada o incorrecta | \`mcp__lemma__update_memory\` / \`forget_memory\` | Guardar otra al lado deja dos versiones y la búsqueda mezcla ambas |
289
+ | Vas a leer código que aún no ubicaste, o que puede tener secretos | \`mcp__lemma__search_workspace\` / \`read_workspace_file\` | Enmascaran API keys antes de que entren a tu contexto |
290
+
291
+ Si las tools de Lemma te llegan diferidas (solo el nombre), cárgalas en **una sola** llamada a
292
+ ToolSearch: \`select:mcp__lemma__search_memory,mcp__lemma__get_memory,mcp__lemma__verify_memory,mcp__lemma__store_memory,mcp__lemma__update_memory,mcp__lemma__read_workspace_file,mcp__lemma__search_workspace\`.
293
+
294
+ Fuera de esos momentos usa tu criterio: para un archivo chico que ya ubicaste, \`Read\` nativo
295
+ cuesta menos que el ida y vuelta, y para procesos, puertos o git Lemma no tiene nada que aportar.
296
+
297
+ ## Referencia: qué tool para qué
274
298
 
275
299
  | Tarea | Tool de Lemma | Por qué |
276
300
  |---|---|---|
@@ -312,14 +336,13 @@ No le pidas que pegue archivos, logs o documentación que puedes obtener tú: ag
312
336
 
313
337
  ## Al iniciar en este proyecto
314
338
 
315
- 1. Llama \`mcp__lemma__get_project_onboarding\` para orientarte con el contexto ya indexado.
316
- 2. Si el problema se parece a algo ya resuelto, llama \`mcp__lemma__search_memory\`.
317
- 3. No lo trates como un hecho hasta verificarlo contra el estado actual del código.
339
+ El hook \`SessionStart\` de Lemma ya te dio un resumen del Brain al arrancar (si no lo ves,
340
+ \`lemma doctor\` dice qué falta). Para más contexto: \`mcp__lemma__get_project_onboarding\`.
341
+ Lo que venga del Brain no es un hecho hasta verificarlo contra el estado actual del código.
318
342
 
319
- ## Al reportar o investigar un bug
343
+ ## Al investigar un bug, además
320
344
 
321
- 1. \`mcp__lemma__search_memory\` con el mensaje de error, por si ya se resolvió algo parecido.
322
- 2. \`lemma_toolbox\` → \`get_telepathic_hints\` con el archivo relevante para contexto de runtime.
345
+ \`lemma_toolbox\` → \`get_telepathic_hints\` con el archivo relevante para contexto de runtime.
323
346
 
324
347
  ## Una sola regla dura
325
348
 
@@ -342,6 +365,13 @@ function configureClaudeCode() {
342
365
  const existingMd = fs.readFileSync(claudeMdPath, 'utf8');
343
366
  if (!existingMd.includes('@nxuss/lemma')) {
344
367
  fs.appendFileSync(claudeMdPath, '\n---\n\n' + CLAUDE_MD_CONTENT, 'utf8');
368
+ } else {
369
+ // Lemma's block — an older one ("úsalo cuando aporte algo real") or this one from an earlier
370
+ // release — is replaced in place with the current rules, keeping whatever the user wrote
371
+ // around it. Gating this on "already trigger-based" left every upgrade on stale rules.
372
+ const lemmaBlockRegex = /# Lemma MCP — Cómo usar[\s\S]*?\*Auto-generado por `lemma init` — @nxuss\/lemma\*/;
373
+ const updated = existingMd.replace(lemmaBlockRegex, CLAUDE_MD_CONTENT.trim());
374
+ if (updated !== existingMd) fs.writeFileSync(claudeMdPath, updated, 'utf8');
345
375
  }
346
376
  } else {
347
377
  fs.writeFileSync(claudeMdPath, CLAUDE_MD_CONTENT, 'utf8');
@@ -363,11 +393,17 @@ function configureClaudeCode() {
363
393
  );
364
394
  settings.enableAllProjectMcpServers = true;
365
395
 
366
- // Rebuild Lemma tool permissions from the current catalog while preserving non-Lemma tools.
367
- const preservedTools = (settings.allowedTools || []).filter(
368
- (tool) => !tool.startsWith('mcp__lemma__')
369
- );
370
- settings.allowedTools = [...preservedTools, ...LEMMA_MCP_TOOLS];
396
+ // Pre-approve the core tools in permissions.allow — the key Claude Code reads from settings
397
+ // files. Earlier versions wrote the whole catalog to a top-level `allowedTools`, which left the
398
+ // tools the playbook asks for (get_memory, update_memory, ...) prompting on every call: a
399
+ // prompt per call is reason enough for an agent to fall back to its native tools. Lemma's
400
+ // entries are dropped from the legacy key; anything else in it is the user's and stays.
401
+ const legacy = (settings.allowedTools || []).filter((tool) => !tool.startsWith('mcp__lemma__'));
402
+ if (legacy.length > 0) settings.allowedTools = legacy;
403
+ else delete settings.allowedTools;
404
+ settings.permissions = settings.permissions && typeof settings.permissions === 'object' ? settings.permissions : {};
405
+ const allow = Array.isArray(settings.permissions.allow) ? settings.permissions.allow : [];
406
+ settings.permissions.allow = Array.from(new Set([...allow, ...LEMMA_PREAPPROVED_TOOLS]));
371
407
 
372
408
  fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
373
409
 
@@ -428,13 +464,13 @@ function configureClaudeCodeGateway(anthropicApiKey) {
428
464
  return { activated: true, settingsPath: claudeSettingsPath };
429
465
  }
430
466
 
431
- const LEMMA_RULES_CONTENT = `# Lemma MCP — Autonomous Behaviors
432
-
433
- > ⚠️ MANDATORY RULES — Follow without exception **for MCP-native clients**.
467
+ const LEMMA_RULES_CONTENT = `# Lemma MCP — When to use it
434
468
 
435
- The MCP server \`lemma\` is connected. For clients with native MCP support
436
- (Claude Code, Cursor, Codex, Windsurf, Kiro, OpenCode), NEVER use native tools
437
- when a Lemma equivalent exists.
469
+ The MCP server \`lemma\` is connected. What it does that your native tools can't is
470
+ **remember across sessions**: the Brain keeps verified fixes and decisions and flags them when
471
+ the code they depend on changes. That only pays off if it is consulted and fed, so the moments
472
+ below are not optional for MCP-native clients (Claude Code, Cursor, Codex, Windsurf, Kiro,
473
+ OpenCode).
438
474
 
439
475
  > **Muse Code:** you DO NOT have native \`mcp__lemma__*\` tools. At session
440
476
  > start, load the \`lemma\` skill (user scope if present, else
@@ -444,36 +480,34 @@ when a Lemma equivalent exists.
444
480
  > hard block; use \`lemma call\` when it actually helps. If no \`lemma\` skill
445
481
  > is installed, tell the user to run \`npx @nxuss/lemma init\`.
446
482
 
447
- ## Mandatory Substitutions (MCP-native clients only)
483
+ ## Triggers — always do these
448
484
 
449
- ## Mandatory Substitutions
485
+ | When… | Call | Why native isn't enough |
486
+ |---|---|---|
487
+ | Session start | \`get_project_onboarding\`, then \`search_memory\` with the task topic | The Brain may already hold the answer |
488
+ | Investigating a bug, an error, or a "why does X" | \`search_memory\` with the error text or question | grep can't find what was learned in another session |
489
+ | A 🧠 Lemma note names memories | \`get_memory\` on the top one | The note carries the headline; the body has the files and the reason |
490
+ | A fix is verified (tests pass, build ok, user confirmed) | \`store_memory\` with \`filePaths\`: the root cause, the trap or what didn't work — not a summary of what changed | Unsaved, the next session investigates it from scratch; a change summary is already in git log and nobody searches for it |
491
+ | A memory turned out outdated or wrong | \`update_memory\` / \`forget_memory\` | A near-duplicate leaves two versions and search mixes them |
492
+ | Reading code you haven't located yet, or that may hold secrets | \`search_workspace\` / \`read_workspace_file\` | They mask API keys before they reach your context |
493
+ | Applying a generated patch | \`validate_patch_sandbox\` first | Validate before writing, not after |
450
494
 
451
- | ❌ NEVER use | ✅ ALWAYS use instead |
452
- |---|---|
453
- | Read / cat / open file | \`read_workspace_file\` |
454
- | Write / save file | \`write_workspace_file\` |
455
- | Create new file | \`create_workspace_file\` |
456
- | List / ls directory | \`list_workspace_dir\` |
457
- | Search / grep in files | \`search_workspace\` |
458
- | Search your own memory | \`search_memory\` |
459
- | Persist solutions | \`store_memory\` |
460
- | Project context | \`get_project_onboarding\` |
461
- | Runtime/bug context | \`get_telepathic_hints\` |
462
- | Apply a patch | \`validate_patch_sandbox\` first |
463
-
464
- ## Mandatory Flow — Session Start
465
-
466
- 1. Call \`get_project_onboarding\` — understand the project
467
- 2. Call \`search_memory\` with the task topic — recall past solutions
468
- 3. When done: call \`store_memory\` with the solution
495
+ Outside those moments, use judgment: for a small file you already located, a native read costs
496
+ less than the round-trip, and for processes, ports or git Lemma has nothing to add.
497
+
498
+ ## Bug Reporting
499
+
500
+ 1. Call \`search_memory\` with the error message
501
+ 2. Call \`get_telepathic_hints\` (via \`lemma_toolbox\`) with the relevant file
469
502
 
470
503
  > Muse: use \`lemma call <tool>\` (or \`node ./lemma-proxy.cjs call <tool>\` in this repo — see \`.agents/skills/lemma/SKILL.md\`).
471
504
 
472
- ## Bug Reporting
505
+ ## One hard rule
473
506
 
474
- 1. Call \`get_telepathic_hints\` with the relevant file
475
- 2. Call \`search_memory\` with the error message
507
+ Any answer that depends on a cache hit, an auto-suggested fix, or a file compressed for your own
508
+ context must be delivered with the real information and without hiding where it came from.
476
509
 
510
+ ---
477
511
  *Auto-generated by \`lemma init\` — @nxuss/lemma*
478
512
  `;
479
513
 
@@ -491,14 +525,14 @@ function updateAgentsMd() {
491
525
  const existing = fs.readFileSync(agentsMdPath, 'utf8');
492
526
  if (!existing.includes('@nxuss/lemma')) {
493
527
  fs.appendFileSync(agentsMdPath, '\n---\n\n' + LEMMA_RULES_CONTENT, 'utf8');
494
- } else if (!existing.includes('Muse Code:') || !existing.includes('MCP-native clients')) {
495
- // Migrate old Lemma AGENTS.md (pre-Muse guard) to new version with Muse compatibility
496
- // Replace the old block in-place to preserve any user content above it
528
+ } else {
529
+ // Replace Lemma's block in place — an older one (pre-Muse guard, the "never use native
530
+ // tools" table) or this one from an earlier release — preserving the user's content.
497
531
  const lemmaBlockRegex = /# Lemma MCP[\s\S]*?\*Auto-generated by `lemma init` — @nxuss\/lemma\*/;
498
532
  if (lemmaBlockRegex.test(existing)) {
499
533
  const updated = existing.replace(lemmaBlockRegex, LEMMA_RULES_CONTENT.trim());
500
- fs.writeFileSync(agentsMdPath, updated, 'utf8');
501
- } else {
534
+ if (updated !== existing) fs.writeFileSync(agentsMdPath, updated, 'utf8');
535
+ } else if (!existing.includes('## Triggers')) {
502
536
  // Fallback: append new block
503
537
  fs.appendFileSync(agentsMdPath, '\n---\n\n' + LEMMA_RULES_CONTENT, 'utf8');
504
538
  }
@@ -527,6 +561,11 @@ function updateWindsurfRules() {
527
561
  const existing = fs.readFileSync(wsRulesPath, 'utf8');
528
562
  if (!existing.includes('@nxuss/lemma')) {
529
563
  fs.appendFileSync(wsRulesPath, '\n---\n\n' + LEMMA_RULES_CONTENT, 'utf8');
564
+ } else {
565
+ // Same in-place refresh as AGENTS.md.
566
+ const lemmaBlockRegex = /# Lemma MCP[\s\S]*?\*Auto-generated by `lemma init` — @nxuss\/lemma\*/;
567
+ const updated = existing.replace(lemmaBlockRegex, LEMMA_RULES_CONTENT.trim());
568
+ if (updated !== existing) fs.writeFileSync(wsRulesPath, updated, 'utf8');
530
569
  }
531
570
  } else {
532
571
  fs.writeFileSync(wsRulesPath, LEMMA_RULES_CONTENT, 'utf8');
@@ -754,12 +793,10 @@ function ensureKiroMigratesAgentsMd() {
754
793
  try {
755
794
  if (fs.existsSync(agentsMdPath)) {
756
795
  const existing = fs.readFileSync(agentsMdPath, 'utf8');
757
- if (existing.includes('@nxuss/lemma') && (!existing.includes('Muse Code:') || !existing.includes('MCP-native clients'))) {
796
+ if (existing.includes('@nxuss/lemma')) {
758
797
  const lemmaBlockRegex = /# Lemma MCP[\s\S]*?\*Auto-generated by `lemma init` — @nxuss\/lemma\*/;
759
- if (lemmaBlockRegex.test(existing)) {
760
- const updated = existing.replace(lemmaBlockRegex, LEMMA_RULES_CONTENT.trim());
761
- fs.writeFileSync(agentsMdPath, updated, 'utf8');
762
- }
798
+ const updated = existing.replace(lemmaBlockRegex, LEMMA_RULES_CONTENT.trim());
799
+ if (updated !== existing) fs.writeFileSync(agentsMdPath, updated, 'utf8');
763
800
  }
764
801
  }
765
802
  } catch {}
@@ -909,7 +946,7 @@ function parseInitArgs(argv = process.argv) {
909
946
  };
910
947
  }
911
948
 
912
- // The hooks that feed the Brain (git post-commit/post-merge/post-checkout, and the PostToolUse
949
+ // The hooks that feed the Brain (git post-merge/post-checkout, and the PostToolUse
913
950
  // hook of each agent host) live in src/cli/{gitHooks,hostHooks}.ts. They were only wired into the
914
951
  // commander `init` in src/cli/lemma-proxy.ts, which the `lemma` binary (lemma-proxy.cjs → this
915
952
  // file) never reaches — so `lemma init` reported success and installed none of them.
@@ -929,6 +966,7 @@ function installBrainFeeds(cwd = process.cwd(), home = os.homedir(), mods = null
929
966
  if (hooks.manual) lines.push(`Git hooks live in versioned ${hooks.manual.hooksDir}/ — not touching them. To feed the Brain, add:\n${hooks.manual.snippet}`);
930
967
  else if (changed.length > 0) lines.push(`Git hooks feed the Brain (${changed.join(', ')})`);
931
968
  else if (hooks.skippedReason) lines.push(`Git hooks skipped: ${hooks.skippedReason}`);
969
+ if (hooks.removed && hooks.removed.length > 0) lines.push(`Git hooks no longer store every commit in the Brain (removed from ${hooks.removed.join(', ')})`);
932
970
  for (const { host: name, outcome } of host.installHostHooks(cwd, home)) {
933
971
  if (outcome.status === 'manual') lines.push(`${outcome.file} couldn't be merged safely — not touching it. For ${name}, add:\n${outcome.snippet}`);
934
972
  else if (outcome.status !== 'unchanged') lines.push(`${name} hook ${outcome.status} (${outcome.file})`);
@@ -1025,7 +1063,7 @@ async function main(argv = process.argv) {
1025
1063
  --gateway Reroute this user's Claude Code model traffic through the proxy
1026
1064
  (~/.claude/settings.json). Requires ANTHROPIC_API_KEY in env.
1027
1065
  Without it, Claude Code keeps its own auth untouched.
1028
- --no-hooks Skip the hooks that feed the Brain (git post-commit/post-merge/
1066
+ --no-hooks Skip the hooks that feed the Brain (git post-merge/
1029
1067
  post-checkout; Claude Code, Codex, Cursor and OpenCode tool hooks).
1030
1068
 
1031
1069
  `);
@@ -1171,4 +1209,4 @@ if (require.main === module) {
1171
1209
  });
1172
1210
  }
1173
1211
 
1174
- module.exports = { main, configureMuse, configureMuseUserSkill, updateAgentsMd, MUSE_SKILL_CONTENT, LEMMA_RULES_CONTENT, installProxyDaemon, removeProxyDaemon, parseInitArgs, createEnvFile, installBrainFeeds };
1212
+ module.exports = { main, configureMuse, configureMuseUserSkill, updateAgentsMd, configureClaudeCode, MUSE_SKILL_CONTENT, LEMMA_RULES_CONTENT, CLAUDE_MD_CONTENT, installProxyDaemon, removeProxyDaemon, parseInitArgs, createEnvFile, installBrainFeeds };