@rubytech/create-sitedesk-code 0.1.340

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 (2951) hide show
  1. package/dist/__tests__/account-id-env.test.js +48 -0
  2. package/dist/__tests__/apt-resolve.test.js +179 -0
  3. package/dist/__tests__/base-toolchain-deps.test.js +67 -0
  4. package/dist/__tests__/brand-fonts.test.js +102 -0
  5. package/dist/__tests__/brew-install.test.js +151 -0
  6. package/dist/__tests__/brew-resolve.test.js +138 -0
  7. package/dist/__tests__/bundler-rewrite-platform-lib.test.js +68 -0
  8. package/dist/__tests__/cdp-port-no-silent-fallback.test.js +53 -0
  9. package/dist/__tests__/claude-ptys-slice.test.js +25 -0
  10. package/dist/__tests__/cloudflared-slice.test.js +20 -0
  11. package/dist/__tests__/cloudflared-version-pin.test.js +24 -0
  12. package/dist/__tests__/entitlement-flag.test.js +43 -0
  13. package/dist/__tests__/init-logging.test.js +85 -0
  14. package/dist/__tests__/install-immutability.test.js +55 -0
  15. package/dist/__tests__/installer-settings-permissions.test.js +220 -0
  16. package/dist/__tests__/installer-specialist-registration.test.js +116 -0
  17. package/dist/__tests__/launchd-plist.test.js +195 -0
  18. package/dist/__tests__/macos-darwin-branch.test.js +83 -0
  19. package/dist/__tests__/macos-version.test.js +96 -0
  20. package/dist/__tests__/peer-brand-detect.test.js +103 -0
  21. package/dist/__tests__/platform-detect.test.js +50 -0
  22. package/dist/__tests__/platform-port-stamp.test.js +28 -0
  23. package/dist/__tests__/plugin-install.test.js +145 -0
  24. package/dist/__tests__/port-canonicalisation.test.js +200 -0
  25. package/dist/__tests__/preflight-port-classifier.test.js +330 -0
  26. package/dist/__tests__/premium-bundle-gate.test.js +59 -0
  27. package/dist/__tests__/premium-mcp-discover.test.js +127 -0
  28. package/dist/__tests__/samba-provision.test.js +294 -0
  29. package/dist/__tests__/snap-chromium.test.js +115 -0
  30. package/dist/__tests__/tier-flag.test.js +53 -0
  31. package/dist/__tests__/watchdog-deferred-arming.test.js +64 -0
  32. package/dist/apt-resolve.js +73 -0
  33. package/dist/brew-install.js +180 -0
  34. package/dist/brew-resolve.js +68 -0
  35. package/dist/bundler-rewrite-platform-lib.js +29 -0
  36. package/dist/index.js +4418 -0
  37. package/dist/init-logging.js +28 -0
  38. package/dist/install-immutability.js +59 -0
  39. package/dist/launchd-plist.js +68 -0
  40. package/dist/lib/plugin-install.js +126 -0
  41. package/dist/lib/premium-mcp-discover.js +41 -0
  42. package/dist/macos-version.js +53 -0
  43. package/dist/peer-brand-detect.js +39 -0
  44. package/dist/permissions-seed.js +147 -0
  45. package/dist/pinned-binaries.js +12 -0
  46. package/dist/platform-detect.js +36 -0
  47. package/dist/port-resolution.js +209 -0
  48. package/dist/preflight-port-classifier.js +222 -0
  49. package/dist/samba-provision.js +275 -0
  50. package/dist/snap-chromium.js +88 -0
  51. package/dist/specialist-registration.js +78 -0
  52. package/dist/tier-flag.js +85 -0
  53. package/dist/uninstall.js +952 -0
  54. package/package.json +35 -0
  55. package/payload/platform/.docs/search-surface-contract.md +58 -0
  56. package/payload/platform/config/brand-registry.json +28 -0
  57. package/payload/platform/config/brand.json +82 -0
  58. package/payload/platform/docs/superpowers/plans/2026-06-02-task-610-follower-202-retry.md +372 -0
  59. package/payload/platform/docs/superpowers/plans/2026-06-04-public-agent-knowledge-delivery.md +230 -0
  60. package/payload/platform/docs/superpowers/specs/2026-06-02-task-610-follower-202-retry-design.md +116 -0
  61. package/payload/platform/lib/account-enumeration/dist/__tests__/enumerate.test.d.ts +2 -0
  62. package/payload/platform/lib/account-enumeration/dist/__tests__/enumerate.test.d.ts.map +1 -0
  63. package/payload/platform/lib/account-enumeration/dist/__tests__/enumerate.test.js +88 -0
  64. package/payload/platform/lib/account-enumeration/dist/__tests__/enumerate.test.js.map +1 -0
  65. package/payload/platform/lib/account-enumeration/dist/__tests__/validate-env.test.d.ts +2 -0
  66. package/payload/platform/lib/account-enumeration/dist/__tests__/validate-env.test.d.ts.map +1 -0
  67. package/payload/platform/lib/account-enumeration/dist/__tests__/validate-env.test.js +55 -0
  68. package/payload/platform/lib/account-enumeration/dist/__tests__/validate-env.test.js.map +1 -0
  69. package/payload/platform/lib/account-enumeration/dist/index.d.ts +82 -0
  70. package/payload/platform/lib/account-enumeration/dist/index.d.ts.map +1 -0
  71. package/payload/platform/lib/account-enumeration/dist/index.js +185 -0
  72. package/payload/platform/lib/account-enumeration/dist/index.js.map +1 -0
  73. package/payload/platform/lib/account-enumeration/src/__tests__/enumerate.test.ts +94 -0
  74. package/payload/platform/lib/account-enumeration/src/__tests__/validate-env.test.ts +57 -0
  75. package/payload/platform/lib/account-enumeration/src/index.ts +218 -0
  76. package/payload/platform/lib/account-enumeration/tsconfig.json +8 -0
  77. package/payload/platform/lib/admin-access-password/__tests__/index.test.ts +142 -0
  78. package/payload/platform/lib/admin-access-password/dist/index.d.ts +49 -0
  79. package/payload/platform/lib/admin-access-password/dist/index.d.ts.map +1 -0
  80. package/payload/platform/lib/admin-access-password/dist/index.js +198 -0
  81. package/payload/platform/lib/admin-access-password/dist/index.js.map +1 -0
  82. package/payload/platform/lib/admin-access-password/src/index.ts +176 -0
  83. package/payload/platform/lib/admin-access-password/tsconfig.json +8 -0
  84. package/payload/platform/lib/admin-conversation-purge/dist/index.d.ts +54 -0
  85. package/payload/platform/lib/admin-conversation-purge/dist/index.d.ts.map +1 -0
  86. package/payload/platform/lib/admin-conversation-purge/dist/index.js +84 -0
  87. package/payload/platform/lib/admin-conversation-purge/dist/index.js.map +1 -0
  88. package/payload/platform/lib/admin-conversation-purge/src/index.ts +120 -0
  89. package/payload/platform/lib/admin-conversation-purge/tsconfig.json +8 -0
  90. package/payload/platform/lib/admins-write/dist/index.d.ts +86 -0
  91. package/payload/platform/lib/admins-write/dist/index.d.ts.map +1 -0
  92. package/payload/platform/lib/admins-write/dist/index.js +245 -0
  93. package/payload/platform/lib/admins-write/dist/index.js.map +1 -0
  94. package/payload/platform/lib/admins-write/src/index.ts +305 -0
  95. package/payload/platform/lib/admins-write/tsconfig.json +8 -0
  96. package/payload/platform/lib/aeo-llms-txt-writer/dist/index.d.ts +33 -0
  97. package/payload/platform/lib/aeo-llms-txt-writer/dist/index.d.ts.map +1 -0
  98. package/payload/platform/lib/aeo-llms-txt-writer/dist/index.js +119 -0
  99. package/payload/platform/lib/aeo-llms-txt-writer/dist/index.js.map +1 -0
  100. package/payload/platform/lib/aeo-llms-txt-writer/src/index.ts +172 -0
  101. package/payload/platform/lib/aeo-llms-txt-writer/tsconfig.json +8 -0
  102. package/payload/platform/lib/anthropic-key/dist/index.d.ts +22 -0
  103. package/payload/platform/lib/anthropic-key/dist/index.d.ts.map +1 -0
  104. package/payload/platform/lib/anthropic-key/dist/index.js +232 -0
  105. package/payload/platform/lib/anthropic-key/dist/index.js.map +1 -0
  106. package/payload/platform/lib/brand-templating/dist/index.d.ts +18 -0
  107. package/payload/platform/lib/brand-templating/dist/index.d.ts.map +1 -0
  108. package/payload/platform/lib/brand-templating/dist/index.js +69 -0
  109. package/payload/platform/lib/brand-templating/dist/index.js.map +1 -0
  110. package/payload/platform/lib/brand-templating/src/index.ts +76 -0
  111. package/payload/platform/lib/brand-templating/tsconfig.json +8 -0
  112. package/payload/platform/lib/device-url/dist/index.d.ts +44 -0
  113. package/payload/platform/lib/device-url/dist/index.d.ts.map +1 -0
  114. package/payload/platform/lib/device-url/dist/index.js +68 -0
  115. package/payload/platform/lib/device-url/dist/index.js.map +1 -0
  116. package/payload/platform/lib/device-url/src/index.ts +78 -0
  117. package/payload/platform/lib/device-url/tsconfig.json +8 -0
  118. package/payload/platform/lib/embed-client/dist/index.d.ts +6 -0
  119. package/payload/platform/lib/embed-client/dist/index.d.ts.map +1 -0
  120. package/payload/platform/lib/embed-client/dist/index.js +93 -0
  121. package/payload/platform/lib/embed-client/dist/index.js.map +1 -0
  122. package/payload/platform/lib/embed-client/src/index.ts +101 -0
  123. package/payload/platform/lib/embed-client/tsconfig.json +8 -0
  124. package/payload/platform/lib/entitlement/PUBKEY-HASH.txt +1 -0
  125. package/payload/platform/lib/entitlement/dist/canonicalize.d.ts +26 -0
  126. package/payload/platform/lib/entitlement/dist/canonicalize.d.ts.map +1 -0
  127. package/payload/platform/lib/entitlement/dist/canonicalize.js +54 -0
  128. package/payload/platform/lib/entitlement/dist/canonicalize.js.map +1 -0
  129. package/payload/platform/lib/entitlement/dist/index.d.ts +76 -0
  130. package/payload/platform/lib/entitlement/dist/index.d.ts.map +1 -0
  131. package/payload/platform/lib/entitlement/dist/index.js +293 -0
  132. package/payload/platform/lib/entitlement/dist/index.js.map +1 -0
  133. package/payload/platform/lib/entitlement/rubytech-pubkey.pem +3 -0
  134. package/payload/platform/lib/graph-mcp/dist/__tests__/cypher-validate-write.test.d.ts +2 -0
  135. package/payload/platform/lib/graph-mcp/dist/__tests__/cypher-validate-write.test.d.ts.map +1 -0
  136. package/payload/platform/lib/graph-mcp/dist/__tests__/cypher-validate-write.test.js +97 -0
  137. package/payload/platform/lib/graph-mcp/dist/__tests__/cypher-validate-write.test.js.map +1 -0
  138. package/payload/platform/lib/graph-mcp/dist/__tests__/cypher-validate.test.d.ts +2 -0
  139. package/payload/platform/lib/graph-mcp/dist/__tests__/cypher-validate.test.d.ts.map +1 -0
  140. package/payload/platform/lib/graph-mcp/dist/__tests__/cypher-validate.test.js +112 -0
  141. package/payload/platform/lib/graph-mcp/dist/__tests__/cypher-validate.test.js.map +1 -0
  142. package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cache.test.d.ts +2 -0
  143. package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cache.test.d.ts.map +1 -0
  144. package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cache.test.js +163 -0
  145. package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cache.test.js.map +1 -0
  146. package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cypher-parser.test.d.ts +2 -0
  147. package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cypher-parser.test.d.ts.map +1 -0
  148. package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cypher-parser.test.js +89 -0
  149. package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cypher-parser.test.js.map +1 -0
  150. package/payload/platform/lib/graph-mcp/dist/__tests__/warnings-envelope.test.d.ts +2 -0
  151. package/payload/platform/lib/graph-mcp/dist/__tests__/warnings-envelope.test.d.ts.map +1 -0
  152. package/payload/platform/lib/graph-mcp/dist/__tests__/warnings-envelope.test.js +140 -0
  153. package/payload/platform/lib/graph-mcp/dist/__tests__/warnings-envelope.test.js.map +1 -0
  154. package/payload/platform/lib/graph-mcp/dist/cypher-rewrite-stamp.d.ts +37 -0
  155. package/payload/platform/lib/graph-mcp/dist/cypher-rewrite-stamp.d.ts.map +1 -0
  156. package/payload/platform/lib/graph-mcp/dist/cypher-rewrite-stamp.js +333 -0
  157. package/payload/platform/lib/graph-mcp/dist/cypher-rewrite-stamp.js.map +1 -0
  158. package/payload/platform/lib/graph-mcp/dist/cypher-shim-read.d.ts +85 -0
  159. package/payload/platform/lib/graph-mcp/dist/cypher-shim-read.d.ts.map +1 -0
  160. package/payload/platform/lib/graph-mcp/dist/cypher-shim-read.js +93 -0
  161. package/payload/platform/lib/graph-mcp/dist/cypher-shim-read.js.map +1 -0
  162. package/payload/platform/lib/graph-mcp/dist/cypher-shim-write.d.ts +71 -0
  163. package/payload/platform/lib/graph-mcp/dist/cypher-shim-write.d.ts.map +1 -0
  164. package/payload/platform/lib/graph-mcp/dist/cypher-shim-write.js +168 -0
  165. package/payload/platform/lib/graph-mcp/dist/cypher-shim-write.js.map +1 -0
  166. package/payload/platform/lib/graph-mcp/dist/cypher-validate.d.ts +50 -0
  167. package/payload/platform/lib/graph-mcp/dist/cypher-validate.d.ts.map +1 -0
  168. package/payload/platform/lib/graph-mcp/dist/cypher-validate.js +197 -0
  169. package/payload/platform/lib/graph-mcp/dist/cypher-validate.js.map +1 -0
  170. package/payload/platform/lib/graph-mcp/dist/index.d.ts +26 -0
  171. package/payload/platform/lib/graph-mcp/dist/index.d.ts.map +1 -0
  172. package/payload/platform/lib/graph-mcp/dist/index.js +845 -0
  173. package/payload/platform/lib/graph-mcp/dist/index.js.map +1 -0
  174. package/payload/platform/lib/graph-mcp/dist/schema-cache.d.ts +76 -0
  175. package/payload/platform/lib/graph-mcp/dist/schema-cache.d.ts.map +1 -0
  176. package/payload/platform/lib/graph-mcp/dist/schema-cache.js +218 -0
  177. package/payload/platform/lib/graph-mcp/dist/schema-cache.js.map +1 -0
  178. package/payload/platform/lib/graph-mcp/dist/schema-cypher-parser.d.ts +42 -0
  179. package/payload/platform/lib/graph-mcp/dist/schema-cypher-parser.d.ts.map +1 -0
  180. package/payload/platform/lib/graph-mcp/dist/schema-cypher-parser.js +87 -0
  181. package/payload/platform/lib/graph-mcp/dist/schema-cypher-parser.js.map +1 -0
  182. package/payload/platform/lib/graph-mcp/src/__tests__/cypher-validate-write.test.ts +150 -0
  183. package/payload/platform/lib/graph-mcp/src/__tests__/cypher-validate.test.ts +141 -0
  184. package/payload/platform/lib/graph-mcp/src/__tests__/schema-cache.test.ts +169 -0
  185. package/payload/platform/lib/graph-mcp/src/__tests__/schema-cypher-parser.test.ts +99 -0
  186. package/payload/platform/lib/graph-mcp/src/__tests__/warnings-envelope.test.ts +151 -0
  187. package/payload/platform/lib/graph-mcp/src/cypher-rewrite-stamp.ts +349 -0
  188. package/payload/platform/lib/graph-mcp/src/cypher-shim-read.ts +141 -0
  189. package/payload/platform/lib/graph-mcp/src/cypher-shim-write.ts +240 -0
  190. package/payload/platform/lib/graph-mcp/src/cypher-validate.ts +249 -0
  191. package/payload/platform/lib/graph-mcp/src/index.ts +1074 -0
  192. package/payload/platform/lib/graph-mcp/src/schema-cache.ts +243 -0
  193. package/payload/platform/lib/graph-mcp/src/schema-cypher-parser.ts +84 -0
  194. package/payload/platform/lib/graph-mcp/tsconfig.json +8 -0
  195. package/payload/platform/lib/graph-search/dist/boosts.d.ts +39 -0
  196. package/payload/platform/lib/graph-search/dist/boosts.d.ts.map +1 -0
  197. package/payload/platform/lib/graph-search/dist/boosts.js +57 -0
  198. package/payload/platform/lib/graph-search/dist/boosts.js.map +1 -0
  199. package/payload/platform/lib/graph-search/dist/dedup.d.ts +29 -0
  200. package/payload/platform/lib/graph-search/dist/dedup.d.ts.map +1 -0
  201. package/payload/platform/lib/graph-search/dist/dedup.js +97 -0
  202. package/payload/platform/lib/graph-search/dist/dedup.js.map +1 -0
  203. package/payload/platform/lib/graph-search/dist/index.d.ts +342 -0
  204. package/payload/platform/lib/graph-search/dist/index.d.ts.map +1 -0
  205. package/payload/platform/lib/graph-search/dist/index.js +848 -0
  206. package/payload/platform/lib/graph-search/dist/index.js.map +1 -0
  207. package/payload/platform/lib/graph-search/dist/query-expansion.d.ts +37 -0
  208. package/payload/platform/lib/graph-search/dist/query-expansion.d.ts.map +1 -0
  209. package/payload/platform/lib/graph-search/dist/query-expansion.js +101 -0
  210. package/payload/platform/lib/graph-search/dist/query-expansion.js.map +1 -0
  211. package/payload/platform/lib/graph-search/dist/route.d.ts +29 -0
  212. package/payload/platform/lib/graph-search/dist/route.d.ts.map +1 -0
  213. package/payload/platform/lib/graph-search/dist/route.js +53 -0
  214. package/payload/platform/lib/graph-search/dist/route.js.map +1 -0
  215. package/payload/platform/lib/graph-search/dist/rrf-fusion.d.ts +31 -0
  216. package/payload/platform/lib/graph-search/dist/rrf-fusion.d.ts.map +1 -0
  217. package/payload/platform/lib/graph-search/dist/rrf-fusion.js +57 -0
  218. package/payload/platform/lib/graph-search/dist/rrf-fusion.js.map +1 -0
  219. package/payload/platform/lib/graph-search/src/__tests__/bm25-label-gate.test.ts +88 -0
  220. package/payload/platform/lib/graph-search/src/__tests__/bm25-only.test.ts +129 -0
  221. package/payload/platform/lib/graph-search/src/__tests__/bm25-strong-bypass-threshold.test.ts +126 -0
  222. package/payload/platform/lib/graph-search/src/__tests__/boosts.test.ts +59 -0
  223. package/payload/platform/lib/graph-search/src/__tests__/brochure-threshold.test.ts +136 -0
  224. package/payload/platform/lib/graph-search/src/__tests__/dedup.test.ts +83 -0
  225. package/payload/platform/lib/graph-search/src/__tests__/escape-and-normalise.test.ts +53 -0
  226. package/payload/platform/lib/graph-search/src/__tests__/expand-batch.test.ts +206 -0
  227. package/payload/platform/lib/graph-search/src/__tests__/fulltext-coverage.test.ts +348 -0
  228. package/payload/platform/lib/graph-search/src/__tests__/hybrid.test.ts +355 -0
  229. package/payload/platform/lib/graph-search/src/__tests__/route.test.ts +62 -0
  230. package/payload/platform/lib/graph-search/src/__tests__/rrf-fusion.test.ts +39 -0
  231. package/payload/platform/lib/graph-search/src/__tests__/vector-index-coverage.test.ts +198 -0
  232. package/payload/platform/lib/graph-search/src/__tests__/vector-threshold.test.ts +170 -0
  233. package/payload/platform/lib/graph-search/src/boosts.ts +61 -0
  234. package/payload/platform/lib/graph-search/src/dedup.ts +108 -0
  235. package/payload/platform/lib/graph-search/src/index.ts +1144 -0
  236. package/payload/platform/lib/graph-search/src/route.ts +70 -0
  237. package/payload/platform/lib/graph-search/src/rrf-fusion.ts +62 -0
  238. package/payload/platform/lib/graph-search/tsconfig.json +9 -0
  239. package/payload/platform/lib/graph-search/vitest.config.ts +9 -0
  240. package/payload/platform/lib/graph-style/dist/index.d.ts +84 -0
  241. package/payload/platform/lib/graph-style/dist/index.d.ts.map +1 -0
  242. package/payload/platform/lib/graph-style/dist/index.js +378 -0
  243. package/payload/platform/lib/graph-style/dist/index.js.map +1 -0
  244. package/payload/platform/lib/graph-style/src/__tests__/parity.test.ts +332 -0
  245. package/payload/platform/lib/graph-style/src/index.ts +382 -0
  246. package/payload/platform/lib/graph-style/tsconfig.json +9 -0
  247. package/payload/platform/lib/graph-style/vitest.config.ts +9 -0
  248. package/payload/platform/lib/graph-trash/dist/index.d.ts +106 -0
  249. package/payload/platform/lib/graph-trash/dist/index.d.ts.map +1 -0
  250. package/payload/platform/lib/graph-trash/dist/index.js +340 -0
  251. package/payload/platform/lib/graph-trash/dist/index.js.map +1 -0
  252. package/payload/platform/lib/graph-trash/package.json +7 -0
  253. package/payload/platform/lib/graph-trash/src/index.ts +493 -0
  254. package/payload/platform/lib/graph-trash/tsconfig.json +8 -0
  255. package/payload/platform/lib/graph-write/dist/__tests__/account-id-gate.test.d.ts +2 -0
  256. package/payload/platform/lib/graph-write/dist/__tests__/account-id-gate.test.d.ts.map +1 -0
  257. package/payload/platform/lib/graph-write/dist/__tests__/account-id-gate.test.js +165 -0
  258. package/payload/platform/lib/graph-write/dist/__tests__/account-id-gate.test.js.map +1 -0
  259. package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.d.ts +2 -0
  260. package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.d.ts.map +1 -0
  261. package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.js +263 -0
  262. package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.js.map +1 -0
  263. package/payload/platform/lib/graph-write/dist/__tests__/audit.test.d.ts +2 -0
  264. package/payload/platform/lib/graph-write/dist/__tests__/audit.test.d.ts.map +1 -0
  265. package/payload/platform/lib/graph-write/dist/__tests__/audit.test.js +147 -0
  266. package/payload/platform/lib/graph-write/dist/__tests__/audit.test.js.map +1 -0
  267. package/payload/platform/lib/graph-write/dist/audit.d.ts +84 -0
  268. package/payload/platform/lib/graph-write/dist/audit.d.ts.map +1 -0
  269. package/payload/platform/lib/graph-write/dist/audit.js +129 -0
  270. package/payload/platform/lib/graph-write/dist/audit.js.map +1 -0
  271. package/payload/platform/lib/graph-write/dist/conversation-provenance.d.ts +30 -0
  272. package/payload/platform/lib/graph-write/dist/conversation-provenance.d.ts.map +1 -0
  273. package/payload/platform/lib/graph-write/dist/conversation-provenance.js +88 -0
  274. package/payload/platform/lib/graph-write/dist/conversation-provenance.js.map +1 -0
  275. package/payload/platform/lib/graph-write/dist/index.d.ts +151 -0
  276. package/payload/platform/lib/graph-write/dist/index.d.ts.map +1 -0
  277. package/payload/platform/lib/graph-write/dist/index.js +380 -0
  278. package/payload/platform/lib/graph-write/dist/index.js.map +1 -0
  279. package/payload/platform/lib/graph-write/src/__tests__/account-id-gate.test.ts +189 -0
  280. package/payload/platform/lib/graph-write/src/__tests__/action-provenance-gate.test.ts +279 -0
  281. package/payload/platform/lib/graph-write/src/__tests__/audit.test.ts +162 -0
  282. package/payload/platform/lib/graph-write/src/audit.ts +182 -0
  283. package/payload/platform/lib/graph-write/src/conversation-provenance.ts +148 -0
  284. package/payload/platform/lib/graph-write/src/index.ts +494 -0
  285. package/payload/platform/lib/graph-write/tsconfig.json +8 -0
  286. package/payload/platform/lib/mcp-eager/dist/index.d.ts +41 -0
  287. package/payload/platform/lib/mcp-eager/dist/index.d.ts.map +1 -0
  288. package/payload/platform/lib/mcp-eager/dist/index.js +50 -0
  289. package/payload/platform/lib/mcp-eager/dist/index.js.map +1 -0
  290. package/payload/platform/lib/mcp-eager/package.json +7 -0
  291. package/payload/platform/lib/mcp-eager/src/index.ts +80 -0
  292. package/payload/platform/lib/mcp-eager/tsconfig.json +8 -0
  293. package/payload/platform/lib/mcp-lifeline/dist/index.d.ts +8 -0
  294. package/payload/platform/lib/mcp-lifeline/dist/index.d.ts.map +1 -0
  295. package/payload/platform/lib/mcp-lifeline/dist/index.js +71 -0
  296. package/payload/platform/lib/mcp-lifeline/dist/index.js.map +1 -0
  297. package/payload/platform/lib/mcp-lifeline/package.json +7 -0
  298. package/payload/platform/lib/mcp-lifeline/src/__tests__/lifeline.test.ts +146 -0
  299. package/payload/platform/lib/mcp-lifeline/src/index.ts +78 -0
  300. package/payload/platform/lib/mcp-lifeline/tsconfig.json +9 -0
  301. package/payload/platform/lib/mcp-lifeline/vitest.config.ts +9 -0
  302. package/payload/platform/lib/mcp-spawn-tee/dist/index.d.ts +41 -0
  303. package/payload/platform/lib/mcp-spawn-tee/dist/index.d.ts.map +1 -0
  304. package/payload/platform/lib/mcp-spawn-tee/dist/index.js +193 -0
  305. package/payload/platform/lib/mcp-spawn-tee/dist/index.js.map +1 -0
  306. package/payload/platform/lib/mcp-spawn-tee/src/__tests__/spawn-tee.test.ts +148 -0
  307. package/payload/platform/lib/mcp-spawn-tee/src/index.ts +198 -0
  308. package/payload/platform/lib/mcp-spawn-tee/tsconfig.json +9 -0
  309. package/payload/platform/lib/mcp-stderr-tee/dist/index.d.ts +51 -0
  310. package/payload/platform/lib/mcp-stderr-tee/dist/index.d.ts.map +1 -0
  311. package/payload/platform/lib/mcp-stderr-tee/dist/index.js +196 -0
  312. package/payload/platform/lib/mcp-stderr-tee/dist/index.js.map +1 -0
  313. package/payload/platform/lib/mcp-stderr-tee/package.json +7 -0
  314. package/payload/platform/lib/mcp-stderr-tee/src/index.ts +206 -0
  315. package/payload/platform/lib/mcp-stderr-tee/tsconfig.json +8 -0
  316. package/payload/platform/lib/models/dist/index.d.ts +58 -0
  317. package/payload/platform/lib/models/dist/index.d.ts.map +1 -0
  318. package/payload/platform/lib/models/dist/index.js +110 -0
  319. package/payload/platform/lib/models/dist/index.js.map +1 -0
  320. package/payload/platform/lib/models/src/index.ts +118 -0
  321. package/payload/platform/lib/models/tsconfig.json +8 -0
  322. package/payload/platform/lib/oauth-llm/dist/index.d.ts +116 -0
  323. package/payload/platform/lib/oauth-llm/dist/index.d.ts.map +1 -0
  324. package/payload/platform/lib/oauth-llm/dist/index.js +386 -0
  325. package/payload/platform/lib/oauth-llm/dist/index.js.map +1 -0
  326. package/payload/platform/lib/obsidian-parser/dist/index.d.ts +98 -0
  327. package/payload/platform/lib/obsidian-parser/dist/index.d.ts.map +1 -0
  328. package/payload/platform/lib/obsidian-parser/dist/index.js +480 -0
  329. package/payload/platform/lib/obsidian-parser/dist/index.js.map +1 -0
  330. package/payload/platform/lib/obsidian-parser/src/index.ts +572 -0
  331. package/payload/platform/lib/obsidian-parser/tsconfig.json +8 -0
  332. package/payload/platform/lib/persistent-components/dist/index.d.ts +20 -0
  333. package/payload/platform/lib/persistent-components/dist/index.d.ts.map +1 -0
  334. package/payload/platform/lib/persistent-components/dist/index.js +31 -0
  335. package/payload/platform/lib/persistent-components/dist/index.js.map +1 -0
  336. package/payload/platform/lib/persistent-components/src/index.ts +27 -0
  337. package/payload/platform/lib/persistent-components/tsconfig.json +8 -0
  338. package/payload/platform/lib/require-port-env/dist/index.d.ts +31 -0
  339. package/payload/platform/lib/require-port-env/dist/index.d.ts.map +1 -0
  340. package/payload/platform/lib/require-port-env/dist/index.js +52 -0
  341. package/payload/platform/lib/require-port-env/dist/index.js.map +1 -0
  342. package/payload/platform/lib/require-port-env/src/index.ts +56 -0
  343. package/payload/platform/lib/require-port-env/tsconfig.json +8 -0
  344. package/payload/platform/lib/screening-patterns/dist/index.d.ts +29 -0
  345. package/payload/platform/lib/screening-patterns/dist/index.d.ts.map +1 -0
  346. package/payload/platform/lib/screening-patterns/dist/index.js +48 -0
  347. package/payload/platform/lib/screening-patterns/dist/index.js.map +1 -0
  348. package/payload/platform/lib/task-secrets/dist/index.d.ts +40 -0
  349. package/payload/platform/lib/task-secrets/dist/index.d.ts.map +1 -0
  350. package/payload/platform/lib/task-secrets/dist/index.js +44 -0
  351. package/payload/platform/lib/task-secrets/dist/index.js.map +1 -0
  352. package/payload/platform/lib/task-secrets/src/__tests__/redact-secrets.test.ts +127 -0
  353. package/payload/platform/lib/task-secrets/src/index.ts +77 -0
  354. package/payload/platform/lib/task-secrets/tsconfig.json +9 -0
  355. package/payload/platform/lib/task-secrets/vitest.config.ts +9 -0
  356. package/payload/platform/neo4j/edge-annotations.json +158 -0
  357. package/payload/platform/neo4j/schema.cypher +2041 -0
  358. package/payload/platform/package-lock.json +4093 -0
  359. package/payload/platform/package.json +31 -0
  360. package/payload/platform/plugins/.claude-plugin/marketplace.json +163 -0
  361. package/payload/platform/plugins/admin/.claude-plugin/plugin.json +21 -0
  362. package/payload/platform/plugins/admin/PLUGIN.md +180 -0
  363. package/payload/platform/plugins/admin/hooks/__tests__/archive-ingest-surface-gate.test.sh +191 -0
  364. package/payload/platform/plugins/admin/hooks/__tests__/askuserquestion-investigate-gate.test.sh +176 -0
  365. package/payload/platform/plugins/admin/hooks/__tests__/hook-emit-stale-lock-ttl.test.sh +102 -0
  366. package/payload/platform/plugins/admin/hooks/__tests__/hook-emit.test.sh +75 -0
  367. package/payload/platform/plugins/admin/hooks/__tests__/post-tool-use-agent.test.sh +173 -0
  368. package/payload/platform/plugins/admin/hooks/__tests__/prompt-optimiser-compliance.test.sh +242 -0
  369. package/payload/platform/plugins/admin/hooks/__tests__/prompt-optimiser-directive.test.sh +191 -0
  370. package/payload/platform/plugins/admin/hooks/admin-authoring-observer.sh +155 -0
  371. package/payload/platform/plugins/admin/hooks/archive-ingest-surface-gate.sh +224 -0
  372. package/payload/platform/plugins/admin/hooks/askuserquestion-investigate-gate.sh +257 -0
  373. package/payload/platform/plugins/admin/hooks/lib/hook-emit.sh +143 -0
  374. package/payload/platform/plugins/admin/hooks/lib/maxy-mcp-plugins.txt +17 -0
  375. package/payload/platform/plugins/admin/hooks/mcp-tool-missing.sh +94 -0
  376. package/payload/platform/plugins/admin/hooks/post-tool-use-agent.sh +155 -0
  377. package/payload/platform/plugins/admin/hooks/prompt-optimiser-compliance.sh +213 -0
  378. package/payload/platform/plugins/admin/hooks/prompt-optimiser-directive.sh +166 -0
  379. package/payload/platform/plugins/admin/hooks/webfetch-preflight.mjs +363 -0
  380. package/payload/platform/plugins/admin/lib/mcp-spawn-tee/index.js +193 -0
  381. package/payload/platform/plugins/admin/lib/mcp-spawn-tee/package.json +3 -0
  382. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-authoring-skill-gate.test.d.ts +2 -0
  383. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-authoring-skill-gate.test.d.ts.map +1 -0
  384. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-authoring-skill-gate.test.js +86 -0
  385. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-authoring-skill-gate.test.js.map +1 -0
  386. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-identity-authenticate.test.d.ts +2 -0
  387. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-identity-authenticate.test.d.ts.map +1 -0
  388. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-identity-authenticate.test.js +34 -0
  389. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-identity-authenticate.test.js.map +1 -0
  390. package/payload/platform/plugins/admin/mcp/dist/__tests__/capabilities-here.test.d.ts +2 -0
  391. package/payload/platform/plugins/admin/mcp/dist/__tests__/capabilities-here.test.d.ts.map +1 -0
  392. package/payload/platform/plugins/admin/mcp/dist/__tests__/capabilities-here.test.js +171 -0
  393. package/payload/platform/plugins/admin/mcp/dist/__tests__/capabilities-here.test.js.map +1 -0
  394. package/payload/platform/plugins/admin/mcp/dist/__tests__/e-sign-discoverable.test.d.ts +2 -0
  395. package/payload/platform/plugins/admin/mcp/dist/__tests__/e-sign-discoverable.test.d.ts.map +1 -0
  396. package/payload/platform/plugins/admin/mcp/dist/__tests__/e-sign-discoverable.test.js +54 -0
  397. package/payload/platform/plugins/admin/mcp/dist/__tests__/e-sign-discoverable.test.js.map +1 -0
  398. package/payload/platform/plugins/admin/mcp/dist/__tests__/plugin-read-skill-resolution.test.d.ts +2 -0
  399. package/payload/platform/plugins/admin/mcp/dist/__tests__/plugin-read-skill-resolution.test.d.ts.map +1 -0
  400. package/payload/platform/plugins/admin/mcp/dist/__tests__/plugin-read-skill-resolution.test.js +91 -0
  401. package/payload/platform/plugins/admin/mcp/dist/__tests__/plugin-read-skill-resolution.test.js.map +1 -0
  402. package/payload/platform/plugins/admin/mcp/dist/__tests__/public-hostname.test.d.ts +2 -0
  403. package/payload/platform/plugins/admin/mcp/dist/__tests__/public-hostname.test.d.ts.map +1 -0
  404. package/payload/platform/plugins/admin/mcp/dist/__tests__/public-hostname.test.js +98 -0
  405. package/payload/platform/plugins/admin/mcp/dist/__tests__/public-hostname.test.js.map +1 -0
  406. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load-required-inputs.test.d.ts +2 -0
  407. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load-required-inputs.test.d.ts.map +1 -0
  408. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load-required-inputs.test.js +141 -0
  409. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load-required-inputs.test.js.map +1 -0
  410. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load.test.d.ts +2 -0
  411. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load.test.d.ts.map +1 -0
  412. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load.test.js +88 -0
  413. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load.test.js.map +1 -0
  414. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-no-prescribed-role.test.d.ts +2 -0
  415. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-no-prescribed-role.test.d.ts.map +1 -0
  416. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-no-prescribed-role.test.js +50 -0
  417. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-no-prescribed-role.test.js.map +1 -0
  418. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-search.test.d.ts +2 -0
  419. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-search.test.d.ts.map +1 -0
  420. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-search.test.js +106 -0
  421. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-search.test.js.map +1 -0
  422. package/payload/platform/plugins/admin/mcp/dist/content-producer-authoring-skills.d.ts +2 -0
  423. package/payload/platform/plugins/admin/mcp/dist/content-producer-authoring-skills.d.ts.map +1 -0
  424. package/payload/platform/plugins/admin/mcp/dist/content-producer-authoring-skills.js +41 -0
  425. package/payload/platform/plugins/admin/mcp/dist/content-producer-authoring-skills.js.map +1 -0
  426. package/payload/platform/plugins/admin/mcp/dist/index.d.ts +2 -0
  427. package/payload/platform/plugins/admin/mcp/dist/index.d.ts.map +1 -0
  428. package/payload/platform/plugins/admin/mcp/dist/index.js +3294 -0
  429. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -0
  430. package/payload/platform/plugins/admin/mcp/dist/lib/catalogue-census.d.ts +14 -0
  431. package/payload/platform/plugins/admin/mcp/dist/lib/catalogue-census.d.ts.map +1 -0
  432. package/payload/platform/plugins/admin/mcp/dist/lib/catalogue-census.js +50 -0
  433. package/payload/platform/plugins/admin/mcp/dist/lib/catalogue-census.js.map +1 -0
  434. package/payload/platform/plugins/admin/mcp/dist/lib/neo4j.d.ts +5 -0
  435. package/payload/platform/plugins/admin/mcp/dist/lib/neo4j.d.ts.map +1 -0
  436. package/payload/platform/plugins/admin/mcp/dist/lib/neo4j.js +40 -0
  437. package/payload/platform/plugins/admin/mcp/dist/lib/neo4j.js.map +1 -0
  438. package/payload/platform/plugins/admin/mcp/dist/lib/onboarding.d.ts +39 -0
  439. package/payload/platform/plugins/admin/mcp/dist/lib/onboarding.d.ts.map +1 -0
  440. package/payload/platform/plugins/admin/mcp/dist/lib/onboarding.js +249 -0
  441. package/payload/platform/plugins/admin/mcp/dist/lib/onboarding.js.map +1 -0
  442. package/payload/platform/plugins/admin/mcp/dist/lib/public-hostname.d.ts +15 -0
  443. package/payload/platform/plugins/admin/mcp/dist/lib/public-hostname.d.ts.map +1 -0
  444. package/payload/platform/plugins/admin/mcp/dist/lib/public-hostname.js +73 -0
  445. package/payload/platform/plugins/admin/mcp/dist/lib/public-hostname.js.map +1 -0
  446. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.d.ts +56 -0
  447. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.d.ts.map +1 -0
  448. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.js +358 -0
  449. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.js.map +1 -0
  450. package/payload/platform/plugins/admin/mcp/dist/tools/__tests__/account-lifecycle.test.d.ts +2 -0
  451. package/payload/platform/plugins/admin/mcp/dist/tools/__tests__/account-lifecycle.test.d.ts.map +1 -0
  452. package/payload/platform/plugins/admin/mcp/dist/tools/__tests__/account-lifecycle.test.js +57 -0
  453. package/payload/platform/plugins/admin/mcp/dist/tools/__tests__/account-lifecycle.test.js.map +1 -0
  454. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts +34 -0
  455. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts.map +1 -0
  456. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js +78 -0
  457. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js.map +1 -0
  458. package/payload/platform/plugins/admin/mcp/dist/tools/admin-identity-authenticate.d.ts +6 -0
  459. package/payload/platform/plugins/admin/mcp/dist/tools/admin-identity-authenticate.d.ts.map +1 -0
  460. package/payload/platform/plugins/admin/mcp/dist/tools/admin-identity-authenticate.js +32 -0
  461. package/payload/platform/plugins/admin/mcp/dist/tools/admin-identity-authenticate.js.map +1 -0
  462. package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.d.ts +28 -0
  463. package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.d.ts.map +1 -0
  464. package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.js +68 -0
  465. package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.js.map +1 -0
  466. package/payload/platform/plugins/admin/mcp/dist/tools/publish-site.d.ts +34 -0
  467. package/payload/platform/plugins/admin/mcp/dist/tools/publish-site.d.ts.map +1 -0
  468. package/payload/platform/plugins/admin/mcp/dist/tools/publish-site.js +176 -0
  469. package/payload/platform/plugins/admin/mcp/dist/tools/publish-site.js.map +1 -0
  470. package/payload/platform/plugins/admin/mcp/package.json +23 -0
  471. package/payload/platform/plugins/admin/mcp/vitest.config.ts +9 -0
  472. package/payload/platform/plugins/admin/references/chat-ui-guide.md +31 -0
  473. package/payload/platform/plugins/admin/references/publish-site-routing.md +44 -0
  474. package/payload/platform/plugins/admin/skills/a4-print-documents/SKILL.md +243 -0
  475. package/payload/platform/plugins/admin/skills/access-manager/SKILL.md +33 -0
  476. package/payload/platform/plugins/admin/skills/access-manager/references/operations.md +176 -0
  477. package/payload/platform/plugins/admin/skills/admin-user-management/SKILL.md +57 -0
  478. package/payload/platform/plugins/admin/skills/business-profile/SKILL.md +55 -0
  479. package/payload/platform/plugins/admin/skills/capabilities-here/SKILL.md +33 -0
  480. package/payload/platform/plugins/admin/skills/datetime/SKILL.md +151 -0
  481. package/payload/platform/plugins/admin/skills/deck-pages/SKILL.md +412 -0
  482. package/payload/platform/plugins/admin/skills/file-presentation/SKILL.md +49 -0
  483. package/payload/platform/plugins/admin/skills/insight/SKILL.md +24 -0
  484. package/payload/platform/plugins/admin/skills/investigate/SKILL.md +320 -0
  485. package/payload/platform/plugins/admin/skills/plainly/SKILL.md +149 -0
  486. package/payload/platform/plugins/admin/skills/plainly/references/worked-examples.md +114 -0
  487. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +4181 -0
  488. package/payload/platform/plugins/admin/skills/plugin-management/SKILL.md +101 -0
  489. package/payload/platform/plugins/admin/skills/professional-document/SKILL.md +186 -0
  490. package/payload/platform/plugins/admin/skills/public-agent-manager/SKILL.md +258 -0
  491. package/payload/platform/plugins/admin/skills/publish-site/SKILL.md +42 -0
  492. package/payload/platform/plugins/admin/skills/qr-code/SKILL.md +38 -0
  493. package/payload/platform/plugins/admin/skills/qr-code/references/data-formats.md +113 -0
  494. package/payload/platform/plugins/admin/skills/session-management/SKILL.md +64 -0
  495. package/payload/platform/plugins/admin/skills/skill-builder/SKILL.md +115 -0
  496. package/payload/platform/plugins/admin/skills/skill-builder/references/lean-pattern.md +110 -0
  497. package/payload/platform/plugins/admin/skills/skill-builder/references/pdf-generation.md +30 -0
  498. package/payload/platform/plugins/admin/skills/specialist-management/SKILL.md +47 -0
  499. package/payload/platform/plugins/admin/skills/stream-log-review/SKILL.md +73 -0
  500. package/payload/platform/plugins/admin/skills/stream-log-review/references/analysis-patterns.md +193 -0
  501. package/payload/platform/plugins/admin/skills/superpowers-sprint/SKILL.md +363 -0
  502. package/payload/platform/plugins/admin/skills/task/SKILL.md +316 -0
  503. package/payload/platform/plugins/admin/skills/unzip-attachment/SKILL.md +84 -0
  504. package/payload/platform/plugins/admin/skills/unzip-attachment/__tests__/preflight.sh +148 -0
  505. package/payload/platform/plugins/admin/skills/unzip-attachment/references/safety.md +116 -0
  506. package/payload/platform/plugins/admin/skills/update-knowledge/SKILL.md +54 -0
  507. package/payload/platform/plugins/admin/skills/upgrade/SKILL.md +36 -0
  508. package/payload/platform/plugins/aeo/.claude-plugin/plugin.json +21 -0
  509. package/payload/platform/plugins/aeo/PLUGIN.md +80 -0
  510. package/payload/platform/plugins/aeo/lib/mcp-spawn-tee/index.js +193 -0
  511. package/payload/platform/plugins/aeo/lib/mcp-spawn-tee/package.json +3 -0
  512. package/payload/platform/plugins/aeo/mcp/dist/__tests__/audit-heuristics.test.d.ts +2 -0
  513. package/payload/platform/plugins/aeo/mcp/dist/__tests__/audit-heuristics.test.d.ts.map +1 -0
  514. package/payload/platform/plugins/aeo/mcp/dist/__tests__/audit-heuristics.test.js +121 -0
  515. package/payload/platform/plugins/aeo/mcp/dist/__tests__/audit-heuristics.test.js.map +1 -0
  516. package/payload/platform/plugins/aeo/mcp/dist/__tests__/schema-mapping.test.d.ts +2 -0
  517. package/payload/platform/plugins/aeo/mcp/dist/__tests__/schema-mapping.test.d.ts.map +1 -0
  518. package/payload/platform/plugins/aeo/mcp/dist/__tests__/schema-mapping.test.js +129 -0
  519. package/payload/platform/plugins/aeo/mcp/dist/__tests__/schema-mapping.test.js.map +1 -0
  520. package/payload/platform/plugins/aeo/mcp/dist/index.d.ts +2 -0
  521. package/payload/platform/plugins/aeo/mcp/dist/index.d.ts.map +1 -0
  522. package/payload/platform/plugins/aeo/mcp/dist/index.js +189 -0
  523. package/payload/platform/plugins/aeo/mcp/dist/index.js.map +1 -0
  524. package/payload/platform/plugins/aeo/mcp/dist/lib/audit-heuristics.d.ts +27 -0
  525. package/payload/platform/plugins/aeo/mcp/dist/lib/audit-heuristics.d.ts.map +1 -0
  526. package/payload/platform/plugins/aeo/mcp/dist/lib/audit-heuristics.js +274 -0
  527. package/payload/platform/plugins/aeo/mcp/dist/lib/audit-heuristics.js.map +1 -0
  528. package/payload/platform/plugins/aeo/mcp/dist/lib/neo4j.d.ts +5 -0
  529. package/payload/platform/plugins/aeo/mcp/dist/lib/neo4j.d.ts.map +1 -0
  530. package/payload/platform/plugins/aeo/mcp/dist/lib/neo4j.js +38 -0
  531. package/payload/platform/plugins/aeo/mcp/dist/lib/neo4j.js.map +1 -0
  532. package/payload/platform/plugins/aeo/mcp/dist/lib/schema-mapping.d.ts +48 -0
  533. package/payload/platform/plugins/aeo/mcp/dist/lib/schema-mapping.d.ts.map +1 -0
  534. package/payload/platform/plugins/aeo/mcp/dist/lib/schema-mapping.js +254 -0
  535. package/payload/platform/plugins/aeo/mcp/dist/lib/schema-mapping.js.map +1 -0
  536. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-audit-page.d.ts +25 -0
  537. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-audit-page.d.ts.map +1 -0
  538. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-audit-page.js +78 -0
  539. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-audit-page.js.map +1 -0
  540. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-emit-jsonld.d.ts +18 -0
  541. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-emit-jsonld.d.ts.map +1 -0
  542. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-emit-jsonld.js +56 -0
  543. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-emit-jsonld.js.map +1 -0
  544. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.d.ts +9 -0
  545. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.d.ts.map +1 -0
  546. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.js +11 -0
  547. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.js.map +1 -0
  548. package/payload/platform/plugins/aeo/mcp/package.json +22 -0
  549. package/payload/platform/plugins/aeo/mcp/vitest.config.ts +9 -0
  550. package/payload/platform/plugins/aeo/skills/structured-answer/SKILL.md +55 -0
  551. package/payload/platform/plugins/browser/.claude-plugin/plugin.json +21 -0
  552. package/payload/platform/plugins/browser/PLUGIN.md +114 -0
  553. package/payload/platform/plugins/browser/lib/mcp-spawn-tee/index.js +193 -0
  554. package/payload/platform/plugins/browser/lib/mcp-spawn-tee/package.json +3 -0
  555. package/payload/platform/plugins/browser/mcp/dist/index.d.ts +2 -0
  556. package/payload/platform/plugins/browser/mcp/dist/index.d.ts.map +1 -0
  557. package/payload/platform/plugins/browser/mcp/dist/index.js +165 -0
  558. package/payload/platform/plugins/browser/mcp/dist/index.js.map +1 -0
  559. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-actions.d.ts +98 -0
  560. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-actions.d.ts.map +1 -0
  561. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-actions.js +455 -0
  562. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-actions.js.map +1 -0
  563. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.d.ts +44 -0
  564. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.d.ts.map +1 -0
  565. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.js +89 -0
  566. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.js.map +1 -0
  567. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-session.d.ts +153 -0
  568. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-session.d.ts.map +1 -0
  569. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-session.js +401 -0
  570. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-session.js.map +1 -0
  571. package/payload/platform/plugins/browser/mcp/package.json +19 -0
  572. package/payload/platform/plugins/business-assistant/.claude-plugin/plugin.json +8 -0
  573. package/payload/platform/plugins/business-assistant/PLUGIN.md +66 -0
  574. package/payload/platform/plugins/business-assistant/references/crm.md +118 -0
  575. package/payload/platform/plugins/business-assistant/references/document-management.md +96 -0
  576. package/payload/platform/plugins/business-assistant/references/escalation.md +126 -0
  577. package/payload/platform/plugins/business-assistant/references/invoicing.md +163 -0
  578. package/payload/platform/plugins/business-assistant/references/profiling.md +50 -0
  579. package/payload/platform/plugins/business-assistant/references/scheduling.md +127 -0
  580. package/payload/platform/plugins/business-assistant/references/site-lead-intake.md +52 -0
  581. package/payload/platform/plugins/business-assistant/references/task-management.md +163 -0
  582. package/payload/platform/plugins/business-assistant/skills/e-sign/SKILL.md +680 -0
  583. package/payload/platform/plugins/cloudflare/.claude-plugin/plugin.json +8 -0
  584. package/payload/platform/plugins/cloudflare/PLUGIN.md +62 -0
  585. package/payload/platform/plugins/cloudflare/mcp/dist/index.d.ts +2 -0
  586. package/payload/platform/plugins/cloudflare/mcp/dist/index.d.ts.map +1 -0
  587. package/payload/platform/plugins/cloudflare/mcp/dist/index.js +24 -0
  588. package/payload/platform/plugins/cloudflare/mcp/dist/index.js.map +1 -0
  589. package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.d.ts +283 -0
  590. package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.d.ts.map +1 -0
  591. package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.js +1155 -0
  592. package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.js.map +1 -0
  593. package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.d.ts +90 -0
  594. package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.d.ts.map +1 -0
  595. package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.js +551 -0
  596. package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.js.map +1 -0
  597. package/payload/platform/plugins/cloudflare/mcp/package.json +18 -0
  598. package/payload/platform/plugins/cloudflare/mcp/vitest.config.ts +10 -0
  599. package/payload/platform/plugins/cloudflare/references/api.md +255 -0
  600. package/payload/platform/plugins/cloudflare/references/d1-data-capture.md +165 -0
  601. package/payload/platform/plugins/cloudflare/references/dashboard-guide.md +184 -0
  602. package/payload/platform/plugins/cloudflare/references/hosting-sites.md +68 -0
  603. package/payload/platform/plugins/cloudflare/references/manual-setup.md +710 -0
  604. package/payload/platform/plugins/cloudflare/references/reset-guide.md +137 -0
  605. package/payload/platform/plugins/cloudflare/references/serving-published-sites.md +73 -0
  606. package/payload/platform/plugins/cloudflare/references/web-analytics.md +64 -0
  607. package/payload/platform/plugins/cloudflare/skills/cloudflare/SKILL.md +91 -0
  608. package/payload/platform/plugins/contacts/.claude-plugin/plugin.json +21 -0
  609. package/payload/platform/plugins/contacts/PLUGIN.md +62 -0
  610. package/payload/platform/plugins/contacts/lib/mcp-spawn-tee/index.js +193 -0
  611. package/payload/platform/plugins/contacts/lib/mcp-spawn-tee/package.json +3 -0
  612. package/payload/platform/plugins/contacts/mcp/dist/index.d.ts +2 -0
  613. package/payload/platform/plugins/contacts/mcp/dist/index.d.ts.map +1 -0
  614. package/payload/platform/plugins/contacts/mcp/dist/index.js +467 -0
  615. package/payload/platform/plugins/contacts/mcp/dist/index.js.map +1 -0
  616. package/payload/platform/plugins/contacts/mcp/dist/lib/neo4j.d.ts +5 -0
  617. package/payload/platform/plugins/contacts/mcp/dist/lib/neo4j.d.ts.map +1 -0
  618. package/payload/platform/plugins/contacts/mcp/dist/lib/neo4j.js +40 -0
  619. package/payload/platform/plugins/contacts/mcp/dist/lib/neo4j.js.map +1 -0
  620. package/payload/platform/plugins/contacts/mcp/dist/lib/resolve-person.d.ts +33 -0
  621. package/payload/platform/plugins/contacts/mcp/dist/lib/resolve-person.d.ts.map +1 -0
  622. package/payload/platform/plugins/contacts/mcp/dist/lib/resolve-person.js +53 -0
  623. package/payload/platform/plugins/contacts/mcp/dist/lib/resolve-person.js.map +1 -0
  624. package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/contact-lookup.test.d.ts +2 -0
  625. package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/contact-lookup.test.d.ts.map +1 -0
  626. package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/contact-lookup.test.js +71 -0
  627. package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/contact-lookup.test.js.map +1 -0
  628. package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/group-create.test.d.ts +2 -0
  629. package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/group-create.test.d.ts.map +1 -0
  630. package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/group-create.test.js +112 -0
  631. package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/group-create.test.js.map +1 -0
  632. package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/group-manage.test.d.ts +2 -0
  633. package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/group-manage.test.d.ts.map +1 -0
  634. package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/group-manage.test.js +102 -0
  635. package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/group-manage.test.js.map +1 -0
  636. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts +23 -0
  637. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts.map +1 -0
  638. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js +123 -0
  639. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js.map +1 -0
  640. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-delete.d.ts +28 -0
  641. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-delete.d.ts.map +1 -0
  642. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-delete.js +39 -0
  643. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-delete.js.map +1 -0
  644. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-erase.d.ts +52 -0
  645. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-erase.d.ts.map +1 -0
  646. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-erase.js +181 -0
  647. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-erase.js.map +1 -0
  648. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-export.d.ts +52 -0
  649. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-export.d.ts.map +1 -0
  650. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-export.js +122 -0
  651. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-export.js.map +1 -0
  652. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-list.d.ts +23 -0
  653. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-list.d.ts.map +1 -0
  654. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-list.js +49 -0
  655. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-list.js.map +1 -0
  656. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.d.ts +22 -0
  657. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.d.ts.map +1 -0
  658. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.js +77 -0
  659. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.js.map +1 -0
  660. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-update.d.ts +14 -0
  661. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-update.d.ts.map +1 -0
  662. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-update.js +43 -0
  663. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-update.js.map +1 -0
  664. package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.d.ts +18 -0
  665. package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.d.ts.map +1 -0
  666. package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.js +100 -0
  667. package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.js.map +1 -0
  668. package/payload/platform/plugins/contacts/mcp/dist/tools/group-manage.d.ts +15 -0
  669. package/payload/platform/plugins/contacts/mcp/dist/tools/group-manage.d.ts.map +1 -0
  670. package/payload/platform/plugins/contacts/mcp/dist/tools/group-manage.js +73 -0
  671. package/payload/platform/plugins/contacts/mcp/dist/tools/group-manage.js.map +1 -0
  672. package/payload/platform/plugins/contacts/mcp/package.json +21 -0
  673. package/payload/platform/plugins/deep-research/.claude-plugin/plugin.json +8 -0
  674. package/payload/platform/plugins/deep-research/PLUGIN.md +19 -0
  675. package/payload/platform/plugins/deep-research/recipes/README.md +36 -0
  676. package/payload/platform/plugins/deep-research/skills/academic-verify/SKILL.md +77 -0
  677. package/payload/platform/plugins/deep-research/skills/book-mirror/SKILL.md +70 -0
  678. package/payload/platform/plugins/deep-research/skills/data-research/SKILL.md +110 -0
  679. package/payload/platform/plugins/deep-research/skills/deep-research/SKILL.md +48 -0
  680. package/payload/platform/plugins/deep-research/skills/deep-research/references/citation-styles.md +52 -0
  681. package/payload/platform/plugins/deep-research/skills/deep-research/references/research-modes.md +22 -0
  682. package/payload/platform/plugins/deep-research/skills/deep-research/references/search-strategy.md +24 -0
  683. package/payload/platform/plugins/deep-research/skills/strategic-reading/SKILL.md +71 -0
  684. package/payload/platform/plugins/docs/.claude-plugin/plugin.json +8 -0
  685. package/payload/platform/plugins/docs/PLUGIN.md +58 -0
  686. package/payload/platform/plugins/docs/references/access-control.md +84 -0
  687. package/payload/platform/plugins/docs/references/admin-identity-gate.md +77 -0
  688. package/payload/platform/plugins/docs/references/admin-session.md +181 -0
  689. package/payload/platform/plugins/docs/references/admin-ui.md +397 -0
  690. package/payload/platform/plugins/docs/references/aeo.md +87 -0
  691. package/payload/platform/plugins/docs/references/attachments.md +44 -0
  692. package/payload/platform/plugins/docs/references/cloudflare.md +102 -0
  693. package/payload/platform/plugins/docs/references/contacts-guide.md +94 -0
  694. package/payload/platform/plugins/docs/references/deployment.md +323 -0
  695. package/payload/platform/plugins/docs/references/getting-started.md +95 -0
  696. package/payload/platform/plugins/docs/references/graph.md +163 -0
  697. package/payload/platform/plugins/docs/references/internals.md +547 -0
  698. package/payload/platform/plugins/docs/references/investigate-and-task-skills.md +9 -0
  699. package/payload/platform/plugins/docs/references/linkedin-extension.md +49 -0
  700. package/payload/platform/plugins/docs/references/memory-guide.md +163 -0
  701. package/payload/platform/plugins/docs/references/neo4j.md +72 -0
  702. package/payload/platform/plugins/docs/references/outlook-guide.md +69 -0
  703. package/payload/platform/plugins/docs/references/platform.md +190 -0
  704. package/payload/platform/plugins/docs/references/plugins-guide.md +189 -0
  705. package/payload/platform/plugins/docs/references/projects-guide.md +94 -0
  706. package/payload/platform/plugins/docs/references/quickbooks.md +29 -0
  707. package/payload/platform/plugins/docs/references/samba.md +93 -0
  708. package/payload/platform/plugins/docs/references/session-retrospective.md +14 -0
  709. package/payload/platform/plugins/docs/references/settings.md +82 -0
  710. package/payload/platform/plugins/docs/references/slides.md +31 -0
  711. package/payload/platform/plugins/docs/references/telegram-guide.md +58 -0
  712. package/payload/platform/plugins/docs/references/troubleshooting.md +291 -0
  713. package/payload/platform/plugins/docs/references/visitor-graph.md +83 -0
  714. package/payload/platform/plugins/docs/references/voice-mirror-guide.md +72 -0
  715. package/payload/platform/plugins/docs/superpowers/plans/2026-06-01-memory-edge.md +589 -0
  716. package/payload/platform/plugins/email/.claude-plugin/plugin.json +21 -0
  717. package/payload/platform/plugins/email/PLUGIN.md +112 -0
  718. package/payload/platform/plugins/email/lib/mcp-spawn-tee/index.js +193 -0
  719. package/payload/platform/plugins/email/lib/mcp-spawn-tee/package.json +3 -0
  720. package/payload/platform/plugins/email/mcp/dist/__tests__/attachment-resolve.test.d.ts +2 -0
  721. package/payload/platform/plugins/email/mcp/dist/__tests__/attachment-resolve.test.d.ts.map +1 -0
  722. package/payload/platform/plugins/email/mcp/dist/__tests__/attachment-resolve.test.js +92 -0
  723. package/payload/platform/plugins/email/mcp/dist/__tests__/attachment-resolve.test.js.map +1 -0
  724. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-edit.test.d.ts +2 -0
  725. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-edit.test.d.ts.map +1 -0
  726. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-edit.test.js +71 -0
  727. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-edit.test.js.map +1 -0
  728. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-send.test.d.ts +2 -0
  729. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-send.test.d.ts.map +1 -0
  730. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-send.test.js +95 -0
  731. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-send.test.js.map +1 -0
  732. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft.test.d.ts +2 -0
  733. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft.test.d.ts.map +1 -0
  734. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft.test.js +129 -0
  735. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft.test.js.map +1 -0
  736. package/payload/platform/plugins/email/mcp/dist/__tests__/email-setup.test.d.ts +2 -0
  737. package/payload/platform/plugins/email/mcp/dist/__tests__/email-setup.test.d.ts.map +1 -0
  738. package/payload/platform/plugins/email/mcp/dist/__tests__/email-setup.test.js +113 -0
  739. package/payload/platform/plugins/email/mcp/dist/__tests__/email-setup.test.js.map +1 -0
  740. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.d.ts +2 -0
  741. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.d.ts.map +1 -0
  742. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js +165 -0
  743. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js.map +1 -0
  744. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-probe.test.d.ts +2 -0
  745. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-probe.test.d.ts.map +1 -0
  746. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-probe.test.js +69 -0
  747. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-probe.test.js.map +1 -0
  748. package/payload/platform/plugins/email/mcp/dist/__tests__/mail-options.test.d.ts +2 -0
  749. package/payload/platform/plugins/email/mcp/dist/__tests__/mail-options.test.d.ts.map +1 -0
  750. package/payload/platform/plugins/email/mcp/dist/__tests__/mail-options.test.js +46 -0
  751. package/payload/platform/plugins/email/mcp/dist/__tests__/mail-options.test.js.map +1 -0
  752. package/payload/platform/plugins/email/mcp/dist/__tests__/providers.test.d.ts +2 -0
  753. package/payload/platform/plugins/email/mcp/dist/__tests__/providers.test.d.ts.map +1 -0
  754. package/payload/platform/plugins/email/mcp/dist/__tests__/providers.test.js +110 -0
  755. package/payload/platform/plugins/email/mcp/dist/__tests__/providers.test.js.map +1 -0
  756. package/payload/platform/plugins/email/mcp/dist/__tests__/recipient-filter.test.d.ts +2 -0
  757. package/payload/platform/plugins/email/mcp/dist/__tests__/recipient-filter.test.d.ts.map +1 -0
  758. package/payload/platform/plugins/email/mcp/dist/__tests__/recipient-filter.test.js +57 -0
  759. package/payload/platform/plugins/email/mcp/dist/__tests__/recipient-filter.test.js.map +1 -0
  760. package/payload/platform/plugins/email/mcp/dist/__tests__/send-raw.test.d.ts +2 -0
  761. package/payload/platform/plugins/email/mcp/dist/__tests__/send-raw.test.d.ts.map +1 -0
  762. package/payload/platform/plugins/email/mcp/dist/__tests__/send-raw.test.js +38 -0
  763. package/payload/platform/plugins/email/mcp/dist/__tests__/send-raw.test.js.map +1 -0
  764. package/payload/platform/plugins/email/mcp/dist/__tests__/setup-probe.test.d.ts +2 -0
  765. package/payload/platform/plugins/email/mcp/dist/__tests__/setup-probe.test.d.ts.map +1 -0
  766. package/payload/platform/plugins/email/mcp/dist/__tests__/setup-probe.test.js +56 -0
  767. package/payload/platform/plugins/email/mcp/dist/__tests__/setup-probe.test.js.map +1 -0
  768. package/payload/platform/plugins/email/mcp/dist/__tests__/smtp-probe.test.d.ts +2 -0
  769. package/payload/platform/plugins/email/mcp/dist/__tests__/smtp-probe.test.d.ts.map +1 -0
  770. package/payload/platform/plugins/email/mcp/dist/__tests__/smtp-probe.test.js +46 -0
  771. package/payload/platform/plugins/email/mcp/dist/__tests__/smtp-probe.test.js.map +1 -0
  772. package/payload/platform/plugins/email/mcp/dist/index.d.ts +2 -0
  773. package/payload/platform/plugins/email/mcp/dist/index.d.ts.map +1 -0
  774. package/payload/platform/plugins/email/mcp/dist/index.js +522 -0
  775. package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -0
  776. package/payload/platform/plugins/email/mcp/dist/lib/attachment-archive.d.ts +39 -0
  777. package/payload/platform/plugins/email/mcp/dist/lib/attachment-archive.d.ts.map +1 -0
  778. package/payload/platform/plugins/email/mcp/dist/lib/attachment-archive.js +0 -0
  779. package/payload/platform/plugins/email/mcp/dist/lib/attachment-archive.js.map +1 -0
  780. package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.d.ts +31 -0
  781. package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.d.ts.map +1 -0
  782. package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.js +103 -0
  783. package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.js.map +1 -0
  784. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.d.ts +17 -0
  785. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.d.ts.map +1 -0
  786. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.js +186 -0
  787. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.js.map +1 -0
  788. package/payload/platform/plugins/email/mcp/dist/lib/compose.d.ts +47 -0
  789. package/payload/platform/plugins/email/mcp/dist/lib/compose.d.ts.map +1 -0
  790. package/payload/platform/plugins/email/mcp/dist/lib/compose.js +75 -0
  791. package/payload/platform/plugins/email/mcp/dist/lib/compose.js.map +1 -0
  792. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-dispatch.d.ts +30 -0
  793. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-dispatch.d.ts.map +1 -0
  794. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-dispatch.js +305 -0
  795. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-dispatch.js.map +1 -0
  796. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-lookup.d.ts +19 -0
  797. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-lookup.d.ts.map +1 -0
  798. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-lookup.js +51 -0
  799. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-lookup.js.map +1 -0
  800. package/payload/platform/plugins/email/mcp/dist/lib/credentials.d.ts +89 -0
  801. package/payload/platform/plugins/email/mcp/dist/lib/credentials.d.ts.map +1 -0
  802. package/payload/platform/plugins/email/mcp/dist/lib/credentials.js +245 -0
  803. package/payload/platform/plugins/email/mcp/dist/lib/credentials.js.map +1 -0
  804. package/payload/platform/plugins/email/mcp/dist/lib/embedding.d.ts +2 -0
  805. package/payload/platform/plugins/email/mcp/dist/lib/embedding.d.ts.map +1 -0
  806. package/payload/platform/plugins/email/mcp/dist/lib/embedding.js +24 -0
  807. package/payload/platform/plugins/email/mcp/dist/lib/embedding.js.map +1 -0
  808. package/payload/platform/plugins/email/mcp/dist/lib/graph.d.ts +29 -0
  809. package/payload/platform/plugins/email/mcp/dist/lib/graph.d.ts.map +1 -0
  810. package/payload/platform/plugins/email/mcp/dist/lib/graph.js +18 -0
  811. package/payload/platform/plugins/email/mcp/dist/lib/graph.js.map +1 -0
  812. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +352 -0
  813. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts.map +1 -0
  814. package/payload/platform/plugins/email/mcp/dist/lib/imap.js +1021 -0
  815. package/payload/platform/plugins/email/mcp/dist/lib/imap.js.map +1 -0
  816. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.d.ts +31 -0
  817. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.d.ts.map +1 -0
  818. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.js +15 -0
  819. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.js.map +1 -0
  820. package/payload/platform/plugins/email/mcp/dist/lib/neo4j.d.ts +5 -0
  821. package/payload/platform/plugins/email/mcp/dist/lib/neo4j.d.ts.map +1 -0
  822. package/payload/platform/plugins/email/mcp/dist/lib/neo4j.js +40 -0
  823. package/payload/platform/plugins/email/mcp/dist/lib/neo4j.js.map +1 -0
  824. package/payload/platform/plugins/email/mcp/dist/lib/providers.d.ts +71 -0
  825. package/payload/platform/plugins/email/mcp/dist/lib/providers.d.ts.map +1 -0
  826. package/payload/platform/plugins/email/mcp/dist/lib/providers.js +782 -0
  827. package/payload/platform/plugins/email/mcp/dist/lib/providers.js.map +1 -0
  828. package/payload/platform/plugins/email/mcp/dist/lib/screening.d.ts +29 -0
  829. package/payload/platform/plugins/email/mcp/dist/lib/screening.d.ts.map +1 -0
  830. package/payload/platform/plugins/email/mcp/dist/lib/screening.js +105 -0
  831. package/payload/platform/plugins/email/mcp/dist/lib/screening.js.map +1 -0
  832. package/payload/platform/plugins/email/mcp/dist/lib/setup-probe.d.ts +42 -0
  833. package/payload/platform/plugins/email/mcp/dist/lib/setup-probe.d.ts.map +1 -0
  834. package/payload/platform/plugins/email/mcp/dist/lib/setup-probe.js +72 -0
  835. package/payload/platform/plugins/email/mcp/dist/lib/setup-probe.js.map +1 -0
  836. package/payload/platform/plugins/email/mcp/dist/lib/smtp.d.ts +61 -0
  837. package/payload/platform/plugins/email/mcp/dist/lib/smtp.d.ts.map +1 -0
  838. package/payload/platform/plugins/email/mcp/dist/lib/smtp.js +140 -0
  839. package/payload/platform/plugins/email/mcp/dist/lib/smtp.js.map +1 -0
  840. package/payload/platform/plugins/email/mcp/dist/scripts/email-auto-respond.d.ts +38 -0
  841. package/payload/platform/plugins/email/mcp/dist/scripts/email-auto-respond.d.ts.map +1 -0
  842. package/payload/platform/plugins/email/mcp/dist/scripts/email-auto-respond.js +817 -0
  843. package/payload/platform/plugins/email/mcp/dist/scripts/email-auto-respond.js.map +1 -0
  844. package/payload/platform/plugins/email/mcp/dist/scripts/email-fetch.d.ts +30 -0
  845. package/payload/platform/plugins/email/mcp/dist/scripts/email-fetch.d.ts.map +1 -0
  846. package/payload/platform/plugins/email/mcp/dist/scripts/email-fetch.js +215 -0
  847. package/payload/platform/plugins/email/mcp/dist/scripts/email-fetch.js.map +1 -0
  848. package/payload/platform/plugins/email/mcp/dist/scripts/send-transactional.d.ts +2 -0
  849. package/payload/platform/plugins/email/mcp/dist/scripts/send-transactional.d.ts.map +1 -0
  850. package/payload/platform/plugins/email/mcp/dist/scripts/send-transactional.js +55 -0
  851. package/payload/platform/plugins/email/mcp/dist/scripts/send-transactional.js.map +1 -0
  852. package/payload/platform/plugins/email/mcp/dist/tools/email-auto-respond-config.d.ts +19 -0
  853. package/payload/platform/plugins/email/mcp/dist/tools/email-auto-respond-config.d.ts.map +1 -0
  854. package/payload/platform/plugins/email/mcp/dist/tools/email-auto-respond-config.js +151 -0
  855. package/payload/platform/plugins/email/mcp/dist/tools/email-auto-respond-config.js.map +1 -0
  856. package/payload/platform/plugins/email/mcp/dist/tools/email-classify.d.ts +6 -0
  857. package/payload/platform/plugins/email/mcp/dist/tools/email-classify.d.ts.map +1 -0
  858. package/payload/platform/plugins/email/mcp/dist/tools/email-classify.js +89 -0
  859. package/payload/platform/plugins/email/mcp/dist/tools/email-classify.js.map +1 -0
  860. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-edit.d.ts +9 -0
  861. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-edit.d.ts.map +1 -0
  862. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-edit.js +23 -0
  863. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-edit.js.map +1 -0
  864. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-send.d.ts +8 -0
  865. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-send.d.ts.map +1 -0
  866. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-send.js +52 -0
  867. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-send.js.map +1 -0
  868. package/payload/platform/plugins/email/mcp/dist/tools/email-draft.d.ts +7 -0
  869. package/payload/platform/plugins/email/mcp/dist/tools/email-draft.d.ts.map +1 -0
  870. package/payload/platform/plugins/email/mcp/dist/tools/email-draft.js +17 -0
  871. package/payload/platform/plugins/email/mcp/dist/tools/email-draft.js.map +1 -0
  872. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.d.ts +15 -0
  873. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.d.ts.map +1 -0
  874. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.js +54 -0
  875. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.js.map +1 -0
  876. package/payload/platform/plugins/email/mcp/dist/tools/email-graph-query.d.ts +24 -0
  877. package/payload/platform/plugins/email/mcp/dist/tools/email-graph-query.d.ts.map +1 -0
  878. package/payload/platform/plugins/email/mcp/dist/tools/email-graph-query.js +293 -0
  879. package/payload/platform/plugins/email/mcp/dist/tools/email-graph-query.js.map +1 -0
  880. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.d.ts +20 -0
  881. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.d.ts.map +1 -0
  882. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.js +195 -0
  883. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.js.map +1 -0
  884. package/payload/platform/plugins/email/mcp/dist/tools/email-otp-extract.d.ts +15 -0
  885. package/payload/platform/plugins/email/mcp/dist/tools/email-otp-extract.d.ts.map +1 -0
  886. package/payload/platform/plugins/email/mcp/dist/tools/email-otp-extract.js +144 -0
  887. package/payload/platform/plugins/email/mcp/dist/tools/email-otp-extract.js.map +1 -0
  888. package/payload/platform/plugins/email/mcp/dist/tools/email-read.d.ts +14 -0
  889. package/payload/platform/plugins/email/mcp/dist/tools/email-read.d.ts.map +1 -0
  890. package/payload/platform/plugins/email/mcp/dist/tools/email-read.js +94 -0
  891. package/payload/platform/plugins/email/mcp/dist/tools/email-read.js.map +1 -0
  892. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.d.ts +13 -0
  893. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.d.ts.map +1 -0
  894. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js +71 -0
  895. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js.map +1 -0
  896. package/payload/platform/plugins/email/mcp/dist/tools/email-search.d.ts +15 -0
  897. package/payload/platform/plugins/email/mcp/dist/tools/email-search.d.ts.map +1 -0
  898. package/payload/platform/plugins/email/mcp/dist/tools/email-search.js +77 -0
  899. package/payload/platform/plugins/email/mcp/dist/tools/email-search.js.map +1 -0
  900. package/payload/platform/plugins/email/mcp/dist/tools/email-send.d.ts +13 -0
  901. package/payload/platform/plugins/email/mcp/dist/tools/email-send.d.ts.map +1 -0
  902. package/payload/platform/plugins/email/mcp/dist/tools/email-send.js +36 -0
  903. package/payload/platform/plugins/email/mcp/dist/tools/email-send.js.map +1 -0
  904. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts +22 -0
  905. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts.map +1 -0
  906. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js +202 -0
  907. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js.map +1 -0
  908. package/payload/platform/plugins/email/mcp/dist/tools/email-status.d.ts +6 -0
  909. package/payload/platform/plugins/email/mcp/dist/tools/email-status.d.ts.map +1 -0
  910. package/payload/platform/plugins/email/mcp/dist/tools/email-status.js +43 -0
  911. package/payload/platform/plugins/email/mcp/dist/tools/email-status.js.map +1 -0
  912. package/payload/platform/plugins/email/mcp/package.json +24 -0
  913. package/payload/platform/plugins/email/mcp/vitest.config.ts +9 -0
  914. package/payload/platform/plugins/email/references/email-reference.md +181 -0
  915. package/payload/platform/plugins/email/skills/email-composition/SKILL.md +208 -0
  916. package/payload/platform/plugins/email/skills/email-ingest/SKILL.md +89 -0
  917. package/payload/platform/plugins/graph/.claude-plugin/plugin.json +8 -0
  918. package/payload/platform/plugins/graph/PLUGIN.md +39 -0
  919. package/payload/platform/plugins/graph-viewer/.claude-plugin/plugin.json +8 -0
  920. package/payload/platform/plugins/graph-viewer/PLUGIN.md +56 -0
  921. package/payload/platform/plugins/graph-viewer/mcp/dist/index.d.ts +7 -0
  922. package/payload/platform/plugins/graph-viewer/mcp/dist/index.d.ts.map +1 -0
  923. package/payload/platform/plugins/graph-viewer/mcp/dist/index.js +70 -0
  924. package/payload/platform/plugins/graph-viewer/mcp/dist/index.js.map +1 -0
  925. package/payload/platform/plugins/graph-viewer/mcp/dist/lib/neo4j.d.ts +5 -0
  926. package/payload/platform/plugins/graph-viewer/mcp/dist/lib/neo4j.d.ts.map +1 -0
  927. package/payload/platform/plugins/graph-viewer/mcp/dist/lib/neo4j.js +43 -0
  928. package/payload/platform/plugins/graph-viewer/mcp/dist/lib/neo4j.js.map +1 -0
  929. package/payload/platform/plugins/graph-viewer/mcp/dist/render/draw.d.ts +28 -0
  930. package/payload/platform/plugins/graph-viewer/mcp/dist/render/draw.d.ts.map +1 -0
  931. package/payload/platform/plugins/graph-viewer/mcp/dist/render/draw.js +73 -0
  932. package/payload/platform/plugins/graph-viewer/mcp/dist/render/draw.js.map +1 -0
  933. package/payload/platform/plugins/graph-viewer/mcp/dist/render/layout.d.ts +40 -0
  934. package/payload/platform/plugins/graph-viewer/mcp/dist/render/layout.d.ts.map +1 -0
  935. package/payload/platform/plugins/graph-viewer/mcp/dist/render/layout.js +117 -0
  936. package/payload/platform/plugins/graph-viewer/mcp/dist/render/layout.js.map +1 -0
  937. package/payload/platform/plugins/graph-viewer/mcp/dist/tools/graph-render.d.ts +45 -0
  938. package/payload/platform/plugins/graph-viewer/mcp/dist/tools/graph-render.d.ts.map +1 -0
  939. package/payload/platform/plugins/graph-viewer/mcp/dist/tools/graph-render.js +199 -0
  940. package/payload/platform/plugins/graph-viewer/mcp/dist/tools/graph-render.js.map +1 -0
  941. package/payload/platform/plugins/graph-viewer/mcp/package.json +25 -0
  942. package/payload/platform/plugins/graph-viewer/mcp/vitest.config.ts +8 -0
  943. package/payload/platform/plugins/graph-viewer/skills/render-graph/SKILL.md +43 -0
  944. package/payload/platform/plugins/linkedin-extension/.claude-plugin/plugin.json +8 -0
  945. package/payload/platform/plugins/linkedin-extension/PLUGIN.md +58 -0
  946. package/payload/platform/plugins/linkedin-extension/extension/README.md +44 -0
  947. package/payload/platform/plugins/linkedin-extension/extension/__tests__/fixtures/profile.html +34 -0
  948. package/payload/platform/plugins/linkedin-extension/extension/__tests__/fixtures/thread.html +36 -0
  949. package/payload/platform/plugins/linkedin-extension/extension/assets/pill.css +52 -0
  950. package/payload/platform/plugins/linkedin-extension/extension/background/sw.js +60 -0
  951. package/payload/platform/plugins/linkedin-extension/extension/content/extractors.js +127 -0
  952. package/payload/platform/plugins/linkedin-extension/extension/content/profile.js +82 -0
  953. package/payload/platform/plugins/linkedin-extension/extension/content/thread.js +84 -0
  954. package/payload/platform/plugins/linkedin-extension/extension/manifest.json +32 -0
  955. package/payload/platform/plugins/linkedin-extension/extension/options/options.html +33 -0
  956. package/payload/platform/plugins/linkedin-extension/extension/options/options.js +30 -0
  957. package/payload/platform/plugins/linkedin-extension/skills/linkedin-extension/SKILL.md +93 -0
  958. package/payload/platform/plugins/linkedin-import/.claude-plugin/plugin.json +8 -0
  959. package/payload/platform/plugins/linkedin-import/PLUGIN.md +27 -0
  960. package/payload/platform/plugins/linkedin-import/skills/linkedin-import/SKILL.md +119 -0
  961. package/payload/platform/plugins/linkedin-import/skills/linkedin-import/references/connections.md +135 -0
  962. package/payload/platform/plugins/linkedin-import/skills/linkedin-import/references/profile.md +94 -0
  963. package/payload/platform/plugins/memory/.claude-plugin/plugin.json +21 -0
  964. package/payload/platform/plugins/memory/PLUGIN.md +290 -0
  965. package/payload/platform/plugins/memory/bin/conversation-archive-ingest.mjs +616 -0
  966. package/payload/platform/plugins/memory/bin/conversation-archive-ingest.sh +106 -0
  967. package/payload/platform/plugins/memory/lib/mcp-spawn-tee/index.js +193 -0
  968. package/payload/platform/plugins/memory/lib/mcp-spawn-tee/package.json +3 -0
  969. package/payload/platform/plugins/memory/mcp/dist/index.d.ts +2 -0
  970. package/payload/platform/plugins/memory/mcp/dist/index.d.ts.map +1 -0
  971. package/payload/platform/plugins/memory/mcp/dist/index.js +2479 -0
  972. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -0
  973. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-revision.test.d.ts +2 -0
  974. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-revision.test.d.ts.map +1 -0
  975. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-revision.test.js +68 -0
  976. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-revision.test.js.map +1 -0
  977. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-rewriter-operator-hint.test.d.ts +2 -0
  978. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-rewriter-operator-hint.test.d.ts.map +1 -0
  979. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-rewriter-operator-hint.test.js +90 -0
  980. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-rewriter-operator-hint.test.js.map +1 -0
  981. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/document-sectioniser.test.d.ts +2 -0
  982. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/document-sectioniser.test.d.ts.map +1 -0
  983. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/document-sectioniser.test.js +41 -0
  984. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/document-sectioniser.test.js.map +1 -0
  985. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-embed-net.test.d.ts +2 -0
  986. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-embed-net.test.d.ts.map +1 -0
  987. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-embed-net.test.js +90 -0
  988. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-embed-net.test.js.map +1 -0
  989. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-label.test.d.ts +2 -0
  990. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-label.test.d.ts.map +1 -0
  991. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-label.test.js +30 -0
  992. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-label.test.js.map +1 -0
  993. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-property.test.d.ts +2 -0
  994. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-property.test.d.ts.map +1 -0
  995. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-property.test.js +25 -0
  996. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-property.test.js.map +1 -0
  997. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-delete-gate.test.d.ts +2 -0
  998. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-delete-gate.test.d.ts.map +1 -0
  999. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-delete-gate.test.js +62 -0
  1000. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-delete-gate.test.js.map +1 -0
  1001. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.d.ts +2 -0
  1002. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.d.ts.map +1 -0
  1003. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.js +50 -0
  1004. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.js.map +1 -0
  1005. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/live-schema-source.test.d.ts +2 -0
  1006. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/live-schema-source.test.d.ts.map +1 -0
  1007. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/live-schema-source.test.js +154 -0
  1008. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/live-schema-source.test.js.map +1 -0
  1009. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.d.ts +2 -0
  1010. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.d.ts.map +1 -0
  1011. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js +226 -0
  1012. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js.map +1 -0
  1013. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/neo4j-password-path.test.d.ts +2 -0
  1014. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/neo4j-password-path.test.d.ts.map +1 -0
  1015. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/neo4j-password-path.test.js +57 -0
  1016. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/neo4j-password-path.test.js.map +1 -0
  1017. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-backlinks.test.d.ts +2 -0
  1018. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-backlinks.test.d.ts.map +1 -0
  1019. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-backlinks.test.js +24 -0
  1020. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-backlinks.test.js.map +1 -0
  1021. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-prune-revisions.test.d.ts +2 -0
  1022. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-prune-revisions.test.d.ts.map +1 -0
  1023. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-prune-revisions.test.js +51 -0
  1024. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-prune-revisions.test.js.map +1 -0
  1025. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-tag-normalisation.test.d.ts +2 -0
  1026. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-tag-normalisation.test.d.ts.map +1 -0
  1027. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-tag-normalisation.test.js +51 -0
  1028. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-tag-normalisation.test.js.map +1 -0
  1029. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/relationship-patterns.test.d.ts +2 -0
  1030. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/relationship-patterns.test.d.ts.map +1 -0
  1031. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/relationship-patterns.test.js +146 -0
  1032. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/relationship-patterns.test.js.map +1 -0
  1033. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/relative-date.test.d.ts +2 -0
  1034. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/relative-date.test.d.ts.map +1 -0
  1035. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/relative-date.test.js +68 -0
  1036. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/relative-date.test.js.map +1 -0
  1037. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/resolve-active-vertical.test.d.ts +2 -0
  1038. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/resolve-active-vertical.test.d.ts.map +1 -0
  1039. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/resolve-active-vertical.test.js +116 -0
  1040. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/resolve-active-vertical.test.js.map +1 -0
  1041. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.d.ts +2 -0
  1042. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.d.ts.map +1 -0
  1043. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.js +71 -0
  1044. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.js.map +1 -0
  1045. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-doc-contradictions.test.d.ts +2 -0
  1046. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-doc-contradictions.test.d.ts.map +1 -0
  1047. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-doc-contradictions.test.js +214 -0
  1048. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-doc-contradictions.test.js.map +1 -0
  1049. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-loader.test.d.ts +2 -0
  1050. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-loader.test.d.ts.map +1 -0
  1051. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-loader.test.js +245 -0
  1052. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-loader.test.js.map +1 -0
  1053. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-validator.test.d.ts +2 -0
  1054. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-validator.test.d.ts.map +1 -0
  1055. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-validator.test.js +642 -0
  1056. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-validator.test.js.map +1 -0
  1057. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-write-path-task802.test.d.ts +2 -0
  1058. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-write-path-task802.test.d.ts.map +1 -0
  1059. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-write-path-task802.test.js +113 -0
  1060. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-write-path-task802.test.js.map +1 -0
  1061. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/timeline-extractor.test.d.ts +2 -0
  1062. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/timeline-extractor.test.d.ts.map +1 -0
  1063. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/timeline-extractor.test.js +111 -0
  1064. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/timeline-extractor.test.js.map +1 -0
  1065. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/typed-edge-schema.test.d.ts +2 -0
  1066. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/typed-edge-schema.test.d.ts.map +1 -0
  1067. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/typed-edge-schema.test.js +85 -0
  1068. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/typed-edge-schema.test.js.map +1 -0
  1069. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/vector-indexed-labels-drift.test.d.ts +2 -0
  1070. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/vector-indexed-labels-drift.test.d.ts.map +1 -0
  1071. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/vector-indexed-labels-drift.test.js +27 -0
  1072. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/vector-indexed-labels-drift.test.js.map +1 -0
  1073. package/payload/platform/plugins/memory/mcp/dist/lib/attachments.d.ts +37 -0
  1074. package/payload/platform/plugins/memory/mcp/dist/lib/attachments.d.ts.map +1 -0
  1075. package/payload/platform/plugins/memory/mcp/dist/lib/attachments.js +69 -0
  1076. package/payload/platform/plugins/memory/mcp/dist/lib/attachments.js.map +1 -0
  1077. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.d.ts +91 -0
  1078. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.d.ts.map +1 -0
  1079. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.js +39 -0
  1080. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.js.map +1 -0
  1081. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-rewriter.d.ts +60 -0
  1082. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-rewriter.d.ts.map +1 -0
  1083. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-rewriter.js +169 -0
  1084. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-rewriter.js.map +1 -0
  1085. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/email.d.ts +3 -0
  1086. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/email.d.ts.map +1 -0
  1087. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/email.js +61 -0
  1088. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/email.js.map +1 -0
  1089. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.d.ts +7 -0
  1090. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.d.ts.map +1 -0
  1091. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.js +36 -0
  1092. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.js.map +1 -0
  1093. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/timestamp-scanner.d.ts +49 -0
  1094. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/timestamp-scanner.d.ts.map +1 -0
  1095. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/timestamp-scanner.js +35 -0
  1096. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/timestamp-scanner.js.map +1 -0
  1097. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.d.ts +47 -0
  1098. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.d.ts.map +1 -0
  1099. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.js +38 -0
  1100. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.js.map +1 -0
  1101. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/whatsapp-text.d.ts +3 -0
  1102. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/whatsapp-text.d.ts.map +1 -0
  1103. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/whatsapp-text.js +155 -0
  1104. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/whatsapp-text.js.map +1 -0
  1105. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/x-dm.d.ts +3 -0
  1106. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/x-dm.d.ts.map +1 -0
  1107. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/x-dm.js +101 -0
  1108. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/x-dm.js.map +1 -0
  1109. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/delta-cursor.d.ts +11 -0
  1110. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/delta-cursor.d.ts.map +1 -0
  1111. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/delta-cursor.js +20 -0
  1112. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/delta-cursor.js.map +1 -0
  1113. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.d.ts +16 -0
  1114. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.d.ts.map +1 -0
  1115. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.js +43 -0
  1116. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.js.map +1 -0
  1117. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sender-bind.d.ts +16 -0
  1118. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sender-bind.d.ts.map +1 -0
  1119. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sender-bind.js +60 -0
  1120. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sender-bind.js.map +1 -0
  1121. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sessionize.d.ts +9 -0
  1122. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sessionize.d.ts.map +1 -0
  1123. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sessionize.js +32 -0
  1124. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sessionize.js.map +1 -0
  1125. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/to-turn-text.d.ts +3 -0
  1126. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/to-turn-text.d.ts.map +1 -0
  1127. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/to-turn-text.js +29 -0
  1128. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/to-turn-text.js.map +1 -0
  1129. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/turn-text-cache-path.d.ts +8 -0
  1130. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/turn-text-cache-path.d.ts.map +1 -0
  1131. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/turn-text-cache-path.js +27 -0
  1132. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/turn-text-cache-path.js.map +1 -0
  1133. package/payload/platform/plugins/memory/mcp/dist/lib/document-chunker.d.ts +45 -0
  1134. package/payload/platform/plugins/memory/mcp/dist/lib/document-chunker.d.ts.map +1 -0
  1135. package/payload/platform/plugins/memory/mcp/dist/lib/document-chunker.js +125 -0
  1136. package/payload/platform/plugins/memory/mcp/dist/lib/document-chunker.js.map +1 -0
  1137. package/payload/platform/plugins/memory/mcp/dist/lib/document-hierarchy.d.ts +9 -0
  1138. package/payload/platform/plugins/memory/mcp/dist/lib/document-hierarchy.d.ts.map +1 -0
  1139. package/payload/platform/plugins/memory/mcp/dist/lib/document-hierarchy.js +61 -0
  1140. package/payload/platform/plugins/memory/mcp/dist/lib/document-hierarchy.js.map +1 -0
  1141. package/payload/platform/plugins/memory/mcp/dist/lib/document-sectioniser.d.ts +10 -0
  1142. package/payload/platform/plugins/memory/mcp/dist/lib/document-sectioniser.d.ts.map +1 -0
  1143. package/payload/platform/plugins/memory/mcp/dist/lib/document-sectioniser.js +47 -0
  1144. package/payload/platform/plugins/memory/mcp/dist/lib/document-sectioniser.js.map +1 -0
  1145. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/index.d.ts +44 -0
  1146. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/index.d.ts.map +1 -0
  1147. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/index.js +14 -0
  1148. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/index.js.map +1 -0
  1149. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-backlinks.d.ts +15 -0
  1150. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-backlinks.d.ts.map +1 -0
  1151. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-backlinks.js +37 -0
  1152. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-backlinks.js.map +1 -0
  1153. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-citation-audit.d.ts +3 -0
  1154. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-citation-audit.d.ts.map +1 -0
  1155. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-citation-audit.js +16 -0
  1156. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-citation-audit.js.map +1 -0
  1157. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-dead-edges.d.ts +19 -0
  1158. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-dead-edges.d.ts.map +1 -0
  1159. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-dead-edges.js +39 -0
  1160. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-dead-edges.js.map +1 -0
  1161. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-orphans.d.ts +19 -0
  1162. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-orphans.d.ts.map +1 -0
  1163. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-orphans.js +42 -0
  1164. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-orphans.js.map +1 -0
  1165. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-prune-revisions.d.ts +21 -0
  1166. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-prune-revisions.d.ts.map +1 -0
  1167. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-prune-revisions.js +27 -0
  1168. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-prune-revisions.js.map +1 -0
  1169. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-stale-truth.d.ts +18 -0
  1170. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-stale-truth.d.ts.map +1 -0
  1171. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-stale-truth.js +60 -0
  1172. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-stale-truth.js.map +1 -0
  1173. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-tag-normalisation.d.ts +25 -0
  1174. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-tag-normalisation.d.ts.map +1 -0
  1175. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-tag-normalisation.js +90 -0
  1176. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-tag-normalisation.js.map +1 -0
  1177. package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.d.ts +2 -0
  1178. package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.d.ts.map +1 -0
  1179. package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.js +6 -0
  1180. package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.js.map +1 -0
  1181. package/payload/platform/plugins/memory/mcp/dist/lib/filter-token.d.ts +36 -0
  1182. package/payload/platform/plugins/memory/mcp/dist/lib/filter-token.d.ts.map +1 -0
  1183. package/payload/platform/plugins/memory/mcp/dist/lib/filter-token.js +86 -0
  1184. package/payload/platform/plugins/memory/mcp/dist/lib/filter-token.js.map +1 -0
  1185. package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.d.ts +41 -0
  1186. package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.d.ts.map +1 -0
  1187. package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.js +113 -0
  1188. package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.js.map +1 -0
  1189. package/payload/platform/plugins/memory/mcp/dist/lib/graph-write-gate.d.ts +76 -0
  1190. package/payload/platform/plugins/memory/mcp/dist/lib/graph-write-gate.d.ts.map +1 -0
  1191. package/payload/platform/plugins/memory/mcp/dist/lib/graph-write-gate.js +148 -0
  1192. package/payload/platform/plugins/memory/mcp/dist/lib/graph-write-gate.js.map +1 -0
  1193. package/payload/platform/plugins/memory/mcp/dist/lib/kd-classify-gate.d.ts +41 -0
  1194. package/payload/platform/plugins/memory/mcp/dist/lib/kd-classify-gate.d.ts.map +1 -0
  1195. package/payload/platform/plugins/memory/mcp/dist/lib/kd-classify-gate.js +69 -0
  1196. package/payload/platform/plugins/memory/mcp/dist/lib/kd-classify-gate.js.map +1 -0
  1197. package/payload/platform/plugins/memory/mcp/dist/lib/label-delete-gate.d.ts +18 -0
  1198. package/payload/platform/plugins/memory/mcp/dist/lib/label-delete-gate.d.ts.map +1 -0
  1199. package/payload/platform/plugins/memory/mcp/dist/lib/label-delete-gate.js +31 -0
  1200. package/payload/platform/plugins/memory/mcp/dist/lib/label-delete-gate.js.map +1 -0
  1201. package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.d.ts +18 -0
  1202. package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.d.ts.map +1 -0
  1203. package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.js +35 -0
  1204. package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.js.map +1 -0
  1205. package/payload/platform/plugins/memory/mcp/dist/lib/live-schema-source.d.ts +119 -0
  1206. package/payload/platform/plugins/memory/mcp/dist/lib/live-schema-source.d.ts.map +1 -0
  1207. package/payload/platform/plugins/memory/mcp/dist/lib/live-schema-source.js +208 -0
  1208. package/payload/platform/plugins/memory/mcp/dist/lib/live-schema-source.js.map +1 -0
  1209. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.d.ts +248 -0
  1210. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.d.ts.map +1 -0
  1211. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js +824 -0
  1212. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js.map +1 -0
  1213. package/payload/platform/plugins/memory/mcp/dist/lib/llm-ranker.d.ts +63 -0
  1214. package/payload/platform/plugins/memory/mcp/dist/lib/llm-ranker.d.ts.map +1 -0
  1215. package/payload/platform/plugins/memory/mcp/dist/lib/llm-ranker.js +210 -0
  1216. package/payload/platform/plugins/memory/mcp/dist/lib/llm-ranker.js.map +1 -0
  1217. package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.d.ts +65 -0
  1218. package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.d.ts.map +1 -0
  1219. package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.js +182 -0
  1220. package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.js.map +1 -0
  1221. package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.d.ts +19 -0
  1222. package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.d.ts.map +1 -0
  1223. package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.js +76 -0
  1224. package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.js.map +1 -0
  1225. package/payload/platform/plugins/memory/mcp/dist/lib/relationship-patterns.d.ts +66 -0
  1226. package/payload/platform/plugins/memory/mcp/dist/lib/relationship-patterns.d.ts.map +1 -0
  1227. package/payload/platform/plugins/memory/mcp/dist/lib/relationship-patterns.js +102 -0
  1228. package/payload/platform/plugins/memory/mcp/dist/lib/relationship-patterns.js.map +1 -0
  1229. package/payload/platform/plugins/memory/mcp/dist/lib/relative-date.d.ts +13 -0
  1230. package/payload/platform/plugins/memory/mcp/dist/lib/relative-date.d.ts.map +1 -0
  1231. package/payload/platform/plugins/memory/mcp/dist/lib/relative-date.js +191 -0
  1232. package/payload/platform/plugins/memory/mcp/dist/lib/relative-date.js.map +1 -0
  1233. package/payload/platform/plugins/memory/mcp/dist/lib/resolve-active-vertical.d.ts +33 -0
  1234. package/payload/platform/plugins/memory/mcp/dist/lib/resolve-active-vertical.d.ts.map +1 -0
  1235. package/payload/platform/plugins/memory/mcp/dist/lib/resolve-active-vertical.js +44 -0
  1236. package/payload/platform/plugins/memory/mcp/dist/lib/resolve-active-vertical.js.map +1 -0
  1237. package/payload/platform/plugins/memory/mcp/dist/lib/schema-loader.d.ts +200 -0
  1238. package/payload/platform/plugins/memory/mcp/dist/lib/schema-loader.d.ts.map +1 -0
  1239. package/payload/platform/plugins/memory/mcp/dist/lib/schema-loader.js +607 -0
  1240. package/payload/platform/plugins/memory/mcp/dist/lib/schema-loader.js.map +1 -0
  1241. package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.d.ts +92 -0
  1242. package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.d.ts.map +1 -0
  1243. package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.js +243 -0
  1244. package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.js.map +1 -0
  1245. package/payload/platform/plugins/memory/mcp/dist/lib/section-types.d.ts +127 -0
  1246. package/payload/platform/plugins/memory/mcp/dist/lib/section-types.d.ts.map +1 -0
  1247. package/payload/platform/plugins/memory/mcp/dist/lib/section-types.js +56 -0
  1248. package/payload/platform/plugins/memory/mcp/dist/lib/section-types.js.map +1 -0
  1249. package/payload/platform/plugins/memory/mcp/dist/lib/timeline-extractor.d.ts +19 -0
  1250. package/payload/platform/plugins/memory/mcp/dist/lib/timeline-extractor.d.ts.map +1 -0
  1251. package/payload/platform/plugins/memory/mcp/dist/lib/timeline-extractor.js +179 -0
  1252. package/payload/platform/plugins/memory/mcp/dist/lib/timeline-extractor.js.map +1 -0
  1253. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.d.ts +35 -0
  1254. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.d.ts.map +1 -0
  1255. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.js +28 -0
  1256. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.js.map +1 -0
  1257. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-schema.d.ts +29 -0
  1258. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-schema.d.ts.map +1 -0
  1259. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-schema.js +160 -0
  1260. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-schema.js.map +1 -0
  1261. package/payload/platform/plugins/memory/mcp/dist/lib/uuid.d.ts +3 -0
  1262. package/payload/platform/plugins/memory/mcp/dist/lib/uuid.d.ts.map +1 -0
  1263. package/payload/platform/plugins/memory/mcp/dist/lib/uuid.js +12 -0
  1264. package/payload/platform/plugins/memory/mcp/dist/lib/uuid.js.map +1 -0
  1265. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/_helpers/emit-capture.d.ts +22 -0
  1266. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/_helpers/emit-capture.d.ts.map +1 -0
  1267. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/_helpers/emit-capture.js +44 -0
  1268. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/_helpers/emit-capture.js.map +1 -0
  1269. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/build-text-representation-bound.test.d.ts +2 -0
  1270. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/build-text-representation-bound.test.d.ts.map +1 -0
  1271. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/build-text-representation-bound.test.js +20 -0
  1272. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/build-text-representation-bound.test.js.map +1 -0
  1273. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights-emit.test.d.ts +2 -0
  1274. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights-emit.test.d.ts.map +1 -0
  1275. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights-emit.test.js +68 -0
  1276. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights-emit.test.js.map +1 -0
  1277. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.d.ts +7 -0
  1278. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.d.ts.map +1 -0
  1279. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.js +298 -0
  1280. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.js.map +1 -0
  1281. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection-emit.test.d.ts +2 -0
  1282. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection-emit.test.d.ts.map +1 -0
  1283. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection-emit.test.js +48 -0
  1284. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection-emit.test.js.map +1 -0
  1285. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection.test.d.ts +2 -0
  1286. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection.test.d.ts.map +1 -0
  1287. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection.test.js +184 -0
  1288. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection.test.js.map +1 -0
  1289. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-preference-embed.test.d.ts +2 -0
  1290. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-preference-embed.test.d.ts.map +1 -0
  1291. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-preference-embed.test.js +67 -0
  1292. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-preference-embed.test.js.map +1 -0
  1293. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-memory-expunge-emit.test.d.ts +2 -0
  1294. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-memory-expunge-emit.test.d.ts.map +1 -0
  1295. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-memory-expunge-emit.test.js +53 -0
  1296. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-memory-expunge-emit.test.js.map +1 -0
  1297. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.test.d.ts +2 -0
  1298. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.test.d.ts.map +1 -0
  1299. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.test.js +75 -0
  1300. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.test.js.map +1 -0
  1301. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-whatsapp-text.test.d.ts +2 -0
  1302. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-whatsapp-text.test.d.ts.map +1 -0
  1303. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-whatsapp-text.test.js +109 -0
  1304. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-whatsapp-text.test.js.map +1 -0
  1305. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.d.ts +2 -0
  1306. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.d.ts.map +1 -0
  1307. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.js +34 -0
  1308. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.js.map +1 -0
  1309. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-add-emit.test.d.ts +2 -0
  1310. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-add-emit.test.d.ts.map +1 -0
  1311. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-add-emit.test.js +40 -0
  1312. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-add-emit.test.js.map +1 -0
  1313. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-remove-emit.test.d.ts +2 -0
  1314. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-remove-emit.test.d.ts.map +1 -0
  1315. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-remove-emit.test.js +39 -0
  1316. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-remove-emit.test.js.map +1 -0
  1317. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/kd-classify-account-dir.test.d.ts +2 -0
  1318. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/kd-classify-account-dir.test.d.ts.map +1 -0
  1319. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/kd-classify-account-dir.test.js +31 -0
  1320. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/kd-classify-account-dir.test.js.map +1 -0
  1321. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/log-ingest.test.d.ts +2 -0
  1322. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/log-ingest.test.d.ts.map +1 -0
  1323. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/log-ingest.test.js +241 -0
  1324. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/log-ingest.test.js.map +1 -0
  1325. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-section-writer.test.d.ts +2 -0
  1326. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-section-writer.test.d.ts.map +1 -0
  1327. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-section-writer.test.js +61 -0
  1328. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-section-writer.test.js.map +1 -0
  1329. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write-emit.test.d.ts +2 -0
  1330. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write-emit.test.d.ts.map +1 -0
  1331. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write-emit.test.js +88 -0
  1332. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write-emit.test.js.map +1 -0
  1333. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.d.ts +2 -0
  1334. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.d.ts.map +1 -0
  1335. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.js +106 -0
  1336. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.js.map +1 -0
  1337. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-classify-emit.test.d.ts +2 -0
  1338. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-classify-emit.test.d.ts.map +1 -0
  1339. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-classify-emit.test.js +58 -0
  1340. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-classify-emit.test.js.map +1 -0
  1341. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-compiled-truth-history.test.d.ts +2 -0
  1342. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-compiled-truth-history.test.d.ts.map +1 -0
  1343. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-compiled-truth-history.test.js +129 -0
  1344. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-compiled-truth-history.test.js.map +1 -0
  1345. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.d.ts +2 -0
  1346. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.d.ts.map +1 -0
  1347. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.js +64 -0
  1348. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.js.map +1 -0
  1349. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-reserved-label.test.d.ts +2 -0
  1350. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-reserved-label.test.d.ts.map +1 -0
  1351. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-reserved-label.test.js +141 -0
  1352. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-reserved-label.test.js.map +1 -0
  1353. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edge.test.d.ts +2 -0
  1354. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edge.test.d.ts.map +1 -0
  1355. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edge.test.js +164 -0
  1356. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edge.test.js.map +1 -0
  1357. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edit-attachment-emit.test.d.ts +2 -0
  1358. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edit-attachment-emit.test.d.ts.map +1 -0
  1359. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edit-attachment-emit.test.js +70 -0
  1360. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edit-attachment-emit.test.js.map +1 -0
  1361. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-admin-conversation.test.d.ts +2 -0
  1362. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-admin-conversation.test.d.ts.map +1 -0
  1363. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-admin-conversation.test.js +168 -0
  1364. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-admin-conversation.test.js.map +1 -0
  1365. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-emit.test.d.ts +2 -0
  1366. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-emit.test.d.ts.map +1 -0
  1367. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-emit.test.js +48 -0
  1368. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-emit.test.js.map +1 -0
  1369. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-reserved-label.test.d.ts +2 -0
  1370. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-reserved-label.test.d.ts.map +1 -0
  1371. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-reserved-label.test.js +86 -0
  1372. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-reserved-label.test.js.map +1 -0
  1373. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-body-server-sliced.test.d.ts +2 -0
  1374. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-body-server-sliced.test.d.ts.map +1 -0
  1375. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-body-server-sliced.test.js +134 -0
  1376. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-body-server-sliced.test.js.map +1 -0
  1377. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-chat-body-server-sliced.test.d.ts +2 -0
  1378. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-chat-body-server-sliced.test.d.ts.map +1 -0
  1379. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-chat-body-server-sliced.test.js +124 -0
  1380. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-chat-body-server-sliced.test.js.map +1 -0
  1381. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-emit.test.d.ts +2 -0
  1382. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-emit.test.d.ts.map +1 -0
  1383. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-emit.test.js +74 -0
  1384. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-emit.test.js.map +1 -0
  1385. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-extract-emit.test.d.ts +2 -0
  1386. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-extract-emit.test.d.ts.map +1 -0
  1387. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-extract-emit.test.js +47 -0
  1388. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-extract-emit.test.js.map +1 -0
  1389. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-inline-rewrite.test.d.ts +2 -0
  1390. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-inline-rewrite.test.d.ts.map +1 -0
  1391. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-inline-rewrite.test.js +66 -0
  1392. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-inline-rewrite.test.js.map +1 -0
  1393. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-section-properties-strip.test.d.ts +2 -0
  1394. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-section-properties-strip.test.d.ts.map +1 -0
  1395. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-section-properties-strip.test.js +104 -0
  1396. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-section-properties-strip.test.js.map +1 -0
  1397. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-web-emit.test.d.ts +2 -0
  1398. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-web-emit.test.d.ts.map +1 -0
  1399. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-web-emit.test.js +65 -0
  1400. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-web-emit.test.js.map +1 -0
  1401. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.d.ts +2 -0
  1402. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.d.ts.map +1 -0
  1403. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.js +175 -0
  1404. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.js.map +1 -0
  1405. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-lookup-by-name.test.d.ts +2 -0
  1406. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-lookup-by-name.test.d.ts.map +1 -0
  1407. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-lookup-by-name.test.js +174 -0
  1408. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-lookup-by-name.test.js.map +1 -0
  1409. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex-emit.test.d.ts +2 -0
  1410. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex-emit.test.d.ts.map +1 -0
  1411. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex-emit.test.js +43 -0
  1412. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex-emit.test.js.map +1 -0
  1413. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex.test.d.ts +2 -0
  1414. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex.test.d.ts.map +1 -0
  1415. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex.test.js +87 -0
  1416. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex.test.js.map +1 -0
  1417. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-rename-attachment-emit.test.d.ts +2 -0
  1418. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-rename-attachment-emit.test.d.ts.map +1 -0
  1419. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-rename-attachment-emit.test.js +65 -0
  1420. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-rename-attachment-emit.test.js.map +1 -0
  1421. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-report-tools.test.d.ts +2 -0
  1422. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-report-tools.test.d.ts.map +1 -0
  1423. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-report-tools.test.js +115 -0
  1424. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-report-tools.test.js.map +1 -0
  1425. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-restore-emit.test.d.ts +2 -0
  1426. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-restore-emit.test.d.ts.map +1 -0
  1427. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-restore-emit.test.js +49 -0
  1428. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-restore-emit.test.js.map +1 -0
  1429. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.d.ts +2 -0
  1430. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.d.ts.map +1 -0
  1431. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.js +128 -0
  1432. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.js.map +1 -0
  1433. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-threshold.test.d.ts +2 -0
  1434. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-threshold.test.d.ts.map +1 -0
  1435. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-threshold.test.js +34 -0
  1436. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-threshold.test.js.map +1 -0
  1437. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-by-name.test.d.ts +2 -0
  1438. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-by-name.test.d.ts.map +1 -0
  1439. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-by-name.test.js +125 -0
  1440. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-by-name.test.js.map +1 -0
  1441. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.d.ts +2 -0
  1442. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.d.ts.map +1 -0
  1443. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.js +79 -0
  1444. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.js.map +1 -0
  1445. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-operator-hint.test.d.ts +2 -0
  1446. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-operator-hint.test.d.ts.map +1 -0
  1447. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-operator-hint.test.js +329 -0
  1448. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-operator-hint.test.js.map +1 -0
  1449. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-compiled-truth-rejection.test.d.ts +2 -0
  1450. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-compiled-truth-rejection.test.d.ts.map +1 -0
  1451. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-compiled-truth-rejection.test.js +39 -0
  1452. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-compiled-truth-rejection.test.js.map +1 -0
  1453. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.d.ts +2 -0
  1454. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.d.ts.map +1 -0
  1455. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.js +81 -0
  1456. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.js.map +1 -0
  1457. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-timeline-learned-at.test.d.ts +2 -0
  1458. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-timeline-learned-at.test.d.ts.map +1 -0
  1459. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-timeline-learned-at.test.js +30 -0
  1460. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-timeline-learned-at.test.js.map +1 -0
  1461. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-delete-emit.test.d.ts +2 -0
  1462. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-delete-emit.test.d.ts.map +1 -0
  1463. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-delete-emit.test.js +62 -0
  1464. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-delete-emit.test.js.map +1 -0
  1465. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-emit.test.d.ts +2 -0
  1466. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-emit.test.d.ts.map +1 -0
  1467. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-emit.test.js +76 -0
  1468. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-emit.test.js.map +1 -0
  1469. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-not-applicable.test.d.ts +2 -0
  1470. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-not-applicable.test.d.ts.map +1 -0
  1471. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-not-applicable.test.js +88 -0
  1472. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-not-applicable.test.js.map +1 -0
  1473. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.d.ts +2 -0
  1474. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.d.ts.map +1 -0
  1475. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.js +151 -0
  1476. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.js.map +1 -0
  1477. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.d.ts +114 -0
  1478. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.d.ts.map +1 -0
  1479. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js +415 -0
  1480. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js.map +1 -0
  1481. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-enrich-rejection.d.ts +41 -0
  1482. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-enrich-rejection.d.ts.map +1 -0
  1483. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-enrich-rejection.js +124 -0
  1484. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-enrich-rejection.js.map +1 -0
  1485. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-list-chunks.d.ts +43 -0
  1486. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-list-chunks.d.ts.map +1 -0
  1487. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-list-chunks.js +96 -0
  1488. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-list-chunks.js.map +1 -0
  1489. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-memory-expunge.d.ts +8 -0
  1490. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-memory-expunge.d.ts.map +1 -0
  1491. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-memory-expunge.js +15 -0
  1492. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-memory-expunge.js.map +1 -0
  1493. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-add.d.ts +7 -0
  1494. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-add.d.ts.map +1 -0
  1495. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-add.js +32 -0
  1496. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-add.js.map +1 -0
  1497. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-list.d.ts +7 -0
  1498. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-list.d.ts.map +1 -0
  1499. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-list.js +7 -0
  1500. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-list.js.map +1 -0
  1501. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-remove.d.ts +7 -0
  1502. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-remove.d.ts.map +1 -0
  1503. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-remove.js +31 -0
  1504. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-remove.js.map +1 -0
  1505. package/payload/platform/plugins/memory/mcp/dist/tools/image-fetch.d.ts +15 -0
  1506. package/payload/platform/plugins/memory/mcp/dist/tools/image-fetch.d.ts.map +1 -0
  1507. package/payload/platform/plugins/memory/mcp/dist/tools/image-fetch.js +64 -0
  1508. package/payload/platform/plugins/memory/mcp/dist/tools/image-fetch.js.map +1 -0
  1509. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.d.ts +11 -0
  1510. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.d.ts.map +1 -0
  1511. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.js +92 -0
  1512. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.js.map +1 -0
  1513. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts +202 -0
  1514. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts.map +1 -0
  1515. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js +1084 -0
  1516. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js.map +1 -0
  1517. package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.d.ts +35 -0
  1518. package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.d.ts.map +1 -0
  1519. package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.js +80 -0
  1520. package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.js.map +1 -0
  1521. package/payload/platform/plugins/memory/mcp/dist/tools/memory-classify.d.ts +34 -0
  1522. package/payload/platform/plugins/memory/mcp/dist/tools/memory-classify.d.ts.map +1 -0
  1523. package/payload/platform/plugins/memory/mcp/dist/tools/memory-classify.js +62 -0
  1524. package/payload/platform/plugins/memory/mcp/dist/tools/memory-classify.js.map +1 -0
  1525. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.d.ts +41 -0
  1526. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.d.ts.map +1 -0
  1527. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.js +73 -0
  1528. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.js.map +1 -0
  1529. package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.d.ts +65 -0
  1530. package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.d.ts.map +1 -0
  1531. package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.js +151 -0
  1532. package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.js.map +1 -0
  1533. package/payload/platform/plugins/memory/mcp/dist/tools/memory-dream-run.d.ts +48 -0
  1534. package/payload/platform/plugins/memory/mcp/dist/tools/memory-dream-run.d.ts.map +1 -0
  1535. package/payload/platform/plugins/memory/mcp/dist/tools/memory-dream-run.js +197 -0
  1536. package/payload/platform/plugins/memory/mcp/dist/tools/memory-dream-run.js.map +1 -0
  1537. package/payload/platform/plugins/memory/mcp/dist/tools/memory-edge.d.ts +30 -0
  1538. package/payload/platform/plugins/memory/mcp/dist/tools/memory-edge.d.ts.map +1 -0
  1539. package/payload/platform/plugins/memory/mcp/dist/tools/memory-edge.js +75 -0
  1540. package/payload/platform/plugins/memory/mcp/dist/tools/memory-edge.js.map +1 -0
  1541. package/payload/platform/plugins/memory/mcp/dist/tools/memory-edit-attachment.d.ts +16 -0
  1542. package/payload/platform/plugins/memory/mcp/dist/tools/memory-edit-attachment.d.ts.map +1 -0
  1543. package/payload/platform/plugins/memory/mcp/dist/tools/memory-edit-attachment.js +95 -0
  1544. package/payload/platform/plugins/memory/mcp/dist/tools/memory-edit-attachment.js.map +1 -0
  1545. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.d.ts +50 -0
  1546. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.d.ts.map +1 -0
  1547. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.js +104 -0
  1548. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.js.map +1 -0
  1549. package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.d.ts +58 -0
  1550. package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.d.ts.map +1 -0
  1551. package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.js +125 -0
  1552. package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.js.map +1 -0
  1553. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest-extract.d.ts +37 -0
  1554. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest-extract.d.ts.map +1 -0
  1555. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest-extract.js +97 -0
  1556. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest-extract.js.map +1 -0
  1557. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest-web.d.ts +32 -0
  1558. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest-web.d.ts.map +1 -0
  1559. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest-web.js +116 -0
  1560. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest-web.js.map +1 -0
  1561. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.d.ts +194 -0
  1562. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.d.ts.map +1 -0
  1563. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js +1303 -0
  1564. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js.map +1 -0
  1565. package/payload/platform/plugins/memory/mcp/dist/tools/memory-list-attachments.d.ts +19 -0
  1566. package/payload/platform/plugins/memory/mcp/dist/tools/memory-list-attachments.d.ts.map +1 -0
  1567. package/payload/platform/plugins/memory/mcp/dist/tools/memory-list-attachments.js +125 -0
  1568. package/payload/platform/plugins/memory/mcp/dist/tools/memory-list-attachments.js.map +1 -0
  1569. package/payload/platform/plugins/memory/mcp/dist/tools/memory-lookup-by-name.d.ts +16 -0
  1570. package/payload/platform/plugins/memory/mcp/dist/tools/memory-lookup-by-name.d.ts.map +1 -0
  1571. package/payload/platform/plugins/memory/mcp/dist/tools/memory-lookup-by-name.js +68 -0
  1572. package/payload/platform/plugins/memory/mcp/dist/tools/memory-lookup-by-name.js.map +1 -0
  1573. package/payload/platform/plugins/memory/mcp/dist/tools/memory-node-exists.d.ts +28 -0
  1574. package/payload/platform/plugins/memory/mcp/dist/tools/memory-node-exists.d.ts.map +1 -0
  1575. package/payload/platform/plugins/memory/mcp/dist/tools/memory-node-exists.js +46 -0
  1576. package/payload/platform/plugins/memory/mcp/dist/tools/memory-node-exists.js.map +1 -0
  1577. package/payload/platform/plugins/memory/mcp/dist/tools/memory-rank.d.ts +61 -0
  1578. package/payload/platform/plugins/memory/mcp/dist/tools/memory-rank.d.ts.map +1 -0
  1579. package/payload/platform/plugins/memory/mcp/dist/tools/memory-rank.js +102 -0
  1580. package/payload/platform/plugins/memory/mcp/dist/tools/memory-rank.js.map +1 -0
  1581. package/payload/platform/plugins/memory/mcp/dist/tools/memory-read-attachment.d.ts +12 -0
  1582. package/payload/platform/plugins/memory/mcp/dist/tools/memory-read-attachment.d.ts.map +1 -0
  1583. package/payload/platform/plugins/memory/mcp/dist/tools/memory-read-attachment.js +100 -0
  1584. package/payload/platform/plugins/memory/mcp/dist/tools/memory-read-attachment.js.map +1 -0
  1585. package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.d.ts +9 -0
  1586. package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.d.ts.map +1 -0
  1587. package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.js +127 -0
  1588. package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.js.map +1 -0
  1589. package/payload/platform/plugins/memory/mcp/dist/tools/memory-rename-attachment.d.ts +13 -0
  1590. package/payload/platform/plugins/memory/mcp/dist/tools/memory-rename-attachment.d.ts.map +1 -0
  1591. package/payload/platform/plugins/memory/mcp/dist/tools/memory-rename-attachment.js +67 -0
  1592. package/payload/platform/plugins/memory/mcp/dist/tools/memory-rename-attachment.js.map +1 -0
  1593. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-list.d.ts +28 -0
  1594. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-list.d.ts.map +1 -0
  1595. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-list.js +64 -0
  1596. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-list.js.map +1 -0
  1597. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-read-latest.d.ts +24 -0
  1598. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-read-latest.d.ts.map +1 -0
  1599. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-read-latest.js +49 -0
  1600. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-read-latest.js.map +1 -0
  1601. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-write.d.ts +34 -0
  1602. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-write.d.ts.map +1 -0
  1603. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-write.js +99 -0
  1604. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-write.js.map +1 -0
  1605. package/payload/platform/plugins/memory/mcp/dist/tools/memory-restore.d.ts +24 -0
  1606. package/payload/platform/plugins/memory/mcp/dist/tools/memory-restore.d.ts.map +1 -0
  1607. package/payload/platform/plugins/memory/mcp/dist/tools/memory-restore.js +47 -0
  1608. package/payload/platform/plugins/memory/mcp/dist/tools/memory-restore.js.map +1 -0
  1609. package/payload/platform/plugins/memory/mcp/dist/tools/memory-review-queue.d.ts +29 -0
  1610. package/payload/platform/plugins/memory/mcp/dist/tools/memory-review-queue.d.ts.map +1 -0
  1611. package/payload/platform/plugins/memory/mcp/dist/tools/memory-review-queue.js +67 -0
  1612. package/payload/platform/plugins/memory/mcp/dist/tools/memory-review-queue.js.map +1 -0
  1613. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts +7 -0
  1614. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts.map +1 -0
  1615. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js +184 -0
  1616. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js.map +1 -0
  1617. package/payload/platform/plugins/memory/mcp/dist/tools/memory-signals-recent.d.ts +35 -0
  1618. package/payload/platform/plugins/memory/mcp/dist/tools/memory-signals-recent.d.ts.map +1 -0
  1619. package/payload/platform/plugins/memory/mcp/dist/tools/memory-signals-recent.js +73 -0
  1620. package/payload/platform/plugins/memory/mcp/dist/tools/memory-signals-recent.js.map +1 -0
  1621. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.d.ts +29 -0
  1622. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.d.ts.map +1 -0
  1623. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.js +22 -0
  1624. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.js.map +1 -0
  1625. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update-by-name.d.ts +15 -0
  1626. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update-by-name.d.ts.map +1 -0
  1627. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update-by-name.js +45 -0
  1628. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update-by-name.js.map +1 -0
  1629. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.d.ts +16 -0
  1630. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.d.ts.map +1 -0
  1631. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js +194 -0
  1632. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js.map +1 -0
  1633. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts +47 -0
  1634. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts.map +1 -0
  1635. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +397 -0
  1636. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -0
  1637. package/payload/platform/plugins/memory/mcp/dist/tools/obsidian-vault-import.d.ts +127 -0
  1638. package/payload/platform/plugins/memory/mcp/dist/tools/obsidian-vault-import.d.ts.map +1 -0
  1639. package/payload/platform/plugins/memory/mcp/dist/tools/obsidian-vault-import.js +477 -0
  1640. package/payload/platform/plugins/memory/mcp/dist/tools/obsidian-vault-import.js.map +1 -0
  1641. package/payload/platform/plugins/memory/mcp/dist/tools/profile-delete.d.ts +24 -0
  1642. package/payload/platform/plugins/memory/mcp/dist/tools/profile-delete.d.ts.map +1 -0
  1643. package/payload/platform/plugins/memory/mcp/dist/tools/profile-delete.js +35 -0
  1644. package/payload/platform/plugins/memory/mcp/dist/tools/profile-delete.js.map +1 -0
  1645. package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.d.ts +46 -0
  1646. package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.d.ts.map +1 -0
  1647. package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.js +423 -0
  1648. package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.js.map +1 -0
  1649. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts +65 -0
  1650. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts.map +1 -0
  1651. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js +395 -0
  1652. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js.map +1 -0
  1653. package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.d.ts +30 -0
  1654. package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.d.ts.map +1 -0
  1655. package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.js +130 -0
  1656. package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.js.map +1 -0
  1657. package/payload/platform/plugins/memory/mcp/package.json +23 -0
  1658. package/payload/platform/plugins/memory/mcp/scripts/boot-smoke.sh +69 -0
  1659. package/payload/platform/plugins/memory/mcp/scripts/generate-edge-docs.ts +75 -0
  1660. package/payload/platform/plugins/memory/mcp/scripts/graph/accept.sh +217 -0
  1661. package/payload/platform/plugins/memory/mcp/scripts/graph/fixture.cypher +59 -0
  1662. package/payload/platform/plugins/memory/mcp/vitest.config.ts +53 -0
  1663. package/payload/platform/plugins/memory/references/graph-primitives.md +394 -0
  1664. package/payload/platform/plugins/memory/references/schema-base.md +338 -0
  1665. package/payload/platform/plugins/memory/references/schema-construction.md +96 -0
  1666. package/payload/platform/plugins/memory/references/schema-creator.md +35 -0
  1667. package/payload/platform/plugins/memory/references/schema-estate-agent.md +154 -0
  1668. package/payload/platform/plugins/memory/references/schema-food-beverage.md +32 -0
  1669. package/payload/platform/plugins/memory/references/schema-hospitality.md +31 -0
  1670. package/payload/platform/plugins/memory/references/schema-knowledge-work.md +80 -0
  1671. package/payload/platform/plugins/memory/references/schema-logistics.md +30 -0
  1672. package/payload/platform/plugins/memory/references/schema-professional-services.md +33 -0
  1673. package/payload/platform/plugins/memory/references/schema-retail.md +33 -0
  1674. package/payload/platform/plugins/memory/references/schema-trades.md +36 -0
  1675. package/payload/platform/plugins/memory/references/transcript-formats/circleback.md +49 -0
  1676. package/payload/platform/plugins/memory/references/transcript-formats/granola.md +50 -0
  1677. package/payload/platform/plugins/memory/references/transcript-formats/otter.md +50 -0
  1678. package/payload/platform/plugins/memory/skills/archive-crawler/SKILL.md +69 -0
  1679. package/payload/platform/plugins/memory/skills/challenge/SKILL.md +54 -0
  1680. package/payload/platform/plugins/memory/skills/concept-synthesis/SKILL.md +81 -0
  1681. package/payload/platform/plugins/memory/skills/connect/SKILL.md +58 -0
  1682. package/payload/platform/plugins/memory/skills/conversation-archive/SKILL.md +193 -0
  1683. package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +207 -0
  1684. package/payload/platform/plugins/memory/skills/conversation-archive-mcp/SKILL.md +170 -0
  1685. package/payload/platform/plugins/memory/skills/conversational-memory/SKILL.md +115 -0
  1686. package/payload/platform/plugins/memory/skills/document-ingest/SKILL.md +331 -0
  1687. package/payload/platform/plugins/memory/skills/emerge/SKILL.md +89 -0
  1688. package/payload/platform/plugins/notion-import/.claude-plugin/plugin.json +8 -0
  1689. package/payload/platform/plugins/notion-import/PLUGIN.md +27 -0
  1690. package/payload/platform/plugins/notion-import/skills/notion-import/SKILL.md +114 -0
  1691. package/payload/platform/plugins/notion-import/skills/notion-import/references/attachments.md +55 -0
  1692. package/payload/platform/plugins/notion-import/skills/notion-import/references/databases.md +83 -0
  1693. package/payload/platform/plugins/notion-import/skills/notion-import/references/page-tree.md +61 -0
  1694. package/payload/platform/plugins/notion-import/skills/notion-import/references/workspace-export.md +41 -0
  1695. package/payload/platform/plugins/obsidian-import/.claude-plugin/plugin.json +8 -0
  1696. package/payload/platform/plugins/obsidian-import/PLUGIN.md +39 -0
  1697. package/payload/platform/plugins/obsidian-import/skills/obsidian-import/SKILL.md +92 -0
  1698. package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/attachments.md +80 -0
  1699. package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/daily-notes.md +31 -0
  1700. package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/vault-structure.md +46 -0
  1701. package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/wikilinks.md +70 -0
  1702. package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +21 -0
  1703. package/payload/platform/plugins/outlook/PLUGIN.md +74 -0
  1704. package/payload/platform/plugins/outlook/lib/mcp-spawn-tee/index.js +193 -0
  1705. package/payload/platform/plugins/outlook/lib/mcp-spawn-tee/package.json +3 -0
  1706. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client.test.d.ts +2 -0
  1707. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client.test.d.ts.map +1 -0
  1708. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client.test.js +94 -0
  1709. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client.test.js.map +1 -0
  1710. package/payload/platform/plugins/outlook/mcp/dist/__tests__/log.test.d.ts +2 -0
  1711. package/payload/platform/plugins/outlook/mcp/dist/__tests__/log.test.d.ts.map +1 -0
  1712. package/payload/platform/plugins/outlook/mcp/dist/__tests__/log.test.js +31 -0
  1713. package/payload/platform/plugins/outlook/mcp/dist/__tests__/log.test.js.map +1 -0
  1714. package/payload/platform/plugins/outlook/mcp/dist/__tests__/pkce-flow.test.d.ts +2 -0
  1715. package/payload/platform/plugins/outlook/mcp/dist/__tests__/pkce-flow.test.d.ts.map +1 -0
  1716. package/payload/platform/plugins/outlook/mcp/dist/__tests__/pkce-flow.test.js +213 -0
  1717. package/payload/platform/plugins/outlook/mcp/dist/__tests__/pkce-flow.test.js.map +1 -0
  1718. package/payload/platform/plugins/outlook/mcp/dist/__tests__/token-store.test.d.ts +2 -0
  1719. package/payload/platform/plugins/outlook/mcp/dist/__tests__/token-store.test.d.ts.map +1 -0
  1720. package/payload/platform/plugins/outlook/mcp/dist/__tests__/token-store.test.js +130 -0
  1721. package/payload/platform/plugins/outlook/mcp/dist/__tests__/token-store.test.js.map +1 -0
  1722. package/payload/platform/plugins/outlook/mcp/dist/auth/pkce-flow.d.ts +65 -0
  1723. package/payload/platform/plugins/outlook/mcp/dist/auth/pkce-flow.d.ts.map +1 -0
  1724. package/payload/platform/plugins/outlook/mcp/dist/auth/pkce-flow.js +261 -0
  1725. package/payload/platform/plugins/outlook/mcp/dist/auth/pkce-flow.js.map +1 -0
  1726. package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.d.ts +61 -0
  1727. package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.d.ts.map +1 -0
  1728. package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.js +170 -0
  1729. package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.js.map +1 -0
  1730. package/payload/platform/plugins/outlook/mcp/dist/index.d.ts +18 -0
  1731. package/payload/platform/plugins/outlook/mcp/dist/index.d.ts.map +1 -0
  1732. package/payload/platform/plugins/outlook/mcp/dist/index.js +184 -0
  1733. package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -0
  1734. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.d.ts +60 -0
  1735. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.d.ts.map +1 -0
  1736. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js +189 -0
  1737. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js.map +1 -0
  1738. package/payload/platform/plugins/outlook/mcp/dist/lib/log.d.ts +23 -0
  1739. package/payload/platform/plugins/outlook/mcp/dist/lib/log.d.ts.map +1 -0
  1740. package/payload/platform/plugins/outlook/mcp/dist/lib/log.js +53 -0
  1741. package/payload/platform/plugins/outlook/mcp/dist/lib/log.js.map +1 -0
  1742. package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.d.ts +26 -0
  1743. package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.d.ts.map +1 -0
  1744. package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.js +50 -0
  1745. package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.js.map +1 -0
  1746. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-event.d.ts +12 -0
  1747. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-event.d.ts.map +1 -0
  1748. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-event.js +32 -0
  1749. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-event.js.map +1 -0
  1750. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-list.d.ts +59 -0
  1751. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-list.d.ts.map +1 -0
  1752. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-list.js +54 -0
  1753. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-list.js.map +1 -0
  1754. package/payload/platform/plugins/outlook/mcp/dist/tools/contacts-list.d.ts +14 -0
  1755. package/payload/platform/plugins/outlook/mcp/dist/tools/contacts-list.d.ts.map +1 -0
  1756. package/payload/platform/plugins/outlook/mcp/dist/tools/contacts-list.js +45 -0
  1757. package/payload/platform/plugins/outlook/mcp/dist/tools/contacts-list.js.map +1 -0
  1758. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.d.ts +15 -0
  1759. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.d.ts.map +1 -0
  1760. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.js +48 -0
  1761. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.js.map +1 -0
  1762. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.d.ts +8 -0
  1763. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.d.ts.map +1 -0
  1764. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.js +49 -0
  1765. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.js.map +1 -0
  1766. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.d.ts +19 -0
  1767. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.d.ts.map +1 -0
  1768. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.js +58 -0
  1769. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.js.map +1 -0
  1770. package/payload/platform/plugins/outlook/mcp/package.json +20 -0
  1771. package/payload/platform/plugins/outlook/mcp/scripts/verify-doc-impl.sh +109 -0
  1772. package/payload/platform/plugins/outlook/references/auth.md +118 -0
  1773. package/payload/platform/plugins/outlook/references/graph-surfaces.md +114 -0
  1774. package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +67 -0
  1775. package/payload/platform/plugins/projects/.claude-plugin/plugin.json +8 -0
  1776. package/payload/platform/plugins/projects/PLUGIN.md +101 -0
  1777. package/payload/platform/plugins/projects/references/investigation.md +63 -0
  1778. package/payload/platform/plugins/projects/references/meeting-to-tasks.md +34 -0
  1779. package/payload/platform/plugins/projects/references/prioritization.md +43 -0
  1780. package/payload/platform/plugins/projects/references/retrospective.md +71 -0
  1781. package/payload/platform/plugins/projects/references/review.md +51 -0
  1782. package/payload/platform/plugins/projects/references/risk-premortem.md +34 -0
  1783. package/payload/platform/plugins/projects/references/sprint.md +172 -0
  1784. package/payload/platform/plugins/projects/references/stakeholder-map.md +43 -0
  1785. package/payload/platform/plugins/prompt-optimiser/.claude-plugin/plugin.json +8 -0
  1786. package/payload/platform/plugins/prompt-optimiser/PLUGIN.md +14 -0
  1787. package/payload/platform/plugins/prompt-optimiser/skills/prompt-optimiser/SKILL.md +321 -0
  1788. package/payload/platform/plugins/prompt-optimiser/skills/prompt-optimiser/__tests__/restatement-ladder.test.sh +21 -0
  1789. package/payload/platform/plugins/quickbooks/.claude-plugin/plugin.json +21 -0
  1790. package/payload/platform/plugins/quickbooks/PLUGIN.md +91 -0
  1791. package/payload/platform/plugins/quickbooks/lib/mcp-spawn-tee/index.js +193 -0
  1792. package/payload/platform/plugins/quickbooks/lib/mcp-spawn-tee/package.json +3 -0
  1793. package/payload/platform/plugins/quickbooks/mcp/dist/index.d.ts +2 -0
  1794. package/payload/platform/plugins/quickbooks/mcp/dist/index.d.ts.map +1 -0
  1795. package/payload/platform/plugins/quickbooks/mcp/dist/index.js +219 -0
  1796. package/payload/platform/plugins/quickbooks/mcp/dist/index.js.map +1 -0
  1797. package/payload/platform/plugins/quickbooks/mcp/dist/lib/oauth.d.ts +37 -0
  1798. package/payload/platform/plugins/quickbooks/mcp/dist/lib/oauth.d.ts.map +1 -0
  1799. package/payload/platform/plugins/quickbooks/mcp/dist/lib/oauth.js +75 -0
  1800. package/payload/platform/plugins/quickbooks/mcp/dist/lib/oauth.js.map +1 -0
  1801. package/payload/platform/plugins/quickbooks/mcp/dist/lib/qbo-client.d.ts +39 -0
  1802. package/payload/platform/plugins/quickbooks/mcp/dist/lib/qbo-client.d.ts.map +1 -0
  1803. package/payload/platform/plugins/quickbooks/mcp/dist/lib/qbo-client.js +178 -0
  1804. package/payload/platform/plugins/quickbooks/mcp/dist/lib/qbo-client.js.map +1 -0
  1805. package/payload/platform/plugins/quickbooks/mcp/dist/lib/secrets.d.ts +36 -0
  1806. package/payload/platform/plugins/quickbooks/mcp/dist/lib/secrets.d.ts.map +1 -0
  1807. package/payload/platform/plugins/quickbooks/mcp/dist/lib/secrets.js +107 -0
  1808. package/payload/platform/plugins/quickbooks/mcp/dist/lib/secrets.js.map +1 -0
  1809. package/payload/platform/plugins/quickbooks/mcp/package.json +19 -0
  1810. package/payload/platform/plugins/quickbooks/skills/quickbooks/SKILL.md +37 -0
  1811. package/payload/platform/plugins/replicate/.claude-plugin/plugin.json +21 -0
  1812. package/payload/platform/plugins/replicate/PLUGIN.md +49 -0
  1813. package/payload/platform/plugins/replicate/lib/mcp-spawn-tee/index.js +193 -0
  1814. package/payload/platform/plugins/replicate/lib/mcp-spawn-tee/package.json +3 -0
  1815. package/payload/platform/plugins/replicate/mcp/dist/index.d.ts +2 -0
  1816. package/payload/platform/plugins/replicate/mcp/dist/index.d.ts.map +1 -0
  1817. package/payload/platform/plugins/replicate/mcp/dist/index.js +126 -0
  1818. package/payload/platform/plugins/replicate/mcp/dist/index.js.map +1 -0
  1819. package/payload/platform/plugins/replicate/mcp/dist/lib/replicate-key.d.ts +15 -0
  1820. package/payload/platform/plugins/replicate/mcp/dist/lib/replicate-key.d.ts.map +1 -0
  1821. package/payload/platform/plugins/replicate/mcp/dist/lib/replicate-key.js +73 -0
  1822. package/payload/platform/plugins/replicate/mcp/dist/lib/replicate-key.js.map +1 -0
  1823. package/payload/platform/plugins/replicate/mcp/dist/tools/image-generate.d.ts +14 -0
  1824. package/payload/platform/plugins/replicate/mcp/dist/tools/image-generate.d.ts.map +1 -0
  1825. package/payload/platform/plugins/replicate/mcp/dist/tools/image-generate.js +201 -0
  1826. package/payload/platform/plugins/replicate/mcp/dist/tools/image-generate.js.map +1 -0
  1827. package/payload/platform/plugins/replicate/mcp/package.json +21 -0
  1828. package/payload/platform/plugins/sales/.claude-plugin/plugin.json +8 -0
  1829. package/payload/platform/plugins/sales/PLUGIN.md +106 -0
  1830. package/payload/platform/plugins/sales/references/close-tracking.md +69 -0
  1831. package/payload/platform/plugins/sales/references/comparisons.md +99 -0
  1832. package/payload/platform/plugins/sales/references/competitive-positioning.md +51 -0
  1833. package/payload/platform/plugins/sales/references/faq.md +73 -0
  1834. package/payload/platform/plugins/sales/references/objection-handling.md +157 -0
  1835. package/payload/platform/plugins/sales/references/pricing.md +101 -0
  1836. package/payload/platform/plugins/scheduling/.claude-plugin/plugin.json +21 -0
  1837. package/payload/platform/plugins/scheduling/PLUGIN.md +153 -0
  1838. package/payload/platform/plugins/scheduling/lib/mcp-spawn-tee/index.js +193 -0
  1839. package/payload/platform/plugins/scheduling/lib/mcp-spawn-tee/package.json +3 -0
  1840. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/time-resolve-description.test.d.ts +2 -0
  1841. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/time-resolve-description.test.d.ts.map +1 -0
  1842. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/time-resolve-description.test.js +16 -0
  1843. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/time-resolve-description.test.js.map +1 -0
  1844. package/payload/platform/plugins/scheduling/mcp/dist/index.d.ts +2 -0
  1845. package/payload/platform/plugins/scheduling/mcp/dist/index.d.ts.map +1 -0
  1846. package/payload/platform/plugins/scheduling/mcp/dist/index.js +440 -0
  1847. package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -0
  1848. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/getUserTimezone.test.d.ts +2 -0
  1849. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/getUserTimezone.test.d.ts.map +1 -0
  1850. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/getUserTimezone.test.js +119 -0
  1851. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/getUserTimezone.test.js.map +1 -0
  1852. package/payload/platform/plugins/scheduling/mcp/dist/lib/embedding.d.ts +2 -0
  1853. package/payload/platform/plugins/scheduling/mcp/dist/lib/embedding.d.ts.map +1 -0
  1854. package/payload/platform/plugins/scheduling/mcp/dist/lib/embedding.js +19 -0
  1855. package/payload/platform/plugins/scheduling/mcp/dist/lib/embedding.js.map +1 -0
  1856. package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.d.ts +80 -0
  1857. package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.d.ts.map +1 -0
  1858. package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.js +410 -0
  1859. package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.js.map +1 -0
  1860. package/payload/platform/plugins/scheduling/mcp/dist/lib/ics.d.ts +63 -0
  1861. package/payload/platform/plugins/scheduling/mcp/dist/lib/ics.d.ts.map +1 -0
  1862. package/payload/platform/plugins/scheduling/mcp/dist/lib/ics.js +471 -0
  1863. package/payload/platform/plugins/scheduling/mcp/dist/lib/ics.js.map +1 -0
  1864. package/payload/platform/plugins/scheduling/mcp/dist/lib/neo4j.d.ts +30 -0
  1865. package/payload/platform/plugins/scheduling/mcp/dist/lib/neo4j.d.ts.map +1 -0
  1866. package/payload/platform/plugins/scheduling/mcp/dist/lib/neo4j.js +89 -0
  1867. package/payload/platform/plugins/scheduling/mcp/dist/lib/neo4j.js.map +1 -0
  1868. package/payload/platform/plugins/scheduling/mcp/dist/lib/time-format.d.ts +48 -0
  1869. package/payload/platform/plugins/scheduling/mcp/dist/lib/time-format.d.ts.map +1 -0
  1870. package/payload/platform/plugins/scheduling/mcp/dist/lib/time-format.js +140 -0
  1871. package/payload/platform/plugins/scheduling/mcp/dist/lib/time-format.js.map +1 -0
  1872. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.d.ts +24 -0
  1873. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.d.ts.map +1 -0
  1874. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +572 -0
  1875. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -0
  1876. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-archive-ics.d.ts +20 -0
  1877. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-archive-ics.d.ts.map +1 -0
  1878. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-archive-ics.js +63 -0
  1879. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-archive-ics.js.map +1 -0
  1880. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.d.ts +7 -0
  1881. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.d.ts.map +1 -0
  1882. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.js +23 -0
  1883. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.js.map +1 -0
  1884. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts +25 -0
  1885. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts.map +1 -0
  1886. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js +121 -0
  1887. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js.map +1 -0
  1888. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-export-ics.d.ts +9 -0
  1889. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-export-ics.d.ts.map +1 -0
  1890. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-export-ics.js +77 -0
  1891. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-export-ics.js.map +1 -0
  1892. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.d.ts +25 -0
  1893. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.d.ts.map +1 -0
  1894. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.js +53 -0
  1895. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.js.map +1 -0
  1896. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-import-ics.d.ts +8 -0
  1897. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-import-ics.d.ts.map +1 -0
  1898. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-import-ics.js +48 -0
  1899. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-import-ics.js.map +1 -0
  1900. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-list.d.ts +20 -0
  1901. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-list.d.ts.map +1 -0
  1902. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-list.js +76 -0
  1903. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-list.js.map +1 -0
  1904. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.d.ts +18 -0
  1905. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.d.ts.map +1 -0
  1906. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js +167 -0
  1907. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js.map +1 -0
  1908. package/payload/platform/plugins/scheduling/mcp/package.json +23 -0
  1909. package/payload/platform/plugins/scheduling/mcp/vitest.config.ts +9 -0
  1910. package/payload/platform/plugins/scheduling/skills/briefing/SKILL.md +88 -0
  1911. package/payload/platform/plugins/scheduling/skills/daily-prep/SKILL.md +63 -0
  1912. package/payload/platform/plugins/slides/.claude-plugin/plugin.json +8 -0
  1913. package/payload/platform/plugins/slides/LICENSE +21 -0
  1914. package/payload/platform/plugins/slides/PLUGIN.md +18 -0
  1915. package/payload/platform/plugins/slides/PROVENANCE.md +40 -0
  1916. package/payload/platform/plugins/slides/commands/add-slide.md +29 -0
  1917. package/payload/platform/plugins/slides/commands/slides-claus.md +39 -0
  1918. package/payload/platform/plugins/slides/commands/slides-new-component.md +39 -0
  1919. package/payload/platform/plugins/slides/commands/slides-outline.md +43 -0
  1920. package/payload/platform/plugins/slides/commands/slides-review.md +52 -0
  1921. package/payload/platform/plugins/slides/commands/slides-theme.md +64 -0
  1922. package/payload/platform/plugins/slides/commands/slides.md +59 -0
  1923. package/payload/platform/plugins/slides/skills/deck-system/REFERENCE.md +581 -0
  1924. package/payload/platform/plugins/slides/skills/deck-system/SKILL.md +611 -0
  1925. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-board.md +426 -0
  1926. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-claus.md +185 -0
  1927. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-mbb.md +450 -0
  1928. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-product-launch.md +579 -0
  1929. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-sales.md +464 -0
  1930. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-sequoia.md +489 -0
  1931. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING.md +273 -0
  1932. package/payload/platform/plugins/slides/skills/deck-system/deck-craft.html +1371 -0
  1933. package/payload/platform/plugins/slides/skills/deck-system/deck-solid.html +1667 -0
  1934. package/payload/platform/plugins/slides/skills/deck-system/deck.html +1359 -0
  1935. package/payload/platform/plugins/substack-import/.claude-plugin/plugin.json +8 -0
  1936. package/payload/platform/plugins/substack-import/PLUGIN.md +34 -0
  1937. package/payload/platform/plugins/substack-import/skills/substack-import/SKILL.md +183 -0
  1938. package/payload/platform/plugins/substack-import/skills/substack-import/references/archive-shape.md +68 -0
  1939. package/payload/platform/plugins/substack-import/skills/substack-import/references/attachments.md +72 -0
  1940. package/payload/platform/plugins/substack-import/skills/substack-import/references/engagement.md +61 -0
  1941. package/payload/platform/plugins/substack-import/skills/substack-import/references/posts.md +80 -0
  1942. package/payload/platform/plugins/substack-import/skills/substack-import/references/subscribers.md +74 -0
  1943. package/payload/platform/plugins/telegram/.claude-plugin/plugin.json +21 -0
  1944. package/payload/platform/plugins/telegram/PLUGIN.md +58 -0
  1945. package/payload/platform/plugins/telegram/lib/mcp-spawn-tee/index.js +193 -0
  1946. package/payload/platform/plugins/telegram/lib/mcp-spawn-tee/package.json +3 -0
  1947. package/payload/platform/plugins/telegram/mcp/dist/index.d.ts +2 -0
  1948. package/payload/platform/plugins/telegram/mcp/dist/index.d.ts.map +1 -0
  1949. package/payload/platform/plugins/telegram/mcp/dist/index.js +253 -0
  1950. package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -0
  1951. package/payload/platform/plugins/telegram/mcp/dist/lib/account-token.d.ts +6 -0
  1952. package/payload/platform/plugins/telegram/mcp/dist/lib/account-token.d.ts.map +1 -0
  1953. package/payload/platform/plugins/telegram/mcp/dist/lib/account-token.js +20 -0
  1954. package/payload/platform/plugins/telegram/mcp/dist/lib/account-token.js.map +1 -0
  1955. package/payload/platform/plugins/telegram/mcp/dist/lib/account-write.d.ts +21 -0
  1956. package/payload/platform/plugins/telegram/mcp/dist/lib/account-write.d.ts.map +1 -0
  1957. package/payload/platform/plugins/telegram/mcp/dist/lib/account-write.js +52 -0
  1958. package/payload/platform/plugins/telegram/mcp/dist/lib/account-write.js.map +1 -0
  1959. package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.d.ts +41 -0
  1960. package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.d.ts.map +1 -0
  1961. package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.js +70 -0
  1962. package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.js.map +1 -0
  1963. package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.d.ts +16 -0
  1964. package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.d.ts.map +1 -0
  1965. package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.js +68 -0
  1966. package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.js.map +1 -0
  1967. package/payload/platform/plugins/telegram/mcp/dist/tools/message.d.ts +20 -0
  1968. package/payload/platform/plugins/telegram/mcp/dist/tools/message.d.ts.map +1 -0
  1969. package/payload/platform/plugins/telegram/mcp/dist/tools/message.js +37 -0
  1970. package/payload/platform/plugins/telegram/mcp/dist/tools/message.js.map +1 -0
  1971. package/payload/platform/plugins/telegram/mcp/package.json +19 -0
  1972. package/payload/platform/plugins/telegram/references/setup-guide.md +53 -0
  1973. package/payload/platform/plugins/telegram/skills/configure/SKILL.md +79 -0
  1974. package/payload/platform/plugins/url-get/.claude-plugin/plugin.json +21 -0
  1975. package/payload/platform/plugins/url-get/PLUGIN.md +91 -0
  1976. package/payload/platform/plugins/url-get/lib/mcp-spawn-tee/index.js +193 -0
  1977. package/payload/platform/plugins/url-get/lib/mcp-spawn-tee/package.json +3 -0
  1978. package/payload/platform/plugins/url-get/mcp/dist/index.d.ts +9 -0
  1979. package/payload/platform/plugins/url-get/mcp/dist/index.d.ts.map +1 -0
  1980. package/payload/platform/plugins/url-get/mcp/dist/index.js +53 -0
  1981. package/payload/platform/plugins/url-get/mcp/dist/index.js.map +1 -0
  1982. package/payload/platform/plugins/url-get/mcp/dist/lib/summarise.d.ts +8 -0
  1983. package/payload/platform/plugins/url-get/mcp/dist/lib/summarise.d.ts.map +1 -0
  1984. package/payload/platform/plugins/url-get/mcp/dist/lib/summarise.js +83 -0
  1985. package/payload/platform/plugins/url-get/mcp/dist/lib/summarise.js.map +1 -0
  1986. package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.d.ts +21 -0
  1987. package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.d.ts.map +1 -0
  1988. package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.js +133 -0
  1989. package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.js.map +1 -0
  1990. package/payload/platform/plugins/url-get/mcp/package.json +22 -0
  1991. package/payload/platform/plugins/whatsapp/.claude-plugin/plugin.json +21 -0
  1992. package/payload/platform/plugins/whatsapp/PLUGIN.md +112 -0
  1993. package/payload/platform/plugins/whatsapp/lib/mcp-spawn-tee/index.js +193 -0
  1994. package/payload/platform/plugins/whatsapp/lib/mcp-spawn-tee/package.json +3 -0
  1995. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/boot-without-env.test.d.ts +2 -0
  1996. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/boot-without-env.test.d.ts.map +1 -0
  1997. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/boot-without-env.test.js +58 -0
  1998. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/boot-without-env.test.js.map +1 -0
  1999. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/format-login-start.test.d.ts +2 -0
  2000. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/format-login-start.test.d.ts.map +1 -0
  2001. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/format-login-start.test.js +16 -0
  2002. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/format-login-start.test.js.map +1 -0
  2003. package/payload/platform/plugins/whatsapp/mcp/dist/call-api.d.ts +14 -0
  2004. package/payload/platform/plugins/whatsapp/mcp/dist/call-api.d.ts.map +1 -0
  2005. package/payload/platform/plugins/whatsapp/mcp/dist/call-api.js +42 -0
  2006. package/payload/platform/plugins/whatsapp/mcp/dist/call-api.js.map +1 -0
  2007. package/payload/platform/plugins/whatsapp/mcp/dist/format.d.ts +7 -0
  2008. package/payload/platform/plugins/whatsapp/mcp/dist/format.d.ts.map +1 -0
  2009. package/payload/platform/plugins/whatsapp/mcp/dist/format.js +21 -0
  2010. package/payload/platform/plugins/whatsapp/mcp/dist/format.js.map +1 -0
  2011. package/payload/platform/plugins/whatsapp/mcp/dist/index.d.ts +8 -0
  2012. package/payload/platform/plugins/whatsapp/mcp/dist/index.d.ts.map +1 -0
  2013. package/payload/platform/plugins/whatsapp/mcp/dist/index.js +436 -0
  2014. package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -0
  2015. package/payload/platform/plugins/whatsapp/mcp/package.json +21 -0
  2016. package/payload/platform/plugins/whatsapp/mcp/vitest.config.ts +9 -0
  2017. package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +307 -0
  2018. package/payload/platform/plugins/whatsapp/skills/connect-whatsapp/SKILL.md +86 -0
  2019. package/payload/platform/plugins/whatsapp/skills/manage-whatsapp-config/SKILL.md +90 -0
  2020. package/payload/platform/plugins/work/.claude-plugin/plugin.json +21 -0
  2021. package/payload/platform/plugins/work/.mcp.json +13 -0
  2022. package/payload/platform/plugins/work/PLUGIN.md +124 -0
  2023. package/payload/platform/plugins/work/lib/mcp-spawn-tee/index.js +193 -0
  2024. package/payload/platform/plugins/work/lib/mcp-spawn-tee/package.json +3 -0
  2025. package/payload/platform/plugins/work/mcp/dist/cli/project-create-cli.d.ts +2 -0
  2026. package/payload/platform/plugins/work/mcp/dist/cli/project-create-cli.d.ts.map +1 -0
  2027. package/payload/platform/plugins/work/mcp/dist/cli/project-create-cli.js +78 -0
  2028. package/payload/platform/plugins/work/mcp/dist/cli/project-create-cli.js.map +1 -0
  2029. package/payload/platform/plugins/work/mcp/dist/index.d.ts +2 -0
  2030. package/payload/platform/plugins/work/mcp/dist/index.d.ts.map +1 -0
  2031. package/payload/platform/plugins/work/mcp/dist/index.js +547 -0
  2032. package/payload/platform/plugins/work/mcp/dist/index.js.map +1 -0
  2033. package/payload/platform/plugins/work/mcp/dist/lib/embeddings.d.ts +7 -0
  2034. package/payload/platform/plugins/work/mcp/dist/lib/embeddings.d.ts.map +1 -0
  2035. package/payload/platform/plugins/work/mcp/dist/lib/embeddings.js +24 -0
  2036. package/payload/platform/plugins/work/mcp/dist/lib/embeddings.js.map +1 -0
  2037. package/payload/platform/plugins/work/mcp/dist/lib/neo4j.d.ts +5 -0
  2038. package/payload/platform/plugins/work/mcp/dist/lib/neo4j.d.ts.map +1 -0
  2039. package/payload/platform/plugins/work/mcp/dist/lib/neo4j.js +40 -0
  2040. package/payload/platform/plugins/work/mcp/dist/lib/neo4j.js.map +1 -0
  2041. package/payload/platform/plugins/work/mcp/dist/tools/project-complete.d.ts +17 -0
  2042. package/payload/platform/plugins/work/mcp/dist/tools/project-complete.d.ts.map +1 -0
  2043. package/payload/platform/plugins/work/mcp/dist/tools/project-complete.js +76 -0
  2044. package/payload/platform/plugins/work/mcp/dist/tools/project-complete.js.map +1 -0
  2045. package/payload/platform/plugins/work/mcp/dist/tools/project-create.d.ts +29 -0
  2046. package/payload/platform/plugins/work/mcp/dist/tools/project-create.d.ts.map +1 -0
  2047. package/payload/platform/plugins/work/mcp/dist/tools/project-create.js +235 -0
  2048. package/payload/platform/plugins/work/mcp/dist/tools/project-create.js.map +1 -0
  2049. package/payload/platform/plugins/work/mcp/dist/tools/project-get.d.ts +40 -0
  2050. package/payload/platform/plugins/work/mcp/dist/tools/project-get.d.ts.map +1 -0
  2051. package/payload/platform/plugins/work/mcp/dist/tools/project-get.js +125 -0
  2052. package/payload/platform/plugins/work/mcp/dist/tools/project-get.js.map +1 -0
  2053. package/payload/platform/plugins/work/mcp/dist/tools/project-list.d.ts +26 -0
  2054. package/payload/platform/plugins/work/mcp/dist/tools/project-list.d.ts.map +1 -0
  2055. package/payload/platform/plugins/work/mcp/dist/tools/project-list.js +81 -0
  2056. package/payload/platform/plugins/work/mcp/dist/tools/project-list.js.map +1 -0
  2057. package/payload/platform/plugins/work/mcp/dist/tools/project-update.d.ts +19 -0
  2058. package/payload/platform/plugins/work/mcp/dist/tools/project-update.d.ts.map +1 -0
  2059. package/payload/platform/plugins/work/mcp/dist/tools/project-update.js +102 -0
  2060. package/payload/platform/plugins/work/mcp/dist/tools/project-update.js.map +1 -0
  2061. package/payload/platform/plugins/work/mcp/dist/tools/session-list.d.ts +20 -0
  2062. package/payload/platform/plugins/work/mcp/dist/tools/session-list.d.ts.map +1 -0
  2063. package/payload/platform/plugins/work/mcp/dist/tools/session-list.js +37 -0
  2064. package/payload/platform/plugins/work/mcp/dist/tools/session-list.js.map +1 -0
  2065. package/payload/platform/plugins/work/mcp/dist/tools/session-name.d.ts +12 -0
  2066. package/payload/platform/plugins/work/mcp/dist/tools/session-name.d.ts.map +1 -0
  2067. package/payload/platform/plugins/work/mcp/dist/tools/session-name.js +28 -0
  2068. package/payload/platform/plugins/work/mcp/dist/tools/session-name.js.map +1 -0
  2069. package/payload/platform/plugins/work/mcp/dist/tools/work-complete.d.ts +16 -0
  2070. package/payload/platform/plugins/work/mcp/dist/tools/work-complete.d.ts.map +1 -0
  2071. package/payload/platform/plugins/work/mcp/dist/tools/work-complete.js +33 -0
  2072. package/payload/platform/plugins/work/mcp/dist/tools/work-complete.js.map +1 -0
  2073. package/payload/platform/plugins/work/mcp/dist/tools/work-create.d.ts +63 -0
  2074. package/payload/platform/plugins/work/mcp/dist/tools/work-create.d.ts.map +1 -0
  2075. package/payload/platform/plugins/work/mcp/dist/tools/work-create.js +141 -0
  2076. package/payload/platform/plugins/work/mcp/dist/tools/work-create.js.map +1 -0
  2077. package/payload/platform/plugins/work/mcp/dist/tools/work-get.d.ts +19 -0
  2078. package/payload/platform/plugins/work/mcp/dist/tools/work-get.d.ts.map +1 -0
  2079. package/payload/platform/plugins/work/mcp/dist/tools/work-get.js +51 -0
  2080. package/payload/platform/plugins/work/mcp/dist/tools/work-get.js.map +1 -0
  2081. package/payload/platform/plugins/work/mcp/dist/tools/work-list.d.ts +18 -0
  2082. package/payload/platform/plugins/work/mcp/dist/tools/work-list.d.ts.map +1 -0
  2083. package/payload/platform/plugins/work/mcp/dist/tools/work-list.js +66 -0
  2084. package/payload/platform/plugins/work/mcp/dist/tools/work-list.js.map +1 -0
  2085. package/payload/platform/plugins/work/mcp/dist/tools/work-ready.d.ts +21 -0
  2086. package/payload/platform/plugins/work/mcp/dist/tools/work-ready.d.ts.map +1 -0
  2087. package/payload/platform/plugins/work/mcp/dist/tools/work-ready.js +54 -0
  2088. package/payload/platform/plugins/work/mcp/dist/tools/work-ready.js.map +1 -0
  2089. package/payload/platform/plugins/work/mcp/dist/tools/work-relate.d.ts +12 -0
  2090. package/payload/platform/plugins/work/mcp/dist/tools/work-relate.d.ts.map +1 -0
  2091. package/payload/platform/plugins/work/mcp/dist/tools/work-relate.js +59 -0
  2092. package/payload/platform/plugins/work/mcp/dist/tools/work-relate.js.map +1 -0
  2093. package/payload/platform/plugins/work/mcp/dist/tools/work-update.d.ts +32 -0
  2094. package/payload/platform/plugins/work/mcp/dist/tools/work-update.d.ts.map +1 -0
  2095. package/payload/platform/plugins/work/mcp/dist/tools/work-update.js +112 -0
  2096. package/payload/platform/plugins/work/mcp/dist/tools/work-update.js.map +1 -0
  2097. package/payload/platform/plugins/work/mcp/package.json +20 -0
  2098. package/payload/platform/plugins/work/skills/execute-task/SKILL.md +103 -0
  2099. package/payload/platform/plugins/workflows/.claude-plugin/plugin.json +21 -0
  2100. package/payload/platform/plugins/workflows/.mcp.json +12 -0
  2101. package/payload/platform/plugins/workflows/PLUGIN.md +160 -0
  2102. package/payload/platform/plugins/workflows/lib/mcp-spawn-tee/index.js +193 -0
  2103. package/payload/platform/plugins/workflows/lib/mcp-spawn-tee/package.json +3 -0
  2104. package/payload/platform/plugins/workflows/mcp/dist/index.d.ts +2 -0
  2105. package/payload/platform/plugins/workflows/mcp/dist/index.d.ts.map +1 -0
  2106. package/payload/platform/plugins/workflows/mcp/dist/index.js +440 -0
  2107. package/payload/platform/plugins/workflows/mcp/dist/index.js.map +1 -0
  2108. package/payload/platform/plugins/workflows/mcp/dist/lib/active-runs.d.ts +38 -0
  2109. package/payload/platform/plugins/workflows/mcp/dist/lib/active-runs.d.ts.map +1 -0
  2110. package/payload/platform/plugins/workflows/mcp/dist/lib/active-runs.js +83 -0
  2111. package/payload/platform/plugins/workflows/mcp/dist/lib/active-runs.js.map +1 -0
  2112. package/payload/platform/plugins/workflows/mcp/dist/lib/embeddings.d.ts +2 -0
  2113. package/payload/platform/plugins/workflows/mcp/dist/lib/embeddings.d.ts.map +1 -0
  2114. package/payload/platform/plugins/workflows/mcp/dist/lib/embeddings.js +19 -0
  2115. package/payload/platform/plugins/workflows/mcp/dist/lib/embeddings.js.map +1 -0
  2116. package/payload/platform/plugins/workflows/mcp/dist/lib/llm-call.d.ts +151 -0
  2117. package/payload/platform/plugins/workflows/mcp/dist/lib/llm-call.d.ts.map +1 -0
  2118. package/payload/platform/plugins/workflows/mcp/dist/lib/llm-call.js +299 -0
  2119. package/payload/platform/plugins/workflows/mcp/dist/lib/llm-call.js.map +1 -0
  2120. package/payload/platform/plugins/workflows/mcp/dist/lib/neo4j.d.ts +5 -0
  2121. package/payload/platform/plugins/workflows/mcp/dist/lib/neo4j.d.ts.map +1 -0
  2122. package/payload/platform/plugins/workflows/mcp/dist/lib/neo4j.js +40 -0
  2123. package/payload/platform/plugins/workflows/mcp/dist/lib/neo4j.js.map +1 -0
  2124. package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.d.ts +66 -0
  2125. package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.d.ts.map +1 -0
  2126. package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.js +187 -0
  2127. package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.js.map +1 -0
  2128. package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.d.ts +25 -0
  2129. package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.d.ts.map +1 -0
  2130. package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.js +56 -0
  2131. package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.js.map +1 -0
  2132. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.d.ts +33 -0
  2133. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.d.ts.map +1 -0
  2134. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.js +130 -0
  2135. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.js.map +1 -0
  2136. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-delete.d.ts +28 -0
  2137. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-delete.d.ts.map +1 -0
  2138. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-delete.js +57 -0
  2139. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-delete.js.map +1 -0
  2140. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.d.ts +51 -0
  2141. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.d.ts.map +1 -0
  2142. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js +382 -0
  2143. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js.map +1 -0
  2144. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.d.ts +24 -0
  2145. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.d.ts.map +1 -0
  2146. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.js +48 -0
  2147. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.js.map +1 -0
  2148. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-list.d.ts +16 -0
  2149. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-list.d.ts.map +1 -0
  2150. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-list.js +44 -0
  2151. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-list.js.map +1 -0
  2152. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-runs.d.ts +28 -0
  2153. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-runs.d.ts.map +1 -0
  2154. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-runs.js +71 -0
  2155. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-runs.js.map +1 -0
  2156. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.d.ts +11 -0
  2157. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.d.ts.map +1 -0
  2158. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.js +150 -0
  2159. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.js.map +1 -0
  2160. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-validate.d.ts +13 -0
  2161. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-validate.d.ts.map +1 -0
  2162. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-validate.js +53 -0
  2163. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-validate.js.map +1 -0
  2164. package/payload/platform/plugins/workflows/mcp/package.json +20 -0
  2165. package/payload/platform/plugins/workflows/mcp/test-runner.mjs +710 -0
  2166. package/payload/platform/plugins/workflows/mcp/test-workflows.sh +77 -0
  2167. package/payload/platform/plugins/workflows/skills/workflow-manager/SKILL.md +95 -0
  2168. package/payload/platform/plugins/x-import/.claude-plugin/plugin.json +8 -0
  2169. package/payload/platform/plugins/x-import/PLUGIN.md +33 -0
  2170. package/payload/platform/plugins/x-import/references/archive-shape.md +124 -0
  2171. package/payload/platform/plugins/x-import/references/transcript-shape.md +121 -0
  2172. package/payload/platform/plugins/x-import/skills/x-import/SKILL.md +123 -0
  2173. package/payload/platform/scripts/__tests__/agents-md-bootstrap.test.sh +111 -0
  2174. package/payload/platform/scripts/__tests__/check-no-raw-mcp-registrations.test.sh +57 -0
  2175. package/payload/platform/scripts/__tests__/check-no-task-id-leaks.test.sh +153 -0
  2176. package/payload/platform/scripts/__tests__/first-token-creates-stream-log.test.sh +37 -0
  2177. package/payload/platform/scripts/__tests__/logs-read-prefix.sh +237 -0
  2178. package/payload/platform/scripts/__tests__/prompt-optimiser-audit.test.sh +59 -0
  2179. package/payload/platform/scripts/__tests__/provision-role-stamp.test.sh +40 -0
  2180. package/payload/platform/scripts/__tests__/resume-tunnel.test.sh +641 -0
  2181. package/payload/platform/scripts/__tests__/sweep-durability.test.sh +103 -0
  2182. package/payload/platform/scripts/admin-conversation-recover.mjs +386 -0
  2183. package/payload/platform/scripts/admin-persist-audit.ts +211 -0
  2184. package/payload/platform/scripts/backfill-bypass-permissions.sh +58 -0
  2185. package/payload/platform/scripts/check-architecture-skill-no-drift.mjs +114 -0
  2186. package/payload/platform/scripts/check-canonical-tool-names.mjs +110 -0
  2187. package/payload/platform/scripts/check-cypher-int-params.mjs +277 -0
  2188. package/payload/platform/scripts/check-no-conversation-id-leaks.mjs +165 -0
  2189. package/payload/platform/scripts/check-no-direct-clipboard.mjs +54 -0
  2190. package/payload/platform/scripts/check-no-esm-require.mjs +164 -0
  2191. package/payload/platform/scripts/check-no-legacy-spawn-route.mjs +37 -0
  2192. package/payload/platform/scripts/check-no-raw-mcp-registrations.mjs +70 -0
  2193. package/payload/platform/scripts/check-no-task-id-leaks.mjs +201 -0
  2194. package/payload/platform/scripts/check-plugin-references.mjs +256 -0
  2195. package/payload/platform/scripts/check-plugin-tools-mcp-consistency.mjs +136 -0
  2196. package/payload/platform/scripts/check-roles-doc-completeness.mjs +96 -0
  2197. package/payload/platform/scripts/check-routing-prose-bash.mjs +134 -0
  2198. package/payload/platform/scripts/check-skill-frontmatter.mjs +142 -0
  2199. package/payload/platform/scripts/check-skill-load-coverage.mjs +100 -0
  2200. package/payload/platform/scripts/check-specialist-tool-surface.mjs +323 -0
  2201. package/payload/platform/scripts/conversation-id-allowlist.txt +142 -0
  2202. package/payload/platform/scripts/dedupe-userprofile-ghosts.sh +388 -0
  2203. package/payload/platform/scripts/generate-canonical-tool-names.mjs +63 -0
  2204. package/payload/platform/scripts/generate-entitlement-fixture.mjs +152 -0
  2205. package/payload/platform/scripts/identity-forbidden-token-check.mjs +87 -0
  2206. package/payload/platform/scripts/installer-device-verify.sh +358 -0
  2207. package/payload/platform/scripts/lib/__tests__/admin-skills-bootstrap.test.sh +64 -0
  2208. package/payload/platform/scripts/lib/admin-skills-bootstrap.sh +109 -0
  2209. package/payload/platform/scripts/lib/agents-md-bootstrap.sh +49 -0
  2210. package/payload/platform/scripts/lib/canonical-tool-names.mjs +88 -0
  2211. package/payload/platform/scripts/lib/provision-account-dir.sh +316 -0
  2212. package/payload/platform/scripts/lib/read-brand-json.sh +69 -0
  2213. package/payload/platform/scripts/lib/resolve-account-dir.sh +131 -0
  2214. package/payload/platform/scripts/log-adherence-check.sh +125 -0
  2215. package/payload/platform/scripts/logs-read-jsonl.test.sh +307 -0
  2216. package/payload/platform/scripts/logs-read.sh +980 -0
  2217. package/payload/platform/scripts/logs-read.test.sh +159 -0
  2218. package/payload/platform/scripts/prompt-optimiser-audit.sh +82 -0
  2219. package/payload/platform/scripts/redact-install-logs.sh +87 -0
  2220. package/payload/platform/scripts/resume-tunnel.sh +280 -0
  2221. package/payload/platform/scripts/rss-sampler.sh +58 -0
  2222. package/payload/platform/scripts/seed-neo4j.sh +211 -0
  2223. package/payload/platform/scripts/setup-account.sh +55 -0
  2224. package/payload/platform/scripts/smoke-boot-services.sh +413 -0
  2225. package/payload/platform/scripts/test-laptop-vnc-boot.sh +88 -0
  2226. package/payload/platform/scripts/verify-skill-tool-surface.sh +389 -0
  2227. package/payload/platform/scripts/vnc.sh +476 -0
  2228. package/payload/platform/scripts/wifi-provision-server/server.js +743 -0
  2229. package/payload/platform/scripts/wifi-provision.sh +492 -0
  2230. package/payload/platform/services/claude-session-manager/dist/admin-identity-audit.d.ts +39 -0
  2231. package/payload/platform/services/claude-session-manager/dist/admin-identity-audit.d.ts.map +1 -0
  2232. package/payload/platform/services/claude-session-manager/dist/admin-identity-audit.js +133 -0
  2233. package/payload/platform/services/claude-session-manager/dist/admin-identity-audit.js.map +1 -0
  2234. package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.d.ts +23 -0
  2235. package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.d.ts.map +1 -0
  2236. package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.js +29 -0
  2237. package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.js.map +1 -0
  2238. package/payload/platform/services/claude-session-manager/dist/auth-snapshot.d.ts +4 -0
  2239. package/payload/platform/services/claude-session-manager/dist/auth-snapshot.d.ts.map +1 -0
  2240. package/payload/platform/services/claude-session-manager/dist/auth-snapshot.js +50 -0
  2241. package/payload/platform/services/claude-session-manager/dist/auth-snapshot.js.map +1 -0
  2242. package/payload/platform/services/claude-session-manager/dist/brand-foreign-filter.d.ts +30 -0
  2243. package/payload/platform/services/claude-session-manager/dist/brand-foreign-filter.d.ts.map +1 -0
  2244. package/payload/platform/services/claude-session-manager/dist/brand-foreign-filter.js +86 -0
  2245. package/payload/platform/services/claude-session-manager/dist/brand-foreign-filter.js.map +1 -0
  2246. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.d.ts +7 -0
  2247. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.d.ts.map +1 -0
  2248. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts +5 -0
  2249. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -0
  2250. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +226 -0
  2251. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -0
  2252. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.js +23 -0
  2253. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.js.map +1 -0
  2254. package/payload/platform/services/claude-session-manager/dist/channel-mcp.d.ts +15 -0
  2255. package/payload/platform/services/claude-session-manager/dist/channel-mcp.d.ts.map +1 -0
  2256. package/payload/platform/services/claude-session-manager/dist/channel-mcp.js +34 -0
  2257. package/payload/platform/services/claude-session-manager/dist/channel-mcp.js.map +1 -0
  2258. package/payload/platform/services/claude-session-manager/dist/channel-targets.d.ts +26 -0
  2259. package/payload/platform/services/claude-session-manager/dist/channel-targets.d.ts.map +1 -0
  2260. package/payload/platform/services/claude-session-manager/dist/channel-targets.js +19 -0
  2261. package/payload/platform/services/claude-session-manager/dist/channel-targets.js.map +1 -0
  2262. package/payload/platform/services/claude-session-manager/dist/config.d.ts +73 -0
  2263. package/payload/platform/services/claude-session-manager/dist/config.d.ts.map +1 -0
  2264. package/payload/platform/services/claude-session-manager/dist/config.js +290 -0
  2265. package/payload/platform/services/claude-session-manager/dist/config.js.map +1 -0
  2266. package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts +150 -0
  2267. package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts.map +1 -0
  2268. package/payload/platform/services/claude-session-manager/dist/fs-watcher.js +913 -0
  2269. package/payload/platform/services/claude-session-manager/dist/fs-watcher.js.map +1 -0
  2270. package/payload/platform/services/claude-session-manager/dist/hooks-discovery.d.ts +7 -0
  2271. package/payload/platform/services/claude-session-manager/dist/hooks-discovery.d.ts.map +1 -0
  2272. package/payload/platform/services/claude-session-manager/dist/hooks-discovery.js +90 -0
  2273. package/payload/platform/services/claude-session-manager/dist/hooks-discovery.js.map +1 -0
  2274. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +56 -0
  2275. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -0
  2276. package/payload/platform/services/claude-session-manager/dist/http-server.js +2797 -0
  2277. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -0
  2278. package/payload/platform/services/claude-session-manager/dist/index.d.ts +2 -0
  2279. package/payload/platform/services/claude-session-manager/dist/index.d.ts.map +1 -0
  2280. package/payload/platform/services/claude-session-manager/dist/index.js +784 -0
  2281. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -0
  2282. package/payload/platform/services/claude-session-manager/dist/input-postcondition.d.ts +22 -0
  2283. package/payload/platform/services/claude-session-manager/dist/input-postcondition.d.ts.map +1 -0
  2284. package/payload/platform/services/claude-session-manager/dist/input-postcondition.js +50 -0
  2285. package/payload/platform/services/claude-session-manager/dist/input-postcondition.js.map +1 -0
  2286. package/payload/platform/services/claude-session-manager/dist/install-log-sink.d.ts +2 -0
  2287. package/payload/platform/services/claude-session-manager/dist/install-log-sink.d.ts.map +1 -0
  2288. package/payload/platform/services/claude-session-manager/dist/install-log-sink.js +6 -0
  2289. package/payload/platform/services/claude-session-manager/dist/install-log-sink.js.map +1 -0
  2290. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.d.ts +49 -0
  2291. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.d.ts.map +1 -0
  2292. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.js +169 -0
  2293. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.js.map +1 -0
  2294. package/payload/platform/services/claude-session-manager/dist/jsonl-observer.d.ts +30 -0
  2295. package/payload/platform/services/claude-session-manager/dist/jsonl-observer.d.ts.map +1 -0
  2296. package/payload/platform/services/claude-session-manager/dist/jsonl-observer.js +204 -0
  2297. package/payload/platform/services/claude-session-manager/dist/jsonl-observer.js.map +1 -0
  2298. package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts +67 -0
  2299. package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts.map +1 -0
  2300. package/payload/platform/services/claude-session-manager/dist/jsonl-path.js +141 -0
  2301. package/payload/platform/services/claude-session-manager/dist/jsonl-path.js.map +1 -0
  2302. package/payload/platform/services/claude-session-manager/dist/jsonl-tail.d.ts +81 -0
  2303. package/payload/platform/services/claude-session-manager/dist/jsonl-tail.d.ts.map +1 -0
  2304. package/payload/platform/services/claude-session-manager/dist/jsonl-tail.js +503 -0
  2305. package/payload/platform/services/claude-session-manager/dist/jsonl-tail.js.map +1 -0
  2306. package/payload/platform/services/claude-session-manager/dist/liveness-divergence.d.ts +19 -0
  2307. package/payload/platform/services/claude-session-manager/dist/liveness-divergence.d.ts.map +1 -0
  2308. package/payload/platform/services/claude-session-manager/dist/liveness-divergence.js +38 -0
  2309. package/payload/platform/services/claude-session-manager/dist/liveness-divergence.js.map +1 -0
  2310. package/payload/platform/services/claude-session-manager/dist/log-sink.d.ts +12 -0
  2311. package/payload/platform/services/claude-session-manager/dist/log-sink.d.ts.map +1 -0
  2312. package/payload/platform/services/claude-session-manager/dist/log-sink.js +48 -0
  2313. package/payload/platform/services/claude-session-manager/dist/log-sink.js.map +1 -0
  2314. package/payload/platform/services/claude-session-manager/dist/mcp-tools-probe.d.ts +38 -0
  2315. package/payload/platform/services/claude-session-manager/dist/mcp-tools-probe.d.ts.map +1 -0
  2316. package/payload/platform/services/claude-session-manager/dist/mcp-tools-probe.js +131 -0
  2317. package/payload/platform/services/claude-session-manager/dist/mcp-tools-probe.js.map +1 -0
  2318. package/payload/platform/services/claude-session-manager/dist/permission-mode-tail.d.ts +22 -0
  2319. package/payload/platform/services/claude-session-manager/dist/permission-mode-tail.d.ts.map +1 -0
  2320. package/payload/platform/services/claude-session-manager/dist/permission-mode-tail.js +71 -0
  2321. package/payload/platform/services/claude-session-manager/dist/permission-mode-tail.js.map +1 -0
  2322. package/payload/platform/services/claude-session-manager/dist/pty-census.d.ts +40 -0
  2323. package/payload/platform/services/claude-session-manager/dist/pty-census.d.ts.map +1 -0
  2324. package/payload/platform/services/claude-session-manager/dist/pty-census.js +125 -0
  2325. package/payload/platform/services/claude-session-manager/dist/pty-census.js.map +1 -0
  2326. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +684 -0
  2327. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -0
  2328. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +2245 -0
  2329. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -0
  2330. package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.d.ts +40 -0
  2331. package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.d.ts.map +1 -0
  2332. package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.js +123 -0
  2333. package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.js.map +1 -0
  2334. package/payload/platform/services/claude-session-manager/dist/public-tool-audit.d.ts +33 -0
  2335. package/payload/platform/services/claude-session-manager/dist/public-tool-audit.d.ts.map +1 -0
  2336. package/payload/platform/services/claude-session-manager/dist/public-tool-audit.js +149 -0
  2337. package/payload/platform/services/claude-session-manager/dist/public-tool-audit.js.map +1 -0
  2338. package/payload/platform/services/claude-session-manager/dist/rc-child-log.d.ts +13 -0
  2339. package/payload/platform/services/claude-session-manager/dist/rc-child-log.d.ts.map +1 -0
  2340. package/payload/platform/services/claude-session-manager/dist/rc-child-log.js +52 -0
  2341. package/payload/platform/services/claude-session-manager/dist/rc-child-log.js.map +1 -0
  2342. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +175 -0
  2343. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -0
  2344. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +644 -0
  2345. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -0
  2346. package/payload/platform/services/claude-session-manager/dist/rc-life.d.ts +4 -0
  2347. package/payload/platform/services/claude-session-manager/dist/rc-life.d.ts.map +1 -0
  2348. package/payload/platform/services/claude-session-manager/dist/rc-life.js +16 -0
  2349. package/payload/platform/services/claude-session-manager/dist/rc-life.js.map +1 -0
  2350. package/payload/platform/services/claude-session-manager/dist/rc-script-spawn.d.ts +80 -0
  2351. package/payload/platform/services/claude-session-manager/dist/rc-script-spawn.d.ts.map +1 -0
  2352. package/payload/platform/services/claude-session-manager/dist/rc-script-spawn.js +306 -0
  2353. package/payload/platform/services/claude-session-manager/dist/rc-script-spawn.js.map +1 -0
  2354. package/payload/platform/services/claude-session-manager/dist/reaper.d.ts +28 -0
  2355. package/payload/platform/services/claude-session-manager/dist/reaper.d.ts.map +1 -0
  2356. package/payload/platform/services/claude-session-manager/dist/reaper.js +118 -0
  2357. package/payload/platform/services/claude-session-manager/dist/reaper.js.map +1 -0
  2358. package/payload/platform/services/claude-session-manager/dist/reseat-ledger.d.ts +49 -0
  2359. package/payload/platform/services/claude-session-manager/dist/reseat-ledger.d.ts.map +1 -0
  2360. package/payload/platform/services/claude-session-manager/dist/reseat-ledger.js +148 -0
  2361. package/payload/platform/services/claude-session-manager/dist/reseat-ledger.js.map +1 -0
  2362. package/payload/platform/services/claude-session-manager/dist/scope-record.d.ts +11 -0
  2363. package/payload/platform/services/claude-session-manager/dist/scope-record.d.ts.map +1 -0
  2364. package/payload/platform/services/claude-session-manager/dist/scope-record.js +63 -0
  2365. package/payload/platform/services/claude-session-manager/dist/scope-record.js.map +1 -0
  2366. package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts +130 -0
  2367. package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts.map +1 -0
  2368. package/payload/platform/services/claude-session-manager/dist/session-sidecar.js +291 -0
  2369. package/payload/platform/services/claude-session-manager/dist/session-sidecar.js.map +1 -0
  2370. package/payload/platform/services/claude-session-manager/dist/session-store.d.ts +49 -0
  2371. package/payload/platform/services/claude-session-manager/dist/session-store.d.ts.map +1 -0
  2372. package/payload/platform/services/claude-session-manager/dist/session-store.js +52 -0
  2373. package/payload/platform/services/claude-session-manager/dist/session-store.js.map +1 -0
  2374. package/payload/platform/services/claude-session-manager/dist/settings-permission-mode.d.ts +12 -0
  2375. package/payload/platform/services/claude-session-manager/dist/settings-permission-mode.d.ts.map +1 -0
  2376. package/payload/platform/services/claude-session-manager/dist/settings-permission-mode.js +57 -0
  2377. package/payload/platform/services/claude-session-manager/dist/settings-permission-mode.js.map +1 -0
  2378. package/payload/platform/services/claude-session-manager/dist/sidecar-store.d.ts +45 -0
  2379. package/payload/platform/services/claude-session-manager/dist/sidecar-store.d.ts.map +1 -0
  2380. package/payload/platform/services/claude-session-manager/dist/sidecar-store.js +118 -0
  2381. package/payload/platform/services/claude-session-manager/dist/sidecar-store.js.map +1 -0
  2382. package/payload/platform/services/claude-session-manager/dist/spawn-rate-limiter.d.ts +28 -0
  2383. package/payload/platform/services/claude-session-manager/dist/spawn-rate-limiter.d.ts.map +1 -0
  2384. package/payload/platform/services/claude-session-manager/dist/spawn-rate-limiter.js +77 -0
  2385. package/payload/platform/services/claude-session-manager/dist/spawn-rate-limiter.js.map +1 -0
  2386. package/payload/platform/services/claude-session-manager/dist/specialist-drift.d.ts +60 -0
  2387. package/payload/platform/services/claude-session-manager/dist/specialist-drift.d.ts.map +1 -0
  2388. package/payload/platform/services/claude-session-manager/dist/specialist-drift.js +203 -0
  2389. package/payload/platform/services/claude-session-manager/dist/specialist-drift.js.map +1 -0
  2390. package/payload/platform/services/claude-session-manager/dist/stuck-turn.d.ts +70 -0
  2391. package/payload/platform/services/claude-session-manager/dist/stuck-turn.d.ts.map +1 -0
  2392. package/payload/platform/services/claude-session-manager/dist/stuck-turn.js +213 -0
  2393. package/payload/platform/services/claude-session-manager/dist/stuck-turn.js.map +1 -0
  2394. package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts +157 -0
  2395. package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts.map +1 -0
  2396. package/payload/platform/services/claude-session-manager/dist/system-prompt.js +482 -0
  2397. package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -0
  2398. package/payload/platform/services/claude-session-manager/dist/systemd-scope.d.ts +164 -0
  2399. package/payload/platform/services/claude-session-manager/dist/systemd-scope.d.ts.map +1 -0
  2400. package/payload/platform/services/claude-session-manager/dist/systemd-scope.js +296 -0
  2401. package/payload/platform/services/claude-session-manager/dist/systemd-scope.js.map +1 -0
  2402. package/payload/platform/services/claude-session-manager/dist/systemd-spawn.d.ts +83 -0
  2403. package/payload/platform/services/claude-session-manager/dist/systemd-spawn.d.ts.map +1 -0
  2404. package/payload/platform/services/claude-session-manager/dist/systemd-spawn.js +345 -0
  2405. package/payload/platform/services/claude-session-manager/dist/systemd-spawn.js.map +1 -0
  2406. package/payload/platform/services/claude-session-manager/dist/tool-surface.d.ts +69 -0
  2407. package/payload/platform/services/claude-session-manager/dist/tool-surface.d.ts.map +1 -0
  2408. package/payload/platform/services/claude-session-manager/dist/tool-surface.js +373 -0
  2409. package/payload/platform/services/claude-session-manager/dist/tool-surface.js.map +1 -0
  2410. package/payload/platform/services/claude-session-manager/dist/types.d.ts +41 -0
  2411. package/payload/platform/services/claude-session-manager/dist/types.d.ts.map +1 -0
  2412. package/payload/platform/services/claude-session-manager/dist/types.js +2 -0
  2413. package/payload/platform/services/claude-session-manager/dist/types.js.map +1 -0
  2414. package/payload/platform/services/claude-session-manager/dist/url-capture.d.ts +12 -0
  2415. package/payload/platform/services/claude-session-manager/dist/url-capture.d.ts.map +1 -0
  2416. package/payload/platform/services/claude-session-manager/dist/url-capture.js +79 -0
  2417. package/payload/platform/services/claude-session-manager/dist/url-capture.js.map +1 -0
  2418. package/payload/platform/services/claude-session-manager/dist/user-title-store.d.ts +39 -0
  2419. package/payload/platform/services/claude-session-manager/dist/user-title-store.d.ts.map +1 -0
  2420. package/payload/platform/services/claude-session-manager/dist/user-title-store.js +138 -0
  2421. package/payload/platform/services/claude-session-manager/dist/user-title-store.js.map +1 -0
  2422. package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.d.ts +36 -0
  2423. package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.d.ts.map +1 -0
  2424. package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.js +63 -0
  2425. package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.js.map +1 -0
  2426. package/payload/platform/services/claude-session-manager/dist/wa-channel-store.d.ts +29 -0
  2427. package/payload/platform/services/claude-session-manager/dist/wa-channel-store.d.ts.map +1 -0
  2428. package/payload/platform/services/claude-session-manager/dist/wa-channel-store.js +124 -0
  2429. package/payload/platform/services/claude-session-manager/dist/wa-channel-store.js.map +1 -0
  2430. package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.d.ts +35 -0
  2431. package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.d.ts.map +1 -0
  2432. package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.js +52 -0
  2433. package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.js.map +1 -0
  2434. package/payload/platform/services/claude-session-manager/dist/webchat-channel-store.d.ts +29 -0
  2435. package/payload/platform/services/claude-session-manager/dist/webchat-channel-store.d.ts.map +1 -0
  2436. package/payload/platform/services/claude-session-manager/dist/webchat-channel-store.js +121 -0
  2437. package/payload/platform/services/claude-session-manager/dist/webchat-channel-store.js.map +1 -0
  2438. package/payload/platform/services/claude-session-manager/package.json +22 -0
  2439. package/payload/platform/services/claude-session-manager/scripts/stash-cleanup.sh +410 -0
  2440. package/payload/platform/services/claude-session-manager/vitest.config.ts +14 -0
  2441. package/payload/platform/services/webchat-channel/dist/instructions.d.ts +9 -0
  2442. package/payload/platform/services/webchat-channel/dist/instructions.d.ts.map +1 -0
  2443. package/payload/platform/services/webchat-channel/dist/instructions.js +106 -0
  2444. package/payload/platform/services/webchat-channel/dist/instructions.js.map +1 -0
  2445. package/payload/platform/services/webchat-channel/dist/notification.d.ts +89 -0
  2446. package/payload/platform/services/webchat-channel/dist/notification.d.ts.map +1 -0
  2447. package/payload/platform/services/webchat-channel/dist/notification.js +118 -0
  2448. package/payload/platform/services/webchat-channel/dist/notification.js.map +1 -0
  2449. package/payload/platform/services/webchat-channel/dist/permission.d.ts +46 -0
  2450. package/payload/platform/services/webchat-channel/dist/permission.d.ts.map +1 -0
  2451. package/payload/platform/services/webchat-channel/dist/permission.js +56 -0
  2452. package/payload/platform/services/webchat-channel/dist/permission.js.map +1 -0
  2453. package/payload/platform/services/webchat-channel/dist/server.d.ts +40 -0
  2454. package/payload/platform/services/webchat-channel/dist/server.d.ts.map +1 -0
  2455. package/payload/platform/services/webchat-channel/dist/server.js +329 -0
  2456. package/payload/platform/services/webchat-channel/dist/server.js.map +1 -0
  2457. package/payload/platform/services/webchat-channel/dist/turn-follow.d.ts +28 -0
  2458. package/payload/platform/services/webchat-channel/dist/turn-follow.d.ts.map +1 -0
  2459. package/payload/platform/services/webchat-channel/dist/turn-follow.js +188 -0
  2460. package/payload/platform/services/webchat-channel/dist/turn-follow.js.map +1 -0
  2461. package/payload/platform/services/webchat-channel/package.json +20 -0
  2462. package/payload/platform/services/whatsapp-channel/dist/jsonl-watch.d.ts +10 -0
  2463. package/payload/platform/services/whatsapp-channel/dist/jsonl-watch.d.ts.map +1 -0
  2464. package/payload/platform/services/whatsapp-channel/dist/jsonl-watch.js +70 -0
  2465. package/payload/platform/services/whatsapp-channel/dist/jsonl-watch.js.map +1 -0
  2466. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +194 -0
  2467. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -0
  2468. package/payload/platform/services/whatsapp-channel/dist/notification.js +265 -0
  2469. package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -0
  2470. package/payload/platform/services/whatsapp-channel/dist/server.d.ts +57 -0
  2471. package/payload/platform/services/whatsapp-channel/dist/server.d.ts.map +1 -0
  2472. package/payload/platform/services/whatsapp-channel/dist/server.js +625 -0
  2473. package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -0
  2474. package/payload/platform/services/whatsapp-channel/dist/targets.d.ts +100 -0
  2475. package/payload/platform/services/whatsapp-channel/dist/targets.d.ts.map +1 -0
  2476. package/payload/platform/services/whatsapp-channel/dist/targets.js +154 -0
  2477. package/payload/platform/services/whatsapp-channel/dist/targets.js.map +1 -0
  2478. package/payload/platform/services/whatsapp-channel/dist/turn-follow.d.ts +22 -0
  2479. package/payload/platform/services/whatsapp-channel/dist/turn-follow.d.ts.map +1 -0
  2480. package/payload/platform/services/whatsapp-channel/dist/turn-follow.js +163 -0
  2481. package/payload/platform/services/whatsapp-channel/dist/turn-follow.js.map +1 -0
  2482. package/payload/platform/services/whatsapp-channel/package.json +20 -0
  2483. package/payload/platform/templates/account.json +14 -0
  2484. package/payload/platform/templates/agents/admin/AGENTS.md +23 -0
  2485. package/payload/platform/templates/agents/admin/IDENTITY.md +65 -0
  2486. package/payload/platform/templates/agents/admin/LEARNINGS.md +3 -0
  2487. package/payload/platform/templates/agents/admin/SOUL.md +1 -0
  2488. package/payload/platform/templates/agents/public/IDENTITY.md +19 -0
  2489. package/payload/platform/templates/specialists/.claude-plugin/plugin.json +4 -0
  2490. package/payload/platform/templates/specialists/agents/citation-auditor.md +37 -0
  2491. package/payload/platform/templates/specialists/agents/coding-assistant.md +73 -0
  2492. package/payload/platform/templates/specialists/agents/compiled-truth-rewriter.md +42 -0
  2493. package/payload/platform/templates/specialists/agents/content-producer.md +65 -0
  2494. package/payload/platform/templates/specialists/agents/data-manager.md +29 -0
  2495. package/payload/platform/templates/specialists/agents/database-operator.md +25 -0
  2496. package/payload/platform/templates/specialists/agents/librarian.md +70 -0
  2497. package/payload/platform/templates/specialists/agents/personal-assistant.md +62 -0
  2498. package/payload/platform/templates/specialists/agents/project-manager.md +63 -0
  2499. package/payload/platform/templates/specialists/agents/public-session-reviewer.md +40 -0
  2500. package/payload/platform/templates/specialists/agents/research-assistant.md +73 -0
  2501. package/payload/platform/templates/specialists/agents/typed-edge-classifier.md +37 -0
  2502. package/payload/platform/templates/systemd/edge.service.template +38 -0
  2503. package/payload/platform/tsconfig.base.json +18 -0
  2504. package/payload/premium-plugins/.claude-plugin/marketplace.json +28 -0
  2505. package/payload/premium-plugins/sitedesk/.claude-plugin/plugin.json +8 -0
  2506. package/payload/premium-plugins/sitedesk/BUNDLE.md +35 -0
  2507. package/payload/premium-plugins/sitedesk/PLUGIN.md +18 -0
  2508. package/payload/premium-plugins/sitedesk/agents/sitedesk--site-manager.md +45 -0
  2509. package/payload/premium-plugins/sitedesk/agents/worker-checkin/IDENTITY.md +11 -0
  2510. package/payload/premium-plugins/sitedesk/agents/worker-checkin/SOUL.md +7 -0
  2511. package/payload/premium-plugins/sitedesk/agents/worker-checkin/template.json +9 -0
  2512. package/payload/premium-plugins/sitedesk/plugins/.claude-plugin/marketplace.json +18 -0
  2513. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/.claude-plugin/plugin.json +8 -0
  2514. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/PLUGIN.md +46 -0
  2515. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/quotation/SKILL.md +79 -0
  2516. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/quotation/references/learning-from-history.md +51 -0
  2517. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/quotation/references/maintenance.md +32 -0
  2518. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/quotation/references/manual-definition.md +42 -0
  2519. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/quotation/references/quote-engine.md +122 -0
  2520. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/quotation/references/quote-generation.md +110 -0
  2521. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/quotation/references/quoting.md +86 -0
  2522. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/quotation/references/verification.md +39 -0
  2523. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/timesheet/SKILL.md +47 -0
  2524. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/timesheet/references/checkin-contract.md +31 -0
  2525. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/timesheet/references/documents.md +28 -0
  2526. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/timesheet/references/roll-up.md +38 -0
  2527. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/timesheet/references/setup.md +20 -0
  2528. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/timesheet/rollup.mjs +90 -0
  2529. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/timesheet/rollup.test.mjs +106 -0
  2530. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/valuation/SKILL.md +108 -0
  2531. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/valuation/references/contract-template.md +34 -0
  2532. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/valuation/references/document-learning.md +63 -0
  2533. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/valuation/references/document-verification.md +52 -0
  2534. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/valuation/references/document.md +108 -0
  2535. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/valuation/references/issue-flow.md +117 -0
  2536. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/valuation/references/job-folder.md +91 -0
  2537. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/valuation/references/roll-up.md +73 -0
  2538. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/valuation/rollup.mjs +147 -0
  2539. package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/.claude-plugin/plugin.json +8 -0
  2540. package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/PLUGIN.md +49 -0
  2541. package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/README.md +70 -0
  2542. package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/commands/make-media.md +13 -0
  2543. package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/brand-extract/SKILL.md +86 -0
  2544. package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/make-media/SKILL.md +75 -0
  2545. package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/make-media/references/intake-and-questions.md +74 -0
  2546. package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/microsite/SKILL.md +88 -0
  2547. package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/microsite/references/placeholders.md +96 -0
  2548. package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/microsite/references/sections.md +48 -0
  2549. package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/microsite/templates/index.html +1004 -0
  2550. package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/microsite/templates/llms.txt +32 -0
  2551. package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/socials/SKILL.md +133 -0
  2552. package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/socials/references/pii-strip.md +64 -0
  2553. package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/socials/references/sources.md +96 -0
  2554. package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/socials/templates/og.html +92 -0
  2555. package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/socials/templates/social-posts.md +47 -0
  2556. package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/socials/templates/socials.html +87 -0
  2557. package/payload/premium-plugins/teaching/.claude-plugin/plugin.json +8 -0
  2558. package/payload/premium-plugins/teaching/PLUGIN.md +58 -0
  2559. package/payload/premium-plugins/teaching/skills/interactive-tutor/SKILL.md +59 -0
  2560. package/payload/premium-plugins/teaching/skills/interactive-tutor/references/assessment.md +70 -0
  2561. package/payload/premium-plugins/teaching/skills/interactive-tutor/references/classroom-conduct.md +43 -0
  2562. package/payload/premium-plugins/teaching/skills/interactive-tutor/references/teaching-modes.md +83 -0
  2563. package/payload/premium-plugins/teaching/skills/lesson-planner/SKILL.md +48 -0
  2564. package/payload/premium-plugins/teaching/skills/lesson-planner/references/context-gathering.md +41 -0
  2565. package/payload/premium-plugins/teaching/skills/lesson-planner/references/plan-structure.md +94 -0
  2566. package/payload/premium-plugins/teaching/skills/study-pack-builder/SKILL.md +52 -0
  2567. package/payload/premium-plugins/teaching/skills/study-pack-builder/references/disaggregation.md +49 -0
  2568. package/payload/premium-plugins/teaching/skills/study-pack-builder/references/materials.md +116 -0
  2569. package/payload/premium-plugins/venture-studio/.claude-plugin/plugin.json +8 -0
  2570. package/payload/premium-plugins/venture-studio/PLUGIN.md +128 -0
  2571. package/payload/premium-plugins/venture-studio/bin/scaffold.sh +116 -0
  2572. package/payload/premium-plugins/venture-studio/skills/brand-pack/SKILL.md +256 -0
  2573. package/payload/premium-plugins/venture-studio/skills/brand-pack/references/color-psychology.md +118 -0
  2574. package/payload/premium-plugins/venture-studio/skills/investor-data-room/SKILL.md +390 -0
  2575. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/business-plan-template.md +64 -0
  2576. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/competitive-battlecard.md +37 -0
  2577. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/competitor-analysis.md +32 -0
  2578. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/compliance-research-checklist.md +53 -0
  2579. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/data-room-structure.md +88 -0
  2580. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/deck-blueprint-template.md +39 -0
  2581. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/design-tokens-application.md +79 -0
  2582. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/html-pdf-pipeline.md +236 -0
  2583. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/internal-workings-scrub.md +33 -0
  2584. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/monetization-strategy.md +35 -0
  2585. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/pricing-strategy.md +37 -0
  2586. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/strategy-frameworks.md +46 -0
  2587. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/termsheet-template.md +88 -0
  2588. package/payload/premium-plugins/venture-studio/skills/investor-data-room/templates/prospectus/index.html +1565 -0
  2589. package/payload/premium-plugins/venture-studio/skills/investor-data-room/templates/prospectus/render-pdf.mjs +91 -0
  2590. package/payload/premium-plugins/venture-studio/skills/investor-data-room/templates/prospectus/term_sheet.html +715 -0
  2591. package/payload/premium-plugins/venture-studio/skills/legal-essentials/SKILL.md +65 -0
  2592. package/payload/premium-plugins/venture-studio/skills/office-hours/SKILL.md +587 -0
  2593. package/payload/premium-plugins/venture-studio/skills/prototype-host/SKILL.md +179 -0
  2594. package/payload/premium-plugins/venture-studio/skills/prototype-host/references/cloudflared-ingress-edit.md +81 -0
  2595. package/payload/premium-plugins/venture-studio/skills/prototype-host/references/scaffold-frameworks.md +60 -0
  2596. package/payload/premium-plugins/venture-studio/skills/prototype-host/references/systemd-user-service.md +104 -0
  2597. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/SKILL.md +342 -0
  2598. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/aarrr-metrics.md +275 -0
  2599. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/assumption-testing.md +93 -0
  2600. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/boolean-search.md +308 -0
  2601. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/build-measure-learn.md +262 -0
  2602. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/business-model-canvas.md +171 -0
  2603. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/commitment-signals.md +246 -0
  2604. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/design-thinking.md +183 -0
  2605. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/earlyvangelist.md +190 -0
  2606. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/first-principles.md +58 -0
  2607. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/fishbone.md +114 -0
  2608. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/five-whys.md +43 -0
  2609. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/ice-scoring.md +237 -0
  2610. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/innovation-accounting.md +290 -0
  2611. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/jtbd.md +105 -0
  2612. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/landing-page.md +361 -0
  2613. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/market-sizing.md +58 -0
  2614. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/market-type.md +167 -0
  2615. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/mom-test.md +193 -0
  2616. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/mvp-types.md +200 -0
  2617. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/og-images.md +239 -0
  2618. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/pareto.md +103 -0
  2619. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/persona-development.md +291 -0
  2620. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/pivot-types.md +225 -0
  2621. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/positioning-statement.md +179 -0
  2622. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/prd.md +363 -0
  2623. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/pre-mortem.md +74 -0
  2624. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/problem-validation.md +253 -0
  2625. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/product-market-fit.md +256 -0
  2626. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/research-synthesis.md +276 -0
  2627. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/strategy-red-team.md +41 -0
  2628. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/three-engines-of-growth.md +248 -0
  2629. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/validation-tests.md +89 -0
  2630. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/value-proposition-canvas.md +121 -0
  2631. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/win-loss-analysis.md +242 -0
  2632. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/workflow-mapping.md +271 -0
  2633. package/payload/premium-plugins/writer-craft/.claude-plugin/plugin.json +21 -0
  2634. package/payload/premium-plugins/writer-craft/PLUGIN.md +134 -0
  2635. package/payload/premium-plugins/writer-craft/agents/writer-craft--manuscript-reviewer.md +96 -0
  2636. package/payload/premium-plugins/writer-craft/lib/mcp-lifeline/dist/index.d.ts +8 -0
  2637. package/payload/premium-plugins/writer-craft/lib/mcp-lifeline/dist/index.d.ts.map +1 -0
  2638. package/payload/premium-plugins/writer-craft/lib/mcp-lifeline/dist/index.js +71 -0
  2639. package/payload/premium-plugins/writer-craft/lib/mcp-lifeline/dist/index.js.map +1 -0
  2640. package/payload/premium-plugins/writer-craft/lib/mcp-lifeline/package.json +7 -0
  2641. package/payload/premium-plugins/writer-craft/lib/mcp-spawn-tee/index.js +193 -0
  2642. package/payload/premium-plugins/writer-craft/lib/mcp-spawn-tee/package.json +3 -0
  2643. package/payload/premium-plugins/writer-craft/lib/mcp-stderr-tee/dist/index.d.ts +51 -0
  2644. package/payload/premium-plugins/writer-craft/lib/mcp-stderr-tee/dist/index.d.ts.map +1 -0
  2645. package/payload/premium-plugins/writer-craft/lib/mcp-stderr-tee/dist/index.js +196 -0
  2646. package/payload/premium-plugins/writer-craft/lib/mcp-stderr-tee/dist/index.js.map +1 -0
  2647. package/payload/premium-plugins/writer-craft/lib/mcp-stderr-tee/package.json +7 -0
  2648. package/payload/premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.d.ts +3 -0
  2649. package/payload/premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.d.ts.map +1 -0
  2650. package/payload/premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.js +58 -0
  2651. package/payload/premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.js.map +1 -0
  2652. package/payload/premium-plugins/writer-craft/mcp/dist/index.d.ts +3 -0
  2653. package/payload/premium-plugins/writer-craft/mcp/dist/index.d.ts.map +1 -0
  2654. package/payload/premium-plugins/writer-craft/mcp/dist/index.js +403 -0
  2655. package/payload/premium-plugins/writer-craft/mcp/dist/index.js.map +1 -0
  2656. package/payload/premium-plugins/writer-craft/mcp/dist/lib/neo4j.d.ts +14 -0
  2657. package/payload/premium-plugins/writer-craft/mcp/dist/lib/neo4j.d.ts.map +1 -0
  2658. package/payload/premium-plugins/writer-craft/mcp/dist/lib/neo4j.js +47 -0
  2659. package/payload/premium-plugins/writer-craft/mcp/dist/lib/neo4j.js.map +1 -0
  2660. package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.d.ts +117 -0
  2661. package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.d.ts.map +1 -0
  2662. package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.js +138 -0
  2663. package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.js.map +1 -0
  2664. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.d.ts +90 -0
  2665. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.d.ts.map +1 -0
  2666. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.js +609 -0
  2667. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.js.map +1 -0
  2668. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.d.ts +19 -0
  2669. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.d.ts.map +1 -0
  2670. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.js +124 -0
  2671. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.js.map +1 -0
  2672. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.d.ts +38 -0
  2673. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.d.ts.map +1 -0
  2674. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.js +93 -0
  2675. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.js.map +1 -0
  2676. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts +61 -0
  2677. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts.map +1 -0
  2678. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js +171 -0
  2679. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js.map +1 -0
  2680. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.d.ts +35 -0
  2681. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.d.ts.map +1 -0
  2682. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.js +127 -0
  2683. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.js.map +1 -0
  2684. package/payload/premium-plugins/writer-craft/mcp/package-lock.json +1327 -0
  2685. package/payload/premium-plugins/writer-craft/mcp/package.json +19 -0
  2686. package/payload/premium-plugins/writer-craft/mcp/scripts/smoke.mjs +420 -0
  2687. package/payload/premium-plugins/writer-craft/mcp/src/index.ts +457 -0
  2688. package/payload/premium-plugins/writer-craft/mcp/src/lib/neo4j.ts +56 -0
  2689. package/payload/premium-plugins/writer-craft/mcp/src/lib/voice-corpus.ts +154 -0
  2690. package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-distil-profile.ts +833 -0
  2691. package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-ingest-session-text.ts +153 -0
  2692. package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-record-feedback.ts +148 -0
  2693. package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-retrieve-conditioning.ts +270 -0
  2694. package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-tag-content.ts +181 -0
  2695. package/payload/premium-plugins/writer-craft/mcp/tsconfig.json +8 -0
  2696. package/payload/premium-plugins/writer-craft/skills/citation-style/SKILL.md +94 -0
  2697. package/payload/premium-plugins/writer-craft/skills/citation-style/references/book-and-chapter-models.md +77 -0
  2698. package/payload/premium-plugins/writer-craft/skills/citation-style/references/citation-rules.md +103 -0
  2699. package/payload/premium-plugins/writer-craft/skills/citation-style/references/journal-article-models.md +74 -0
  2700. package/payload/premium-plugins/writer-craft/skills/citation-style/references/other-source-models.md +146 -0
  2701. package/payload/premium-plugins/writer-craft/skills/citation-style/references/reference-list-rules.md +70 -0
  2702. package/payload/premium-plugins/writer-craft/skills/editorial-practice/SKILL.md +108 -0
  2703. package/payload/premium-plugins/writer-craft/skills/editorial-practice/references/copyediting.md +73 -0
  2704. package/payload/premium-plugins/writer-craft/skills/editorial-practice/references/developmental-editing.md +85 -0
  2705. package/payload/premium-plugins/writer-craft/skills/editorial-practice/references/genre-specific-editing.md +78 -0
  2706. package/payload/premium-plugins/writer-craft/skills/editorial-practice/references/line-editing.md +55 -0
  2707. package/payload/premium-plugins/writer-craft/skills/editorial-practice/references/self-editing.md +89 -0
  2708. package/payload/premium-plugins/writer-craft/skills/persuasive-storytelling/SKILL.md +114 -0
  2709. package/payload/premium-plugins/writer-craft/skills/persuasive-storytelling/references/audience-analysis.md +73 -0
  2710. package/payload/premium-plugins/writer-craft/skills/persuasive-storytelling/references/crafting-persuasive-story.md +76 -0
  2711. package/payload/premium-plugins/writer-craft/skills/persuasive-storytelling/references/persuasion-case-studies.md +67 -0
  2712. package/payload/premium-plugins/writer-craft/skills/persuasive-storytelling/references/transformation-framework.md +86 -0
  2713. package/payload/premium-plugins/writer-craft/skills/point-of-view/SKILL.md +97 -0
  2714. package/payload/premium-plugins/writer-craft/skills/point-of-view/references/indirect-narration.md +72 -0
  2715. package/payload/premium-plugins/writer-craft/skills/point-of-view/references/pov-types-and-voice.md +91 -0
  2716. package/payload/premium-plugins/writer-craft/skills/point-of-view/references/protagonist-filter.md +71 -0
  2717. package/payload/premium-plugins/writer-craft/skills/point-of-view/references/tense-and-person.md +85 -0
  2718. package/payload/premium-plugins/writer-craft/skills/prose-craft/SKILL.md +100 -0
  2719. package/payload/premium-plugins/writer-craft/skills/prose-craft/references/punctuation-and-grammar.md +72 -0
  2720. package/payload/premium-plugins/writer-craft/skills/prose-craft/references/repetition.md +71 -0
  2721. package/payload/premium-plugins/writer-craft/skills/prose-craft/references/sound-and-rhythm.md +64 -0
  2722. package/payload/premium-plugins/writer-craft/skills/prose-craft/references/word-economy.md +93 -0
  2723. package/payload/premium-plugins/writer-craft/skills/reader-engagement/SKILL.md +100 -0
  2724. package/payload/premium-plugins/writer-craft/skills/reader-engagement/references/cause-effect-setup-payoff.md +79 -0
  2725. package/payload/premium-plugins/writer-craft/skills/reader-engagement/references/conflict-escalation.md +81 -0
  2726. package/payload/premium-plugins/writer-craft/skills/reader-engagement/references/hooking-readers.md +67 -0
  2727. package/payload/premium-plugins/writer-craft/skills/reader-engagement/references/neurochemistry-of-engagement.md +94 -0
  2728. package/payload/premium-plugins/writer-craft/skills/review-manuscript/SKILL.md +111 -0
  2729. package/payload/premium-plugins/writer-craft/skills/review-manuscript/references/review-manuscript-checklist.md +119 -0
  2730. package/payload/premium-plugins/writer-craft/skills/review-prose/SKILL.md +99 -0
  2731. package/payload/premium-plugins/writer-craft/skills/review-prose/references/prose-review-checklist.md +112 -0
  2732. package/payload/premium-plugins/writer-craft/skills/review-scene/SKILL.md +99 -0
  2733. package/payload/premium-plugins/writer-craft/skills/review-scene/references/scene-analysis-framework.md +95 -0
  2734. package/payload/premium-plugins/writer-craft/skills/story-architecture/SKILL.md +106 -0
  2735. package/payload/premium-plugins/writer-craft/skills/story-architecture/references/blueprinting-and-scene-cards.md +118 -0
  2736. package/payload/premium-plugins/writer-craft/skills/story-architecture/references/inner-issue-and-protagonist-goal.md +66 -0
  2737. package/payload/premium-plugins/writer-craft/skills/story-architecture/references/misbelief-desire-worldview.md +87 -0
  2738. package/payload/premium-plugins/writer-craft/skills/story-architecture/references/origin-scenes-and-escalation.md +82 -0
  2739. package/payload/premium-plugins/writer-craft/skills/story-blueprint/SKILL.md +133 -0
  2740. package/payload/premium-plugins/writer-craft/skills/story-blueprint/references/blueprinting-exercises.md +118 -0
  2741. package/payload/premium-plugins/writer-craft/skills/story-blueprint/references/blueprinting-process.md +128 -0
  2742. package/payload/premium-plugins/writer-craft/skills/voice-mirror/SKILL.md +241 -0
  2743. package/payload/server/adminuser-self-heal-LC7HZAC6.js +54 -0
  2744. package/payload/server/chunk-NE7G5GT7.js +5807 -0
  2745. package/payload/server/chunk-PFF6I7KP.js +31 -0
  2746. package/payload/server/maxy-edge.js +832 -0
  2747. package/payload/server/package.json +11 -0
  2748. package/payload/server/power-health.cjs +129 -0
  2749. package/payload/server/public/assets/AdminLoginScreens-CHTeh_Vu.js +1 -0
  2750. package/payload/server/public/assets/AdminLoginScreens-CWMpccrR.css +1 -0
  2751. package/payload/server/public/assets/AdminShell-DjoP7YoA.js +1 -0
  2752. package/payload/server/public/assets/Checkbox-D58GsKoQ.js +1 -0
  2753. package/payload/server/public/assets/OperatorConversations-CDdp2nVn.css +1 -0
  2754. package/payload/server/public/assets/OperatorConversations-RmqANYz8.js +9 -0
  2755. package/payload/server/public/assets/_baseFor-DVaNaTfF.js +1 -0
  2756. package/payload/server/public/assets/admin-LGICBqil.js +1 -0
  2757. package/payload/server/public/assets/admin-types-CJrGd46U.js +1 -0
  2758. package/payload/server/public/assets/arc-CxLB9WCE.js +1 -0
  2759. package/payload/server/public/assets/architecture-YZFGNWBL-DN-MYxff.js +1 -0
  2760. package/payload/server/public/assets/architectureDiagram-Q4EWVU46-D-EdJPSY.js +36 -0
  2761. package/payload/server/public/assets/array-8_H1156C.js +1 -0
  2762. package/payload/server/public/assets/blockDiagram-DXYQGD6D-CXx9RgCm.js +132 -0
  2763. package/payload/server/public/assets/browser-CRgweVtw.js +1 -0
  2764. package/payload/server/public/assets/c4Diagram-AHTNJAMY-RFBXEe0B.js +10 -0
  2765. package/payload/server/public/assets/channel-y27xl53N.js +1 -0
  2766. package/payload/server/public/assets/chat-CXPRTVW7.js +1 -0
  2767. package/payload/server/public/assets/chunk-2KRD3SAO-DBqAFwK9.js +1 -0
  2768. package/payload/server/public/assets/chunk-336JU56O-DdnFEz6R.js +2 -0
  2769. package/payload/server/public/assets/chunk-426QAEUC-D8Iwaegm.js +1 -0
  2770. package/payload/server/public/assets/chunk-4BX2VUAB-cnw-3Gbs.js +1 -0
  2771. package/payload/server/public/assets/chunk-4TB4RGXK-BnqJ0bDc.js +206 -0
  2772. package/payload/server/public/assets/chunk-55IACEB6-BwyHvvzo.js +1 -0
  2773. package/payload/server/public/assets/chunk-5FUZZQ4R-DXA9U02I.js +62 -0
  2774. package/payload/server/public/assets/chunk-5PVQY5BW-D78bZ_8D.js +2 -0
  2775. package/payload/server/public/assets/chunk-67CJDMHE-CtE_Mgv7.js +1 -0
  2776. package/payload/server/public/assets/chunk-7N4EOEYR-CUZDaySl.js +1 -0
  2777. package/payload/server/public/assets/chunk-AA7GKIK3-CYQ3jO4X.js +1 -0
  2778. package/payload/server/public/assets/chunk-BSJP7CBP-BbA_HyTR.js +1 -0
  2779. package/payload/server/public/assets/chunk-CIAEETIT-D7_YqRhG.js +1 -0
  2780. package/payload/server/public/assets/chunk-EDXVE4YY-B23LrtSw.js +1 -0
  2781. package/payload/server/public/assets/chunk-ENJZ2VHE-D3fTHYKN.js +10 -0
  2782. package/payload/server/public/assets/chunk-FMBD7UC4-DFAA2tyh.js +15 -0
  2783. package/payload/server/public/assets/chunk-FOC6F5B3-BF4IHvlI.js +1 -0
  2784. package/payload/server/public/assets/chunk-ICPOFSXX-DBUGemHy.js +122 -0
  2785. package/payload/server/public/assets/chunk-K5T4RW27-rMMs08Eh.js +94 -0
  2786. package/payload/server/public/assets/chunk-KGLVRYIC-BD2r8R2G.js +1 -0
  2787. package/payload/server/public/assets/chunk-LIHQZDEY-D4sYTTwM.js +1 -0
  2788. package/payload/server/public/assets/chunk-ORNJ4GCN-CAs_uFzb.js +1 -0
  2789. package/payload/server/public/assets/chunk-OYMX7WX6-Fkp-2ORc.js +231 -0
  2790. package/payload/server/public/assets/chunk-Pqm5yXtL.js +1 -0
  2791. package/payload/server/public/assets/chunk-QZHKN3VN-qHqDpwz3.js +1 -0
  2792. package/payload/server/public/assets/chunk-U2HBQHQK-D_pxZh25.js +70 -0
  2793. package/payload/server/public/assets/chunk-X2U36JSP-CeVmvvRf.js +1 -0
  2794. package/payload/server/public/assets/chunk-XPW4576I-iWP54fKp.js +32 -0
  2795. package/payload/server/public/assets/chunk-YZCP3GAM-CNtbWJNN.js +1 -0
  2796. package/payload/server/public/assets/chunk-ZZ45TVLE-BmlFjU_9.js +1 -0
  2797. package/payload/server/public/assets/classDiagram-6PBFFD2Q-DgVoYWhO.js +1 -0
  2798. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-C0WNP3uN.js +1 -0
  2799. package/payload/server/public/assets/clone-D50F_pvg.js +1 -0
  2800. package/payload/server/public/assets/cormorant-cyrillic-300-normal-CzPHYadL.woff +0 -0
  2801. package/payload/server/public/assets/cormorant-cyrillic-300-normal-DFUoTmrg.woff2 +0 -0
  2802. package/payload/server/public/assets/cormorant-cyrillic-400-normal-C8QS47vb.woff2 +0 -0
  2803. package/payload/server/public/assets/cormorant-cyrillic-400-normal-D3EsxgFc.woff +0 -0
  2804. package/payload/server/public/assets/cormorant-cyrillic-500-normal-B7dJQtg-.woff +0 -0
  2805. package/payload/server/public/assets/cormorant-cyrillic-500-normal-BLlg2W5x.woff2 +0 -0
  2806. package/payload/server/public/assets/cormorant-cyrillic-ext-300-normal-BXl3lXsi.woff2 +0 -0
  2807. package/payload/server/public/assets/cormorant-cyrillic-ext-300-normal-DmxSOTe3.woff +0 -0
  2808. package/payload/server/public/assets/cormorant-cyrillic-ext-400-normal-Bgrpe4p1.woff +0 -0
  2809. package/payload/server/public/assets/cormorant-cyrillic-ext-400-normal-BlcaxZtM.woff2 +0 -0
  2810. package/payload/server/public/assets/cormorant-cyrillic-ext-500-normal-CdQuyvtc.woff +0 -0
  2811. package/payload/server/public/assets/cormorant-cyrillic-ext-500-normal-pZw22qtS.woff2 +0 -0
  2812. package/payload/server/public/assets/cormorant-latin-300-normal-CJ5dfen0.woff2 +0 -0
  2813. package/payload/server/public/assets/cormorant-latin-300-normal-DQZObO_3.woff +0 -0
  2814. package/payload/server/public/assets/cormorant-latin-400-normal-BGH8Vunh.woff2 +0 -0
  2815. package/payload/server/public/assets/cormorant-latin-400-normal-C3_-2Ua-.woff +0 -0
  2816. package/payload/server/public/assets/cormorant-latin-500-normal-Dj3SQ6fR.woff +0 -0
  2817. package/payload/server/public/assets/cormorant-latin-500-normal-EBdSCOD3.woff2 +0 -0
  2818. package/payload/server/public/assets/cormorant-latin-ext-300-normal-CkiUx0UG.woff +0 -0
  2819. package/payload/server/public/assets/cormorant-latin-ext-300-normal-De3D72RL.woff2 +0 -0
  2820. package/payload/server/public/assets/cormorant-latin-ext-400-normal-DuQ88yz3.woff2 +0 -0
  2821. package/payload/server/public/assets/cormorant-latin-ext-400-normal-DuXFa1Dr.woff +0 -0
  2822. package/payload/server/public/assets/cormorant-latin-ext-500-normal-AH9qog1s.woff2 +0 -0
  2823. package/payload/server/public/assets/cormorant-latin-ext-500-normal-DAuUCO41.woff +0 -0
  2824. package/payload/server/public/assets/cormorant-vietnamese-300-normal-BVqIp_mg.woff2 +0 -0
  2825. package/payload/server/public/assets/cormorant-vietnamese-300-normal-CEMS9Pw-.woff +0 -0
  2826. package/payload/server/public/assets/cormorant-vietnamese-400-normal-C-RiYxEf.woff2 +0 -0
  2827. package/payload/server/public/assets/cormorant-vietnamese-400-normal-DmUuA7Y2.woff +0 -0
  2828. package/payload/server/public/assets/cormorant-vietnamese-500-normal-DsPuwQHi.woff2 +0 -0
  2829. package/payload/server/public/assets/cormorant-vietnamese-500-normal-tGBW_mI7.woff +0 -0
  2830. package/payload/server/public/assets/cose-bilkent-S5V4N54A-C7YmF1Pg.js +1 -0
  2831. package/payload/server/public/assets/cytoscape.esm-h10p_6j-.js +321 -0
  2832. package/payload/server/public/assets/dagre-BAmiDDtR.js +1 -0
  2833. package/payload/server/public/assets/dagre-KV5264BT-Ca3ESJhc.js +4 -0
  2834. package/payload/server/public/assets/data-CttrzhfL.js +1 -0
  2835. package/payload/server/public/assets/defaultLocale-pD7tFa1r.js +1 -0
  2836. package/payload/server/public/assets/diagram-5BDNPKRD-BgT1ORf2.js +10 -0
  2837. package/payload/server/public/assets/diagram-G4DWMVQ6-BTaUIiem.js +24 -0
  2838. package/payload/server/public/assets/diagram-MMDJMWI5-Bdb2g6Uo.js +43 -0
  2839. package/payload/server/public/assets/diagram-TYMM5635-CkLGC0zZ.js +24 -0
  2840. package/payload/server/public/assets/dist-Bkbhs3jw.js +1 -0
  2841. package/payload/server/public/assets/dm-sans-latin-400-normal-BwCSEQnW.woff +0 -0
  2842. package/payload/server/public/assets/dm-sans-latin-400-normal-CW0RaeGs.woff2 +0 -0
  2843. package/payload/server/public/assets/dm-sans-latin-500-normal-B9HHJjqV.woff2 +0 -0
  2844. package/payload/server/public/assets/dm-sans-latin-500-normal-Dr3UlScf.woff +0 -0
  2845. package/payload/server/public/assets/dm-sans-latin-ext-400-normal-BjWJ59Pq.woff +0 -0
  2846. package/payload/server/public/assets/dm-sans-latin-ext-400-normal-BtiwyxMk.woff2 +0 -0
  2847. package/payload/server/public/assets/dm-sans-latin-ext-500-normal-BJfUCQsA.woff2 +0 -0
  2848. package/payload/server/public/assets/dm-sans-latin-ext-500-normal-DR84L5F-.woff +0 -0
  2849. package/payload/server/public/assets/erDiagram-SMLLAGMA-D_sj4DMg.js +85 -0
  2850. package/payload/server/public/assets/flatten-E2Sr0FeD.js +1 -0
  2851. package/payload/server/public/assets/flowDiagram-DWJPFMVM-iLERoZTe.js +162 -0
  2852. package/payload/server/public/assets/ganttDiagram-T4ZO3ILL-D60hjMBy.js +292 -0
  2853. package/payload/server/public/assets/gitGraph-7Q5UKJZL-D-L2yzYf.js +1 -0
  2854. package/payload/server/public/assets/gitGraphDiagram-UUTBAWPF-Di0XM6fi.js +106 -0
  2855. package/payload/server/public/assets/graph-CIBba84R.js +51 -0
  2856. package/payload/server/public/assets/graph-labels-Bi0fu8Ns.js +1 -0
  2857. package/payload/server/public/assets/graphlib-C8fUP7uV.js +1 -0
  2858. package/payload/server/public/assets/info-OMHHGYJF-BQn6jndO.js +1 -0
  2859. package/payload/server/public/assets/infoDiagram-42DDH7IO-BwMdbiXg.js +2 -0
  2860. package/payload/server/public/assets/init-CwJ4b81e.js +1 -0
  2861. package/payload/server/public/assets/isEmpty-CLz-UprQ.js +1 -0
  2862. package/payload/server/public/assets/ishikawaDiagram-UXIWVN3A-CwgI4B5Z.js +70 -0
  2863. package/payload/server/public/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
  2864. package/payload/server/public/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
  2865. package/payload/server/public/assets/jetbrains-mono-cyrillic-500-normal-DJqRU3vO.woff +0 -0
  2866. package/payload/server/public/assets/jetbrains-mono-cyrillic-500-normal-DmUKJPL_.woff2 +0 -0
  2867. package/payload/server/public/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
  2868. package/payload/server/public/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
  2869. package/payload/server/public/assets/jetbrains-mono-greek-500-normal-D7SFKleX.woff +0 -0
  2870. package/payload/server/public/assets/jetbrains-mono-greek-500-normal-JpySY46c.woff2 +0 -0
  2871. package/payload/server/public/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
  2872. package/payload/server/public/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  2873. package/payload/server/public/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
  2874. package/payload/server/public/assets/jetbrains-mono-latin-500-normal-CJOVTJB7.woff +0 -0
  2875. package/payload/server/public/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
  2876. package/payload/server/public/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
  2877. package/payload/server/public/assets/jetbrains-mono-latin-ext-500-normal-Cut-4mMH.woff2 +0 -0
  2878. package/payload/server/public/assets/jetbrains-mono-latin-ext-500-normal-ckzbgY84.woff +0 -0
  2879. package/payload/server/public/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
  2880. package/payload/server/public/assets/jetbrains-mono-vietnamese-500-normal-DNRqzVM1.woff +0 -0
  2881. package/payload/server/public/assets/journeyDiagram-VCZTEJTY-CxBu-tze.js +139 -0
  2882. package/payload/server/public/assets/kanban-definition-6JOO6SKY-D2qlheA5.js +89 -0
  2883. package/payload/server/public/assets/katex-DJPjIBAI.js +257 -0
  2884. package/payload/server/public/assets/line-Bdod7uzQ.js +1 -0
  2885. package/payload/server/public/assets/linear-BiVe6QzC.js +1 -0
  2886. package/payload/server/public/assets/mermaid-parser.core-xZN7hC6M.js +4 -0
  2887. package/payload/server/public/assets/mermaid.core-D0IylAac.js +11 -0
  2888. package/payload/server/public/assets/mindmap-definition-QFDTVHPH-J_Szhwf1.js +96 -0
  2889. package/payload/server/public/assets/operator-mwkYv8g5.js +1 -0
  2890. package/payload/server/public/assets/ordinal-5RtyPJVt.js +1 -0
  2891. package/payload/server/public/assets/packet-4T2RLAQJ-DmkQBx4h.js +1 -0
  2892. package/payload/server/public/assets/page-BpxHz1N-.js +30 -0
  2893. package/payload/server/public/assets/path-CK8wrAxY.js +1 -0
  2894. package/payload/server/public/assets/pie-ZZUOXDRM-DDnxYUBm.js +1 -0
  2895. package/payload/server/public/assets/pieDiagram-DEJITSTG-CV5DxUVx.js +30 -0
  2896. package/payload/server/public/assets/preload-helper-Bf_JiD2A.js +1 -0
  2897. package/payload/server/public/assets/public-CiUboUwu.js +1 -0
  2898. package/payload/server/public/assets/quadrantDiagram-34T5L4WZ-BsFMVizF.js +7 -0
  2899. package/payload/server/public/assets/radar-PYXPWWZC-7H4k0ChM.js +1 -0
  2900. package/payload/server/public/assets/reduce-B3Mw_0s1.js +1 -0
  2901. package/payload/server/public/assets/requirementDiagram-MS252O5E-C5eRRvGc.js +84 -0
  2902. package/payload/server/public/assets/rough.esm-Dwml_la6.js +1 -0
  2903. package/payload/server/public/assets/sankeyDiagram-XADWPNL6-CJYv5gpw.js +10 -0
  2904. package/payload/server/public/assets/sequenceDiagram-FGHM5R23-B25563_2.js +157 -0
  2905. package/payload/server/public/assets/src-BKOAoFQc.js +1 -0
  2906. package/payload/server/public/assets/stateDiagram-FHFEXIEX-BLyNJYOA.js +1 -0
  2907. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BSVuxZxz.js +1 -0
  2908. package/payload/server/public/assets/timeline-definition-GMOUNBTQ-D-HgOM6Q.js +120 -0
  2909. package/payload/server/public/assets/treeView-SZITEDCU-BLXWTQtW.js +1 -0
  2910. package/payload/server/public/assets/treemap-W4RFUUIX-DiePDF5d.js +1 -0
  2911. package/payload/server/public/assets/vennDiagram-DHZGUBPP-Cw1JElYp.js +34 -0
  2912. package/payload/server/public/assets/wardley-RL74JXVD-OSUWK5LN.js +1 -0
  2913. package/payload/server/public/assets/wardleyDiagram-NUSXRM2D-BqMWzEko.js +20 -0
  2914. package/payload/server/public/assets/xychartDiagram-5P7HB3ND-DBp71TLT.js +7 -0
  2915. package/payload/server/public/brand/claude.png +0 -0
  2916. package/payload/server/public/brand/maxy-black.png +0 -0
  2917. package/payload/server/public/brand/maxy-monochrome.png +0 -0
  2918. package/payload/server/public/brand/maxy.png +0 -0
  2919. package/payload/server/public/brand/sitedesk-black.png +0 -0
  2920. package/payload/server/public/brand/sitedesk-favicon-180.png +0 -0
  2921. package/payload/server/public/brand/sitedesk-favicon-32.png +0 -0
  2922. package/payload/server/public/brand/sitedesk-favicon-512.png +0 -0
  2923. package/payload/server/public/brand/sitedesk-horizontal-dark.png +0 -0
  2924. package/payload/server/public/brand/sitedesk-horizontal.png +0 -0
  2925. package/payload/server/public/brand/sitedesk-icon.svg +8 -0
  2926. package/payload/server/public/brand/sitedesk-monochrome.png +0 -0
  2927. package/payload/server/public/brand/sitedesk-square.png +0 -0
  2928. package/payload/server/public/brand/sitedesk-stacked.png +0 -0
  2929. package/payload/server/public/brand/sitedesk-white.png +0 -0
  2930. package/payload/server/public/brand/star.png +0 -0
  2931. package/payload/server/public/brand-constants.json +8 -0
  2932. package/payload/server/public/brand-defaults.css +12 -0
  2933. package/payload/server/public/browser.html +17 -0
  2934. package/payload/server/public/chat.html +20 -0
  2935. package/payload/server/public/consent.css +97 -0
  2936. package/payload/server/public/consent.js +259 -0
  2937. package/payload/server/public/data.html +17 -0
  2938. package/payload/server/public/favicon.ico +0 -0
  2939. package/payload/server/public/graph.html +19 -0
  2940. package/payload/server/public/index.html +22 -0
  2941. package/payload/server/public/operator.html +23 -0
  2942. package/payload/server/public/privacy.html +129 -0
  2943. package/payload/server/public/public.html +21 -0
  2944. package/payload/server/public/robots.txt +5 -0
  2945. package/payload/server/public/sw.js +24 -0
  2946. package/payload/server/public/v.js +244 -0
  2947. package/payload/server/public/vnc-popout.html +63 -0
  2948. package/payload/server/public/whatsapp-wallpaper.webp +0 -0
  2949. package/payload/server/server-init-line-stamper.cjs +26 -0
  2950. package/payload/server/server-init.cjs +251 -0
  2951. package/payload/server/server.js +21647 -0
@@ -0,0 +1,4181 @@
1
+ ---
2
+ name: platform-architecture
3
+ description: Use when grounding any documented-surface claim about what SiteDesk ships — plugins, skills, specialists, install/deploy flows, internals. This is the install catalogue, not evidence of what is enabled on the current account. For install state on this account, call `capabilities-here`; for documented surface, cite the `Source:` URL inline.
4
+ content-hash: sha256:b692930990bf9196318b14c82f048bf430dc71d2a018690a3a14f817d4daa876
5
+ brand: sitedesk-code
6
+ product-name: SiteDesk
7
+ ---
8
+
9
+ # SiteDesk platform architecture (catalogue)
10
+
11
+ Invoked by the admin agent directly.
12
+
13
+ This skill is the install catalogue — every surface the platform can ship. It is not evidence of what is installed on the current account. Cite for documented surface. For 'what is installed here' / 'what can you do', call `capabilities-here` and read `account-manage`; do not infer install state from this body.
14
+
15
+ This skill is generated. Its body is the concatenated source markdown for every public SiteDesk docs page, emitted by `docs/scripts/copy-docs.mjs` as `docs/public/llms-full.sitedesk-code.txt` and assembled here by `maxy-code/scripts/assemble-architecture-skill.mjs`. Do not hand-edit — the drift gate in `platform/scripts/check-architecture-skill-no-drift.mjs` will fail CI.
16
+
17
+ When you load this skill to ground a factual claim, cite the `Source:` URL printed above the block you drew from. The URL is the canonical public docs page (https://sitedesk.online); relay it as a markdown link in your reply. Training-data recall is not a permitted source — the body below is.
18
+
19
+ ---
20
+ # SiteDesk Documentation — full corpus
21
+
22
+ Concatenated source markdown for every public SiteDesk docs page. Pages are separated by `---` and labelled with their canonical URL.
23
+
24
+ ---
25
+ # Getting Started
26
+ Source: https://docs.getmaxy.com/getting-started.md
27
+
28
+ # Getting Started with SiteDesk
29
+
30
+ ## What SiteDesk Is
31
+
32
+ SiteDesk is your Operations Manager — an operations layer that runs on a device on your premises. It plays four roles: follows through on your commitments, responds to your customers at any hour, handles your finances (quotes, invoices, chasing), and manages your picture — what's overdue, what's at risk, what needs a decision.
33
+
34
+ You don't adopt a new system. You just talk, and the organisation happens. SiteDesk connects to your services — WhatsApp, Telegram, email, your contacts, your calendar — and acts proactively. It remembers context across conversations and takes action on your behalf.
35
+
36
+ Because SiteDesk runs locally, your data stays in your home. It never passes through someone else's cloud.
37
+
38
+ ## The Two Interfaces
39
+
40
+ **Admin (you)** — accessed at your local address (e.g. `maxy.local:19200`) or remotely via your Cloudflare domain. The admin interface is protected by a PIN. This is where you manage SiteDesk: configure settings, manage contacts, review activity, and have full conversations. The admin agent has access to all your plugins and can take action.
41
+
42
+ **Public (visitors)** — anyone who reaches your public URL gets the public agent. It handles product enquiries, collects prospect details, and answers questions about your business. It cannot read or write your private data.
43
+
44
+ ## Install the Dashboard as an App
45
+
46
+ The admin dashboard and the chat dashboard can be installed as standalone apps, so they open in their own window with their own icon instead of a browser tab. Installing changes nothing about how SiteDesk works — it is the same dashboard, just launched like any other app.
47
+
48
+ **On a phone or tablet:**
49
+
50
+ - **iPhone or iPad (Safari):** open the dashboard, tap the Share button, then **Add to Home Screen**. A SiteDesk icon appears on your home screen; tapping it opens the dashboard full-screen.
51
+ - **Android (Chrome):** open the dashboard, then either tap the **Install** prompt Chrome offers, or open the browser menu and choose **Install app** / **Add to Home screen**.
52
+
53
+ **On a computer (Chrome or Edge):** open the dashboard, then click the **Install** icon at the right of the address bar (or open the browser menu and choose **Install**). The dashboard opens in its own window from then on.
54
+
55
+ The admin dashboard and the chat dashboard install as two separate apps, so you can keep both on your home screen or dock. Each one opens straight to its own screen.
56
+
57
+ ## First Power-On (New Device)
58
+
59
+ If your device has no WiFi configured and no ethernet cable connected, it creates a temporary WiFi network for setup:
60
+
61
+ 1. Power on the device and wait about 60 seconds
62
+ 2. On your phone, look for a WiFi network called **{ProductName}-Setup** (e.g. `SiteDesk-Setup`)
63
+ 3. Connect to that network — a setup page opens automatically
64
+ 4. Select your home WiFi network from the list and enter the password
65
+ 5. The device connects to your WiFi and the temporary network disappears
66
+ 6. Your phone automatically reconnects to your home WiFi
67
+
68
+ After WiFi is configured, open your browser and go to `{hostname}.local:19200` (the setup page shows this address).
69
+
70
+ If you already have ethernet connected, the temporary WiFi network does not appear — go directly to the admin interface.
71
+
72
+ ## First Run
73
+
74
+ When you first open the admin interface:
75
+
76
+ 1. Set your PIN — this protects access to the admin interface
77
+ 2. Connect to Claude — SiteDesk will guide you through connecting to your Claude account
78
+ 3. Enter your PIN to log in
79
+ 4. SiteDesk walks you through onboarding: choosing which plugins to activate, connecting to WiFi (skip if already configured via the setup network above), setting up remote access, and configuring your account
80
+
81
+ This setup is resumable — if you close the browser mid-setup, SiteDesk picks up where you left off next time.
82
+
83
+ After install, a live admin terminal is available inside the Software Update window — your Pi's shell, accessible through the admin UI, for upgrades and any other shell work without needing to SSH.
84
+
85
+ ## How to Use SiteDesk
86
+
87
+ Conversation is the only interface. Type or speak what you need:
88
+
89
+ - "Add John Smith to my contacts, he's a potential client from the conference"
90
+ - "Schedule a call with Sarah for Thursday at 2pm"
91
+ - "What did I last discuss with Tom?"
92
+ - "Send a Telegram message to the team: standup in 10 minutes"
93
+ - "Create a one-pager PDF about our new product launch"
94
+
95
+ SiteDesk understands plain language. You don't need to learn commands or navigate menus.
96
+
97
+ ### Voice Notes
98
+
99
+ When the text field is empty, a microphone button appears in place of the send button. Tap it to record a voice note — speak naturally and tap send when done. SiteDesk transcribes your voice note and responds to what you said, the same as if you had typed it. You can also pause and resume recording, or tap the trash icon to discard and start over.
100
+
101
+ Voice recording requires a secure connection (HTTPS). When accessing SiteDesk over the local network via HTTP, use the tunnel URL for voice notes.
102
+
103
+ You can also drop, paste, or pick an audio file (`.opus`, `.ogg`, `.m4a`, `.mp3`, `.wav`, `.webm`) into the chat composer — for example a voice note forwarded from WhatsApp. The file is transcribed the same way the in-browser recording is, and only the transcript reaches SiteDesk; the audio itself is discarded after transcription. If you type a message and attach an audio file on the same send, both arrive — the transcript follows your typed text.
104
+
105
+ ## What SiteDesk Remembers
106
+
107
+ SiteDesk maintains a memory graph of everything important: contacts, conversations, preferences, relationships, and context. When you tell SiteDesk something, it stores it. When you ask about something later, it retrieves it.
108
+
109
+ You can always tell SiteDesk to remember or forget specific things: "Remember that I prefer morning calls" or "Forget what I said about the Johnson account."
110
+
111
+ ## Reaching Your Data When SiteDesk Is Unavailable
112
+
113
+ If the AI is ever unreachable — network outage, API provider down — you can still access your own data through the **Data** item in the admin header menu. It opens a page with two panels:
114
+
115
+ - **Graph search** — type a keyword to search your knowledge documents, sections, and notes directly in Neo4j. No AI involved.
116
+ - **Files** — browse everything under your install's `data/` folder. Click a folder to open it, a file to download it. Use **Upload** to drop new files into `data/uploads/`.
117
+
118
+ Everything on this page works without calling any AI service. It's there so your data is never locked behind an agent that can't respond.
119
+
120
+ ## Getting Help
121
+
122
+ Ask SiteDesk anything. If you want to know what it can do, just ask: "What can you help me with?" or "How do I set up Telegram?"
123
+
124
+ ---
125
+ # How SiteDesk Works
126
+ Source: https://docs.getmaxy.com/platform.md
127
+
128
+ # How SiteDesk Works
129
+
130
+ ## The Short Version
131
+
132
+ SiteDesk runs on a Raspberry Pi in your home. It uses Claude (Anthropic's AI) as its brain and extends it with plugins — modular capabilities like contacts, Telegram, and memory. Everything stays local: your data, your conversations, your memory graph.
133
+
134
+ ## The Raspberry Pi
135
+
136
+ SiteDesk is a server that lives on your local network. It's always on, always available, and accessible:
137
+
138
+ - **Locally:** `maxy.local:19200` (or the IP address of your Pi)
139
+ - **Remotely:** via your personal domain, routed through a Cloudflare tunnel
140
+
141
+ The Pi runs the web interface, the AI agent, and all the plugin servers. When you send a message, the Pi processes it — not a cloud service.
142
+
143
+ ## The Two Agents
144
+
145
+ SiteDesk runs two agents simultaneously:
146
+
147
+ **Admin agent (you)** — full access to all tools and plugins. This is the agent you interact with at your local or remote URL. It can read and write contacts, send Telegram messages, manage your account, and perform any task you have plugins for. Protected by your PIN. Your admin agent runs through your own Claude Code OAuth session — it never bills the Anthropic API. Authentication and SDK details are documented in the developer doc `.docs/platform.md` admin-agent section.
148
+
149
+ **Public agent (visitors)** — read-only access. Handles enquiries from people who reach your public URL. It can answer questions about your business and collect prospect contact details, but it cannot access your private data or take actions.
150
+
151
+ ## Plugins
152
+
153
+ Everything SiteDesk can do is provided by a plugin. Each plugin is a self-contained package:
154
+
155
+ - Behaviour instructions (how the agent should act)
156
+ - Tools (specific actions the agent can take, exposed via MCP servers)
157
+ - Reference documents (detailed knowledge loaded on demand)
158
+
159
+ **How tools and roles reach the session.** Each `claude` PTY spawn registers every plugin's MCP server and every bundled subagent directory before the operator's first turn — a per-spawn `mcp-config.json` written by the session manager and passed as `--mcp-config` on the PTY argv, plus one `--add-dir` per agents directory. Admin sessions see every plugin and every role; public sessions see only plugins with at least one public-allowlisted tool. The manager refuses to start when a plugin's `PLUGIN.md` declares tools without a matching `mcp:` block (forensic signal: `boot-failed reason=mcp-allowlist-without-server …`). See `internals.md` "Spawn-time MCP and subagent registration" for the full mechanism and `internals.md` "Tool Eagerness" for the separate ToolSearch-vs-eager registration concern.
160
+
161
+ **MCP helper death observability.** `claude` spawns each plugin MCP helper as its own child, so the manager cannot see a helper die. Every spawn-capable plugin therefore wraps its `mcp:` command with `lib/mcp-spawn-tee`, a parent-side node wrapper that is the helper's real parent and observes its true exit code, signal, and lifetime (including SIGKILL / transport crashes). The wrapper tees the helper's stderr to a wrapper-only per-session file `~/.{brand}/logs/mcp-<server>-<sessionId>.log` — never mixed with the admin-server enumeration copy — and emits lifecycle lines keyed `session=<id8> server=<name>`: `[mcp-helper] op=spawn … pid= entry=`, `[mcp-helper] op=boot … head=<first stderr bytes>`, and `[mcp-helper] op=exit … code= signal= lifetimeMs= stderr-tail=` on every exit (including a clean one). Lines are written synchronously to the per-session file and best-effort mirrored to `server.log` via the loopback log-ingest route. Diagnose a dead helper by `grep '\[mcp-helper\]' ~/.{brand}/logs/server.log` filtered by `session=<id8>`, then read the per-session file for its last output. Both spawn paths are wrapped: the manager's per-spawn `.mcp.json` and the generated `.claude-plugin/plugin.json` manifests that channel sessions take helpers from — the manifest generator copies the tee into each `mcp-manifest: auto` plugin at `lib/mcp-spawn-tee/index.js`, because the plugin-install cache snapshot severs `${PLATFORM_ROOT}`-relative paths, and a missing tee dist at generation time is FATAL. Full contract and diagnostic path in [`.docs/mcp-helper-observability.md`](../../../.docs/mcp-helper-observability.md). The alive-but-wedged case (no process exit) is the deferred `[mcp-helper-census]` reconciler.
162
+
163
+ **Where premium bundle subs live.** Bundle subs (`loop`, `property-data`, `brochures`, etc. inside `real-agent`) live exclusively at `premium-plugins/<bundle>/plugins/<sub>/` and are registered via the resolver's bundle-descent walk. Standalone premiums (no `BUNDLE.md`, e.g. `writer-craft`, `teaching`, `venture-studio`) live exclusively at `premium-plugins/<name>/` and are registered via the resolver's dual-root scan (`platform/plugins/` and `premium-plugins/` are both `pluginsRoots`). Neither shape is flat-copied into `platform/plugins/<name>/`. A divergent flat copy of a bundle sub is treated as an operator override: the resolver refuses to boot with `boot-failed reason=mcp-plugin-duplicate <plugin> declared by more than one plugins root: <pathA> (sha=…) vs <pathB> (sha=…)` so the operator can `sha256sum` both paths and remove the stale one. Byte-identical bundle-sub flat copies left over from installer versions that flat-copied bundle subs are reaped on the first post-upgrade boot (`[premium-auto-deliver] reaped sub=<name> reason=duplicate-of-premium-tree`). Standalone flat copies (leaked by the pre-fix `autoDeliverPremiumPlugins` standalone branch) are reaped unconditionally — there is no documented override path for standalones at `platform/plugins/<name>/` — and the reaper logs `[premium-auto-deliver] reaped standalone=<name> matches-source=<true|false>` so divergent reaps leave a forensic trail.
164
+
165
+ Plugins are installed and managed through conversation. You can add marketplace plugins (like Stripe) or use SiteDesk's built-in ones (contacts, memory, Telegram).
166
+
167
+ ## Roles
168
+
169
+ SiteDesk ships thirteen roles it can dispatch for specific tasks — like members of your team. You don't need to configure or manage them — SiteDesk decides when to use each role and handles everything automatically. You may see activity like "Dispatching personal-assistant..." in the chat timeline when this happens.
170
+
171
+ The catalogue below is what the platform ships. It is not evidence of what is installed on the current account. For the live install set on this account, ask SiteDesk to call `capabilities-here`.
172
+
173
+ | Role | What it does |
174
+ |------|-------------|
175
+ | Archive Ingest Operator | Ingests bulk external archives — Obsidian, ICS, X, Notion — and surfaces schema-mapping ambiguity rather than catching all unmapped relations as :MENTIONS. |
176
+ | Citation Auditor | Audits :TimelineEvent rows for missing citations and writes either citations directly or a CitationProposal stub. |
177
+ | Coding Assistant | Runs shell commands, drives git repositories, and reads or edits code on your behalf — the specialist you reach for when the work belongs in a developer terminal. |
178
+ | Compiled Truth Rewriter | Recomputes a node's compiledTruth (and public twin where applicable) from its 90-day timeline plus optional operator hints. |
179
+ | Content Producer | Produces visual output from your graph: generates images, renders pages to PDF, and hosts static websites you upload as a zip. |
180
+ | Data Manager | Keeps the account data directory organised consistently with the graph ontology, pairing every file move with a database-operator reference update. |
181
+ | Database Operator | Executes graph writes on admin's behalf when delegated via the Task tool — admin names each write, the specialist runs it. |
182
+ | Librarian | Owns foreground ingest of documents, conversation transcripts, and external archives into the memory graph. |
183
+ | Personal Assistant | Handles the operational tasks you'd give a personal assistant: scheduling meetings, managing your platform settings, connecting messaging channels, and completing browser-based tasks on your behalf. |
184
+ | Project Manager | Manages your tasks, projects, sessions, and workflows: linking work to people and goals, and keeping everything organised. |
185
+ | Public Session Reviewer | Reads a gated public-agent transcript and dispatches database-operator for each per-visitor memory write. |
186
+ | Research Assistant | Researches topics online, manages your knowledge graph, and produces supporting visuals. |
187
+ | Typed Edge Classifier | Reads recently-written prose nodes and writes typed edges from a closed allowlist. |
188
+
189
+ Roles are installed during setup and listed when SiteDesk introduces itself. Some premium bundles add their own specialists (e.g. the `real-agent` bundle adds a listing curator, negotiator, valuer, compliance officer, and buyer-enquiry public agent). Roles installed mid-session become active from the next session.
190
+
191
+ ## Memory
192
+
193
+ SiteDesk maintains a graph database (Neo4j) of everything you've told it. People, conversations, preferences, and context are stored as connected nodes. When you ask SiteDesk something, it searches this graph to retrieve relevant context before responding.
194
+
195
+ **The recording loop.** SiteDesk dispatches `database-operator` inline at its own discretion when a write must complete before the assistant response ends. The full graph-completeness sweep runs on demand: when you invoke the `/insight` admin skill, it runs a four-pass instruction and SiteDesk walks the session for any node, edge, or commitment that was discussed but not written in-flight, dispatches one `database-operator` Task per candidate write, then carries on in the same session.
196
+
197
+ The memory graph is stored on your Pi. It never leaves your network.
198
+
199
+ The graph view (at `/graph`) lets you explore the memory directly. Pick a category from the filter, then type to search inside it — typing makes the canvas narrower, not wider. Drag the slider to control how many matches you see (1 to 2000). If the search shows a yellow banner saying "Vector ranking unavailable," it means the local AI ranking model is offline; results are still returned using keyword match, but ordering is less semantic until the ranker recovers.
200
+
201
+ ## The Web Interface
202
+
203
+ The web app runs on your Pi on port 19200. A small always-on front door (`maxy-edge`) owns that port. The edge also hosts the `/api/admin/version` route so the HeaderMenu version display keeps reading even during a mid-restart of the brand service. Login cookies are HMAC-signed with a shared key on disk, so both processes recognise the same session without any coordination and you do not have to log in again after an update. Every request is also classified as LAN or external based on the network shape it arrived on — LAN browsers reach admin directly; the remote password screen only appears on the tunnel-exposed admin domain. It provides:
204
+
205
+ - **Admin chat** (at `/`) — your primary interface, PIN-protected
206
+ - **Public chat** (at `/{agent-name}`) — visitor-facing agents, each with their own URL. On public hostnames, the root path serves the default agent.
207
+ - **Telegram bot landing** (at `/bot`)
208
+
209
+ There is no dashboard, no settings panel, no menus. Everything is done through conversation.
210
+
211
+ The chat input auto-grows as you type — it expands to fit your message and shrinks back when you delete text. You can also drag the resize handle above the input to set a custom height.
212
+
213
+ The admin interface is a three-pane layout: a sidebar on the left with navigation (Sessions, People, Agents, Projects, Tasks, Artefacts) and your recent conversations; the chat in the middle; and an artefact pane on the right that opens when you select a document, click a project, or open Browser, Data, or Graph from the menu, holding the surface side-by-side with the conversation so the chat stays live while you work in it. At the very top of the sidebar — above the nav rows — a borderless row holds two controls: a "+ New session" button on the left that spawns a fresh Claude Code session, and a Mode trigger on the right showing the current permission mode (Ask, Accept edits, Plan, or Auto). The sidebar's vertical order is: new-session strip first, then the nav (Sessions, People, Agents, Projects, Tasks, Artefacts), then the sessions list, then the footer. Both controls render as plain text-plus-icon affordances with no surrounding rectangle. The "+ New session" button is a text-width hit target — its clickable area is exactly the icon plus label, not the whole row — and shows no hover fill; the only hover feedback is the pointer cursor. The Mode trigger is pushed flush to the right edge of the row. Clicking the Mode trigger opens a popover downward from the row whose header reads "Mode" and lists the four permission modes with the current selection check-marked. The sidebar's nav rows swap the list view in place: Sessions shows recent conversations, Projects shows your active work projects, and Artefacts lists every KnowledgeDocument plus this account's agent templates (your admin agent's IDENTITY, SOUL, and KNOWLEDGE files plus one entry per enabled specialist). Each recent session row carries a three-state indicator: three pulsing dots when the session is busy (currently processing a turn), a solid sage dot when it is idle (live PTY waiting for input), and a hollow ring when it is archived (PTY exited, JSONL on disk for audit). The list itself splits into three views via a segmented control above the rows: **Active** shows every live session, **Archived** shows every JSONL on disk whose PTY has exited, and **All** shows both. The view choice persists across reloads. An "Include subagents" toggle inside the Active view surfaces specialist spawns (database-operator, premium-plugin agents, anything spawned with a `--agent` flag) which are hidden by default so the list reflects what you started directly. Each row also carries a small uppercase badge — `admin` for operator-driven sessions, the specialist name (for example `db-op`) for background work — so the source of any row is unambiguous at a glance. The People, Agents, and Tasks rows are graph shortcuts: clicking each opens the artefact-pane Graph filtered to every Person, every public Agent, or every Task in your account respectively, with no side-list, because the graph itself is the result. Public agents become first-class graph entities the moment you create them, with edges to their IDENTITY/SOUL/KNOWLEDGE files, edges to every knowledge document they have access to, and edges from every conversation they have handled, so a single Agents click reveals the whole shape of who knows what and who has been talking to whom. Click an artefact row to open the document. KnowledgeDocuments and your admin agent's templates are editable: type in the document and changes save automatically; specialist agent templates are read-only because they ship with SiteDesk and your edits would be overwritten on the next install. PDF artefacts render inline so you can read them without leaving the pane. If your browser doesn't have a built-in PDF viewer, a Download button appears instead. Artefacts that have no readable file backing them (orphan rows, files removed from disk, unsupported content types) show a one-line banner explaining the skip instead of opening to a blank pane. Click a project row to open the Graph view focused on that project's neighbourhood; clicking a second project swaps the focus rather than stacking on top. The sidebar's right edge is drag-resizable on every shell-hosted admin page (Sessions root, Chat, Graph, Browser, and Data): drag the handle to widen or narrow the sidebar, and your chosen width is remembered across reloads and shared across all of them. AdminShell mounts the drag handle itself, so every route that wraps its content in `<AdminShell>` gets sidebar resize for free; the handle does not render in the mobile drawer. The chat and artefact divider is also drag-resizable: drag the line between the columns to make either side wider; double-click it to reset to half of the available width (viewport minus sidebar), clamped to the chat and artefact min-width floors. Your chosen width is remembered across reloads. On wider screens (>1280px) all three panes are visible. The sidebar narrows at 1280px, the artefact pane hides at 1080px (Browser, Data, and Graph then open as full-window pages instead), and the sidebar collapses to a 56px icon rail at 820px. On every viewport the chat header reads left to right as a triptych: a dedicated sidebar toggle (the panel-right icon, which swaps to panel-right-open when the sidebar is showing), the brand mark next to the title in the centre, and the menu burger on the right. This header toggle is the sole sidebar-toggle button; the sidebar itself no longer carries a duplicate. The burger opens the navigation flyout: Dashboard, Data, Graph, Browser, and Chat at the top — Dashboard routes back to `/`, so every satellite page keeps a one-click way home, and the Chat item carries the Claude mark rather than a generic icon — then Public (the agents list) between the two dividers, and below the second divider the version row, Disconnect Claude, and Log out. Tap the sidebar toggle to show or hide the sidebar: on phones (<720px) it slides the drawer in or out, on wider screens it collapses or expands the sidebar column. The brand mark in the centre is decorative; clicks go through the dedicated toggle so the affordance is unambiguous. The drawer animation only fires on tap (220ms slide in or out); resizing your window across the 720px boundary snaps the layout without animation, so you never see a half-open flash. At ≤640px the session metadata pane stacks each label above its value instead of the desktop two-column grid, and the row of action buttons (Open in new tab / Download JSONL / View JSONL / Rename / Pin / Archive / End or Purge) collapses behind a single Actions trigger that opens a popover upward from the foot of the pane. Breakpoint summary: >1280px = full sidebar + chat + artefact pane (drag-resizable divider); 1280px→1080px = sidebar narrows; 1080px→820px = artefact pane hides (Browser/Data/Graph open as full-window pages instead); 820px→720px = sidebar collapses to 56px icon rail; ≤720px = sidebar becomes off-canvas drawer (vertical stack of nav, recents list, foot, the same shape as the desktop sidebar, just on top of the chat instead of beside it).
214
+
215
+ Page titles are brand-aware: the browser tab shows your product name (e.g. `Real Agent` instead of `SiteDesk`) on every shell — chat, graph, and data — so a non-default brand never leaks the default name in tab strips or browser history.
216
+
217
+ **Session lifecycle and reconcile model.** The sidebar Sessions list is driven by a single Server-Sent Events feed at `/api/admin/claude-sessions/events`. The session manager watches the two directories Claude Code writes (`${CLAUDE_CONFIG_DIR}/sessions/<pid>.json` for live state, `${CLAUDE_CONFIG_DIR}/projects/<slug>/<sid>.jsonl` for transcripts) and emits `row-created`, `row-updated`, `row-archived`, or `row-removed` deltas to every connected browser tab. Three real delete shapes map to deltas — there is no fourth: PID file gone with JSONL surviving demotes the row to `row-archived`; PID file gone with no JSONL ever written (a hidden spawn that exits before writing a JSONL) emits `row-removed` against the unindexed sessionId; a JSONL deletion against an already-unindexed row also emits `row-removed`. This branch reconciles transient hidden spawns — without it, ghost rows persist after a hidden spawn exits. On connect the manager replays the current row index so a freshly-opened tab catches up without polling, then streams deltas as files change on disk. Two open tabs see the same list within ~300ms of any spawn, status flip, or exit; no refresh button required for state to be current. The legacy `/list` fetch and `useAdminSessions` hook stay mounted to serve the ConversationsModal and the post-action reconcile path in `session-actions`, but the sidebar's visible rows come from the row store, not from `/list`. Each EventSource open emits `[admin-events] client-connected ip=<…> seeded-rows=<n>` server-side and `[admin-ui] session-row-store connected events-received=<n>` in the browser console; transport drops log `[admin-ui] session-row-store reconnect trigger=<auto|manual> attempt=<n> delay-ms=<n>` until the EventSource reattaches. The small dot at the right edge of the Active/Archived/All segmented control is the live-updates indicator: sage when the SSE feed is connected, grey when the feed has dropped. The grey state is an actionable button — clicking it cancels any pending backoff and re-opens the feed immediately, with the click logged as `trigger=manual` so manual retries are distinguishable from automatic ones in the console. The refresh icon at the top of the Sessions list is the operator-recoverable reconcile path against any SSE gap: it fetches `/api/admin/claude-sessions` and passes the authoritative id set to the row store, which evicts any indexed row that the server no longer reports. SSE replay only re-asserts currently-indexed rows and never emits `row-removed` for a row that vanished while disconnected, so without this manual surface a stale row can persist until the operator reloads the tab. Each click logs `[admin-ui] session-row-store reconcile evicted=<n> kept=<n>` when at least one row is evicted, and is silent otherwise.
218
+
219
+ The row feed sits behind `requireAdminSession` like every other admin route, so the URL must carry `?session_key=<cacheKey>` — `EventSource` cannot send custom headers, so the query string is the only viable transport. Every admin URL (fetch and EventSource alike) routes through the shared `appendAdminSessionKey(url, cacheKey)` helper exported from `app/lib/useAdminFetch.ts`, which is the single source of truth for the convention; no caller constructs the query string by hand. On a 4xx rejection the browser-side store probes the same URL once per reconnect (suppressed after a successful `open`, capped at one fetch per attempt) and logs `[admin-ui] session-row-store sse-error status=<n> code=<code> attempt=<n>`. The `code` field uses the closed `AdminSessionRejectCode` taxonomy (`session-missing | session-not-registered | session-expired-age | grant-expired`, plus a default `unknown` bucket) that mirrors the server-side rejection emitted by `requireAdminSession`, so a single grep correlates client and server timelines on the same code.
220
+
221
+ The trade-off is a longer-lived connection per tab: the manager's per-process subscriber count rises with open tabs, and the SSE channel must survive proxy idle timeouts. The manager emits a 25-second keep-alive comment line on every connection (ignored by EventSource consumers, refreshes the proxy clock) and the browser-side store force-closes-and-reconnects on transport errors with exponential backoff capped at 30s.
222
+
223
+ The row payload carries `url: string | null` — the `claude.ai/code/session_<suffix>` URL captured from the `/remote-control` banner. **Disk is the only source of truth.** Spawn metadata that previously lived in an in-memory `SessionStore` (senderId, role, channel, url, startedAt, permissionMode, model, hidden, specialist) now rides a sidecar file alongside the JSONL: `<projectsDir>/<sessionId>.meta.json`. The watcher reads the sidecar at row-build time and stamps the nine fields onto the `SessionRow`; the serialiser reads `row.url` directly with no in-memory side channel. The value is `null` whenever the spawn is headless (`HEADLESS_ROLES` — `--remote-control` not passed), or before url-capture has fired on a channel-facing spawn (~2 s after spawn), or on rows whose JSONL+sidecar pair was archived before the banner landed. When url-capture eventually fires, `pty-spawner` writes the URL to the sidecar via `updateSidecar`, calls `watcher.refreshSidecar(sessionId)` to refresh the row index, and the manager pushes a `row-updated` SSE frame carrying the fresh URL — the client's Open-in-new-tab arrow appears in step. The Sidebar gates the arrow on `row.live && row.url !== null` and opens `row.url` directly with no `/meta` round-trip; each click logs `[admin-ui] sidebar-open-in-new-tab outcome=<ok|blocked> sessionId=<8-char>` (`blocked` fires when a popup blocker swallows `window.open`).
224
+
225
+ **Manager state shape.** The manager keeps exactly two pieces of in-process state — the live `PtyHandle` map (in `pty-spawner.ts`, keyed on sessionId, holding the file descriptor and runtime flags that cannot go on disk) and the watcher's row index (rebuilt from disk on each event). Everything else lives on disk: the JSONL transcript at `<projectsDir>/<sessionId>.jsonl` (live) or `<projectsDir>/archive/<sessionId>.jsonl` (archived), the sidecar at the matching path with `.meta.json`, and the PID file at `${CLAUDE_CONFIG_DIR}/sessions/<pid>.json`. A manager restart re-reads the sidecars at boot so every row that had one before the restart re-enters the in-memory index with full senderId/role/channel populated. Archived JSONLs created before the sidecar writer existed index normally but with seven null sidecar fields. The watcher enumerates BOTH the top-level projects dir AND its `archive/` subdir, watches both with `fs.watch`, and coalesces a top↔archive rename into one `row-updated` event (no `row-removed` followed by `row-created` — the rename is one logical state change keyed on sessionId). The sidebar surface that consumes this index is `/api/admin/sidebar-sessions`, not the legacy session-manager `/list` route, which has been removed.
226
+
227
+ **Spawn lifecycle: PID-file driven.** Clicking "+ New session" opens the `NewSessionModal`. Modal submit POSTs to the wrapper with the operator's typed text as `initialMessage`, plus per-session `permissionMode` and `model` overrides; only then does the PTY spawn. The manager waits for Claude Code's PID file at `${CLAUDE_CONFIG_DIR}/sessions/<pid>.json`. The PID file lands at process init (for `entrypoint: cli` spawns) and carries the intrinsic `sessionId`, `bridgeSessionId`, `agent`, and `status` directly. The manager's filesystem watcher reports the create event; the spawn response includes the canonical `sessionId` from that file. URL capture still runs in parallel to populate the operator-facing iframe URL, but it no longer gates readiness. The JSONL transcript is written on the first operator turn (true on 2.1.143 and 2.1.128); the watcher fires a separate event for that, and `/list`, `/meta`, `/log` resolve any of four ids — `sessionId`, `bridgeSessionId`, `bridgeSuffix`, or numeric `pid` — to the same row. The JSONL's first `role=user` line equals the operator's typed text byte-for-byte; Claude Code's `tail.aiTitle` is computed from that real content and remains the canonical sidebar row label. The wrapper at `platform/ui/server/routes/admin/claude-sessions.ts` is still the single canonical entry point for any programmatic admin spawn-with-prompt — see `admin-session.md` "Spawn-with-initialMessage wrapper" and `internals.md` "Programmatic spawn entry point". Resume flows are unaffected (the prior transcript is the stimulus).
228
+
229
+ The sidebar row's displayed name is `tail.aiTitle` verbatim, parsed by `jsonl-enumerator.ts` from the JSONL Claude Code writes. Until Claude Code has written its title, the row label is null and the cell renders empty — no UI-stamped sidecar layer, no 8-char id fallback. When Claude Code later updates its title mid-session, the next `/list` or `/events` tick surfaces the new label.
230
+
231
+ Each session row also carries a small muted timestamp crumb under the name showing when the session was last active: "just now", "5m", "3h", "yesterday", a weekday name for 2-6 days back, "20 May" for older dates this year, or "20 May 2025" for prior years. Live rows tick forward on their own without a refresh — every row advances together on a single shared 30-second cadence so two rows with identical names (a fresh session whose `aiTitle` has not landed yet, plus a resumed session whose title also has not landed) are distinguishable at a glance. A row that renders "—" instead of a time is a loud-fail signal: the session manager lost the row's `updatedAt` (the JSONL `mtimeMs` for archived rows, the PID-file `updatedAt`/`startedAt` for live rows). Investigate the server log rather than treating "—" as a normal value. The pure formatter lives at `app/lib/relative-time.ts` and is pinned by `app/lib/__tests__/relative-time.test.ts` (every breakpoint, every '—' input, DST cross 2026-03-29); the shared tick is `app/lib/use-now-tick.ts`; the row-render wiring is pinned by `app/__tests__/Sidebar-timestamp.test.tsx`.
232
+
233
+ **Stop vs. delete.** `POST /<id>/stop` sends SIGTERM, leaves the JSONL on disk for audit, and is idempotent against an already-dead row. `DELETE /<id>` removes the JSONL + per-session subdir and returns 409 if the PTY is still alive (stop first). Any unknown id returns 404; nothing returns a silent 204 against an id the manager does not know.
234
+
235
+ **View JSONL.** Alongside the Download button, the pane carries a **View JSONL** button that opens a full-pane modal streaming the transcript in-app from `GET /<id>/log?follow=1`. The modal is the canonical surface for reading transcripts inside the admin UI — Download remains the export route for offline / external tooling. The viewer renders one row per line, collapsed by default to a role badge plus a 200-char preview; click a row to expand into the pretty-printed JSON, click again to collapse, or click the copy icon to copy the raw line bytes (round-trip integrity preserved — no re-stringify). A search input filters visible rows by case-insensitive substring match against the line's JSON; the stream keeps landing in the backing list regardless of filter state. For live sessions (`status: 'alive'`) the modal tails new lines as they're written; for ended sessions it renders the initial-read flush and then idles. The status pill in the footer reflects the live session status (alive → "streaming", ended → "complete"), not the underlying stream state — keeps the operator's mental model aligned with the pane's other indicators even though the manager's `/log?follow=1` keeps the underlying watcher open until aborted. Malformed lines (`JSON.parse` failure) render inline as a `parse-error` row with the raw text and the failure reason; the stream continues. The backing list caps at 50,000 entries (ring buffer with eldest-drop); past the cap, the header reads "N older dropped" — the cap protects browser memory on multi-day database-operator sessions where the JSONL can grow to tens of thousands of lines. Closing the modal (X button, overlay click, or Escape) aborts the fetch (`AbortController.abort()`) which propagates to the manager's `out.onAbort` and releases the `watchFile` listener. Observability: the manager emits `[claude-session-manager] log-follow-open sessionId=<sid> initialBytes=<n> pid=<n>` when the stream opens (after the initial-read flush) and `log-follow-close sessionId=<sid> reason=aborted linesStreamed=<n> ms=<n>` when it closes — `linesStreamed` counts `\n` bytes written across both initial-read and tail, matching `wc -l`. The browser console mirrors with `[admin-ui] jsonl-viewer-open sessionId=<8> alive=<bool>` on mount and `[admin-ui] jsonl-viewer-close sessionId=<8> reason=unmount linesRendered=<n> ms=<n>` on unmount, plus `[admin-ui] jsonl-viewer parse-error sessionId=<8> lineNumber=<n>` once per malformed line (capped at 100/session to avoid console flood). Auth is unchanged — the existing `requireAdminSession` middleware covers `/log?follow=1` exactly as it already does for `/log?download=1`.
236
+
237
+ **Download JSONL.** `GET /<id>/log?download=1` is a one-shot byte-stream of the session's JSONL transcript with attachment-disposition headers, designed for the pane's **Download JSONL** button. Headers: `Content-Type: application/x-ndjson`, `Content-Disposition: attachment; filename="<sessionId>.jsonl"` (the basename is sanitised so any non-`[A-Za-z0-9._-]` character is replaced with underscore), `Cache-Control: no-store`. Four status branches: **200** with the byte-identical file body; **404** `{error: 'session-not-found'}` when the store has no row for the id; **202** `{pending: true, jsonlPath: null}` when the row exists but claude has not flushed the first turn yet; **404** `{error: 'jsonl-missing-on-disk'}` when the row carries a `jsonlPath` but the file has been removed under the manager (post-Purge race). The download branch is declared **before** the follow check, so `?download=1` always wins over `?follow=1` if both are set. The proxy at `app.get('/:sessionId/log')` rebuilds the upstream query from a fixed `follow|download` allowlist; inbound query keys outside that allowlist are dropped. Observability: `[claude-session-manager] log-download sessionId=<sid> bytes=<n> ms=<n>` lands per successful stream completion; the browser console emits `[admin-ui] pane-download-jsonl sessionId=<8> outcome=initiated` on click. `outcome=initiated` rather than `outcome=ok` is intentional — the handler resolves before the browser writes the bytes, so the log line names "the request was kicked off", not "the file landed". If the file does not appear in the operator's downloads folder, check the manager line for the bytes count and the browser's downloads UI for the suppression record. Auth is unchanged from the rest of the `/api/admin/claude-sessions` surface (cookie session via `requireAdminSession`); there is no new key surface.
238
+
239
+ **Two spawn surfaces, one primitive.** The manager runs two on-device spawn surfaces, both backed by the same primitive: **node-pty wrapped in `systemd-run --user --scope`** (via `index.ts::spawnPtyAdapter`).
240
+
241
+ - **`claude rc` daemon** — spawned at platform boot by `rc-daemon.ts`. One supervised daemon per account; owns the long-lived composer session that backs claude.ai/code Remote Control. Master fd held for the daemon's lifetime, released on natural exit / restart. **Headless consent pre-seed.** Before the first spawn, `ensureRemoteControlConsent` writes `{"remoteControlAtStartup": true}` into `$CLAUDE_CONFIG_DIR/.claude.json` (read-merge-write, atomic tmp+rename, idempotent). Without this, headless `claude rc` hangs at `Enable Remote Control? (y/n)` — nothing answers, the supervisor restarts the child, eventually marks the daemon permanently-failed. The key is the same one `claude` itself writes when the user answers `y` at the prompt; siblings (`teammateMode`, `hasUsedRemoteControl`, claude's auth blocks) are preserved.
242
+ - **`claude --remote-control` on-device sidebar spawn** — spawned per-click by `/rc-spawn` in `http-server.ts`. One PTY per click; the manager holds the master fd **for the session's entire lifetime**. The pty master IS the live session — claude operates on the slave, and closing the master hangs up the slave. Valid master-release points: (1) explicit operator teardown — `/stop` → `stopSession` → `op=archive-release` — and (2) the natural-exit path inside `pty.onExit → handlePtyNaturalExit`.
243
+
244
+ Inside the scope, `sh -c 'trap "" HUP; exec "$@"' sh <claudeBin> <args...>` keeps claude resident across PTY master-close (SIGHUP trap) and preserves the pid through the exec chain. The earlier `script(1)` wrap and the non-PTY scope primitive are gone; node-pty allocates the TTY directly.
245
+
246
+ **`/rc-spawn` lifecycle observability.** Every on-device sidebar resume emits a stream of `[rc-spawn]` lines tagged with the same `unitToken=rc-resume-<uuid>` so one spawn's full lifeline can be reconstructed by `grep` alone. The lines, in order:
247
+
248
+ | Step | Line shape |
249
+ |------|-----------|
250
+ | 1 | `[rc-spawn] op=request unitToken=<t> sessionId=<8|new> name=<…|none> mode=<resume|fresh> jsonl=<path|none>` |
251
+ | 2 | `[rc-spawn] op=argv unitToken=<t> cwd=<dir> argv=<json>` (inner claude argv; the `systemd-run --scope` wrap is composed by the spawnPty adapter) |
252
+ | 3 | `[rc-spawn] op=pty-spawned unitToken=<t> pid=<pid> openFds=<n>` (fd baseline) |
253
+ | 4 | `[rc-spawn] op=child-output unitToken=<t> pid=<pid> head=<json>` (first ≤1 KB or 500 ms idle — claude's own words) |
254
+ | 5 | `[rc-spawn] op=early-exit unitToken=<t> pid=<pid> ranMs=<n> exitCode=<n> signal=<…>` — fires when `pty.onExit` lands before the pid file |
255
+ | 6 | `[rc-spawn] op=pidfile-present unitToken=<t> pid=<pid> path=<sessions/<pid>.json> ageMs=<n> bridgeId=<…>` — **terminal success.** The on-disk PID file IS the evidence; no synchronous liveness inference. The tracker remains in `livePtys` for the session's lifetime. |
256
+ | 7 | `[pty-tracker] op=spawn sessionId=<8> pid=<pid> size=<n>` (also fires for spawnClaudeSession; same line shape on the rc-spawn path) |
257
+ | 8 | `[rc-spawn] op=exit unitToken=<t> pid=<pid> ranMs=<n>` paired with `[pty-tracker] op=exit` from `handlePtyNaturalExit` — fires when claude exits on its own (operator typed `/quit`, SIGINT in the PTY, crash). |
258
+
259
+ **Operator-archive release.** When the operator clicks End in the UI, `/stop` → `stopSession` → `archiveReleaseTracker` emits a single verified release line:
260
+
261
+ `[rc-spawn] op=archive-release sessionId=<8> pid=<pid> master-fd=<closed|close-failed err=…> fdBefore=<n> fdAfter=<n> fdDelta=<n> removedFds=<list|none> trackerRemoved=<bool> verified=<bool>`
262
+
263
+ `verified=true` requires `master-fd=closed` AND `fdDelta>=1` AND `trackerRemoved=true`. `master-fd=close-failed` is logged at error level (`[rc-spawn-error]` prefix) — never swallowed; the next post-archive sweep is the catch-net.
264
+
265
+ **Cross-arm `[rc-life]` schema.** rc-spawn and rc-daemon emit a shared log shape so the populations can be compared from `server.log` alone. One spawn's full lifeline is `grep <unitToken>`; one surface's signature is `grep 'source=rc-spawn'` or `'source=rc-daemon'`. Success on both surfaces is `op=pidfile-present`; failure is `op=spawn-failed` / `op=early-exit` / `op=wait-pid-failed`. Full schema and operator runbook in [`.docs/rc-life-observability.md`](../../../.docs/rc-life-observability.md). **Measured `remoteBound`.** The rc-daemon liveness emit reports `remoteBound` as a measured value flipped by `detectRcHandshake` once the daemon's own post-bind output (`Capacity:` header or an `N of M` capacity line) is seen on the PTY. A daemon that is alive but not registered to Remote Control therefore prints `pidAlive=true remoteBound=false` — previously masked by a hardcoded literal. A class-guard test (`rc-life-literals.test.ts`) scans every `emitRcLife` call across the manager and fails if any status-shaped field is set to a boolean/string literal. The captured PTY output is now dumped on **every** exit (not only fast exits), prefix `exit-output` or `fast-exit-output`, so a late-life prompt-hang is no longer invisible.
266
+
267
+ **Post-archive fd sweep.** Independent of spawn/archive request traffic, the manager runs a 60 s sweep that walks both directions of the master-fd invariant:
268
+
269
+ - `[fd-audit] op=orphan-master sessionId=<8> pid=<n> archivedAt=<ms> heldSinceArchiveMs=<n> fd=<n|unknown>` — fires per tracker whose row is archived (the leak).
270
+ - `[fd-audit] op=orphan-master-escalate sessionId=<8> fd=<n|unknown> heldSinceArchiveMs=<n>` — fires when `heldSinceArchiveMs ≥ 300 000` ms (5 min); strongest leak signal.
271
+ - `[fd-audit] op=post-archive-sweep archivedSessions=<n> orphanMasters=<n> openFds=<n> livePtys=<n>` — once per sweep.
272
+ - `[fd-audit] op=master-reconcile liveTrackers=<n> liveSessions=<n> archivedWithMaster=<n> orphanLiveSessionsNoMaster=<n>` — once per sweep. `archivedWithMaster>0` = fd leak; `orphanLiveSessionsNoMaster>0` = inverse defect (a live session whose master is gone — it cannot operate). Both are alarms.
273
+
274
+ The sweep is the catch-net for `master-fd=close-failed` and any future regression that orphans a tracker after archive. The steady-state `archivedWithMaster=0 orphanLiveSessionsNoMaster=0` is itself the signal the sweep ran.
275
+
276
+ **Manager-shutdown master-audit.** On SIGTERM/SIGINT the manager emits `[manager-shutdown] op=master-audit held=<n> liveSessionsClosed=<n>` after walking `livePtys`. `held` is the count of trackers at shutdown entry; `liveSessionsClosed` is the subset whose master was destroyed by this shutdown. This is the data the out-of-scope "does manager restart kill on-device live sessions?" question is decided by — a logged number, not speculation.
277
+
278
+ `openFdCount()` reads `/proc/self/fd` directly on Linux and returns `-1` on darwin (the dev-Mac path). The fd-leak audit on the laptop: `~/maxy-code/platform/scripts/logs-read.sh --tail server 400 | grep -E '\[fd-audit\]|op=archive-release'`. Full per-spawn lifeline: `grep -E '\[rc-spawn\]|\[pty-tracker\]'` filtered by `unitToken`.
279
+
280
+ **WhatsApp inbound `/input` post-condition + sink-timestamp invariant.** An accepted `/input` returns `200` the moment the PTY write lands, but a `200` is not proof a turn submitted. The manager fires a bounded post-condition poll and logs `op=input-submitted … ackMs=…` (PTY went `busy` or a new JSONL user entry appeared) or `op=input-no-turn … ptyStatus=… lastJsonlEntryAgeMs=…` when the window elapses — so an accepted-but-unsubmitted input is visible in ≈8s, not only at the 300s turn-timeout. On timeout the bridge attributes the cause from the JSONL tail: `op=turn-timeout cause=no-turn` (no completed turn) vs `cause=relay-missed` (an assistant `end_turn` landed but the follower never relayed it); a per-sender `op=inbound-outcome relay-ok=N timeout-no-turn=N timeout-relay-missed=N` tally makes the failure rate one grep. **Sink-timestamp invariant:** every `server.log` line is stamped with a leading ISO timestamp at the stdout/stderr sink of the process that emits it — two sinks, one per process (UI: `server-init.cjs`; manager: `src/install-log-sink.ts`) — because both systemd units append to one `server.log` and `append:` bypasses journald. Never hand-inline a timestamp in a log call. Full lifeline, failure signatures, and diagnostic greps in [`.docs/whatsapp-inbound-lifeline.md`](../../../.docs/whatsapp-inbound-lifeline.md).
281
+
282
+ **PTY lifecycle contract.** A PTY reaches its end via one of two branches: **operator-request** (operator clicks End or the auto-archive Stop hook calls `killSession`) or **natural-exit** (the claude child exits on its own — operator typed `/quit`, SIGINT in the PTY, crash, network drop on `--remote-control`). Both branches honour a single invariant: the pty master file descriptor is released by an explicit `pty.destroy()` and the in-process tracker entry is removed before the next `/list` or `/events` tick. The tracker is a module-scoped `Map<sessionId, PtyTracker>` in `pty-spawner.ts` — the metadata-rich `SessionStore` is gone; the tracker holds only what the file system cannot (PtyHandle + pid + bridge ids + runtime flags). Without the explicit destroy, the master fd lingers in node-pty's internal socket until V8 GC finalises the IPty object — non-deterministic and accumulates under load until the kernel pty cap (Linux 3072, macOS 511) refuses new spawns. Without the explicit row removal, the manager shutdown loop SIGTERMs PIDs that already logged `process-exited`, masking the leak only because the manager restarts every few hours. When both branches fire on the same exit (operator clicks End and node-pty's `onExit` fans out the SIGTERM to both listeners), a per-row `fdReleased` flag short-circuits the second branch so `pty.destroy()` runs exactly once on the live socket — without the flag, the second call throws "socket already destroyed" and the operator-request line would falsely log `master-fd=close-failed`. If the first branch's destroy throws and is rescued, the flag stays unset and the second branch retries (defense in depth). Every `kill … pid=<n>` log line carries a `master-fd=closed` suffix (or `master-fd=close-failed err=<msg>` on the rescued throw branch — a graceful degradation so a corner-case socket-state failure cannot turn a logically-successful exit into a 500); the operator-request line additionally identifies `reason=operator-request`, the natural-exit line identifies `reason=process-exited`. Both branches are verified by the `stop-session-fd-release` and `endpoint-stop-delete` integration tests (operator-request live and already-exited cycles + natural-exit cycle + throw-then-retry coordination, Linux kernel-level ptmx fd accounting on each).
283
+
284
+ The metadata pane subscribes to the same /list projection. When an operator clicks End on an alive row, the DELETE returns 200 and the post-mutation refetch decides what happens next: a session that wrote a JSONL surfaces as a dehydrated `status: 'ended'` row (the pane swaps `End session` for `Purge JSONL` plus `Resume`), and a session that never wrote a JSONL (`Turns: 0`) leaves the list entirely (the pane shows a `Session ended without a transcript. Close this pane.` banner with a Close button and no destructive action). The manager's `/list` and `/meta` are the only authorities on post-End state; the client does not pre-empt either response with an optimistic mutation.
285
+
286
+ **Admin URL hygiene: `?sessionId=<id>` is retained only while `/meta` returns 200.** The shell hydrates `selectedSessionId` from the query-string on mount so a banner-click redirect can re-open a session. The first `/meta 404` (the session has been deleted out from under the slug) strips the query-string via `history.replaceState`, clears the selection, and emits `[admin-ui] stale-session-slug-stripped sessionId=<8-prefix> trigger=meta-404`. A reload from the dead URL therefore starts at base instead of re-resolving a 404.
287
+
288
+ The Data search panel ranks results by combining vector similarity with keyword (BM25) matching. Each row shows a one-line score breakdown — `vector 0.NN · bm25 0.NN · combined 0.NN` — so you can tell whether a row surfaced because of meaning, exact-keyword match, or both. A bm25 column of `0.00` across every row means your search term wasn't in the keyword index, so ranking fell back to pure vector similarity (this can produce surprising results — the breakdown tells you when to interpret with caution). Above the result list, a chip row shows the unique types in your current results — click one to filter, click again to clear. Click any row to jump straight to that node's neighbourhood in the Graph; from the artefact pane the graph opens alongside chat, from the standalone Data page it opens in place.
289
+
290
+ ## Software Update and Cloudflare Setup
291
+
292
+ Both flows run on the native Claude Code PTY surface in admin chat. There is no in-app upgrade modal and no Cloudflare setup form — the agent invokes the relevant Bash command directly and its stdout streams into chat verbatim.
293
+
294
+ - **Software update.** Re-run the installer (`npx -y @rubytech/create-<brand>@latest`) from a shell; HeaderMenu's version row turns sage when `installed === latest`.
295
+ - **Cloudflare setup.** Operator asks in chat; the agent invokes `cloudflared` directly via the Bash tool, following the numbered steps in `plugins/cloudflare/references/manual-setup.md`. cloudflared's stdout and stderr stream into the PTY; the OAuth URL printed by `cloudflared tunnel login` is linkified by the terminal so the operator clicks it and authorises Cloudflare in their own browser.
296
+
297
+ **Mid-turn stream-drop banners.** If a chat turn ends abruptly the bubble shows one of two messages depending on what actually happened. You see "Server is restarting — reconnect will happen automatically." only when the app server itself emits the restart signal — typically during a Software Update or a Cloudflare setup that re-launches the brand service. You see "Lost connection — retrying." when your browser's connection to the Pi dropped mid-stream while the server was still up — typically a flaky Wi-Fi moment or the tunnel hiccupping. Either way the chat resumes once the connection is back; the previously-rendered messages stay on screen so you don't lose context.
298
+
299
+ **Authorisation** is inherited from the same `canAccessAdmin()` gate that wraps every `/api/admin/*` route.
300
+
301
+ ## Session Slot Safeguards
302
+
303
+ SiteDesk runs each chat — yours and every visitor's — as a separate `claude` process on your Pi. Three safeguards keep these processes from piling up:
304
+
305
+ - **Specialist cap.** Background specialists (`database-operator`, `content-producer`, etc.) are limited to three running at once. If you ask for a fourth while three are still working, the oldest idle one is shut down first. If all three are actively running, the request is rejected with `specialist-cap-reached`.
306
+ - **Operator reserve.** Two slots are always held back for *you* — your own chats and one-off tasks. Specialist work that would consume the last reserved slot is rejected with `operator-slots-reserved`. Your interactive chats are never blocked.
307
+ - **Idle reaper.** Every 30 seconds the platform looks for specialist processes that started, then went silent without producing any output. After two minutes of silence the platform shuts them down.
308
+
309
+ All three are tunable via env vars (`CLAUDE_SESSION_MANAGER_SPECIALIST_CAP`, `CLAUDE_SESSION_MANAGER_OPERATOR_RESERVE`, `CLAUDE_SESSION_MANAGER_TOTAL_PTY_CAP`, `CLAUDE_SESSION_MANAGER_RECORDER_IDLE_TTL_MS`); developer details in `.docs/platform.md` § "Claude Session Manager — PTY Slot Safeguards".
310
+
311
+ If you suspect background processes are piling up, run `grep '\[reaper\]' ~/.{brand}/logs/server.log | tail -50` — each tick logs how many rows it scanned and reaped.
312
+
313
+ ## Tool Permissions
314
+
315
+ Every install seeds `permissions.allow:[]` plus `defaultMode:"bypassPermissions"` into both the brand-scoped settings file (`~/.{brand}/.claude/settings.json`) and every account-scoped one (`<install>/data/accounts/<id>/.claude/settings.json`). `bypassPermissions` alone stops Claude Code from sending tool calls to its remote auto-classifier (it skips all permission checks), which would otherwise surface a permission prompt in the chat that an unattended session never answers. The `allow` array stays empty and **must never contain `"*"`**: Claude Code ≥ 2.1.167 rejects `"*"` as an allow token and renders a blocking Settings Warning that, under `--remote-control`, stops every `/rc-spawn` from binding. What each subagent is allowed to use is still controlled by the `tools:` line in its agent file, not by a top-level allowlist. To verify after an install: `cat ~/.{brand}/.claude/settings.json | jq '.permissions'` (expect `allow: []`). To repair an install seeded before this change: `bash <install>/platform/scripts/backfill-bypass-permissions.sh ~/.{brand}`.
316
+
317
+ **`autoMode` trust block.** The same brand-scoped writer ([`permissions-seed.ts`](../../../packages/create-maxy-code/src/permissions-seed.ts), `AUTO_MODE_BLOCK`) also seeds the harness `autoMode` block. `bypassPermissions` skips the auto-mode classifier entirely, so the block is **belt-and-suspenders**: it only matters when a session is toggled into `auto` mode, where the classifier otherwise soft-denies the doctrine-sanctioned Cloudflare scoped-token mint ("permission/credential escalation") because the install's own Cloudflare infra is not in the classifier's default trusted environment. The block keeps `"$defaults"` first in `environment` and `allow` (so the built-in Data-Exfiltration / force-push / prod-deploy guards stay intact) and adds prose declaring `api.cloudflare.com` the install's own provider endpoint plus an allow for minting/persisting narrow per-scope tokens. It is seeded **only** into the brand/user settings (`~/.{brand}/.claude/settings.json`) — the classifier never reads `autoMode` from the shared project (account-scoped) settings, so `setup-account.sh` does not carry it. An auto-mode agent cannot seed this itself (the default `hard_deny` "Auto-Mode Bypass" blocks any agent editing `.claude/settings*.json`); installer seed is the only path. To verify after an install: `CLAUDE_CONFIG_DIR=~/.{brand}/.claude claude auto-mode config | jq '.environment, .allow'` (expect the Cloudflare entries, `$defaults` expanded) and `jq '.autoMode' ~/.{brand}/.claude/settings.json`.
318
+
319
+ ---
320
+ # Plugins Guide
321
+ Source: https://docs.getmaxy.com/plugins-guide.md
322
+
323
+ # Plugins Guide
324
+
325
+ ## What a Plugin Is
326
+
327
+ A plugin extends what SiteDesk can do. Each plugin adds a focused capability — contacts management, Telegram messaging, scheduling, email, research. Plugins are modular: you enable only what you need.
328
+
329
+ SiteDesk's own capabilities are plugins too. Marketplace plugins (like Stripe) work the same way — SiteDesk manages all of them through conversation.
330
+
331
+ The tables below are the install catalogue — every plugin the platform can ship. They are not evidence of what is enabled on the current account. For the live install set, ask SiteDesk to call `capabilities-here`.
332
+
333
+ ## Plugin Groups
334
+
335
+ ### Core (always active)
336
+
337
+ These are part of SiteDesk's foundation and cannot be disabled:
338
+
339
+ | Plugin | What it does |
340
+ |--------|-------------|
341
+ | `admin` | Platform management — system status, account settings, logs, session control. Also hosts the cross-cutting `plainly` skill: every text-producing agent (admin, public, every specialist) applies a plain-English precision pass to prose returned to humans, as a prime-directive prerogative. Agent-to-machine payloads (image-generate prompts, memory-write arguments, cypher) pass through verbatim. This is a prompt-level skill contract, not a hook: each agent's IDENTITY loads `skill-load skillName=plainly` on its first text-producing turn and applies the pass thereafter. Hosts the `superpowers-sprint` skill: structured sprint workflow built on the `superpowers` and `code-review` upstream plugins, dispatched on "run a sprint" or any `.tasks/NNN-*.md` invocation. |
342
+ | `memory` | Graph memory — search, write, reindex, and ingest knowledge |
343
+ | `browser` | Headless browser rendering — `browser-render` runs a JavaScript-heavy page in the device's Chromium and returns its rendered DOM. The JS-rendering leg of retrieval: WebFetch (summary) / `url-get` (verbatim, server-rendered) / `browser-render` (JS-rendered). |
344
+ | `maxy-guide` | User guide and platform documentation (this plugin) |
345
+ | `cloudflare` | Cloudflare Tunnel — remote access via your custom domain |
346
+ | `scheduling` | Calendar and scheduling — events, appointments, recurring triggers. Any activity involving time (date, timestamp, day of week, month, duration) routes through `time-resolve` first. Two read-only tools (`current-datetime`, `time-resolve`) are always available to every public agent regardless of enabled plugins. |
347
+ | `email` | Agent email account — setup, read, send, reply, search, auto-respond |
348
+ | `tasks` | Task lifecycle — create, update, list, relate, complete |
349
+ | `workflows` | Persistent named workflows — reusable instruction sets |
350
+ | `contacts` | CRM contact management — create, lookup, update, list |
351
+ | `prompt-optimiser` | Prompt optimiser — two modes. Chat-app mode turns a rough draft or task description into a single finished, copy-pasteable prompt tuned for Opus 4.7 adaptive thinking (claude.ai, Mac, iOS). In-session mode is applied automatically: a standing `UserPromptSubmit` directive hook (`admin/hooks/prompt-optimiser-directive.sh`) injects context every turn telling the admin agent to restate each non-trivial prompt through this skill and act on the restatement, skipped for one-word confirmations, slash-commands, and direct continuations. Compliance is behavioural — the hook steers the agent, it cannot force the skill call. The hook also persists the exact injected `additionalContext` per turn to `$LOG_DIR/prompt-optimiser-directives/<session>/<epoch>-<pid>.txt` and records `len`, `sha256`, and the stored `file=` path in `$LOG_DIR/prompt-optimiser-directive.log`, so any past turn's full ~17 KB directive is recoverable and verifiable (the JSONL attachment row Claude Code keeps is truncated to ≤2.6 KB). `platform/scripts/prompt-optimiser-audit.sh` reconciles breadcrumbs against stored files per session (`injected=N stored=M`; `N!=M` is the leak signature, and any breadcrumb whose `file=` is missing is named). |
352
+ | `url-get` | Faithful page retrieval — fetches a server-rendered page, writes a verbatim markdown copy to an account-scoped reference file (no model in the path, so no copyright refusal), and returns the cleaned page text (capped) plus the file path. No summary and no subprocess: a caller that wants a summary invokes url-get from a delegated subagent. Use instead of WebFetch when a faithful copy is needed (e.g. ingesting your own published writing). |
353
+
354
+ ### SiteDesk Plugins (user-selectable)
355
+
356
+ These are enabled during onboarding and can be added or removed at any time. Some plugins enhance a specific specialist role — when enabled, that specialist gains additional capabilities.
357
+
358
+ | Plugin | What it does | Enhances |
359
+ |--------|-------------|----------|
360
+ | `business-assistant` | Customer enquiries, scheduling, quoting, invoicing, daily briefings | Personal assistant |
361
+ | `sales` | Buying signal detection, closing techniques, objection handling | Personal assistant |
362
+ | `deep-research` | Structured multi-source research — query decomposition, source evaluation, citations | Research assistant |
363
+ | `projects` | Structured project execution — phased sprints, investigations, reviews, retrospectives, plus method references for stakeholder mapping, risk pre-mortems, task prioritization, and meeting-to-tasks | Project manager |
364
+ | `telegram` | Telegram bot — BotFather setup, messaging, channels | Personal assistant |
365
+ | `whatsapp` | WhatsApp messaging, pairing, and conversation browsing | Personal assistant |
366
+ | `replicate` | Image generation — three models for photorealistic, design, and fast draft images | Content producer, Research assistant |
367
+ | `linkedin-import` | Import a LinkedIn Basic Data Export — Profile and Connections today, more CSVs as references land | Database operator |
368
+ | `notion-import` | Import a Notion workspace export (markdown + CSV) — pages, databases, hierarchy, attachments, schema-bounded relations, `@person` mentions account-filtered | Librarian |
369
+ | `obsidian-import` | Import an extracted Obsidian vault — pages map to `:KnowledgeDocument`, wikilinks resolve to intra-vault pages or existing entities, tags become `:DefinedTerm`, embedded images become `:DigitalDocument`. Two-phase tool (dry-run → operator disambiguation → commit). | Librarian |
370
+ | `x-import` | Import an X (Twitter) Basic Data Export — tweet stream renders as one chronological transcript and ingests as a single `:KnowledgeDocument` (`source='x'`); each DM `sessionId` ingests as one `:ConversationArchive` (`source='x-dm'`, keyed on `conversationIdentity`) via `conversation-archive-ingest.sh`. Mentions, replies, and quote-tweet authors resolve to `:Person` on lowercased `xHandle`; every handle and DM senderId confirms against existing nodes (no auto-create). Per-thread KD granularity and `:Post` / `:DirectMessage` labels are explicitly rejected. | Librarian |
371
+ | `substack-import` | Import a Substack "Export your data" archive — per-essay `:KnowledgeDocument {kind:'substack-post'}` via librarian/document-ingest with synthetic stable `attachmentId = "substack-post-${substackPostId}"` (survives Substack edits); one `:KnowledgeDocument {kind:'substack-subscriber-roster'}` per import run with `:MENTIONS {mentionContext:'substack-subscription', tier, totalOpens, totalClicks, lastOpenedAt, lastClickedAt, engagementWindowDays}` to each subscriber `:Person` MERGEd on `(accountId, email)`. Engagement aggregates parsed from `email_activity.csv` (or `subscriber_activity.csv` / `emails.csv`); overwrite-on-reimport. No new label, no new edge type, no new graph writer. Images attach via canonical `:HAS_ENCLOSURE` (or `:MENTIONS` fallback). Bulk-gate at >200 posts or >2000 subscribers. | Librarian |
372
+ | `memory/skills/conversation-archive` | Source-agnostic conversation transcript ingest. One skill for WhatsApp `_chat.txt`, Telegram, Signal, LinkedIn DMs, Zoom transcript, meeting minutes, iMessage, Slack, X DMs — `--source <enum>` selects the per-source normaliser. Single Bash entry — `bash platform/plugins/memory/bin/conversation-archive-ingest.sh <archive> --source <enum> --participant-person-ids <csv> --scope <admin\|public>` — runs normalise → operator-confirms owner + every distinct sender (owner derived from env via Cypher, no flag) → sessionize at the fixed 8h gap → emit one JSON line carrying prepared sessions (turn-attributed text + per-session cursor). The dispatched specialist iterates the sessions in-turn, produces a typed-section JSON chunking for each, and calls the `memory-ingest` MCP tool with `conversationIdentity` set (writes `:ConversationArchive`, source=<enum>) once per session — chunks + cursor advance commit atomically inside one Cypher transaction, so a kill mid-archive resumes from the next session on re-issue without re-classifying anything already written. Re-imports are delta-append. Auto-creating participants is forbidden — any sender outside the operator-confirmed closed set LOUD-FAILs with `parser-miss`. Distinct from the live `whatsapp` plugin (Baileys). | Database operator |
373
+ | `memory/skills/conversation-archive-enrich` | Phase 2 for any named `:ConversationArchive` — source-agnostic per-row insight derivation. Operator-triggered (never auto-fires on Phase 1 completion). Walks the parent's `:Section` chunks in pages via the read-only MCP tool `mcp__plugin_memory_memory__conversation-archive-list-chunks`; the dispatched specialist reads each chunk in-turn and emits claims under the four-kind contract (`mention`, `task`, `preference`, `observed-relationship`); the skill hands those claims to `mcp__plugin_memory_memory__conversation-archive-derive-insights` for per-kind cypher emission, then runs the per-row operator gate (`wire / skip / reject`). Idempotent on `(elementId(chunk), kind, contentHash)` — re-runs collapse identical claims. Confidence floor is a hedging-avoidance instruction the skill embeds in the specialist's per-chunk prompt, not a numeric post-filter; the LLM step runs in-turn from the dispatched specialist rather than as a server-side OAuth round-trip. | Database operator |
374
+
375
+ ### Claude Official (marketplace)
376
+
377
+ Third-party plugins from the Claude marketplace:
378
+
379
+ | Plugin | What it does |
380
+ |--------|-------------|
381
+ | `stripe` | Live access to payment and business data |
382
+
383
+ ### Claude Anthropic Verticals (marketplace, opt-in)
384
+
385
+ Optional plugins from Anthropic's vertical marketplaces. The installer registers `claude-for-financial-services` and `knowledge-work-plugins` so the install commands work; none are auto-installed. You pick each deliberately during first-run onboarding (Step 1) or by name at any time.
386
+
387
+ | Plugin | Marketplace | What it does |
388
+ |--------|-------------|-------------|
389
+ | `kyc-screener` | `claude-for-financial-services` | Parses onboarding documents, runs a rules engine, flags gaps. Outputs are draft work product for human review — your compliance specialist owns sign-off. Relevant to UK estate agents under MLR 2017. |
390
+ | `meeting-prep-agent` | `claude-for-financial-services` | Briefing pack before every client meeting, FSI-flavoured templates. Overlaps with the business-assistant calendar-prep flow — choose one deliberately. |
391
+ | `pdf-viewer` | `knowledge-work-plugins` | Live interactive viewer to view, annotate, and sign PDFs — mark up contracts, fill forms, stamp approvals, place signatures, download the annotated copy. Click-through replaces conversation for this surface (v0.2.0, different shape from chat-driven skills). |
392
+
393
+ Install verbatim:
394
+
395
+ - `claude plugin install kyc-screener@claude-for-financial-services`
396
+ - `claude plugin install meeting-prep-agent@claude-for-financial-services`
397
+ - `claude plugin install pdf-viewer@knowledge-work-plugins`
398
+
399
+ ### Premium Plugins
400
+
401
+ Brand decides which premium plugins ship. The brand's `shipsPremiumBundles` field in `brand.json` is the gate; three shapes are supported:
402
+
403
+ - **omitted / false** — ship nothing from `premium-plugins/` (the legacy SiteDesk default).
404
+ - **`true`** — ship every bundle under `premium-plugins/*` (Real Agent / `realagent-code`).
405
+ - **`["bundle-a", "bundle-b"]`** — ship only the named bundle directories (SiteDesk Code's `["venture-studio"]`). Names with no matching directory on disk are silently dropped; non-allowlisted bundles are stripped from any account that was previously stamped with them.
406
+
407
+ There is no per-account purchase record; the brand decides the shipping set.
408
+
409
+ | Plugin | Type | What it does | Public agent |
410
+ |--------|------|-------------|-------------|
411
+ | `teaching` | Skills | Interactive tutoring, lesson planning, and study pack generation from your knowledge base | Yes — all 3 skills serve students and parents |
412
+ | `real-agent` | Bundle (13 sub-plugins) | UK estate agency skills — sales, listings, vendor management, buyer management, lead generation, coaching, business operations, teaching, Loop CRM (five value pillars: auto-respond, viewing lifecycle, pipeline mining, listings prospecting, maintenance & preferences), PropertyData market analytics (valuation, sold prices, £/sqft baselines, £/sqft growth, demand-rent, area risk, planning precedent, UPRN matching, property-type distribution), gov.uk EPC floor-area lookup, property brochures, social-share image cards, A4 market reports, and single-address preval packs (full UK address → 4-page A4 PDF covering valuation, area, and demand). 3 specialist roles (negotiator, valuer, compliance) | 4 sub-plugins (estate-sales, buyers, estate-coaching, estate-teaching) |
413
+ | `writer-craft` | Skills + Agent | Manuscript review and writing craft — story architecture, reader engagement, prose craft, editorial practice, and multi-level review | No — writing craft serves the author |
414
+ | `venture-studio` | Skills + Agent | Founding-a-business workflow — office-hours discovery, brand pack, zero-to-prototype validation, the full investor data room (business plan, prospectus, term sheet, deck blueprint, A4 print pipeline), and a `legal-essentials` skill that drafts an NDA and a UK-GDPR/PECR privacy policy. Carries citation-routed method references for market sizing (TAM/SAM/SOM), pricing, monetization, competitor analysis, battlecards, strategy frameworks (SWOT/PESTLE/Porter's/Ansoff), and a pre-fundraise strategy red-team. Pre-seeds a `Project` with one `Task` per artefact so nothing gets forgotten. | No — founder-facing only |
415
+ | `management-consulting` | Skills | 21 MBB-style strategy skills for client engagements — situation assessment, growth-barrier and assumption diagnosis, market mapping, competitive intel, segmentation, profit-pool analysis, strategic options, pricing, business cases, portfolio review, operating-model design, initiative prioritization, transformation roadmaps, war-gaming, risk registers, KPI design, value realization, stakeholder alignment, executive narrative, and decision memos. No MCP server. | No — consultant-facing only |
416
+
417
+ **How it works:** Every boot SiteDesk delivers the brand's premium plugins from staging into `platform/plugins/` and stamps `enabledPlugins` against what is actually on disk. No conversation needed — the brand's full set is active from the first turn after install. Updates and reinstalls re-deliver from staging.
418
+
419
+ Some premium plugins are **bundles** — multiple sub-plugins shipped under one directory in `premium-plugins/`, each independently activatable. For example, Real Agent ships 10 sub-plugins covering different aspects of estate agency work. They are all enabled by default. Sub-plugins you don't want active can be turned off individually with "disable <name>"; enabling or disabling individual sub-plugins does not affect the others.
420
+
421
+ If you ask SiteDesk about a tool from a plugin your brand does not ship (for example, a SiteDesk install asking about a Real Agent Loop CRM tool), SiteDesk responds with a structured `<tool-surface-error>` envelope naming the missing plugin and the remedy, rather than improvising with a generic alternative.
422
+
423
+ **Public agent embedding:** Premium plugins marked as public-eligible have their full content (skills and reference knowledge) embedded in public agent prompts. This means a public agent for a Real Agent member can handle buyer enquiries, book viewings, deliver coaching content, and onboard new applicants — all powered by the premium plugin's domain knowledge. Plugins marked admin-only (listings, vendors, leads, business) are only available to the account owner's admin agent.
424
+
425
+ Some premium plugins include specialist helpers that SiteDesk can dispatch for specific tasks (e.g. the writer-craft plugin includes a manuscript reviewer). These are activated automatically when the plugin is enabled.
426
+
427
+ Some premium plugins include pre-built public agent templates — ready-made configurations for customer-facing agents. When you enable the plugin, SiteDesk shows you what templates are available and offers to create agents from them. You review and approve every file before the agent is created. The template is a starting point — you can edit the identity, personality, plugins, and settings to make it yours. The result is a standard public agent, indistinguishable from one you created from scratch.
428
+
429
+ Some premium plugins ship pre-built workflows that are created when the plugin is enabled. These workflows are fully yours — you can inspect, edit, run, and manage them through conversation, exactly like workflows you create yourself. The plugin provides the starting point; you own the result.
430
+
431
+ **If a premium plugin ever stops working** — `documents`, `teaching`, anything else you've paid for — and SiteDesk responds as if it doesn't have those tools, the platform's health check (`/api/health.missingPlugins`) will name the affected plugin. Tell SiteDesk "deliver the {{plugin}} plugin" — it re-runs the same delivery step that fires automatically at session start. If the plugin isn't in the device's staging area, re-run the installer for this brand.
432
+
433
+ ## Choosing Plugins
434
+
435
+ During first-time setup, SiteDesk presents a plugin selection screen where you choose which plugins to activate. Core plugins are pre-selected and locked. Recommended plugins are pre-selected but optional. You can change your mind later.
436
+
437
+ ## Adding or Removing Plugins
438
+
439
+ Tell SiteDesk:
440
+
441
+ - "Enable the Telegram plugin"
442
+ - "Add the Stripe plugin"
443
+ - "Disable the deep-research plugin"
444
+
445
+ SiteDesk handles the installation or removal. If the plugin requires any setup (API keys, bot tokens, configuration), SiteDesk will walk you through it.
446
+
447
+ ## Viewing Your Plugins
448
+
449
+ Ask SiteDesk: "What plugins do I have?" or "List my plugins."
450
+
451
+ ## Operator-Authored Plugins (skill-builder output)
452
+
453
+ Skills you create at runtime through the admin `skill-builder` skill are saved on disk as their own plugin under `data/accounts/{accountId}/plugins/{pluginName}/`. The admin agent calls `mcp__plugin_admin_admin__store-skill`, which composes `PLUGIN.md` (on first call) and `skills/{skillName}/SKILL.md` plus any reference files. The agent supplies `pluginName`, `skillName`, `description`, `publicEmbed`, `body`, and optional references — the path is computed by the tool, never by the agent.
454
+
455
+ These operator-authored plugins survive reinstall because the installer's wipe zone excludes `data/`. At admin session start the platform mirrors `data/accounts/{accountId}/plugins/*` into the runtime plugins directory so the same `parsePluginFrontmatter` / `assemblePublicPluginContent` / `loadEmbeddedPlugins` loaders that read shipped and premium plugins also pick up operator-authored ones — no special-case loader path. The admin agent sees every operator skill by default; per-skill `publicEmbed: true|false` controls which skills surface to the public agent.
456
+
457
+ To edit an operator-authored skill later, ask SiteDesk to update it — the admin agent re-runs `store-skill` for the same `pluginName`/`skillName` and the new content overwrites in place. To remove one, delete the directory under `data/accounts/{accountId}/plugins/{pluginName}/skills/{skillName}/` (or the whole plugin) — the next session start re-mirrors the remaining skills only.
458
+
459
+ `pluginName` collisions with shipped plugin names are refused by `store-skill` with a structured error. See [.docs/agents.md](../../../../.docs/agents.md) § "Operator-authored skills as plugin files" for the full contract.
460
+
461
+ ## Brand Templating (for plugin and skill authors)
462
+
463
+ Skill content, plugin manifests, agent templates, and reference files reference the operator-visible brand name only via the literal `SiteDesk` placeholder. The platform substitutes from `brand.json.productName` at read time — SiteDesk installs render `SiteDesk`, Real Agent installs render `Real Agent`, all from the same source content.
464
+
465
+ **Author rule:** never write the literal string `SiteDesk` (or any brand name) in shipped skill, plugin, or template content. Use `SiteDesk` whenever the operator should see the brand name. The audit grep `grep -rn "\bMaxy\b" platform/plugins/admin/skills/ platform/plugins/*/skills/ platform/templates/agents/` must return zero matches; a literal brand name is a defect, not a stylistic choice.
466
+
467
+ The runtime substitution happens at every read site that flows content into a system prompt or operator-visible UI: the admin agent's `plugin-read` tool (references + `PLUGIN.md`), the `skill-load` tool (SKILL.md by skill name — one-call resolver+reader, the canonical primitive for SKILL.md), the public agent's recursive plugin assembly, and `IDENTITY` / `SOUL` / `AGENTS` / `KNOWLEDGE` markdown reads. Missing or empty `productName` hard-fails — there is no fallback to a default brand string. See [.docs/agents.md](../../.docs/agents.md) § "Brand templating" for the full contract.
468
+
469
+ ## MCP Plugin Observability (for plugin authors)
470
+
471
+ Every `console.error` line from a plugin's MCP server can be teed into the per-conversation agent stream log so a single `logs-read` call returns one conversation's full timeline — agent events and plugin diagnostics interleaved in chronological order.
472
+
473
+ **Opt-in (one line at the top of the MCP server's entry file):**
474
+
475
+ ```typescript
476
+ import { initStderrTee } from "../../../../lib/mcp-stderr-tee/dist/index.js";
477
+ initStderrTee("your-plugin-name");
478
+ ```
479
+
480
+ After this, every `console.error("[your-tool]...")` from any tool in the plugin appears as `[<iso-ts>] [mcp:your-plugin-name] [your-tool]...` in the per-conversation stream log `claude-agent-stream-{sessionId}.log`, alongside the usual agent events. The raw per-server file `mcp-your-plugin-name-stderr-{date}.log` is still produced for deep-dive grep.
481
+
482
+ **Premium plugins.** Source lives at `premium-plugins/<bundle>/plugins/<name>/mcp/src/` — deeper than platform plugins, so the source-relative import to `platform/lib/mcp-stderr-tee/dist/index.js` uses more `../` segments. The bundler rewrites the compiled output to the canonical `../../../../lib/mcp-stderr-tee/dist/index.js` at staging time and ships `platform/lib/mcp-stderr-tee/{dist,package.json}` into `premium-plugins/<bundle>/lib/mcp-stderr-tee/` so the import resolves at deployed depth. The bundler fails loudly if `platform/lib/mcp-stderr-tee/package.json` is missing (it must pin `type` so install-location parent walks cannot mis-classify the dist file) or if any lib referenced by a rewritten import has no source dist.
483
+
484
+ **How the tee decides which file to write to:** the platform sets `STREAM_LOG_PATH` as an environment variable on every MCP server spawn, pointing to the conversation-scoped stream log. The MCP server does not know about conversations — it just trusts `STREAM_LOG_PATH`. Multiple concurrent conversations produce multiple concurrent MCP server processes, each teeing to its own file; no cross-conversation leakage.
485
+
486
+ **Bash commands stream straight into the PTY.** SiteDesk Code's admin and public chat run on the native Claude Code PTY. The per-conversation server-side stream log that the retired web-UI dispatcher tailed is gone; agent-invoked Bash commands (including direct `cloudflared` invocations for Cloudflare setup) print their stdout and stderr directly, and the PTY renders the output in chat verbatim.
487
+
488
+ **Retrieve MCP diagnostic lines for a conversation:**
489
+
490
+ - All servers: `logs-read { type: "system", sessionId: "..." }` → grep `[mcp:<name>]` on the returned stream log.
491
+ - One server raw feed: `logs-read { type: "mcp" }` → tails the most recent `mcp-<name>-stderr-*.log` (per-plugin, not per-conversation).
492
+
493
+ **Tee-state markers** land in the stream log: `[platform] [mcp-tee-attach] server=<name> streamLogPath=...` when the tee wires up, `[platform] [mcp-tee-skip] server=<name> destination=... reason=...` when a destination fails (missing `LOG_DIR`, unwritable path, `STREAM_LOG_PATH` not set, etc.), `[platform] [mcp-tee-detach] server=<name>` on graceful shutdown. If a server invoked tools but no `[mcp:<name>]` lines appear in the conversation's log, look for the skip marker first.
494
+
495
+ **Main-subprocess stderr.** The same teeing pattern applies to the main Claude Code subprocess's stderr — every line lands in the per-conversation stream log as `[subproc-stderr] …`, with lifecycle markers `[subproc-stderr-tee-attached] pid=…` and `[subproc-stderr-tee-detached] pid=… bytes=N lines=N`. A `bytes=0 lines=0` detach means the tee was attached but the subprocess emitted nothing on stderr — which is the normal state today, because the Claude Code CLI is a bundled Bun runtime binary that does not honour Node's `NODE_DEBUG` env var. The platform records this explicitly with one line per spawn: `[subproc-debug-unavailable] reason=bundled-bun-binary-ignores-node-debug pid=… cli=claude`. A reader who finds a `[spawn]` without these markers should treat that as a regression of the tee infrastructure, not as silence.
496
+
497
+ ## Failure-path observability contract (earlier platform fixes + earlier platform fixes)
498
+
499
+ The `initStderrTee` wrapper writes to the per-conversation stream log and per-server raw file via `createWriteStream` — async, buffered. Any diagnostic `console.error(…)` followed by an immediate `process.exit(…)` is lost: the event loop never drains the WriteStream before the process terminates. Same race for any synchronous module-load throw: Node's uncaught-exception handler writes the stack to raw fd 2 and exits before the patched async stream flushes. The platform's `[mcp-init-error] tail="(no stderr file)"` line — operationally useless — is the public symptom of this race.
500
+
501
+ **Two layers now close the gap, each load-bearing on its own:**
502
+
503
+ 1. **Plugin-side sync-write discipline.** Plugins that call `process.exit` during module load (rare — `graph-mcp` is the in-tree example; it spawns a child at boot to proxy upstream stdio) use `fs.appendFileSync` at every named exit path to guarantee the cause lands in both log destinations before exit. Lines follow the `[mcp:<name>] [<plugin-prefix>] <cause>` format so existing `grep '[mcp:<name>]'` investigator paths work. Each destination is wrapped in its own try/catch — an unwritable log must not mask the primary failure. This is the discipline propagated to any plugin author who knows their failure paths.
504
+
505
+ 2. **Parent-side `mcp-spawn-tee` wrapper.** Every node-based core MCP server is spawned via the `lib/mcp-spawn-tee` wrapper rather than `node <entry>` directly. The wrapper spawns the real entry with `stdio: ['inherit', 'inherit', 'pipe']` and writes child stderr chunks to `${LOG_DIR}/mcp-${name}-stderr-<date>.log` via `appendFileSync` while passing the same chunks through to its own stderr (Claude Code's consumer is unchanged). Synchronous `appendFileSync` survives `process.exit`, so the per-server file captures even (a) module-load throws before `initStderrTee` runs, (b) `MODULE_NOT_FOUND` on the entry script itself, and (c) anything else a plugin author missed. The wrapper writes `[mcp-spawn-tee-attached] server=<name> pid=<n>` on attach and forwards SIGTERM/SIGINT to the child. This is the layer that makes capture independent of plugin discipline. Playwright stays unwrapped because it spawns via `npx`, not `node`.
506
+
507
+ A third layer closes the same gap from the platform side: when `claude-agent.ts` observes an `init` event with any MCP server reporting `status:"failed"`, it reads the last 512 bytes of `${LOG_DIR}/mcp-<name>-stderr-<date>.log` and emits `[mcp-init-error] server=<name> tail=<quoted>` into the stream log. Absent file → `tail="(no stderr file)"`; empty file → `tail="(empty)"`. With the spawn-tee wrapper now interposing on every core MCP, `tail="(no stderr file)"` means the wrapper itself is broken — file follow-up.
508
+
509
+ **Signal inventory after a failed session:** `[init] FAILED MCP servers: <names>` (names), `[mcp-init-error] server=<name> tail=…` (cause for each, from the platform's tail probe), `[mcp-spawn-tee-attached] server=<name> pid=<n>` (proof the wrapper attached), `[mcp-spawn-tee-exit] server=<name> code=<n>|signal=<s>` (proof the wrapper saw the exit), and optionally `[mcp:<name>] [<plugin>] …` from plugin-side sync-writes. Their union gives the investigator three independent sources for the same failure.
510
+
511
+ **Boot-smoke as publish-time gate.** The memory MCP carries `scripts/boot-smoke.sh` that spawns `dist/index.js` with stub env, sleeps 2s, asserts `kill -0 <pid>`, and reports `[boot-smoke] memory ok|FAILED tail=<n-lines>`. Wired to `prepublish` in `plugins/memory/mcp/package.json`. The pattern is propagatable to other plugin MCPs — it's deliberately not generalised yet because each plugin's stub-env requirements differ (memory needs ACCOUNT_ID + PLATFORM_ROOT + NEO4J_URI + SESSION_ID; others differ).
512
+
513
+ ---
514
+ # Install Overview
515
+ Source: https://docs.getmaxy.com/install.md
516
+
517
+ # Installing SiteDesk Code
518
+
519
+ SiteDesk Code installs from one npm one-liner on every supported host. The host you choose determines the supervisor (systemd vs launchd), the Cloudflare flow (provisioned vs operator-opt-in), and the VNC requirement (Pi/cloud VM only).
520
+
521
+ | Host | Doc | Supervisor | Cloudflare tunnel | Hostname flag |
522
+ |---|---|---|---|---|
523
+ | Raspberry Pi 5 (16GB) on Ubuntu Server 24.04 | [pi.md](pi.md) | systemd user-service | provisioned post-install via `cloudflared tunnel login` in the Pi's VNC browser | `--hostname` required |
524
+ | Hetzner Cloud CAX31 (16GB arm64) on Ubuntu 24.04 | [hetzner.md](hetzner.md) | systemd user-service | provisioned post-install via `cloudflared tunnel login` in a noVNC browser reached over SSH port-forward | `--hostname` required |
525
+ | macOS 14+ on Apple Silicon | [macos.md](macos.md) | launchd LaunchAgent | not provisioned; operator runs `cloudflared tunnel login` post-install if they want public reach | `--hostname` optional |
526
+
527
+ The installer source is `maxy-code/packages/create-maxy-code/`. The same package is published as `@rubytech/create-maxy-code` and `@rubytech/create-realagent-code`; the publisher rewrites the package name at bundle time per brand.
528
+
529
+ Engineers reading the codebase should also see [../deployment.md](../deployment.md) for call-site detail (which branch in `index.ts` does what, log-line shapes, branch-by-branch decisions).
530
+
531
+ ---
532
+ # macOS Install
533
+ Source: https://docs.getmaxy.com/install/macos.md
534
+
535
+ # Installing SiteDesk Code on macOS
536
+
537
+ End-to-end install for a fresh macOS account on Apple Silicon (M-series). Every command is copy-pasteable and uses auto-yes flags so nothing prompts interactively.
538
+
539
+ The doc is brand-aware. Examples use the default brand `maxy-code`; substitute `realagent-code` (or any other brand under `maxy-code/brands/`) wherever you want a parallel install. Each brand is fully isolated — its own persist directory, its own LaunchAgent, its own admin UI port, its own `CLAUDE_CONFIG_DIR`.
540
+
541
+ > Pi install: see [pi.md](pi.md) for the Raspberry Pi flow.
542
+ > Other hosts and engineering detail: see [index.md](index.md) and [../deployment.md](../deployment.md).
543
+
544
+ ## Requirements
545
+
546
+ - macOS 14 (Sonoma) or newer. The installer refuses to run on 13 and below; you will see `[create-maxy] platform=darwin macos=… — refusing: macOS 14+ required`.
547
+ - Apple Silicon (M1/M2/M3/M4). Intel Macs are not part of the supported matrix — the installer pins `node@22` from Homebrew's Apple Silicon cellar (`/opt/homebrew`) and other paths assume that prefix.
548
+ - Admin (sudo) account. The installer asks for your password once when it sets the system hostname via `scutil`; everything else runs unprivileged.
549
+ - A working internet connection — Homebrew, npm, and Cloudflare endpoints are all reached during install.
550
+
551
+ ## 1. Install Node 22 via Homebrew
552
+
553
+ ```bash
554
+ # Homebrew (skip if already installed)
555
+ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
556
+
557
+ # Node 22 — pinned formula
558
+ brew install node@22
559
+ brew link --overwrite --force node@22
560
+
561
+ # Verify (must be 22.6 or newer)
562
+ node --version
563
+ ```
564
+
565
+ Node from the system PATH must resolve to `/opt/homebrew/opt/node@22/bin/node`. If `which node` points anywhere else, fix the PATH before continuing — the installer reads node from `PATH` and a 20.x binary will trip the engines check.
566
+
567
+ ## 2. Run the installer
568
+
569
+ The default brand is `maxy-code`. Run from any directory; the installer creates and writes everything under `$HOME/.maxy-code`.
570
+
571
+ ```bash
572
+ npx -y @rubytech/create-maxy-code@latest
573
+ ```
574
+
575
+ That command:
576
+ - creates the persist directory `$HOME/.maxy-code/` (logs, config, plugin state, the `.claude/` config tree, browser profile);
577
+ - exports `CLAUDE_CONFIG_DIR=$HOME/.maxy-code/.claude` for every Claude Code invocation it spawns (default `~/.claude` is the wrong tree on a multi-brand machine);
578
+ - builds the platform payload bundled in the npm tarball;
579
+ - writes a launchd LaunchAgent at `~/Library/LaunchAgents/com.rubytech.maxy-code.plist` and loads it with `launchctl bootstrap gui/$UID`;
580
+ - prints the admin UI URL when the supervisor reports the server is listening.
581
+
582
+ The full install log lands at `$HOME/.maxy-code/logs/create-maxy-<timestamp>.log`. Every phase line is prefixed `[create-maxy] phase=… brand=… platform=darwin` — that's the canonical signal if you want to attach an install log to a support request.
583
+
584
+ ### Optional: `--hostname`
585
+
586
+ By default the installer leaves your existing macOS hostname alone and serves the admin UI at `http://<your-existing-LocalHostName>.local:<port>`. If you want a dedicated name on the LAN, pass `--hostname`:
587
+
588
+ ```bash
589
+ npx -y @rubytech/create-maxy-code@latest --hostname maxy
590
+ ```
591
+
592
+ That triggers three `sudo scutil --set` calls — `HostName`, `LocalHostName`, `ComputerName` — and the admin UI then resolves at `http://maxy.local:<port>` from any device on the same Bonjour/mDNS network. The flag is the only path that mutates system hostname state; omitting it preserves whatever you had.
593
+
594
+ ### Installing a second brand
595
+
596
+ To run, for example, `realagent-code` alongside the default install, repeat step 2 with that brand's package:
597
+
598
+ ```bash
599
+ npx -y @rubytech/create-realagent-code@latest
600
+ ```
601
+
602
+ The persist directory becomes `$HOME/.realagent-code`, the LaunchAgent becomes `com.rubytech.realagent-code`, and the admin URL switches to `http://realagent-code.local:<port>`. Every brand has its own isolated tree — there is no shared state, and `CLAUDE_CONFIG_DIR` is always `$HOME/.<brand>/.claude` for that brand, never the default `~/.claude`.
603
+
604
+ ## 3. Confirm the LaunchAgent is up
605
+
606
+ ```bash
607
+ launchctl print gui/$(id -u)/com.rubytech.maxy-code | head -20
608
+ ```
609
+
610
+ You should see `state = running`. If the state is `not running` or the command fails, inspect the plist and the supervised stdout/stderr files referenced inside it:
611
+
612
+ ```bash
613
+ cat ~/Library/LaunchAgents/com.rubytech.maxy-code.plist
614
+ ```
615
+
616
+ The plist points at the wrapper script the installer wrote and at log files under `$HOME/.maxy-code/logs/`. `launchctl bootstrap`'s exit code is recorded in the install log as `[create-maxy] launchd-plist=… loaded=true|false`.
617
+
618
+ ## 4. Open the admin UI
619
+
620
+ The install log's final block prints the URL. For the default brand on a default install:
621
+
622
+ ```
623
+ ================================================================
624
+
625
+ Open in your browser: http://<hostname>.local:<port>
626
+
627
+ ================================================================
628
+ ```
629
+
630
+ Open that URL in any browser. The admin UI loads, the operator account is provisioned on first visit, and the platform's chat surface is ready.
631
+
632
+ ## 5. Verify reboot persistence
633
+
634
+ Reboot the Mac. After login, the LaunchAgent reattaches automatically because the plist sets `RunAtLoad=true` and `KeepAlive=true`. Re-open the admin URL — it should respond within a few seconds without you doing anything.
635
+
636
+ If the admin UI does not respond after reboot:
637
+ - Re-check `launchctl print gui/$(id -u)/com.rubytech.maxy-code` for `state = running`.
638
+ - Tail the supervised log under `$HOME/.maxy-code/logs/`.
639
+ - The wrapper script reloads `$HOME/.maxy-code/.env` before exec'ing the platform binary; if you edited that file by hand and broke a quoted value, the supervisor will respawn on a fast loop and the URL never becomes reachable.
640
+
641
+ ## Uninstall
642
+
643
+ ```bash
644
+ npx @rubytech/create-maxy-code --uninstall
645
+ ```
646
+
647
+ This unloads the LaunchAgent (`launchctl bootout gui/$UID/com.rubytech.maxy-code`), removes the plist, removes the Homebrew formula state the installer added, and removes the persist directory `$HOME/.maxy-code/`. After it completes the brand leaves no trace.
648
+
649
+ To uninstall a non-default brand, point at its package — for example:
650
+
651
+ ```bash
652
+ npx @rubytech/create-realagent-code --uninstall
653
+ ```
654
+
655
+ ## What this install does not do
656
+
657
+ macOS is the lightweight surface. Compared with the Pi install, the macOS path deliberately skips:
658
+
659
+ - **No cgroup / resource decoupling.** Pi installs decouple Claude Code's cgroup from systemd's session scope so a closed VNC viewer cannot reap the long-running agent. macOS uses launchd, which is already per-user and does not have the same cleanup pathology, so the work is unnecessary.
660
+ - **No VNC.** The admin UI is the surface. You drive it from a browser on the same machine or any device on the LAN; there is no display server to bootstrap.
661
+ - **No `cloudflared` tunnel by default.** Pi installs ship a tunnel because the device is typically headless and on a residential network. On a Mac the LAN URL is usually enough; if you want a public URL, install `cloudflared` separately and run `cloudflared tunnel login` from the terminal. The tunnel uses the CLI's interactive `tunnel login` flow; other Cloudflare operations (DNS, Pages, D1) use the API with a token the agent mints from an operator-provisioned master.
662
+
663
+ ## Smoke checklist
664
+
665
+ The full operator-side fresh-Mac smoke is tracked separately (see `.tasks/339-macos-installer-smoke-task-297.md`). The headline pass criteria:
666
+
667
+ 1. Install on a clean account with no prior SiteDesk footprint completes and prints an admin URL.
668
+ 2. The admin UI opens at that URL and the chat surface is interactive.
669
+ 3. Reboot — the URL is reachable again after login without any manual action.
670
+ 4. Run `--hostname <name>` on a second install path; the URL switches to `<name>.local`.
671
+ 5. Uninstall removes the LaunchAgent, the plist, and the persist directory.
672
+
673
+ If any step fails, attach `$HOME/.<brand>/logs/create-maxy-<timestamp>.log` to the report.
674
+
675
+ ---
676
+ # Raspberry Pi Install
677
+ Source: https://docs.getmaxy.com/install/pi.md
678
+
679
+ # Installing SiteDesk Code on a Raspberry Pi
680
+
681
+ End-to-end install for a fresh Raspberry Pi 5 (16GB) on Ubuntu Server 24.04 (64-bit). Every command is copy-pasteable and uses auto-yes flags so nothing prompts interactively. The same flow works on a Pi 4 (8GB). For a Hetzner Cloud install (CAX31 ARM64 ~€13/mo), see [hetzner.md](hetzner.md) — same installer, slightly different bootstrap for the Cloudflare tunnel because there is no LAN to the operator.
682
+
683
+ The doc is brand-aware. Examples use the default brand `maxy-code`; substitute `realagent-code` (or any other brand under `maxy-code/brands/`) wherever you want a parallel install. Each brand is fully isolated — its own persist directory, its own systemd user-service, its own Neo4j port, its own VNC display, its own Cloudflare tunnel, its own `CLAUDE_CONFIG_DIR`.
684
+
685
+ > macOS install: see [macos.md](macos.md) for the laptop flow.
686
+ > Architecture notes for engineers: see [../deployment.md](../deployment.md).
687
+
688
+ ## Requirements
689
+
690
+ - Raspberry Pi 5, 16GB RAM (canonical) — Pi 4 8GB works but the first install runs slower.
691
+ - Ubuntu Server 24.04 LTS, 64-bit, freshly imaged with Raspberry Pi Imager. Earlier Ubuntu / Pi OS releases are not part of the supported matrix.
692
+ - The pi has a wired or Wi-Fi route to the internet and an SSH-reachable user with sudo (the username does not matter — Rubytech images ship `admin` by default).
693
+ - A Cloudflare account whose dashboard you can sign into in a web browser. The tunnel signs in via `cloudflared tunnel login` (OAuth, in the Pi's VNC browser after install); DNS/Pages/D1 use the Cloudflare API with a token the agent mints from a master token you provision once.
694
+ - A connected monitor or a working VNC viewer for the one-time `cloudflared tunnel login` step. After that step the Pi runs headless.
695
+
696
+ For Hetzner Cloud, see [hetzner.md](hetzner.md). The apt path, systemd user-service, and Cloudflare flow are the same; the difference is that a cloud VM has no physical display and no LAN to the operator, so the noVNC browser is reached over SSH port-forwarding for the one-time Cloudflare bootstrap.
697
+
698
+ ## 1. Prepare the OS
699
+
700
+ Update the package index and install Node 22 from NodeSource. Pi OS / Ubuntu archive Node is too old; the installer reads `node` from `PATH` and a 20.x binary trips the engines check.
701
+
702
+ ```bash
703
+ sudo apt-get update
704
+ curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
705
+ sudo apt-get install -y nodejs
706
+
707
+ # Verify (must be 22.6 or newer)
708
+ node --version
709
+ ```
710
+
711
+ Everything else the installer needs (apt deps for the VNC stack, `cloudflared`, Neo4j, Ollama, Chromium) is installed by `@rubytech/create-maxy-code` in step 2 — do not pre-install them by hand.
712
+
713
+ ## 2. Run the installer
714
+
715
+ The default brand is `maxy-code`. Run as the same user that will operate the device (do not run with `sudo`; the installer escalates internally where it needs to). The `--hostname` flag is required on Pi and cloud VM — it becomes the Cloudflare-fronted hostname and the systemd unit name, and it is the hostname the LAN sees over mDNS.
716
+
717
+ ```bash
718
+ npx -y @rubytech/create-maxy-code@latest --hostname <hostname>
719
+ ```
720
+
721
+ Pick a `<hostname>` that is short, lowercase, and unique across your Cloudflare account (e.g. `maxy-alice`). The installer sets `HostName`, `LocalHostName`, and the Avahi `host-name` to this value, then registers a systemd user-service named `<hostname>.service` that owns the platform process.
722
+
723
+ That command:
724
+
725
+ - creates the persist directory `$HOME/.maxy-code/` (logs, config, plugin state, the `.claude/` config tree, browser profile);
726
+ - exports `CLAUDE_CONFIG_DIR=$HOME/.maxy-code/.claude` for every Claude Code invocation it spawns (default `~/.claude` is the wrong tree on a multi-brand machine);
727
+ - `apt-get install -y` for the base deps, the VNC stack (`tigervnc-standalone-server`, `python3-websockify`, `novnc`, `xdg-utils`, `chromium`, `xterm`, `xdotool`), `cloudflared`, Neo4j 5.x, and `nodejs`;
728
+ - swaps a snap-Chromium for a deb-packaged Chromium (or Google Chrome) when the Ubuntu image ships Chromium as a snap — snap-confined Chromium cannot run inside the VNC display;
729
+ - builds the platform payload bundled in the npm tarball;
730
+ - writes a systemd user-service at `~/.config/systemd/user/<hostname>.service` and enables it with `systemctl --user enable --now`;
731
+ - prints the LAN URL `http://<hostname>.local:<port>` when the supervisor reports the server is listening. The Cloudflare-fronted public URL is not provisioned at install time — step 4 below.
732
+
733
+ The full install log lands at `$HOME/.maxy-code/logs/install-<timestamp>.log`. Every phase line is prefixed `[create-maxy] phase=… brand=… platform=linux` — that is the canonical signal if you want to attach an install log to a support request.
734
+
735
+ If `~/.maxy-code/logs/install-*.log` is empty after a failed install, grep the installer's stdout for `[create-maxy] platform=`, `[create-maxy] log=`, and `[create-maxy] init-logging FAILED reason=`. The installer emits those to stdout (and stderr for the last one) before any log file write.
736
+
737
+ ### Installing a second brand
738
+
739
+ To run, for example, `realagent-code` alongside the default install on the same Pi, repeat step 2 with that brand's package and a different hostname:
740
+
741
+ ```bash
742
+ npx -y @rubytech/create-realagent-code@latest --hostname <realagent-hostname>
743
+ ```
744
+
745
+ The persist directory becomes `$HOME/.realagent-code`, the systemd user-service becomes `<realagent-hostname>.service`, Neo4j is provisioned as a dedicated `neo4j-<realagent-hostname>` service on its own port, and the VNC display + websockify + ttyd ports all shift to the brand's reserved range. There is no shared state; `CLAUDE_CONFIG_DIR` is always `$HOME/.<brand>/.claude` for that brand, never the default `~/.claude`.
746
+
747
+ ## 3. Confirm the systemd user-service is up
748
+
749
+ ```bash
750
+ systemctl --user status <hostname>.service
751
+ ```
752
+
753
+ You should see `Active: active (running)`. If the unit is in `failed` or `activating` state, tail the supervised journal:
754
+
755
+ ```bash
756
+ journalctl --user -u <hostname>.service -n 200 --no-pager
757
+ ```
758
+
759
+ The unit reads its environment from `$HOME/.maxy-code/.env`; if you edited that file by hand and broke a quoted value, the supervisor will respawn on a fast loop and the LAN URL never becomes reachable.
760
+
761
+ The installer also wires `loginctl enable-linger <user>` so the user-service survives logout. If `loginctl show-user <user> | grep Linger` does not return `Linger=yes`, re-run the installer or `sudo loginctl enable-linger <user>` by hand — without linger the service stops when you log out of the Pi.
762
+
763
+ ## 4. Bootstrap the Cloudflare tunnel
764
+
765
+ The installer puts `cloudflared` on PATH but does not provision the tunnel — Cloudflare tunnel auth happens once, interactively, in a browser the operator drives. The tunnel's only auth path is `cloudflared tunnel login`, which writes a browser-issued cert to `$HOME/.maxy-code/.cloudflared/cert.pem` on success. Other Cloudflare operations (DNS, Pages, D1) use the API with a token the agent mints from an operator-provisioned master — see the `cloudflare` plugin.
766
+
767
+ Open the Pi's VNC browser at `http://<hostname>.local:<port>/vnc` (or over the LAN at whichever port the install log printed for noVNC). In the chat surface, ask the agent to run the Cloudflare setup — the [`cloudflare`](../../platform/plugins/cloudflare/PLUGIN.md) plugin's `cloudflare` skill walks `cloudflared tunnel login`, `cloudflared tunnel create`, `cloudflared tunnel route dns`, and the systemd `<hostname>-cloudflared.service` unit in order, streaming `cloudflared`'s stdout verbatim into chat. The OAuth URL the CLI prints is linkified by the PTY; the operator clicks it inside the VNC browser and authorises the cert against the right Cloudflare account.
768
+
769
+ Setup is done when, and only when, `curl -I https://<hostname>.<your-zone>` issued from outside the local network returns `HTTP/2 200`. No state file, no `tunnel run` exit code, and no "service is active" claim substitutes for the live HTTPS response.
770
+
771
+ ## 5. Open the admin UI
772
+
773
+ After step 4 the public URL is your Cloudflare-fronted hostname. Open it in any browser, sign in, and the admin UI loads.
774
+
775
+ On the LAN (or pre-tunnel), the URL is `http://<hostname>.local:<port>` — the install log's final block prints both addresses:
776
+
777
+ ```
778
+ ================================================================
779
+
780
+ Open in your browser: http://<hostname>.local:<port>
781
+ Public URL (after Cloudflare setup): https://<hostname>.<your-zone>
782
+
783
+ ================================================================
784
+ ```
785
+
786
+ ## 6. Verify reboot persistence
787
+
788
+ Reboot the Pi (`sudo reboot`). After the boot completes, the systemd user-service reattaches automatically because the unit is enabled and `loginctl enable-linger` was set. Re-open the LAN or public URL — it should respond within ten or twenty seconds without you doing anything.
789
+
790
+ If the admin UI does not respond after reboot:
791
+
792
+ - `systemctl --user status <hostname>.service` — confirm `active (running)`.
793
+ - `journalctl --user -u <hostname>.service -n 200 --no-pager` — tail the supervisor log.
794
+ - `loginctl show-user <user> | grep Linger` — confirm `Linger=yes`. Without it the user-service does not start until you SSH in.
795
+ - `systemctl --user status <hostname>-cloudflared.service` — confirm the tunnel is up. The platform unit can be healthy while the tunnel is not, in which case the LAN URL works and the public URL does not.
796
+
797
+ ## Uninstall
798
+
799
+ ```bash
800
+ npx -y @rubytech/create-maxy-code@latest --uninstall
801
+ ```
802
+
803
+ This stops and disables the systemd user-service, removes the unit file, removes the Avahi service file, removes the brand's `sysctl.d` QUIC-tuning file, and removes the persist directory `$HOME/.maxy-code/`. Shared apt packages (Node, Neo4j, Chromium, the VNC stack, `cloudflared`) stay on the system — the operator removes them with `sudo apt-get purge` if they want a clean slate.
804
+
805
+ To uninstall a non-default brand, point at its package — for example:
806
+
807
+ ```bash
808
+ npx -y @rubytech/create-realagent-code@latest --uninstall
809
+ ```
810
+
811
+ ## What this install does not do
812
+
813
+ - **No SCP / rsync.** The Pi is reached over npm only. Updates are `npx -y @rubytech/create-maxy-code@latest …` again, never a file push from the operator's laptop.
814
+ - **Tunnel auth is OAuth; the API is permitted for the rest.** The tunnel's only auth path is `cloudflared tunnel login` in the Pi's VNC browser. DNS, Pages, and D1 use the Cloudflare API with a short-lived narrow token the agent mints from an operator-provisioned master token (see the `cloudflare` plugin); tokens are never written to a project tree or echoed.
815
+ - **No shared state across brands.** Two brands on one Pi each have their own Neo4j port, systemd unit, VNC display, websockify port, tunnel, and persist directory. They do not share DNS, ports, or filesystem state.
816
+
817
+ ## Smoke checklist
818
+
819
+ Fresh-Pi smoke pass criteria:
820
+
821
+ 1. Install on a clean Ubuntu Server 24.04 image with no prior SiteDesk footprint completes, prints a LAN URL, and the systemd user-service is `active (running)`.
822
+ 2. The LAN URL `http://<hostname>.local:<port>` opens the admin UI and the chat surface is interactive.
823
+ 3. Cloudflare setup driven by the `cloudflare` plugin's `cloudflare` skill ends with `curl -I https://<hostname>.<your-zone>` returning `HTTP/2 200` from outside the LAN.
824
+ 4. Reboot — both URLs are reachable again after boot without any manual action.
825
+ 5. Install a second brand with a different `--hostname`; both brands' admin UIs are reachable on their own ports / public URLs and neither has touched the other's state.
826
+ 6. Uninstall removes the systemd unit, the Avahi service file, and the persist directory.
827
+
828
+ If any step fails, attach `$HOME/.<brand>/logs/install-<timestamp>.log` to the report.
829
+
830
+ ---
831
+ # Hetzner Cloud Install
832
+ Source: https://docs.getmaxy.com/install/hetzner.md
833
+
834
+ # Installing SiteDesk Code on a Hetzner Cloud server
835
+
836
+ End-to-end install for a fresh Hetzner Cloud server on the **CAX31** tier (8 vCPU Ampere Altra ARM64, 16 GB RAM, 160 GB NVMe, ~€13/mo). CAX is the right tier because it is ARM64, identical chip family to the Raspberry Pi 5, so every binary built by the installer compiles the same way it does on the Pi. Every command is copy-pasteable and uses auto-yes flags so nothing prompts interactively.
837
+
838
+ The doc is brand-aware. Examples use the default brand `maxy-code`; substitute `realagent-code` (or any other brand under `maxy-code/brands/`) wherever you want a parallel install. Each brand is fully isolated — its own persist directory, its own systemd user-service, its own Neo4j port, its own VNC display, its own Cloudflare tunnel, its own `CLAUDE_CONFIG_DIR`.
839
+
840
+ > Pi install: see [pi.md](pi.md). macOS install: see [macos.md](macos.md). Architecture notes for engineers: see [../deployment.md](../deployment.md).
841
+
842
+ > **Data sovereignty note.** Installing on Hetzner moves the operator's graph and conversations from a device they own onto a rented server. For internal use or for operators who explicitly prefer cloud hosting, fine. As the default for customers, this cuts against the inverted-SaaS positioning — surface the trade-off before recommending it.
843
+
844
+ ## Server spec
845
+
846
+ | Field | Value | Why |
847
+ |---|---|---|
848
+ | Tier | **CAX31** | 8 vCPU, 16 GB RAM, 160 GB NVMe, ~€13/mo. RAM matches the Pi 16GB; ARM64 keeps binary compatibility. CAX11/21 are under-spec for the platform's Neo4j + Chromium + Ollama footprint. |
849
+ | Image | Ubuntu 24.04 LTS (arm64) | Same image family supported by the Pi install. Earlier Ubuntu / non-LTS images are not part of the supported matrix. |
850
+ | Location | Nearest to the operator (Falkenstein, Nuremberg, Helsinki, Hillsboro, Singapore) | Latency to the admin browser; choice does not affect the install. |
851
+ | Network | IPv4 + IPv6 | The Cloudflare tunnel terminates all public traffic; the server's own IPv4 is not exposed to operators after step 4. |
852
+ | Firewall | SSH (22) inbound only | Every other inbound surface is fronted by the Cloudflare tunnel, which dials *out* to Cloudflare. |
853
+ | SSH key | Added at provision time | Hetzner does not enable password SSH on the default Ubuntu image when an SSH key is attached. |
854
+
855
+ A CAX11 or CAX21 cannot run the platform. The Pi 16GB is the floor; CAX31 is the like-for-like Hetzner equivalent.
856
+
857
+ ## 1. Provision the server
858
+
859
+ In the [Hetzner Cloud console](https://console.hetzner.cloud):
860
+
861
+ 1. Create a project (or use an existing one).
862
+ 2. Add server → **Location**: nearest region → **Image**: Ubuntu 24.04 → **Type**: Arm64 → **CAX31**.
863
+ 3. Add your SSH key under **SSH keys** (or paste it inline). Skip the cloud-init / user-data field.
864
+ 4. Name the server (e.g. `maxy-alice`) and create it.
865
+
866
+ When the server reaches `Running`, copy its public IPv4. SSH in as `root`:
867
+
868
+ ```bash
869
+ ssh root@<ipv4>
870
+ ```
871
+
872
+ ## 2. Prepare the OS
873
+
874
+ Update the package index and install Node 22 from NodeSource. The Ubuntu archive Node is too old; the installer reads `node` from `PATH` and a 20.x binary trips the engines check.
875
+
876
+ ```bash
877
+ apt-get update
878
+ curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
879
+ apt-get install -y nodejs
880
+
881
+ # Verify (must be 22.6 or newer)
882
+ node --version
883
+ ```
884
+
885
+ Create a non-root user that will own the install and the systemd user-service. Running the platform as `root` is supported but not recommended; the rest of this doc assumes a user named `admin` (matching the Pi default).
886
+
887
+ ```bash
888
+ adduser --disabled-password --gecos "" admin
889
+ usermod -aG sudo admin
890
+ echo "admin ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/admin
891
+ chmod 440 /etc/sudoers.d/admin
892
+ mkdir -p /home/admin/.ssh
893
+ cp ~/.ssh/authorized_keys /home/admin/.ssh/authorized_keys
894
+ chown -R admin:admin /home/admin/.ssh
895
+ chmod 700 /home/admin/.ssh
896
+ chmod 600 /home/admin/.ssh/authorized_keys
897
+
898
+ # From now on, SSH as admin, not root
899
+ ssh admin@<ipv4>
900
+ ```
901
+
902
+ Everything else the installer needs (apt deps for the VNC stack, `cloudflared`, Neo4j, Ollama, Chromium) is installed by `@rubytech/create-maxy-code` in step 3.
903
+
904
+ ## 3. Run the installer
905
+
906
+ The default brand is `maxy-code`. Run as the `admin` user (do not use `sudo`; the installer escalates internally where it needs to). The `--hostname` flag is required on a cloud VM — it becomes the Cloudflare-fronted hostname and the systemd unit name.
907
+
908
+ ```bash
909
+ npx -y @rubytech/create-maxy-code@latest --hostname <hostname>
910
+ ```
911
+
912
+ Pick a `<hostname>` that is short, lowercase, and unique across your Cloudflare account (e.g. `maxy-alice`). The installer:
913
+
914
+ - creates the persist directory `$HOME/.maxy-code/` (logs, config, plugin state, `.claude/` config tree, browser profile);
915
+ - exports `CLAUDE_CONFIG_DIR=$HOME/.maxy-code/.claude` for every Claude Code invocation;
916
+ - `apt-get install -y` for base deps, the VNC stack (`tigervnc-standalone-server`, `python3-websockify`, `novnc`, `xdg-utils`, `chromium`, `xterm`, `xdotool`), `cloudflared`, Neo4j 5.x, and `nodejs`;
917
+ - swaps a snap-Chromium for a deb-packaged Chromium when the Ubuntu image ships Chromium as a snap;
918
+ - builds the platform payload bundled in the npm tarball;
919
+ - writes a systemd user-service at `~/.config/systemd/user/<hostname>.service` and enables it with `systemctl --user enable --now`;
920
+ - prints the loopback URL `http://localhost:<port>` when the supervisor reports the server is listening.
921
+
922
+ The full install log lands at `$HOME/.maxy-code/logs/install-<timestamp>.log`.
923
+
924
+ ### Installing a second brand
925
+
926
+ Repeat step 3 with the other brand's package and a different hostname:
927
+
928
+ ```bash
929
+ npx -y @rubytech/create-realagent-code@latest --hostname <realagent-hostname>
930
+ ```
931
+
932
+ The persist directory becomes `$HOME/.realagent-code`, the systemd user-service becomes `<realagent-hostname>.service`, Neo4j is provisioned on its own port, and the VNC display + websockify + ttyd ports shift to the brand's reserved range.
933
+
934
+ ## 4. Reach the dashboard and VNC browser over SSH port-forwarding
935
+
936
+ On the Pi both the admin UI and the noVNC page are reachable over the LAN. On Hetzner there is no LAN to the operator, so both surfaces are forwarded over SSH until the Cloudflare tunnel exists.
937
+
938
+ All `ssh -L` commands in this step are run on **your local machine** — the machine you SSH from, not on the Hetzner server.
939
+
940
+ Both the dashboard and the VNC browser can be forwarded in a single SSH session using two `-L` flags. On your local machine, open one terminal and run:
941
+
942
+ ```bash
943
+ ssh -L 19200:localhost:19200 -L 6080:localhost:6080 admin@<ipv4> # maxy-code
944
+ # or
945
+ ssh -L 19200:localhost:19200 -L 6081:localhost:6081 admin@<ipv4> # realagent-code
946
+ ```
947
+
948
+ While that session is open:
949
+ - `http://localhost:19200` — dashboard
950
+ - `http://localhost:6080/vnc.html` — VNC browser (Claude's OAuth and Cloudflare setup run here)
951
+
952
+ The server-side ports are fixed by brand (`19200` dashboard, `6080`/`6081` VNC). When managing multiple servers simultaneously, vary only the left-hand (local) ports:
953
+
954
+ ```bash
955
+ # One terminal per server, on your local machine
956
+ ssh -L 19200:localhost:19200 -L 6080:localhost:6080 admin@server1
957
+ ssh -L 19201:localhost:19200 -L 6081:localhost:6080 admin@server2
958
+ ssh -L 19202:localhost:19200 -L 6082:localhost:6080 admin@server3
959
+ ```
960
+
961
+ After the Cloudflare tunnel is provisioned, close the SSH session — every surface is reachable at the public hostname.
962
+
963
+ ## 5. Bootstrap the Cloudflare tunnel
964
+
965
+ The installer puts `cloudflared` on PATH but does not provision the tunnel — Cloudflare tunnel auth happens once, interactively, in the noVNC browser the operator drives over the SSH forward from step 4. The tunnel's only auth path is `cloudflared tunnel login`, which writes a browser-issued cert to `$HOME/.maxy-code/.cloudflared/cert.pem` on success. Other Cloudflare operations (DNS, Pages, D1) use the API with a token the agent mints from an operator-provisioned master — see the `cloudflare` plugin.
966
+
967
+ In the noVNC browser session, open the admin UI at `http://localhost:<port>`. In chat, ask the agent to run the Cloudflare setup — the [`cloudflare`](../../platform/plugins/cloudflare/PLUGIN.md) plugin's `cloudflare` skill walks `cloudflared tunnel login`, `cloudflared tunnel create`, `cloudflared tunnel route dns`, and the systemd `<hostname>-cloudflared.service` unit in order, streaming `cloudflared`'s stdout verbatim into chat. The OAuth URL the CLI prints is linkified by the PTY; the operator clicks it inside the noVNC browser and authorises the cert against the right Cloudflare account.
968
+
969
+ Setup is done when, and only when, `curl -I https://<hostname>.<your-zone>` issued from the operator's laptop returns `HTTP/2 200`. No state file, no `tunnel run` exit code, and no "service is active" claim substitutes for the live HTTPS response.
970
+
971
+ The SSH port-forward from step 4 can be closed after this point.
972
+
973
+ ## 6. Open the admin UI
974
+
975
+ After step 5 the public URL is your Cloudflare-fronted hostname. Open it in any browser (laptop, phone, tablet), sign in, and the admin UI loads.
976
+
977
+ The Hetzner server's IPv4 is not advertised anywhere; the only public surface is the Cloudflare hostname. If the operator's laptop is offline, the loopback URL inside an SSH session (`http://localhost:<port>` over `ssh -L`) still works.
978
+
979
+ ## 7. Verify reboot persistence
980
+
981
+ Reboot the server (`sudo reboot`). After it comes back up, SSH back in and confirm:
982
+
983
+ ```bash
984
+ systemctl --user status <hostname>.service
985
+ systemctl --user status <hostname>-cloudflared.service
986
+ ```
987
+
988
+ Both should be `Active: active (running)` within ten or twenty seconds of boot. `loginctl show-user admin | grep Linger` must report `Linger=yes` — without it the user-service does not start until you SSH in. The installer sets linger; if it is missing, run `sudo loginctl enable-linger admin`.
989
+
990
+ Open the public URL from outside the server's network and confirm the admin UI is reachable without any manual action.
991
+
992
+ ## Uninstall
993
+
994
+ ```bash
995
+ npx -y @rubytech/create-maxy-code@latest --uninstall
996
+ ```
997
+
998
+ This stops and disables the systemd user-service, removes the unit file, removes the brand's `sysctl.d` QUIC-tuning file, and removes the persist directory `$HOME/.maxy-code/`. Shared apt packages (Node, Neo4j, Chromium, the VNC stack, `cloudflared`) stay on the system. To wipe the box completely, destroy the Hetzner server from the cloud console.
999
+
1000
+ To uninstall a non-default brand, point at its package:
1001
+
1002
+ ```bash
1003
+ npx -y @rubytech/create-realagent-code@latest --uninstall
1004
+ ```
1005
+
1006
+ ## What this install does not do
1007
+
1008
+ - **No SCP / rsync.** Updates are `npx -y @rubytech/create-maxy-code@latest …` again, never a file push from the operator's laptop.
1009
+ - **Tunnel auth is OAuth; the API is permitted for the rest.** The tunnel's only auth path is `cloudflared tunnel login` in the noVNC browser over SSH forward. DNS, Pages, and D1 use the Cloudflare API with a short-lived narrow token the agent mints from an operator-provisioned master token (see the `cloudflare` plugin).
1010
+ - **No shared state across brands.** Two brands on one server each have their own Neo4j port, systemd unit, VNC display, websockify port, tunnel, and persist directory.
1011
+ - **No public IPv4 exposure.** The Hetzner firewall opens port 22 only; every operator-facing surface is fronted by the Cloudflare tunnel.
1012
+
1013
+ ## Smoke checklist
1014
+
1015
+ Fresh-Hetzner smoke pass criteria:
1016
+
1017
+ 1. Provision a CAX31 with Ubuntu 24.04 arm64 and an SSH key; SSH in as `root`, create `admin`, switch.
1018
+ 2. Install completes on the clean image, prints a loopback URL, and the systemd user-service is `active (running)`.
1019
+ 3. The noVNC page reached over `ssh -L 8080:localhost:<novnc-port>` displays the admin UI.
1020
+ 4. Cloudflare setup driven by the `cloudflare` plugin's `cloudflare` skill ends with `curl -I https://<hostname>.<your-zone>` returning `HTTP/2 200` from the operator's laptop.
1021
+ 5. Reboot the server; both `<hostname>.service` and `<hostname>-cloudflared.service` come back up; the public URL is reachable again without any manual action.
1022
+ 6. Install a second brand with a different `--hostname`; both brands' admin UIs are reachable on their own public hostnames and neither has touched the other's state.
1023
+ 7. Uninstall removes the systemd unit and the persist directory.
1024
+
1025
+ If any step fails, attach `$HOME/.<brand>/logs/install-<timestamp>.log` to the report.
1026
+
1027
+ ---
1028
+ # Cloudflare Tunnel
1029
+ Source: https://docs.getmaxy.com/cloudflare.md
1030
+
1031
+ # Cloudflare Tunnel — the dashboard is the source of truth
1032
+
1033
+ Each installation has its own Cloudflare account. The **tunnel** sign-in is OAuth: the agent invokes `cloudflared tunnel login` via Bash; the Cloudflare Authorize URL streams into the admin chat PTY and the native terminal renders it as a clickable link. Click it, authorise in your own browser, and `cloudflared` writes `cert.pem` to the brand's config directory. For **everything else** (DNS, Pages, D1, Access) the agent uses the Cloudflare API, authenticated by a short-lived narrow token it mints from a master token you provision once in the dashboard (an advanced step the agent never automates). Some account-side jobs — adding a domain, switching accounts — are still easiest in your browser, and the agent relays those click-paths; the rest it can do directly via the API.
1034
+
1035
+ ## Identity model
1036
+
1037
+ | Concept | Source |
1038
+ |------|--------|
1039
+ | **Product identity** (SiteDesk vs Real Agent) | `brand.json` (`productName`, `configDir`) — known at install. |
1040
+ | **Cloudflare account identity** | `cert.pem` from OAuth. One account per brand per device. |
1041
+ | **Domain scope** (which zones the operator can route) | The operator picks the zone in the dashboard during OAuth or names it in chat; the agent can also enumerate zones via the API with a minted read-scoped token. |
1042
+ | **Local tunnel state** | `~/{configDir}/cloudflared/` — `cert.pem`, `<UUID>.json`, `config.yml`, `alias-domains.json`. |
1043
+
1044
+ Tunnel auth on the operator-owned path (Mode A) is the OAuth cert (`cert.pem`); API operations use a narrow token the agent mints from your master token. That master may be account-scoped (`cfat_…`) or user-scoped (`cfut_…`); the agent detects the type and routes API endpoints accordingly (the account vs user token endpoints) — see `plugins/cloudflare/references/api.md`. To switch Cloudflare accounts, the agent runs the reset flow from `plugins/cloudflare/references/reset-guide.md` (deletes the cert and every tunnel on the current account), then the manual-setup flow again — `cloudflared tunnel login` picks a fresh account when you sign in.
1045
+
1046
+ ## Setup flow
1047
+
1048
+ Ask the agent to set up Cloudflare. The agent confirms the domain is already on your Cloudflare account (if not, it quotes the dashboard click-path — see below) and collects the inputs in plain chat:
1049
+
1050
+ - **Admin address** — the hostname that will serve the admin chat (e.g. `admin.yourdomain.com`).
1051
+ - **Public address** — optional hostname for the public agent (e.g. `public.yourdomain.com` or `chat.yourdomain.com`).
1052
+ - **Proxy apex** — optional bare-domain hostname (e.g. `yourdomain.com`) that should also serve the public agent.
1053
+ - **Admin password** — the password used to gate remote access to the admin surface.
1054
+
1055
+ The agent then sets the admin password via `curl -X POST http://127.0.0.1:${PORT}/api/remote-auth/set-password` (same endpoint the local onboarding form uses), and works through `plugins/cloudflare/references/manual-setup.md` Steps 1–7 directly via the Bash tool. `cloudflared`'s stdout streams into the PTY verbatim. The OAuth URL is linkified by the terminal; click it in your own browser to authorise. After the tunnel is up, the agent appends each non-`public.*` public or apex hostname to `~/{configDir}/alias-domains.json` so `isPublicHost()` classifies it as public, and starts the brand's cloudflared user service.
1056
+
1057
+ If any step's `cloudflared` invocation exits non-zero, the agent names the literal exit code, surfaces the stderr verbatim, and cites `reset-guide.md` for the next action — no retry under a different flag, no Playwright-driven dashboard inspection.
1058
+
1059
+ The setup-done claim only fires after the agent runs `curl -I https://<admin-hostname>` from outside the local network and the response shows a `200` line. That HTTP response is the only success terminal.
1060
+
1061
+ ## Getting a domain on Cloudflare
1062
+
1063
+ The tunnel needs a domain on the Cloudflare account the device will sign into. Two paths, both in your browser:
1064
+
1065
+ **Option A: Buy a new domain through Cloudflare.** Navigate to cloudflare.com → Domains and buy one. Cloudflare sets everything up.
1066
+
1067
+ **Option B: Add an existing domain.** In the dashboard: Websites → Add a site. Cloudflare imports the existing DNS records; review them to confirm your website and email entries are preserved. Cloudflare gives you two nameservers; replace the registrar's nameservers with those. Propagation is usually minutes (up to 24 hours); the zone shows **Active** when ready.
1068
+
1069
+ Existing website traffic continues to work during and after the switch. Only DNS resolution changes owners.
1070
+
1071
+ ## Reset / account switch
1072
+
1073
+ Ask the agent to reset Cloudflare. The agent executes the reset flow from `plugins/cloudflare/references/reset-guide.md`:
1074
+
1075
+ - Deletes every tunnel on the brand's current Cloudflare account (via the bound cert).
1076
+ - Wipes the brand's `${CFG_DIR}`.
1077
+ - Stops the brand's cloudflared user service.
1078
+
1079
+ The agent does **not** stop token-mode connector processes or delete stray misrouted CNAMEs in the dashboard. If any of those apply, the agent guides you through the manual cleanup — `pkill -f 'cloudflared.*tunnel run --token'` on the device, or deleting the stray CNAME in the dashboard.
1080
+
1081
+ After reset, run setup again. The fresh `cloudflared tunnel login` will pick whichever Cloudflare account you sign into.
1082
+
1083
+ ## Manual runbook
1084
+
1085
+ The step-by-step runbook at `plugins/cloudflare/references/manual-setup.md` is the contract the agent follows. It is also what an operator runs by hand when needed — every numbered step is an isolated `cloudflared` command block with success conditions and troubleshooting.
1086
+
1087
+ ## Dashboard operations the CLI cannot do
1088
+
1089
+ The CLI cannot add a domain, switch accounts, edit an apex CNAME, or delete stray records. `plugins/cloudflare/references/dashboard-guide.md` has one numbered click-path per operation. The agent quotes the relevant steps verbatim when you need to do one of these things.
1090
+
1091
+ ## Troubleshooting
1092
+
1093
+ ### Tunnel won't start
1094
+
1095
+ Ask the agent to check. The agent reads `systemctl --user status ${BRAND}-cloudflared.service` and the cloudflared log under `~/{configDir}/cloudflared/`. Common states:
1096
+
1097
+ - **No cloudflared process running** — the cloudflared service exited or never started. The agent runs the manual-setup flow to re-issue tunnel creation.
1098
+ - **`tunnel not found`** — the UUID in `config.yml` does not match any tunnel on the currently-bound account. Usually follows an account switch that didn't reset local state. The agent runs the reset flow and then a fresh setup.
1099
+
1100
+ ### URL returns 530
1101
+
1102
+ DNS propagation or account mismatch. Wait 30–60 seconds and retry first. If the 530 persists:
1103
+
1104
+ - The domain may be on a Cloudflare account different from the one `cert.pem` is bound to — the agent re-runs the manual setup steps to re-validate.
1105
+ - The UDP buffer for QUIC may be undersized on this device — check the cloudflared log for `failed to sufficiently increase receive buffer size`.
1106
+
1107
+ ### URL returns connection refused
1108
+
1109
+ The tunnel is live but nothing is listening on the platform port. Start the platform service: `systemctl --user start ${BRAND}.service`.
1110
+
1111
+ ### Admin hostname serves the public agent
1112
+
1113
+ `admin.yourdomain` is being misclassified as public. The platform UI treats a host as public when either (a) the hostname starts with `public.`, or (b) the hostname appears in `${CFG_DIR}/alias-domains.json`. Older install flows wrote every routed hostname into `alias-domains.json`; the pollution survives across reinstalls.
1114
+
1115
+ The agent reads `alias-domains.json`, removes the offending `admin.*` entry, and the platform UI hot-reloads — no restart needed. See `plugins/cloudflare/references/reset-guide.md` § "Remove a rogue entry from alias-domains.json" for the exact `jq` command.
1116
+
1117
+ ### DNS not resolving
1118
+
1119
+ The most common cause is wrong nameservers on the domain. The domain must use Cloudflare's nameservers, not the registrar's defaults. In the dashboard: Websites → your domain → status must say **Active**, not **Pending**. If Pending, follow the dashboard's nameserver instructions and wait for propagation.
1120
+
1121
+ ### Remote login issues
1122
+
1123
+ - 5 failed login attempts → 15-minute lockout — wait for expiry.
1124
+ - The remote password is set during Cloudflare Tunnel onboarding — the agent asks for one in chat and stores it deterministically. The browser form at `/__remote-auth/setup` remains available for resets on the local network.
1125
+
1126
+ ## What the agent does and does not do
1127
+
1128
+ **Does:** invokes `cloudflared` directly via Bash, following `plugins/cloudflare/references/manual-setup.md` step by step; quotes click-paths from the reference files verbatim; verifies external reachability with `curl -I` and surfaces the response.
1129
+
1130
+ **Does not:** drive the Cloudflare dashboard via Playwright, browser-automate master-token creation, synthesise alternative `cloudflared` flag sequences not in the runbook, write or echo any API token, write or edit `cert.pem` / `config.yml` directly outside the runbook's instructions.
1131
+
1132
+ When a command fails, the agent reports the failure and cites the relevant recovery step. It does not improvise.
1133
+
1134
+ ---
1135
+ # Access Control
1136
+ Source: https://docs.getmaxy.com/access-control.md
1137
+
1138
+ # Access Control
1139
+
1140
+ ## What It Is
1141
+
1142
+ Access control determines who can chat with your public agent. By default, anyone with your public URL can start a conversation. You can restrict this so only invited people have access, and so the agent remembers each invitee separately without leaking what one visitor said to the others.
1143
+
1144
+ ## Access Modes
1145
+
1146
+ Each public agent has one of two access modes:
1147
+
1148
+ | Mode | Who can chat | What the agent remembers |
1149
+ |------|--------------|--------------------------|
1150
+ | Open (default) | Anyone with the URL. No login required. | Public-scope knowledge only. Nothing per-visitor. |
1151
+ | Gated | Invitation only. Visitors authenticate by clicking a fresh emailed link each session. | A separate per-visitor memory slice. Visitor A and visitor B never see each other's memory. |
1152
+
1153
+ ## How to Set It Up
1154
+
1155
+ Tell SiteDesk: "Set my public agent to gated access" or "Make the coaching agent invitation-only."
1156
+
1157
+ SiteDesk flips the agent's access mode. The next visitor to your public URL sees a sign-in screen instead of the chat.
1158
+
1159
+ ## Inviting Visitors
1160
+
1161
+ Tell SiteDesk: "Invite sarah@client.co to the coaching agent."
1162
+
1163
+ SiteDesk creates an invitation and emails the visitor a magic link. At creation time the invitation is stamped with a one-off `sliceToken` — that token is what binds every per-visitor memory write to this specific invitation for the life of the invite.
1164
+
1165
+ Only email invitations are supported. Phone, OTP, and password flows are not part of the current build.
1166
+
1167
+ ## What Visitors Experience
1168
+
1169
+ - **First visit (invited):** The visitor opens the email and clicks the magic link. They land on your public URL, the cookie is set, and the chat opens. No password to remember.
1170
+ - **Return visits / lost the email:** The visitor visits your URL directly, types the email they were invited on, and clicks "Send me a link." A fresh magic link arrives within seconds. The new link replaces the previous one — old links go inert.
1171
+ - **Browser close:** The cookie is session-only. Closing the tab signs the visitor out. They click the latest magic link, or request a new one, to come back.
1172
+ - **Revoked or expired:** Their next request is bounced back to the sign-in screen. They cannot get past it until you re-invite them.
1173
+
1174
+ ## Per-Visitor Memory
1175
+
1176
+ Every gated visitor has their own ringfenced memory slice. When the agent talks to visitor A, it sees everything tagged with A's slice plus the agent's general public-scope knowledge. It cannot see visitor B's slice, and it cannot see your admin-scope notes. The same gate applies in reverse — nothing the visitor says leaks into your admin graph by accident.
1177
+
1178
+ The slice is populated automatically at the end of each conversation. When a visitor's chat session is reaped (idle timeout, or the visitor closes the tab), a background reviewer reads the transcript and writes anything worth saving into the visitor's slice. The visitor sees the new context the next time they return.
1179
+
1180
+ You can read what's in a visitor's slice via the cypher tools in conversation — "show me what we know about Sarah" — but the slice writes themselves happen autonomously without your involvement.
1181
+
1182
+ ## Managing Access
1183
+
1184
+ All access management is done through conversation with SiteDesk:
1185
+
1186
+ - "Who has access to my coaching agent?" — lists active visitors and their `sliceToken`.
1187
+ - "Revoke Sarah's access" — flips her grant to revoked AND immediately drops her active session, so she cannot continue talking on a live cookie. Her slice's historical memory stays in the graph; you can purge it separately if needed.
1188
+ - "Extend Tom's access by 30 days" — pushes the expiry date forward. Slice unchanged.
1189
+ - "Resend Sarah's invitation" — generates a fresh magic link and emails it. The slice stays the same, so her existing memory carries over.
1190
+
1191
+ Revoking + re-inviting the same person on a new invitation produces a fresh slice — the old slice's memory does not transfer. This is by design: a fresh invitation is a fresh relationship.
1192
+
1193
+ ## Visitor Identity
1194
+
1195
+ When a visitor is authenticated, your public agent knows their name and contact details — it reads them from the visitor's `:Person` node, which is linked to their grant. It can personalise responses ("Welcome back, Sarah") without needing to ask.
1196
+
1197
+ ## Action Approval
1198
+
1199
+ External-facing actions — sending emails, WhatsApp messages, Telegram messages, and erasing contacts — require your approval before SiteDesk executes them. This is human oversight as required by the EU AI Act.
1200
+
1201
+ When SiteDesk needs to send a message or perform a consequential action, it drafts the action and queues it for your review. You'll see it in your next chat turn:
1202
+
1203
+ - "Approve it" — SiteDesk executes the action immediately
1204
+ - "Reject it" — the action is cancelled
1205
+ - "Change the subject to X" — SiteDesk modifies the action and executes the edited version
1206
+
1207
+ Internal operations (creating tasks, updating contacts, searching memory) execute automatically without approval.
1208
+
1209
+ ### Changing the Policy
1210
+
1211
+ Tell SiteDesk to change which actions require approval:
1212
+
1213
+ - "Auto-send follow-up emails from now on" — emails execute without approval
1214
+ - "Require approval for all WhatsApp messages" — restores the default gating
1215
+ - "What actions currently require my approval?" — lists the current policy
1216
+
1217
+ Changes are per-account and take effect immediately.
1218
+
1219
+ ## Filesystem Access (SMB Share)
1220
+
1221
+ Brand isolation extends to the device filesystem. Every SiteDesk install provisions an SMB share scoped to that brand's install folder, credentialled by the brand's install owner and the SiteDesk PIN. A device that hosts more than one brand carries one share per brand; tearing one brand down never exposes another brand's files. See [Samba Share](./samba.md) for the credential model, per-OS mount syntax, and peer-brand lifecycle.
1222
+
1223
+ ---
1224
+ # Settings
1225
+ Source: https://docs.getmaxy.com/settings.md
1226
+
1227
+ # Settings
1228
+
1229
+ ## Output Style
1230
+
1231
+ Controls how SiteDesk communicates with you.
1232
+
1233
+ | Style | Behaviour |
1234
+ |-------|-----------|
1235
+ | `default` | Concise, direct responses — gets to the point |
1236
+ | `explanatory` | More detailed responses with educational context — explains reasoning and trade-offs |
1237
+
1238
+ **Changing output style:** Tell SiteDesk "Switch to explanatory mode" or "Use default output style."
1239
+
1240
+ Changes take effect on the next session. The current session continues with the existing style.
1241
+
1242
+ ## Effort Level
1243
+
1244
+ Controls how much work SiteDesk puts into each task — specifically, how many steps it takes before stopping and checking with you.
1245
+
1246
+ | Level | Max turns | Use when |
1247
+ |-------|-----------|----------|
1248
+ | `low` | 5 | Quick questions, simple lookups |
1249
+ | `medium` | 10 | Standard tasks — most daily use |
1250
+ | `high` | 20 | Complex multi-step tasks |
1251
+ | `auto` | 20 | Let SiteDesk decide (same ceiling as high) |
1252
+ | `max` | 40 | Long autonomous workflows |
1253
+
1254
+ **Changing effort level:** Tell SiteDesk "Set effort to high" or "Use low effort mode."
1255
+
1256
+ Changes take effect on the next session.
1257
+
1258
+ ## Thinking View
1259
+
1260
+ Controls how SiteDesk's thinking process is displayed in the chat.
1261
+
1262
+ | Mode | Behaviour |
1263
+ |------|-----------|
1264
+ | `default` | Thinking steps shown expanded, tool use collapsed |
1265
+ | `expanded` | Everything shown expanded — thinking, tool use, and results |
1266
+ | `collapsed` | Everything collapsed — compact view, expand on tap |
1267
+
1268
+ **Changing thinking view:** Tell SiteDesk "Show thinking by default", "Show everything expanded", or "Hide thinking."
1269
+
1270
+ Changes take effect on the next session.
1271
+
1272
+ ## Viewing Current Settings
1273
+
1274
+ Ask SiteDesk: "What are my current settings?" or "What output style am I using?"
1275
+
1276
+ ## Default Agent
1277
+
1278
+ Controls which public agent serves the root URL (`/`). Visitors who go to your public site without specifying an agent slug see this agent.
1279
+
1280
+ **Changing the default agent:** Tell SiteDesk "Make sales the default agent" or "Set the default to support."
1281
+
1282
+ The change takes effect on the next page load. The previous default agent remains accessible at its `/{slug}` URL.
1283
+
1284
+ ## Account Preferences
1285
+
1286
+ You can ask SiteDesk to show or change any of the following:
1287
+
1288
+ - Default agent (which public agent serves the root URL)
1289
+ - Admin model (which Claude model powers the admin agent)
1290
+ - Public model (which Claude model powers the public agent)
1291
+ - Output style
1292
+ - Effort level
1293
+ - Context mode
1294
+ - Enabled plugins
1295
+
1296
+ Tell SiteDesk what you want to change and it handles the rest.
1297
+
1298
+ ## PIN
1299
+
1300
+ Your admin PIN is set during initial setup. To change it, ask SiteDesk: "Change my admin PIN."
1301
+
1302
+ SiteDesk will ask for your current PIN to verify, then set the new one.
1303
+
1304
+ ## Adding admins
1305
+
1306
+ To add another admin to your account, tell SiteDesk: "Add {name} as an admin with PIN {pin}." SiteDesk creates the device-level user entry (`users.json`), the account-level role entry (`account.json` admins[]), and the graph identity (Neo4j AdminUser node) — the three stores stay in lockstep. If any leg fails, SiteDesk returns an error naming exactly which store is dirty and what was already written; the admin record is partial and may need manual reconciliation. PINs are unique across all users on the device — a new admin needs a PIN no one else on the device is using.
1307
+
1308
+ If you ask SiteDesk to add an admin with a specific PIN and it returns a tier-cap or PIN-collision error, repeat the request with the same PIN every time you retry — otherwise SiteDesk auto-generates a different 4-digit PIN, silently substituting what you asked for.
1309
+
1310
+ ---
1311
+ # Contacts
1312
+ Source: https://docs.getmaxy.com/contacts-guide.md
1313
+
1314
+ # Contacts Guide
1315
+
1316
+ ## What a Contact Is
1317
+
1318
+ A contact is a Person node in SiteDesk's memory graph. Each person has a first name and at least one identifier — email address, phone number, or both. Optional fields include last name and job title. Contacts are linked to conversations, other people, and business context.
1319
+
1320
+ ## Adding a Contact
1321
+
1322
+ Tell SiteDesk naturally:
1323
+
1324
+ - "Add John Smith to my contacts — he's a potential client I met at the conference"
1325
+ - "Create a contact for sarah@acme.com, her name is Sarah Chen, she's the head of procurement at Acme"
1326
+ - "Add Hazel to contacts, phone +27747309676, she's a virtual assistant"
1327
+
1328
+ SiteDesk will extract the details and confirm the record before saving.
1329
+
1330
+ Required: first name and at least one of email or phone number. Everything else is optional but useful.
1331
+
1332
+ ## Looking Up a Contact
1333
+
1334
+ Ask naturally:
1335
+
1336
+ - "What do you know about John Smith?"
1337
+ - "Look up Sarah Chen"
1338
+ - "Find the contact from Acme procurement"
1339
+ - "Look up +27747309676"
1340
+
1341
+ SiteDesk searches by name, email, phone number, or any detail you provide.
1342
+
1343
+ ## Updating a Contact
1344
+
1345
+ Tell SiteDesk what changed:
1346
+
1347
+ - "Update John Smith's email to john@newcompany.com"
1348
+ - "Add a note to Sarah Chen's record: prefers evening calls"
1349
+ - "John Smith is now at Horizon Capital, not Acme"
1350
+
1351
+ ## Listing Contacts
1352
+
1353
+ - "List all my contacts"
1354
+ - "Show me everyone from Acme"
1355
+ - "Who are my contacts in fintech?"
1356
+
1357
+ ## Deleting a Contact
1358
+
1359
+ To remove a single contact from the graph:
1360
+
1361
+ - "Delete Dan from my contacts"
1362
+ - "Remove the duplicate contact for Sarah Chen"
1363
+ - "Delete the contact with email dan@example.com"
1364
+
1365
+ SiteDesk will confirm which Person record matches, then remove the Person node and its direct relationships (e.g. links to conversations, other people) using a graph detach-delete. The contact is gone after confirmation — this cannot be undone.
1366
+
1367
+ This is different from GDPR erasure (`contact-erase`). Deleting a contact removes the Person node from the graph only. GDPR erasure cascades across all data stores — access credentials, conversations, messages, and emails — to satisfy an Article 17 right-to-erasure request. Use "delete" for routine contact cleanup; use "erase all data" when fulfilling a data subject's erasure request.
1368
+
1369
+ ## Exporting Contact Data (GDPR Subject Access)
1370
+
1371
+ When a person requests a copy of all data held about them, ask SiteDesk:
1372
+
1373
+ - "Export all data we hold on john@example.com"
1374
+ - "Show me everything we know about +447700900123"
1375
+
1376
+ SiteDesk gathers the Person record, access credentials, conversation history, and emails into a single structured document. The output is self-contained — it can be handed directly to the data subject to satisfy an Article 15 request.
1377
+
1378
+ ## Erasing Contact Data (GDPR Right to Erasure)
1379
+
1380
+ When a person requests deletion of all their data, ask SiteDesk:
1381
+
1382
+ - "Delete all data we hold on john@example.com"
1383
+ - "Erase everything for Sarah Chen"
1384
+
1385
+ SiteDesk first shows a preview of what would be deleted (counts per data type). Confirm the deletion to proceed. The erasure cascade covers:
1386
+
1387
+ - The Person record itself
1388
+ - All access credentials (AccessGrant nodes)
1389
+ - Conversations and messages attributed to the contact
1390
+ - Emails sent to or from the contact's email address
1391
+
1392
+ The deletion is permanent and irreversible. A receipt is returned listing exactly what was removed.
1393
+
1394
+ Note: server logs may contain residual references to the contact's identifiers. Manual log review is recommended for complete erasure.
1395
+
1396
+ ## Stored Fields
1397
+
1398
+ | Field | Description |
1399
+ |-------|-------------|
1400
+ | `givenName` | First name (required) |
1401
+ | `familyName` | Last name (optional) |
1402
+ | `email` | Email address (identifier — at least one of email or telephone required; used to deduplicate) |
1403
+ | `telephone` | Phone number (identifier — at least one of email or telephone required; used to deduplicate) |
1404
+ | `jobTitle` | Job title or role |
1405
+ | `source` | Where this contact came from (e.g. "public.maxy.bot", "telegram", "manual") |
1406
+ | `status` | Contact status (e.g. "active", "prospect", "booked") |
1407
+ | `createdOn` | When the record was created |
1408
+
1409
+ ---
1410
+ # Memory
1411
+ Source: https://docs.getmaxy.com/memory-guide.md
1412
+
1413
+ # Memory Guide
1414
+
1415
+ ## Brain-first lookup
1416
+
1417
+ The graph is the brain, and every turn that needs to know something runs the same five-step loop in order: (1) classify the question (entity, temporal, event, general, or none — the inbound gateway emits this as `retrievalClass`), (2) read the graph with `memory-search` (and `profile-read` when the question is about the operator) as the first tool call of the turn, (3) walk one hop to hydrate a partial hit before calling it a miss, (4) call an external tool only when steps 2–3 confirmed the graph has nothing useful, and (5) write the external evidence back via `database-operator`. The loop is what makes the next turn smarter; an external call whose result is never persisted is a leak in the brain. `retrievalClass = none` (greetings, meta-instructions) is the only exception. Operator-facing doctrine lives in [`.docs/brain-first.md`](../../../.docs/brain-first.md).
1418
+
1419
+ ## How Memory Works
1420
+
1421
+ SiteDesk maintains a graph of everything you've told it. Contacts, conversations, preferences, relationships, business context — all stored as connected nodes in a local Neo4j database on your Raspberry Pi.
1422
+
1423
+ When you ask SiteDesk about something, it searches this graph first. It retrieves relevant context before responding, which is why SiteDesk can pick up where you left off even across separate sessions.
1424
+
1425
+ The graph lives entirely on your hardware. Nothing is sent to the cloud.
1426
+
1427
+ ## What Gets Remembered
1428
+
1429
+ SiteDesk stores:
1430
+
1431
+ - **Contacts** — people, companies, relationships between them
1432
+ - **Conversations** — key decisions, commitments, follow-ups mentioned in chat
1433
+ - **Preferences** — things you've told SiteDesk about how you like to work
1434
+ - **Context** — project status, ongoing threads, background you've shared
1435
+
1436
+ SiteDesk remembers details you mention naturally: "I'm meeting with Sarah on Thursday" creates a memory that Thursday has a meeting with Sarah.
1437
+
1438
+ ## Telling SiteDesk to Remember Something
1439
+
1440
+ Just say it naturally:
1441
+
1442
+ - "Remember that I prefer morning calls"
1443
+ - "Note that the Johnson account is on hold until March"
1444
+ - "My wife's name is Emma, keep that in mind"
1445
+
1446
+ SiteDesk will confirm and store it.
1447
+
1448
+ ## How SiteDesk learns how you work
1449
+
1450
+ SiteDesk also learns how you work without you having to teach it deliberately. Six broad areas cover the way most operators run a business — communication, scheduling, decisions, workflow, content, and interaction. Inside each area sits a small set of concrete fields (SiteDesk tracks around 28 in total) such as your preferred channel, quiet hours, workday start time, risk tolerance, content tonality, or address form. SiteDesk tracks which of these specific fields you have spoken into and which are still empty. While any are empty, it folds one organic question per turn into the conversation aimed at the next gap — never a list, never a form, never the same question twice. If you tell SiteDesk a field doesn't apply to you ("I work weekends, weekend availability isn't a thing for me"), it marks that field as covered and never re-asks. Once every field is either set or marked not-applicable, the proactive questions stop and SiteDesk answers what you ask without volunteering more. This is why session 300 should feel sharper than session 3: the longer you work together, the less SiteDesk needs to ask.
1451
+
1452
+ ## Telling SiteDesk to Forget Something
1453
+
1454
+ Be direct:
1455
+
1456
+ - "Forget everything about the Johnson account"
1457
+ - "Remove Sarah's contact record"
1458
+ - "Clear what you know about my pricing preferences"
1459
+ - "Delete that pricing guide I uploaded"
1460
+
1461
+ SiteDesk will confirm before deleting anything significant. Documents are soft-deleted first (excluded from search but recoverable for 7 days). Say "permanently delete" to remove immediately.
1462
+
1463
+ ## Managing Documents
1464
+
1465
+ ### Listing files
1466
+
1467
+ Ask: "What files do I have stored?" or "List my attachments"
1468
+
1469
+ SiteDesk shows all uploaded files with their ingestion status — whether they've been processed into the knowledge graph.
1470
+
1471
+ When you upload something for ingestion, SiteDesk emits a one-line size estimate before it starts: short documents (<5K chars) classify in ~10s; mid-size (10K–20K chars) take ~45–90s; very large (>20K) up to ~3 minutes. If the classifier exceeds its 3-minute ceiling SiteDesk aborts loudly with a "Classifier unavailable — timeout" blocker and writes nothing — you can re-upload or split the document.
1472
+
1473
+ ### Reading files
1474
+
1475
+ Ask: "Show me what's in the pricing guide" or "Read the quarterly report"
1476
+
1477
+ SiteDesk returns the full content of text and markdown files, extracted text from PDFs, and metadata for images.
1478
+
1479
+ ### Editing files
1480
+
1481
+ Ask: "Update the pricing in that document" or "Change the introduction paragraph"
1482
+
1483
+ SiteDesk reads the file, makes the edit, and prepares it for re-ingestion into the knowledge graph. Only text and markdown files can be edited — PDFs and images cannot.
1484
+
1485
+ ### Renaming files
1486
+
1487
+ Ask: "Rename that file to quarterly-report-q1.pdf"
1488
+
1489
+ SiteDesk updates the filename in both the stored metadata and the knowledge graph.
1490
+
1491
+ ### Deleting documents
1492
+
1493
+ Ask: "Delete the old pricing guide"
1494
+
1495
+ By default, documents are soft-deleted — they stop appearing in search results but remain recoverable for 7 days. To permanently delete immediately, say "permanently delete" or "force delete".
1496
+
1497
+ ## Searching Memory
1498
+
1499
+ Ask naturally:
1500
+
1501
+ - "What do you know about Tom Henderson?"
1502
+ - "What did I last discuss about the Acme proposal?"
1503
+ - "Who have I met from the fintech conference?"
1504
+
1505
+ ## Thinking tools
1506
+
1507
+ Three slash commands that apply analysis to what's already in your graph:
1508
+
1509
+ **`/challenge <claim>`** — stress-tests an assertion. SiteDesk searches your graph for nodes that contradict or qualify the claim — nodes that assert the opposite, name exceptions, or add significant caveats — and presents the strongest counter-case it finds. If nothing in your graph challenges the claim, it says so rather than inventing one. Results cite node IDs and relevance scores so you can inspect the sources directly.
1510
+
1511
+ **`/connect <topic-A> <topic-B>`** — finds the bridge. SiteDesk searches both topics, collects their immediate graph neighborhoods, and looks for nodes they share. If a direct bridge exists it names it in one sentence. If not, it surfaces the closest approach — the two nodes that are semantically nearest across the two sides — and proposes the connection you could draw.
1512
+
1513
+ **`/emerge`** — names the unnamed clusters. SiteDesk retrieves your KnowledgeDocument and Section nodes that are not yet connected to a Concept node, groups them by shared theme, and proposes a Concept name for each cluster. You approve or skip each proposal one at a time; nothing is written without your confirmation. Clusters of fewer than three nodes are listed at the end as "too small to cluster."
1514
+
1515
+ ## Listing and counting
1516
+
1517
+ SiteDesk answers relational questions — "list all my people", "how many tasks do I have", "find the person with email X", "show me the 20 most recently created nodes" — via direct read-only Cypher against your Neo4j. This is faster and more precise than semantic search when the question is "the exact set where", not "things similar to".
1518
+
1519
+ You can also open a visual view of your graph at any time from the burger menu → **Graph**. Click the **Filter** button in the toolbar to open the filter menu — it lists only the top-level entity types in your schema (Conversation, Person, Task, KnowledgeDocument, …), one row per type, showing your per-type node count and sorted so the most-connected types sit at the top. Child types (messages inside a conversation, sections inside a document), conversation channel variants (admin vs public), message role variants (user vs assistant), and workflow execution plumbing (`ToolCall`, `WorkflowRun`, `WorkflowStep`, `StepResult`) never appear as filter rows — you reach children by clicking the parent and exploring its neighbourhood. Active rows render a force-directed map, coloured by label. Click a node to pivot into its 1-hop neighbourhood; click another node inside that neighbourhood to pivot again. Clicking a Message shows its details in the side panel; the Conversation view stays put — you read sibling messages without losing the chain on canvas. A breadcrumb strip above the canvas shows where you are (`Filter › Conversation › AssistantMessage`). The **Back** control pops one level — three clicks in always undoes with three Back presses; the filter view is the irreducible root. Click the **×** inside the filter menu to clear your chip selection. Type in the search box to highlight matches; submitting a search also widens the filter to include any node types the hits belong to, so relevant matches render instead of disappearing into a "not in current view" banner.
1520
+
1521
+ Conversations and Messages carry role/channel sublabels so you can read the chat topology by colour alone — admin vs public conversations and user vs assistant messages render in distinct shades on the canvas. The filter menu intentionally does not split them into separate rows — the base chip is the entry point; you see the variants as colours once you're inside a neighbourhood.
1522
+
1523
+ **Save a default view:** once you have the rows you want, click **Set default view** in the filter menu. Next time you open **Graph**, those rows are pre-selected and your data renders immediately. The default is per-admin, per-account — each admin on each account has their own.
1524
+
1525
+ **Delete a node:** drag it to the trash icon top-right of the canvas. No confirmation — deletes are reversible for 30 days. To restore, toggle **Show trashed** inside the filter menu and click **Restore** on the node, or ask SiteDesk in chat ("restore the <label> I just deleted"). Deleting a conversation also trashes its messages in the same step, so they reappear together on restore.
1526
+
1527
+ **Bulk cleanup of conversations in chat:** when you ask SiteDesk to clean up conversations in bulk ("trash all empty conversations," "clean up the single-assistant tests"), the agent uses a deterministic selector with a fixed set of filter names — it cannot author custom delete queries. The server re-runs the same filter on every candidate before it trashes, so a stale list can't destroy something the filter wouldn't match now. If the filter matches nothing, SiteDesk reports "no candidates" and nothing happens.
1528
+
1529
+ The page reads only your own brand's Neo4j — a SiteDesk device and a Real Agent device share no graph state even when on the same laptop. No credentials are required; the view inherits your admin session.
1530
+
1531
+ **Typo-proof cypher.** When SiteDesk runs direct Cypher to answer a relational question, the query is checked against your Neo4j's live label and relationship-type taxonomy before it executes. Cypher that references an unknown name (an edge or label that does not exist in your graph) is rejected for writes and flagged with a warnings header for reads, so SiteDesk never silently acts on a query that targeted the wrong set of nodes. You should not see this — it runs invisibly — but it is the safety net that stops a fabricated edge name from producing "empty" results that are really just unreachable. Before acting on a bulk operation SiteDesk surfaces the result count and a sample; if it ever describes a cypher rejection, that means its first attempt was malformed and it corrected itself.
1532
+
1533
+ ## Bi-temporal timeline events
1534
+
1535
+ Every factual statement SiteDesk extracts from your conversations is stored as a `:TimelineEvent` node. Each event carries two separate timestamps:
1536
+
1537
+ - **`occurredAt`** (valid-time) — when the fact was true in the world. Set from the text itself; can reference a date in the past ("Alice joined in 1990" stores `occurredAt = 1990-01-01`).
1538
+ - **`learnedAt`** (transaction-time) — when the system ingested this event. Always the wall-clock time of the write; never back-dated.
1539
+
1540
+ This distinction lets you ask two qualitatively different questions:
1541
+
1542
+ - *"What happened to Alice in 1990?"* — query by `occurredAt`.
1543
+ - *"What did SiteDesk learn about Alice last Tuesday?"* — query by `learnedAt`.
1544
+
1545
+ `memory-compiled-truth-history` returns both fields for every timeline event on an entity under the `timelineEvents` array, alongside the compiled-truth revision history in the `revisions` array.
1546
+
1547
+ **Backfill:** Timeline events written before this feature was added have `learnedAt` set to their `createdAt` value by the schema migration. Events without `createdAt` (very old nodes) receive the migration run time as an approximation.
1548
+
1549
+ ## Write doctrine
1550
+
1551
+ Every new node in SiteDesk's graph is created with at least one connection to an existing node. A contact connects to the conversation or organisation it came from; a task connects to the session that raised it or the entities it will affect; a session summary connects to the conversation it summarises. A node with no connection is noise — it cannot be attributed, traversed, or explained — so the graph refuses to create one. If SiteDesk ever tries to record something without a link, the write is rejected and SiteDesk asks you to clarify where it belongs.
1552
+
1553
+ Every node also carries a provenance stamp — which agent wrote it, in which session, via which tool. You never see these fields, but they are how operators trace unusual growth back to the code path that produced it, and why your graph stays clean over time.
1554
+
1555
+ **Two write surfaces, one substrate.** General agents write through schema-aware helpers — SiteDesk can record a new contact, a new commitment, a new preference without ever typing a database query, and the helper enforces the connection-and-provenance rule above structurally. The graph-steward role (the specialist SiteDesk dispatches when you ask for graph hygiene — "merge those two duplicate contacts," "wire those four tasks to the meeting," "rename the legacy label across the graph") additionally has a raw Cypher write tool for the multi-step operations the helpers cannot express. The steward role internalises the same connection-and-provenance discipline in its prompt; a post-write audit emits a warning on every breach so the same rules apply to both surfaces. Both paths feed the same hourly orphan trend and the same forensic provenance fields — read-side, you cannot tell the two apart, and that is the point.
1556
+
1557
+ ## Vertical schemas
1558
+
1559
+ On top of the base graph, each brand boots one optional **vertical** — an extra set of entity types tailored to a trade. The vertical is named by `brand.json#vertical` and defined in a `schema-<name>.md` reference; the memory plugin loads it at startup and validates every write against base + the active vertical. Real Agent boots `schema-estate-agent` (Listing, Property, Viewing, Offer). SiteDesk boots `schema-construction`, which adds the building-contractor entities — `Job`, `LineItem`, `Valuation`, `Milestone`, `QuoteDocument`, `VariationNote`, `InboundInvoice`, `WhatsAppGroup` — grounded in real builder job folders so a job's quote, valuations, variations, and received supplier and subcontractor invoices all hang off one `Job` node. The default SiteDesk brand boots no vertical (base graph only).
1560
+
1561
+ ## Public-facing summaries for customer-readable subjects
1562
+
1563
+ Some entities in your graph are knowable by people outside your team — companies you work with, projects you've delivered, the business itself. For those entities (SiteDesk treats `:Organization`, `:Concept`, `:Project`, and `:LocalBusiness` this way), SiteDesk maintains two summaries: a private one only you and your specialist agents see, and a customer-facing public one your public agents are allowed to surface.
1564
+
1565
+ Whenever SiteDesk updates the private summary on one of these entities, it automatically rewrites the public summary in the same step using a separate prompt that strips operator-voice ("needs follow-up", "action: chase next week"), internal sentiment, and anything that reads like a note-to-self. The two summaries stay in lockstep without you doing anything.
1566
+
1567
+ If you want to write the public summary yourself — for instance, because the auto-generated version misses something you want customers to see — just tell SiteDesk the wording you want for the public summary on that entity, and SiteDesk will write it directly. It stays locked in for seven days; after that, the next automatic refresh can take over again, unless you re-pin it.
1568
+
1569
+ People entries (`:Person`) are deliberately excluded from this dual-summary system. Notes about contacts are private by definition and never get a public-facing form.
1570
+
1571
+ ## Privacy
1572
+
1573
+ All memory is stored on your local Raspberry Pi. The Neo4j database never leaves your network. SiteDesk does not sync memory to any cloud service or third party.
1574
+
1575
+ If you want to wipe everything and start fresh, ask: "Reset my memory graph." SiteDesk will ask for confirmation before doing so.
1576
+
1577
+ ---
1578
+ # Projects
1579
+ Source: https://docs.getmaxy.com/projects-guide.md
1580
+
1581
+ # Projects Guide
1582
+
1583
+ ## What a Project Is
1584
+
1585
+ A project is a named body of work with multiple steps, dependencies, and a lifecycle. Unlike standalone tasks, a project has child work items that can depend on each other, a health signal that tracks progress, and lifecycle phases (planning, active, blocked, verifying, complete, abandoned).
1586
+
1587
+ Projects are ideal when the user has work involving multiple people, sequential steps, or deliverables — a kitchen refit, a client engagement, a product launch.
1588
+
1589
+ ## Creating a Project
1590
+
1591
+ Tell SiteDesk naturally:
1592
+
1593
+ - "Create a project for Mrs. Chen's kitchen refit — strip the old kitchen, plumbing first fix, electrical first fix, install units, then tiling and finishing"
1594
+ - "Set up a project for the bathroom renovation, standard tier, due by end of June"
1595
+ - "Start a project: boiler install for Sarah Thompson, quick job, just order parts, install, and test"
1596
+
1597
+ SiteDesk creates the project and all work items in one step. Dependencies between steps (e.g., "install units after plumbing and electrical") are set up automatically based on the order and relationships you describe.
1598
+
1599
+ Each project has a tier that reflects its complexity:
1600
+ - **Quick** — straightforward, few steps (e.g., boiler install)
1601
+ - **Standard** — moderate complexity, multiple phases (e.g., kitchen refit)
1602
+ - **Full** — significant scope, many dependencies (e.g., new build project)
1603
+
1604
+ ## Checking Project Status
1605
+
1606
+ Ask naturally:
1607
+
1608
+ - "What are my projects?"
1609
+ - "How's the kitchen refit going?"
1610
+ - "Show me the Davies bathroom project"
1611
+ - "What should I focus on?"
1612
+
1613
+ SiteDesk shows project health at a glance:
1614
+ - **Green** — on track, no issues
1615
+ - **Amber** — warning signs (overdue task or blocker)
1616
+ - **Red** — at risk (multiple overdue, critical blocker, or stale)
1617
+
1618
+ When you start a new conversation, SiteDesk automatically shows active project summaries so you know where things stand without asking.
1619
+
1620
+ ## Updating a Project
1621
+
1622
+ Tell SiteDesk when things change:
1623
+
1624
+ - "Move the kitchen refit to the active phase"
1625
+ - "The materials for the kitchen refit are delayed by a week"
1626
+ - "Update the Davies bathroom target date to July 15th"
1627
+ - "Change the boiler install to a standard tier — it's more complex than we thought"
1628
+
1629
+ SiteDesk records phase changes and issues as part of the project's history, creating an audit trail.
1630
+
1631
+ ## Completing a Project
1632
+
1633
+ Tell SiteDesk:
1634
+
1635
+ - "Mark the boiler install as done"
1636
+ - "Complete the kitchen refit project"
1637
+
1638
+ If any work items are still pending, SiteDesk will let you know and ask how to handle them — cancel, defer, or keep working on them.
1639
+
1640
+ ## Abandoning a Project
1641
+
1642
+ If a project is no longer needed:
1643
+
1644
+ - "Abandon the Davies bathroom — client cancelled"
1645
+ - "Stop the kitchen refit project"
1646
+
1647
+ SiteDesk records the reason and marks the project as abandoned.
1648
+
1649
+ ## Projects vs. Tasks
1650
+
1651
+ Use a **task** for standalone work — a single action, a reminder, a follow-up. Use a **project** when the work has multiple steps that depend on each other, a client or stakeholder, and a lifecycle that progresses through phases.
1652
+
1653
+ When you describe multi-step work, SiteDesk will ask if you'd like to structure it as a project. Over time, it learns your preference and stops asking.
1654
+
1655
+ ## Working a Task End to End
1656
+
1657
+ Ask SiteDesk naturally:
1658
+
1659
+ - "What's outstanding?"
1660
+ - "What's on my plate?"
1661
+ - "What should I work on next?"
1662
+ - "Pick something to do"
1663
+
1664
+ SiteDesk reads the ready set for your account, groups the open Tasks under their parent Projects, and asks you to pick one. You pick — it never auto-selects.
1665
+
1666
+ Once you pick, the loop runs end to end:
1667
+
1668
+ 1. **Grounding** — pulls the Task and its surrounding context (parent Project, related documents, prior conversation) so the run starts from what is already known, not a blank slate.
1669
+ 2. **Delegation** — routes the work to the right specialist surface. A research task goes to deep-research, an email reply to email composition, a document to professional-document, and so on. Nothing is reimplemented inline.
1670
+ 3. **Write-back** — every artefact produced (document, email, ingested file) is linked to the Task in the graph, progress is logged on the Task, and the Task is closed when done.
1671
+
1672
+ This means you can always trace a finished piece of work back to the Task that asked for it, and a Task that says "complete" always has its output attached.
1673
+
1674
+ Cross-account access is refused. A Task that belongs to a different account on the same install is invisible to this loop — SiteDesk will not read it, name it, or surface it.
1675
+
1676
+ ---
1677
+ # Slides
1678
+ Source: https://docs.getmaxy.com/slides.md
1679
+
1680
+ # Slides — user guide
1681
+
1682
+ The Slides plugin turns a description into a finished, self-contained HTML slide deck. The output is one `deck.html` file — inline CSS and JavaScript, no build step, no dependencies beyond Google Fonts. Open it in any browser, navigate with arrow keys or swipe, and press `P` to export to PDF.
1683
+
1684
+ ## When to use it
1685
+
1686
+ - You need a deck and want to describe what to say rather than format slides by hand.
1687
+ - You have an existing `deck.html` and want to add slides, restyle it, or get a critique.
1688
+ - You want a presentation that lives as plain text — version-controllable, diffable, and readable without a binary editor.
1689
+
1690
+ ## The commands
1691
+
1692
+ - **`/slides`** — generate a complete deck from a description. Auto-detects the best storytelling format (talk, pitch, sales, board, product launch) and writes a single `deck.html`. You can pass the brief inline (`/slides "a 20-minute talk on AI-assisted development"`) or run it bare and describe in the follow-up.
1693
+ - **`/slides-outline`** — draft just the structure (section-by-section) without producing HTML, so you can agree the narrative first.
1694
+ - **`/add-slide`** — insert one or more slides into an existing deck, matching its theme and components.
1695
+ - **`/slides-theme`** — restyle a deck. Three built-in themes: **Default** (warm, editorial), **Craft** (richer textures, art overlays), **Solid** (glass morphism, gradients). Any other argument is treated as a custom theme described in text or extracted from an attached image.
1696
+ - **`/slides-review`** — critique the current deck on storytelling, design, and voice consistency.
1697
+ - **`/slides-new-component`** — build a new reusable slide component aligned with the design system's tokens.
1698
+ - **`/slides-claus`** — generate a deck using the Solid theme with the Claus storytelling structure.
1699
+
1700
+ ## Storytelling formats
1701
+
1702
+ `/slides` routes to one of six narrative structures based on your brief: conference **talk** (TED-style), **Sequoia** investor pitch, McKinsey **SCR** (situation-complication-resolution), **product launch**, **board update**, and **sales**. Name the format in your brief to force one explicitly.
1703
+
1704
+ ## What you get
1705
+
1706
+ A 25-component design system (title slides, metric cards, quotes, comparison tables, timelines, and more), responsive layout, and three interchangeable themes — all inside one portable file.
1707
+
1708
+ ## Notes
1709
+
1710
+ This is a frozen, vendored copy of the open-source Slides™ framework (MIT). It ships installed and available on every account; enable it per session like any other plugin if it is not already active.
1711
+
1712
+ ---
1713
+ # Telegram
1714
+ Source: https://docs.getmaxy.com/telegram-guide.md
1715
+
1716
+ # Telegram Guide
1717
+
1718
+ ## What the Telegram Plugin Does
1719
+
1720
+ The Telegram plugin connects SiteDesk to a Telegram bot. Once set up, you can:
1721
+
1722
+ - Send messages to individuals or groups via SiteDesk ("Send a message to the team: standup in 10 minutes")
1723
+ - Receive messages from your Telegram bot and have SiteDesk respond
1724
+ - Use Telegram as a channel for SiteDesk notifications and alerts
1725
+
1726
+ ## Setup
1727
+
1728
+ ### Step 1: Create a Telegram bot
1729
+
1730
+ 1. Open Telegram and search for `@BotFather`
1731
+ 2. Send `/newbot` and follow the prompts to choose a name and username
1732
+ 3. BotFather will give you a token — it looks like `123456789:ABCdefGhijklMNOpqrstUVWxyz`
1733
+ 4. Keep this token — you'll need it in the next step
1734
+
1735
+ ### Step 2: Connect the plugin
1736
+
1737
+ Tell SiteDesk: "Set up Telegram" or "Configure the Telegram bot." Setup runs entirely in the admin chat — there is no settings page.
1738
+
1739
+ SiteDesk asks for your bot token, then asks whether this is an **admin bot** (only your numeric Telegram IDs may message it) or a **public bot** (customer-facing, with a DM policy). It verifies the token, registers the bot's webhook on your brand's edge, stores the token under your brand's config (never in a shared system directory), and — for a public bot — sets the agent that will answer. The bot is now connected.
1740
+
1741
+ ### Step 3: Start the bot
1742
+
1743
+ In Telegram, open your bot and send `/start`, then a message. SiteDesk receives it and replies in the same chat. Admin-bot messages from your registered IDs reach the admin agent; public-bot messages reach the public agent you selected.
1744
+
1745
+ ## Sending Messages via SiteDesk
1746
+
1747
+ Once connected, tell SiteDesk to send messages on your behalf:
1748
+
1749
+ - "Send a Telegram message to John: I'll be 10 minutes late"
1750
+ - "Message the team channel: server maintenance at 11pm"
1751
+ - "Tell Sarah via Telegram that the proposal is ready"
1752
+
1753
+ SiteDesk needs a chat ID or username to target a specific person or group. For groups, you'll need to add the bot to the group first.
1754
+
1755
+ ## Getting a Chat ID
1756
+
1757
+ To message a specific person or group, SiteDesk needs their chat ID. The easiest way:
1758
+
1759
+ 1. Have the person (or yourself) send any message to your bot
1760
+ 2. Ask SiteDesk: "What chat IDs have messaged the bot recently?"
1761
+ 3. SiteDesk will look up the message history and show you the IDs
1762
+
1763
+ ## Message History
1764
+
1765
+ Ask SiteDesk: "What messages has the bot received?" or "Show recent Telegram activity."
1766
+
1767
+ ## Troubleshooting
1768
+
1769
+ **Bot not responding:** Check that the bot token is correct — ask SiteDesk "What's my Telegram bot token configured as?" and verify it matches BotFather.
1770
+
1771
+ **Can't send to a group:** The bot must be a member of the group. Add it via the group settings in Telegram, then try again.
1772
+
1773
+ **Messages not arriving:** Make sure the bot hasn't been blocked. Try sending `/start` to the bot directly.
1774
+
1775
+ ---
1776
+ # Outlook
1777
+ Source: https://docs.getmaxy.com/outlook-guide.md
1778
+
1779
+ # Outlook Plugin — Operator Guide
1780
+
1781
+ The `outlook` plugin gives the admin agent read-only access to Microsoft 365 / Outlook.com via Microsoft Graph. Per-account OAuth (Auth Code + PKCE), encrypted token storage, automatic refresh.
1782
+
1783
+ ## Quickstart
1784
+
1785
+ 1. **Register an Entra app once per SiteDesk install** — see `platform/plugins/outlook/references/auth.md` for full steps. Set `OUTLOOK_CLIENT_ID` (and `OUTLOOK_TENANT_ID`, default `common`) in the operator's environment.
1786
+ 2. **Per account: register the Outlook account** — in admin chat, ask the agent to "register my Outlook account". The agent runs `outlook-account-register`, which prints an authorization URL.
1787
+ 3. **Open the URL in the VNC browser** — sign in to your Microsoft account, consent to the requested scopes (`offline_access`, `User.Read`, `Mail.Read`, `Calendars.Read`, `Contacts.Read`).
1788
+ 4. **Done.** Subsequent tool calls (mail, calendar, contacts) use the persisted refresh token transparently.
1789
+
1790
+ ## Tools
1791
+
1792
+ | Tool | Purpose |
1793
+ |------|---------|
1794
+ | `outlook-account-register` | Run the PKCE flow for this account. One-time per account; re-run if tokens expire (90 days) or consent is revoked. |
1795
+ | `outlook-mail-list` | Recent mail. Default top=25, folder=Inbox. |
1796
+ | `outlook-mail-search` | Microsoft Graph `$search` over the mailbox. |
1797
+ | `outlook-calendar-list` | Calendar events in next rangeDays days (default 7, max 365). |
1798
+ | `outlook-calendar-event` | Full detail of a single event by id. |
1799
+ | `outlook-contacts-list` | Top contacts. Default top=50. |
1800
+ | `outlook-mailbox-info` | Health probe — auth state, refresh-window, folder count. |
1801
+
1802
+ ## Observability
1803
+
1804
+ All log lines start with `[outlook-mcp]` and write to `server.log`. They are key=value, account-scoped:
1805
+
1806
+ | Event | Line shape |
1807
+ |-------|------------|
1808
+ | Auth init | `auth-init account=<id> codeChallenge=<sha256-prefix-8> redirectPath=<callback-path>` |
1809
+ | Auth callback | `auth-callback account=<id> elapsedMs=<N>` |
1810
+ | Auth ok | `auth-ok account=<id> graphUserId=<id> scopes=<csv> tokenExpSec=<N>` |
1811
+ | Token refreshed | `token-refreshed account=<id> oldExpSec=<N> newExpSec=<N>` |
1812
+ | Refresh failed | `token-refresh-failed account=<id> reason=<err>` (terminal) |
1813
+ | Mail list | `mail-list account=<id> folder=<id-or-Inbox> count=<N> elapsedMs=<N>` |
1814
+ | Mail search | `mail-search account=<id> query=<trunc-32> count=<N> elapsedMs=<N>` |
1815
+ | Calendar list | `calendar-list account=<id> rangeDays=<N> count=<N> elapsedMs=<N>` |
1816
+ | Calendar event | `calendar-event account=<id> eventId=<trunc-12> elapsedMs=<N>` |
1817
+ | Contacts list | `contacts-list account=<id> count=<N> elapsedMs=<N>` |
1818
+ | Mailbox info | `mailbox-info account=<id> tokenWithinRefreshWindow=<bool> folderCount=<N>` |
1819
+ | Graph error | `graph-error account=<id> status=<N> code=<graphErrorCode> retryAfterMs=<N-or-null>` |
1820
+ | On-prem rejected | `on-prem-rejected account=<id> mailServer=<host>` (terminal) |
1821
+
1822
+ ## Diagnostic paths
1823
+
1824
+ ```bash
1825
+ # All outlook lines for one account, last 50
1826
+ ssh laptop 'grep -E "^\[outlook-mcp\]" ~/.maxy/logs/server.log | grep "account=<id>" | tail -50'
1827
+
1828
+ # Token-leak audit — must always return zero
1829
+ grep -rn -iE "Bearer |access_token=" ~/.maxy/logs/server.log | head
1830
+ ```
1831
+
1832
+ Latency triage: `mail-list count=0 elapsedMs<200` consistent → permissions issue; `elapsedMs > 5000` → Graph slowness or DNS.
1833
+
1834
+ ## Failure modes
1835
+
1836
+ | Operator-visible message | Cause | Fix |
1837
+ |---|---|---|
1838
+ | `Outlook not connected for account=X; run outlook-account-register` | Tokens never saved | Run register tool |
1839
+ | `Outlook refresh token expired for account=X; run outlook-account-register` | >90 days since last refresh, or consent revoked | Run register tool |
1840
+ | `Outlook token refresh failed for account=X; re-auth required` | Network down at refresh time, or refresh token invalidated | Verify network; re-register |
1841
+ | `Outlook auth expired for account=X; run outlook-account-register` | Refresh-then-retry still got 401 | Re-register |
1842
+ | `Outlook rate-limited without Retry-After hint` | Graph 429 with no backoff guidance | Wait + retry; if persistent, file bug |
1843
+ | `Microsoft Graph does not support on-premises Exchange. Use earlier platform fixes (IMAP).` | Mailbox is on hybrid Exchange | Use the `email` plugin |
1844
+
1845
+ ## Out of scope
1846
+
1847
+ Write tools (send, draft, move, flag), OneDrive / Files, push notifications, on-premises Exchange, M365 admin scopes (`User.Read.All`, `AuditLog.Read.All`), public-agent exposure, multi-tenant federation. See `platform/plugins/outlook/PLUGIN.md` for the full out-of-scope list.
1848
+
1849
+ ---
1850
+ # QuickBooks Online
1851
+ Source: https://docs.getmaxy.com/quickbooks.md
1852
+
1853
+ # QuickBooks Online
1854
+
1855
+ Connect QuickBooks Online so the agent can read your books and create records — invoices, customers, bills, payments, and reports — over Intuit's REST API.
1856
+
1857
+ QuickBooks Online is the cloud product. Your books live in Intuit's cloud, so every request proves two things: that the connecting app is yours, and that someone authorized it to touch a specific company. SiteDesk ships to your own machine and never runs a shared backend, so it cannot hold one master QuickBooks identity for everyone. Instead you bring your own Intuit app, and its keys are stored only on your install.
1858
+
1859
+ ## What you do once
1860
+
1861
+ **1. Register an Intuit app.** Go to [developer.intuit.com](https://developer.intuit.com), create an app, and turn on the Accounting scope. Copy the app's **client ID** and **client secret**. In the app's OAuth settings, add a **redirect URI**: your public agent address followed by `/api/quickbooks/callback`. Intuit does not allow `localhost` for live use, which is why the address is your public one. Start with the free **sandbox** keys (Intuit gives you up to five practice companies) before moving to real books.
1862
+
1863
+ **2. Hand the keys to the agent.** Tell the agent your client ID and secret, and whether they are sandbox or production. The agent stores them on your install only.
1864
+
1865
+ **3. Authorize each company.** Ask the agent to start a connection. It gives you a link; you open it, sign in to Intuit, and approve one company. That is the only manual step per company. An accountant with several companies under one app just repeats this for each.
1866
+
1867
+ ## What the agent does after that
1868
+
1869
+ Everything else is automatic. The agent keeps the connection alive on its own, refreshing access behind the scenes, and can:
1870
+
1871
+ - **Read** anything — "show me unpaid invoices since January", "list my customers", "what bills are due this week".
1872
+ - **Pull reports** — profit and loss, balance sheet, aged receivables, for any date range.
1873
+ - **Create and update records** — raise an invoice, add a customer, enter a bill, record a payment.
1874
+
1875
+ ## Keeping it healthy
1876
+
1877
+ A QuickBooks connection goes stale if it sits unused for about 100 days, or if you revoke access from your Intuit account. Ask the agent to run a connection audit now and then; if a company shows as not alive, just re-authorize it with a fresh link. Reading has a generous free monthly allowance and writing is free, so the agent favours precise lookups over pulling everything.
1878
+
1879
+ ## Moving to real books
1880
+
1881
+ Switching your Intuit app from sandbox to production requires passing Intuit's own production security review. That is between you and Intuit; it is not something the agent does for you.
1882
+
1883
+ ---
1884
+ # LinkedIn Extension
1885
+ Source: https://docs.getmaxy.com/linkedin-extension.md
1886
+
1887
+ # LinkedIn Extension — operator guide
1888
+
1889
+ Capture a LinkedIn profile or DM thread to your SiteDesk graph with one click. The plugin ships a small Chrome extension; the admin already knows how to receive its payloads.
1890
+
1891
+ ## Install (one time)
1892
+
1893
+ 1. Open `chrome://extensions`.
1894
+ 2. Toggle **Developer mode** on (top right).
1895
+ 3. Click **Load unpacked**.
1896
+ 4. Select `platform/plugins/linkedin-extension/extension/` on disk.
1897
+ 5. Click the puzzle icon → pin **SiteDesk LinkedIn Ingest** → open its options.
1898
+ 6. Paste two values:
1899
+ - **Admin host** — your tunnel URL, e.g. `https://your-tunnel.example.com`.
1900
+ - **Session key** — open your admin browser, copy the value of `session_key` from the cookie. (Same key the admin uses to authenticate every other admin request.)
1901
+ 7. Save. The pill is now armed.
1902
+
1903
+ ## Use
1904
+
1905
+ - **Profile** — open any `https://www.linkedin.com/in/<slug>/` page. An **Add to SiteDesk** pill appears in the top section. Click it. Within a few seconds the pill turns green: the profile is in your graph.
1906
+ - **DM thread** — open any `https://www.linkedin.com/messaging/thread/<id>/` conversation. The same pill appears. Click it; the full transcript is captured plus the participants and any explicit commitments (meetings booked, actions promised, prices discussed).
1907
+ - **Re-click** — the pill is idempotent. Re-clicking the same URL refreshes the document body and regenerates the summary; identities and entities `MERGE` rather than duplicate.
1908
+
1909
+ ## What lands in the graph
1910
+
1911
+ Every click produces **one `:KnowledgeDocument`** keyed on the page URL, holding the verbatim scraped text as its body and a child `:Section:Note` for the LLM summary. Structured entities layer on top, but only when the body **assertively states** them:
1912
+
1913
+ - A `:Person` for the profile subject (or each thread participant), `MERGE`d on canonical keys.
1914
+ - A `:Organization` for an asserted current employer, with a `WORKS_AT` edge from the person.
1915
+ - An `:Event` with `ATTENDED_BY` edges when a meeting time is explicitly proposed and confirmed.
1916
+ - A `:Task` with `RAISED_BY` / `ABOUT` edges when an action is promised without a specific time.
1917
+ - A `:Service` / `:PriceSpecification` when an offer is discussed.
1918
+
1919
+ Soft signals ("interested in chatting", "would love to compare notes") stay in the document body. They are never promoted to graph nodes.
1920
+
1921
+ The plugin will never create `:Communication`, `:ConversationArchive` rows (i.e. KnowledgeDocument nodes that carry `conversationIdentity`), or `:Message` nodes — those shapes are reserved for other flows (live chat, archive ingest).
1922
+
1923
+ ## When the pill turns amber
1924
+
1925
+ The pill shows **Sign in to SiteDesk** when your session key has expired. Click it to open the options page; paste a fresh `session_key` from your admin browser; save. The next click on the LinkedIn pill will succeed.
1926
+
1927
+ ## When the pill turns red
1928
+
1929
+ - **Missing: ...** — LinkedIn shipped a DOM change and the extractor cannot find a required field. Open a console tab on the LinkedIn page and check the `[linkedin-ext-scrape]` log line for the field names. Drop a ticket pointing at the affected selector; the [`SKILL.md`](../../plugins/linkedin-extension/skills/linkedin-extension/SKILL.md) lists the selector table and the steps for adding a fallback.
1930
+ - **Capture failed** — the admin reached, but the request did not complete cleanly. Check the admin logs (`journalctl -u maxy.service | grep linkedin-ingest`). The `[linkedin-ingest-route]` lines name the reason (`schema`, `dispatch-failed`).
1931
+
1932
+ ## Related plugins
1933
+
1934
+ - **linkedin-import** — bulk ingest of the LinkedIn ZIP export (history). Different surface; both ship and complement each other.
1935
+ - **memory.document-ingest** — the generic ingest pipeline this plugin's payloads route through. Future communication surfaces (email, Telegram, WhatsApp) plug in here too.
1936
+
1937
+ ---
1938
+ # Admin Chat Attachments
1939
+ Source: https://docs.getmaxy.com/attachments.md
1940
+
1941
+ # Admin Chat Attachments
1942
+
1943
+ What you can drag-and-drop into the admin chat window, what happens to each file, and the size caps.
1944
+
1945
+ ## Accepted file types
1946
+
1947
+ | Type | MIME | Notes |
1948
+ |------|------|-------|
1949
+ | Images | `image/jpeg`, `image/png`, `image/gif`, `image/webp` | Rendered inline by the agent when relevant. |
1950
+ | PDF | `application/pdf` | The agent reads the text; scanned PDFs go via OCR if available. |
1951
+ | Plain text, Markdown, CSV, HTML | `text/plain`, `text/markdown`, `text/csv`, `text/html` | Read directly. |
1952
+ | Calendar | `text/calendar` | Ingested into the graph if the agent finds a reason to keep it. |
1953
+ | Voice note | `audio/*` | Transcribed before the message is routed to the agent. |
1954
+ | **Zip archive** | `application/zip`, `application/x-zip-compressed` | Unpacked by the agent after safety checks. See below. |
1955
+
1956
+ Anything else is refused at upload time with a message naming the type.
1957
+
1958
+ ## Size caps
1959
+
1960
+ - **Per file:** 50 MB. Enforced at the upload endpoint — files over this limit never reach disk.
1961
+ - **Per message:** up to 5 files.
1962
+ - **Uncompressed contents of a single zip:** 100 MB. A zip whose declared uncompressed total is over this limit is refused before any byte is extracted (decompression-bomb guard).
1963
+
1964
+ ## What happens with a zip archive
1965
+
1966
+ When you drop a `.zip` into chat, the agent:
1967
+
1968
+ 1. **Checks the archive is safe.** It refuses archives that try to write outside their own extraction folder, contain symlinks, are password-protected, or declare more than 100 MB of uncompressed content. You'll see the exact reason in chat if any check fails.
1969
+ 2. **Extracts it to a fresh folder.** Contents land under `{your-account-dir}/extracted/{id}/` — one folder per archive, never mixed.
1970
+ 3. **Lists what's in it.** The agent tells you the top-level entries, the total file count, and the uncompressed size.
1971
+ 4. **Asks before doing anything else.** For each class of file (text/markdown, images, PDFs, other), it proposes one next step — for example "ingest these notes into memory" or "re-attach the images back to chat so you can see them" — and waits for you to say yes.
1972
+
1973
+ Nothing is ingested, sent, or acted on automatically. The extraction is local and visible; you decide what happens next.
1974
+
1975
+ ## What is **not** supported
1976
+
1977
+ - `tar`, `tar.gz`, `7z`, `rar` — zip only. If you have one of these, unzip/convert locally and upload the zip (or the extracted files directly).
1978
+ - Nested archives — a zip-inside-a-zip is extracted one level; you can ask the agent to unpack the inner one afterwards.
1979
+ - Password-protected zips — the agent will tell you to unlock locally and re-upload.
1980
+ - Uploads larger than 50 MB — split the archive, or upload the individual files.
1981
+
1982
+ ## Where the files live
1983
+
1984
+ Uploads go to `{install-dir}/data/uploads/{account-id}/{file-id}/` — outside the platform wipe zone, so they survive re-installs. Extracted zip contents go to `{account-dir}/extracted/{file-id}/`. Both are local to your device.
1985
+
1986
+ ---
1987
+ # Answer Engine Optimisation
1988
+ Source: https://docs.getmaxy.com/aeo.md
1989
+
1990
+ # AEO (Answer Engine Optimisation) — user guide
1991
+
1992
+ The AEO plugin shapes the site for answer engines (Claude, ChatGPT, Perplexity, Google AI Overviews, Bing Copilot). It does three things: emits schema.org JSON-LD from typed graph entities, generates `/llms.txt` and `/llms-full.txt`, and audits any page against eight heuristics.
1993
+
1994
+ ## When to use it
1995
+
1996
+ - A new page is being authored and you want it to be cited when customers ask an answer engine about your service.
1997
+ - An existing page is not being cited. Audit it to find the structural reasons.
1998
+ - You're standing up a new site and want the `llms.txt` pair generated so answer engines can index your content directly.
1999
+
2000
+ ## The tools
2001
+
2002
+ ### `aeo-emit-jsonld`
2003
+
2004
+ Generates a `<script type="application/ld+json">` block for a typed entity. Two modes:
2005
+
2006
+ - **From the graph.** Pass `entityId` (Neo4j elementId of an `Organization`, `Person`, `Service`, `Product`, `CreativeWork`, `FAQPage`, `RealEstateListing`, or `Event`). The tool resolves the entity, maps the label to its schema.org type, and emits the block.
2007
+ - **Inline.** Pass `label` (one of the supported page types) plus a `properties` object. Use this when the page isn't backed by a stored entity (yet) but you want the JSON-LD shape.
2008
+
2009
+ Returns the parsed JSON-LD object and a ready-to-inline script block string. Inline the script in your page `<head>`.
2010
+
2011
+ ### `aeo-write-llms-txt`
2012
+
2013
+ Generates the `llms.txt` / `llms-full.txt` pair for the account. Source is every `KnowledgeDocument` for the account that has a `url` property. Returns both files as strings plus a count of pages skipped because they had no URL.
2014
+
2015
+ Wire the output to your site host. Convention: `/llms.txt` (index) and `/llms-full.txt` (concatenated content), served as `text/plain`. Format follows the current draft at `https://llmstxt.org/`.
2016
+
2017
+ ### `aeo-audit-page`
2018
+
2019
+ Runs the eight-heuristic audit. Pass either `url` (the tool fetches) or `html` (you supply the rendered content). Returns:
2020
+
2021
+ ```
2022
+ {
2023
+ "score": 0–100,
2024
+ "heuristics": [
2025
+ {
2026
+ "name": "structured-answer",
2027
+ "status": "pass" | "warn" | "fail",
2028
+ "detail": "first <p> after <h1> is 142 chars",
2029
+ "suggestion": "Add one ≤280-character <p> immediately after the <h1>…"
2030
+ },
2031
+
2032
+ ],
2033
+ "target": "<url or '(inline html)'>",
2034
+ "audit": { "runAt": "<iso>", "elementId": "<set when persisted>" }
2035
+ }
2036
+ ```
2037
+
2038
+ Pass `persist: true` plus `targetKnowledgeDocumentId` to write the result as an `:AEOAudit` node linked to the document.
2039
+
2040
+ ## The eight heuristics
2041
+
2042
+ | Heuristic | What it checks |
2043
+ |---|---|
2044
+ | `h1-present` | exactly one `<h1>` |
2045
+ | `jsonld-present` | at least one parseable JSON-LD block |
2046
+ | `structured-answer` | first `<p>` after `<h1>` is ≤280 chars |
2047
+ | `faq-section` | `FAQPage` JSON-LD on the page |
2048
+ | `meta-description` | 80–160 char `<meta name="description">` |
2049
+ | `canonical-url` | `<link rel="canonical">` present |
2050
+ | `og-tags` | `og:title` and `og:description` both set |
2051
+ | `heading-hierarchy` | no level skips (h1→h3 etc.) |
2052
+
2053
+ `structured-answer` is the highest-impact: that one paragraph is what gets lifted into the engine's answer. A page can fail every other heuristic and still be cited if this one passes.
2054
+
2055
+ ## Observability
2056
+
2057
+ Every tool emits a single log line per invocation:
2058
+
2059
+ - `[aeo-emit-jsonld] entityId=… schemaType=… source=graph|inline`
2060
+ - `[aeo-llms-txt] site=… pages=… skippedNoUrl=… indexBytes=… fullBytes=…`
2061
+ - `[aeo-audit] target=… score=… fails=… warns=…`
2062
+
2063
+ Diagnostic path: `grep -E '^\[aeo-' platform-logs/*.log | grep <urlOrEntityId>`.
2064
+
2065
+ ## What this plugin does not do
2066
+
2067
+ - **No citation monitor — out of scope.** Tracking whether your brand is cited by Claude / ChatGPT / Perplexity / Gemini would require multi-engine answer harvesting that doesn't fit maxy-code's no-API-key architecture. Archived without sprinting. Check citation manually when needed.
2068
+ - **No auto-emission on page render.** `aeo-emit-jsonld` is callable on demand. Wiring it into the platform's page-generator render path is per-renderer work, filed as a follow-up.
2069
+ - **No publish-hook regeneration of `llms.txt`.** The tool runs on demand. Hooking it into the publish event is a follow-up.
2070
+
2071
+ ## See also
2072
+
2073
+ - Plugin manifest: `platform/plugins/aeo/PLUGIN.md`
2074
+ - Structured-answer template: `platform/plugins/aeo/skills/structured-answer/SKILL.md`
2075
+ - Schema declaration: `platform/neo4j/schema.cypher` (search `AEOAudit`)
2076
+ - Spec source: `https://llmstxt.org/`
2077
+
2078
+ ---
2079
+ # Session Retrospective
2080
+ Source: https://docs.getmaxy.com/session-retrospective.md
2081
+
2082
+ # Insight pass
2083
+
2084
+ When you type `/insight` on its own in an admin session, the admin agent runs one extra review over the session so far, then carries on. It walks the conversation and writes down four kinds of thing that would otherwise be lost:
2085
+
2086
+ - corrections and learnings you gave the agent during the session,
2087
+ - tonal and working-style preferences worth carrying forward,
2088
+ - people, decisions, commitments, or business facts that came up but were not yet saved to the graph,
2089
+ - typed edges between any new prose-bearing nodes (messages, meetings, notes, pages) and the entities they mention — the auto-extraction pass that "wires the graph" so future questions can hop from a person to the companies they founded to the events they attended.
2090
+
2091
+ You can run it whenever you want the brain brought up to date — for example before you open a second session that needs the first session's learnings, preferences, or graph writes.
2092
+
2093
+ The pass is one or two messages from the agent, then a short summary of what was written. It runs inside the session you are already in: nothing happens in the background, no second session is spawned, and the session is not closed, reset, or cleared — the conversation continues straight afterward against the same live state. The typed-edge pass itself is delegated to the `database-operator` specialist so the writes land where graph writes are supposed to live.
2094
+
2095
+ You can tell the pass ran correctly by the final reply naming the five counts (learnings, tonal observations, graph updates, typed edges accepted, prose nodes scanned). The typed-edge pass is scoped by "what changed since the last completed insight pass," so two passes in a row never re-process the same nodes, and a session that never runs one simply defers its extraction to the next time you type `/insight`.
2096
+
2097
+ ---
2098
+ # Visitor Graph
2099
+ Source: https://docs.getmaxy.com/visitor-graph.md
2100
+
2101
+ # Visitor graph
2102
+
2103
+ Behavioural analytics that connect anonymous page visits to known `:Person` contacts. Replaces the anonymous click-through metric with a fully attributed graph.
2104
+
2105
+ ## What this gives the operator
2106
+
2107
+ - A morning briefing surface: "who has been on the site overnight, and what did they look at?"
2108
+ - An engagement-ranked nurture queue, ordered by recency × depth × dwell.
2109
+ - A graph-backed click-through-rate report for property recommendations.
2110
+ - A full event timeline for any one session, for prep and diagnosis.
2111
+ - A signed-cookie that recognises a named visitor on later visits without re-clicking the marketing link.
2112
+
2113
+ ## Data model
2114
+
2115
+ | Node | Meaning |
2116
+ |------|---------|
2117
+ | `:Session` | One browser tab session. Composite key `(accountId, sessionId)`. |
2118
+ | `:AnonVisitor` | Pre-identification browser identity. Merges into `:Person` on first signed-token click. |
2119
+ | `:PageView` | One page load. Carries `referrer`, `path`, optional `dwellMs`. |
2120
+ | `:Click` | One DOM click on a tagged element (`data-track="<label>"`). |
2121
+ | `:ScrollMilestone` | Roll-up of scroll depth — one node per `:PageView`, `maxDepth` ∈ {25,50,75,100}. |
2122
+ | `:Page` | URL metadata. Content-only, survives erasure. |
2123
+ | `:Recommendation` | Materialised `[property-recommended]` log line for CTR computation. |
2124
+
2125
+ | Edge | Direction |
2126
+ |------|-----------|
2127
+ | `VISITED` | `Person → Session` or `AnonVisitor → Session` |
2128
+ | `OWNS_VISITOR` | `Person → AnonVisitor` (cross-session merge) |
2129
+ | `HAS_EVENT` | `Session → PageView / Click / ScrollMilestone` |
2130
+ | `OF_PAGE` | `PageView → Page` |
2131
+ | `OF_LISTING` | `PageView → Listing` |
2132
+ | `FOR_SESSION` | `Recommendation → Session` |
2133
+
2134
+ ## How identity gets resolved
2135
+
2136
+ The signed-token cookie `mxy_v` carries a `:Person` elementId, signed HMAC-SHA256 with a brand-local 32-byte secret (file at `~/.<brand>/credentials/visitor-token-secret`, minted on first read). When the recommender's `/listings/<slug>/click?session=<sk>&v=<token>` URL is visited:
2137
+
2138
+ 1. The click handler verifies the HMAC on `<token>`.
2139
+ 2. If valid, the same token value is written into `mxy_v` (Max-Age 30 days, SameSite=Lax, HttpOnly, Secure).
2140
+ 3. On subsequent visits, `POST /v/event` reads the cookie, verifies it, and attributes every event to the bound `:Person`.
2141
+
2142
+ When a previously-anonymous browser binds for the first time, any `:Session` already attributed to the `:AnonVisitor` is re-attached to the `:Person`, and the merge fires `[anonvisitor-merge]` with the count of reattributed sessions.
2143
+
2144
+ ## Tools
2145
+
2146
+ All under the `real-agent-buyers` plugin, admin-side only:
2147
+
2148
+ | Tool | Purpose |
2149
+ |------|---------|
2150
+ | `visitor-recent-by-person` | Recent sessions for a known `:Person` (morning round, 1:1 prep). |
2151
+ | `visitor-recent-by-page` | Recent visitors of a given listing slug or URL. |
2152
+ | `visitor-engagement-score` | Engagement-ranked `:Person` list (nurture queue). |
2153
+ | `visitor-recommendation-ctr` | Graph-backed CTR over a window, joined from `:Recommendation` and `:Click` nodes. |
2154
+ | `visitor-session-detail` | Full event timeline for one `:Session`. |
2155
+ | `visitor-event-ingest` | Admin companion to `POST /v/event` for test harness work. |
2156
+ | `visitor-backfill-from-logs` | One-shot importer: parses `[property-recommended]` and `[property-card-click]` log lines into the graph; used to recover late-arriving sessions and for ad-hoc forensics. |
2157
+ | `mint-visitor-token` | Mints a signed token bound to a `:Person` for outbound URLs in `morning-round`, `lead-nurturing`, `vendor-updates`. Returns `{ token, expiryMs }`; the agent appends `&v=<token>` to `/listings/<slug>/click?session=<sk>`. Same secret file as the UI server; both processes share it via the wx-create pattern. |
2158
+
2159
+ ## Privacy
2160
+
2161
+ The full description is at `/privacy` on every brand domain. Highlights:
2162
+
2163
+ - First-party cookie only, no third-party scripts.
2164
+ - Retention is erasure-on-request, not time-based; visit data persists until a `:Person` is erased.
2165
+ - Right-to-erasure cascades through `contact-erase`: `:Session`, every `:HAS_EVENT` child, and any owned `:AnonVisitor` are removed when the `:Person` is erased. `:Page` and `:Listing` are content metadata and intentionally preserved.
2166
+
2167
+ ## Verification
2168
+
2169
+ Quick checks the operator can run after deployment:
2170
+
2171
+ 1. Load a published listing page; grep `[visitor-event] type=pageview` in `server.log` within 1s.
2172
+ 2. Scroll past 50%; grep `[visitor-event] type=scroll depth=50`.
2173
+ 3. Click an element marked `data-track="floorplan"`; grep `[visitor-event] type=click label=floorplan`.
2174
+ 4. Run `visitor-backfill-from-logs` over a log window where live writes were lost (process restart, etc.); the response reports `recWritten` and `clickWritten` counts. Subsequent runs over the same window are idempotent for `:Recommendation` and append-only for `:Click`.
2175
+
2176
+ ## Failure signals
2177
+
2178
+ | Symptom | What it means | Where to look |
2179
+ |---------|---------------|---------------|
2180
+ | `[visitor-event]` count drops to zero with no `[v-event-error]` | Pixel silently failing on the brand domain (probably CSP, CORS, or origin mismatch). | Check brand.json `publishedSiteOrigins`; check browser console on a published listing page. |
2181
+ | `[token-bind] reject reason=bad-sig` spikes | HMAC verify failing — either the secret rotated and old cookies are being rejected (expected during rotation) or the recommender is minting against a stale secret. | Compare `~/.<brand>/credentials/visitor-token-secret` across processes. |
2182
+ | `[anonvisitor-merge]` never fires after first signed-token click | The pixel isn't reading the cookie. | Inspect the `mxy_v` cookie in DevTools; check CORS `Access-Control-Allow-Credentials: true`. |
2183
+ | `[v-event-error] reason=rate-limit` for legitimate operator traffic | Operator IP shares a NAT with high-volume crawlers. | Adjust `RATE_LIMIT` in `visitor-event.ts` or whitelist the IP at the proxy. |
2184
+
2185
+ ---
2186
+ # Voice Mirror
2187
+ Source: https://docs.getmaxy.com/voice-mirror-guide.md
2188
+
2189
+ # Voice Mirror Guide
2190
+
2191
+ ## What It Does
2192
+
2193
+ SiteDesk reads emails, posts, documents, and your own chat messages, and uses them to make sure agent-drafted copy reads like you wrote it — not like generic AI prose.
2194
+
2195
+ Anthropic models cannot be fine-tuned. Voice mirror works by feeding the model two things alongside every drafting task:
2196
+
2197
+ - A **style card** distilled from your own writing — sentence length, register, favourite phrases, things you never say.
2198
+ - A handful of **exemplars** — actual paragraphs you wrote, picked for relevance to the current draft.
2199
+
2200
+ The model conditions on both and produces copy that reads as yours.
2201
+
2202
+ Voice mirror maintains a separate profile for each type of content you write: plain text, email, social posts, articles, notes, and marketing copy. The right profile is applied automatically based on what you're drafting.
2203
+
2204
+ When SiteDesk produces anything that will go out under your name (a document, public-facing copy, anything you will send onward), it applies your voice before it writes the first line, not after you ask for a rewrite. You do not have to request it.
2205
+
2206
+ ## How Your Voice Is Captured
2207
+
2208
+ ### Automatically — from chat
2209
+
2210
+ Every admin chat session feeds your writing into the `text` profile automatically. When the session ends, SiteDesk reads the transcript, filters out slash commands, system messages, and large paste blocks, and adds each genuine turn as a corpus entry. This happens in the background with no action needed from you.
2211
+
2212
+ ### Via backfill — from historical content
2213
+
2214
+ Use the backfill flow to teach SiteDesk your writing from emails, documents, and social posts you've already written.
2215
+
2216
+ In the admin chat, ask: **"Start the voice-mirror backfill."**
2217
+
2218
+ SiteDesk asks which stream to backfill first — discrete documents (emails, posts, PDFs) or chat archives (WhatsApp, Telegram, etc.). **Pick chat archives first if you have any imported.** Chat is where your unguarded voice lives; email is the same voice in dress clothes.
2219
+
2220
+ - **Chat archives** — tag a whole conversation in one click. SiteDesk doesn't ask about individual messages because chunks within a conversation almost always share the same voice. Options per conversation: yours, mixed (multiple authors on your side — rare), or not yours (e.g. a Slack channel where you only forwarded other people's messages).
2221
+ - **Documents and posts** — paginated 10 at a time. SiteDesk shows each item with its detected format (email, article, note, social-post). Tag the whole batch, a subset by number, or per-item if you want a precise label like `human-led-agent-assisted` (you wrote the content, SiteDesk polished). Override the detected format if one is wrong.
2222
+
2223
+ Skip a batch if none qualify, or stop at any time — the next session resumes where you left off.
2224
+
2225
+ ## Distilling Your Profile
2226
+
2227
+ Once you have corpus entries tagged (or after automatic PTY ingestion fills the `text` profile), ask: **"Build my voice profile."**
2228
+
2229
+ SiteDesk reads the corpus for each format, summarises your style as a YAML card, and saves it to the graph. It picks up your sentence rhythms, the constructions you reach for, the words you avoid — separately for email, articles, social posts, and so on.
2230
+
2231
+ The profile re-runs automatically when your corpus grows by ≥20% for any format or every 30 days, whichever comes first.
2232
+
2233
+ ## Your Voice and the House Voice
2234
+
2235
+ There are two kinds of profile. **Your voice** is learned from your own writing — it's what an email drafted under your name should sound like. **The house voice** is learned from everyone's writing on the account as a whole — it's what something that goes out under the business's name should sound like, like a brochure or an investor document.
2236
+
2237
+ Drafting picks the right one for you: emails use your voice; brochures and investor documents use the house voice. If you ask for your own voice but haven't tagged any of your own writing yet, SiteDesk quietly uses the house voice instead, so drafts still sound right rather than generic.
2238
+
2239
+ When you tag content, it's attributed to you by default. On a shared account with more than one person, you can attribute a piece to whoever actually wrote it, so each person's voice stays their own while the house voice draws on all of it.
2240
+
2241
+ ## Feedback Loop
2242
+
2243
+ When you edit an agent draft before sending — shorten a sentence, change a sign-off, swap a phrase — SiteDesk captures the edit and feeds it into the next distillation. The more you edit, the closer the voice gets.
2244
+
2245
+ This happens silently as part of the edit-loop in any drafting skill (email composition is the first wired surface).
2246
+
2247
+ ## Opt-Out Per Skill
2248
+
2249
+ Voice mirror is on by default for every drafting skill. To opt out for one, set `voiceMirror: false` in that skill's frontmatter. The skill falls back to a neutral British business register.
2250
+
2251
+ ## What It Won't Do
2252
+
2253
+ - **Blend two named people** — you get a profile per person plus one house voice for the whole account, but not a bespoke "Joel + Neo combined" voice.
2254
+ - **Copy public figures** — voice mirror only learns from your own writing.
2255
+ - **Clone audio** — text only, no speech synthesis.
2256
+ - **Guess** — historical content stays `unknown` until you mark it. SiteDesk never auto-classifies your writing. (Automatic ingestion applies only to your live PTY sessions where authorship is certain.)
2257
+
2258
+ ## Status
2259
+
2260
+ Voice mirror is live end-to-end. Six corpus formats (text, email, social-post, article, note, marketing-copy), five tools (`voice-tag-content`, `voice-distil-profile`, `voice-retrieve-conditioning`, `voice-record-feedback`, `voice-ingest-session-text`), on-demand session-turn capture, and wiring into the three live drafting surfaces (email composition, property brochures, investor data room) are all live. When no voice profile exists on the account for a given format, every drafting skill degrades gracefully — the output matches what it was before voice mirror was installed.
2261
+
2262
+ ---
2263
+ # Admin UI Reference
2264
+ Source: https://docs.getmaxy.com/admin-ui.md
2265
+
2266
+ # Admin UI reference
2267
+
2268
+ A compact map of the admin web app: every `/api/admin/*` mount, every
2269
+ sidebar surface, and the operator-facing widgets that read host or session
2270
+ state. The deep architecture lives in [`platform.md`](platform.md) (UI
2271
+ layout, session reconcile, route lifecycle) and
2272
+ [`admin-session.md`](admin-session.md) (the session-cookie / PIN-rebind /
2273
+ SDK-resume contract). This file is the index that points at them.
2274
+
2275
+ ## Scope and tree decision
2276
+
2277
+ The `maxy-code/` tree does **not** ship a `.docs/platform.md` developer
2278
+ doc. The legacy root tree (`getmaxy/`) carries one at
2279
+ `.docs/platform.md` for the original SiteDesk installer; the SiteDesk Code tree
2280
+ keeps its architecture surface in two places:
2281
+
2282
+ - `maxy-code-prd.md` at the repo root — product requirements and the
2283
+ source of truth for every task in `.tasks/`.
2284
+ - `platform/plugins/docs/references/platform.md` — operator-facing
2285
+ architecture, loaded by the docs plugin at session start.
2286
+
2287
+ Anything that would have gone into `maxy-code/.docs/platform.md` belongs
2288
+ in one of those two files instead. `maxy-code/.docs/` itself is
2289
+ reserved for vertical / integration notes (LinkedIn extension,
2290
+ PropertyData, Real Agent standalone, MCP server inventory) — not for
2291
+ core-platform docs.
2292
+
2293
+ ## UI conventions
2294
+
2295
+ **Icons are Lucide components only — no emoji.** Every glyph rendered in
2296
+ `platform/ui` JSX (the `/chat` web chat, the WhatsApp/channel readers, the
2297
+ admin shell, the `/data` grid) is a `lucide-react` component (e.g.
2298
+ `<Paperclip>`, `<FileText>`), never an emoji/emoticon character in the rendered
2299
+ string. The rule is enforced at build time by
2300
+ [`scripts/check-no-emoji-in-jsx.mjs`](../../../ui/scripts/check-no-emoji-in-jsx.mjs),
2301
+ which fails `prebuild` if any emoji codepoint appears in a `.ts`/`.tsx` file
2302
+ under `app/` (tests excluded). Inline an icon at the surrounding text size and
2303
+ colour (`size={14}` matches body text; Lucide inherits `currentColor`).
2304
+
2305
+ ## Admin Hono routes
2306
+
2307
+ Every admin sub-app is mounted by
2308
+ [`platform/ui/server/routes/admin/index.ts`](../../../ui/server/routes/admin/index.ts)
2309
+ under a per-area prefix. The outer `requireAdminSession` middleware
2310
+ runs in `server/index.ts` before the aggregator; individual handlers
2311
+ re-apply `requireAdminSession` where they need a resolved `senderId`.
2312
+
2313
+ `/actions` and `/version` are **not** mounted here — they live on
2314
+ `maxy-edge.service` via `server/edge-admin.ts` so the upgrade view
2315
+ survives the mid-run restart of the brand service. Double-mounting
2316
+ either is a regression.
2317
+
2318
+ ### Sessions and chat
2319
+
2320
+ | Mount | Purpose | Key methods |
2321
+ |---|---|---|
2322
+ | `/session` | Admin cookie session: PIN-gated mint, validate, rotate. | `GET /`, `POST /` |
2323
+ | `/sessions` | Legacy admin-server conversation routes. No UI consumer remains after the ConversationsModal was retired; the surviving handlers are deletion candidates and not described here. | (legacy, no live caller) |
2324
+ | `/sidebar-sessions` | Sole data path for the sidebar Sessions list. One JSONL on disk equals one row. The row's delete button is the only way a row disappears. Each row carries `sessionId`, `title`, `startedAt`, `live`, `isSubagent`, `pid: number \| null` (basename of the matched `sessions/<pid>.json`), and `projectDir` (the directory holding the JSONL — consumed by the delete route). The payload also carries top-level `accountId` so the pane renders the full UUID label whose first ~8 chars prefix-match the truncated Remote Control daemon entry in claude.ai/code. The legacy `rcUrl` field is gone — the row's external-link affordance now POSTs `/session-rc-spawn` to start a fresh local `claude --remote-control <name> --session-id <sid>` PTY on every click. | `GET /` |
2325
+ | `/session-delete` | POST `{ sessionId, projectDir }`. Best-effort SIGTERM of the live PID (resolved from `sessions/<pid>.json` body match) then unlink the JSONL + `<sid>.meta.json` sidecar. Absent PID file is not an error. Containment: `projectDir` must live under `<CLAUDE_CONFIG_DIR>/projects/`. | `POST /` |
2326
+ | `/session-rc-spawn` | POST `{ sessionId?, name? }`. Fire-and-forget `claude --remote-control [name] [--session-id <sid>]`. Present `sessionId` resumes; absent starts a fresh session (also used by the sidebar's "New session" button — it no longer opens claude.ai/code directly). Proxies to the manager's `/rc-spawn`, which waits up to **60 s** (raised from 12 s) for the spawned PTY to bind and returns `{ spawnedPid, sessionId, bridgeSessionId, slug, outcome, reason }`. For a webchat-bound spawn (every admin-gated host's "New session", returning a same-origin `/chat?session=<id>` target — `resolveRcSpawnOutcome` → `sameOrigin:true`) the Sidebar navigates the **current** tab via `window.location.assign`, replacing the dashboard in place (back returns to it); only a claude.ai/code slug (`sameOrigin:false`, the bare-admin resume bridge, never a new-session outcome) navigates a separately-opened tab. On `timeout` or `spawn-failed` it shows an error modal (reason + sessionId) and **never** opens a bare claude.ai/code tab. The new process registers itself as its own Remote Control entry in claude.ai/code. | `POST /` |
2327
+ | `/claude-sessions` | **Spawn surface only**. `POST /` is the Sidebar new-session-with-prompt path, cookie-auth only (the recorder loopback caller was removed; LinkedIn ingest moved to `/rc-spawn`). The former UI-facing handlers (SSE row feed, list, resume, stop, rename, archive, delete, `/:id/meta`, `/:id/input`, `/:id/log`) were removed — the maxy dashboard no longer manages or displays sessions. | `POST /` |
2328
+
2329
+ **Admin session management moved entirely to claude's own interfaces** (claude.ai/code, claude desktop). A manager-owned per-account `claude rc --spawn same-dir` daemon registers the device as a Remote Control target there; the composer creates / resumes / stops / renames / archives / deletes sessions, with model + permission-mode applied at inception. The model lever is `account.json.adminModel` → `CLAUDE_CONFIG_DIR/settings.json "model"`, written by the daemon supervisor at boot; the reasoning-effort lever is `account.json.effort` → `settings.json "effortLevel"` (accepted values `low|medium|high|xhigh`; any other value, e.g. legacy `"auto"`, leaves the key unset so claude's own default governs), written by the same read-merge-write at boot. A third inception lever, permission mode, is added: `account.json.adminPermissionMode` → `settings.json "permissions.defaultMode"` (the 5 composer-writable modes `default|acceptEdits|plan|auto|bypassPermissions`; `dontAsk` is out of scope). Unlike model/effort (top-level keys), this lever **deep-merges** the nested `permissions.defaultMode`, owning only that key and preserving sibling `permissions` keys (allow/deny/…) — what the binary and the spawn lifeline actually read. **For admin sessions, permission mode is fixed (Bypass) and not operator-chosen, while model and effort ARE operator-chosen at launch** via the composer's `+` new-session popover — a radio model list (Opus / Sonnet / Haiku) plus a 5-stop Faster→Smarter effort slider (Low / Medium / High / Extra / Max, where `max` applies via the `--effort` argv rather than `settings.json`); the popover description lives in `.docs/admin-webchat-native-channel.md`. Absent a pick (and on every resume), the daemon-pinned defaults govern: the `/chat` composer *footer* carries no live re-seat pickers — `rc-daemon.ts` pins settings.json `model`/`effortLevel`/`permissions.defaultMode` to `claude-opus-4-8[1m]` / `medium` / `bypassPermissions` regardless of `account.json` (read by the rc-spawn webchat path), and `pty-spawner.ts` forces the claude.ai/code PTY `--permission-mode` to `bypassPermissions` for `role=admin`. Public sessions are fixed to `claude-sonnet-4-6` (the `/public-spawn` chokepoint + `buildPublicWebchatSpawnRequest`), keeping `dontAsk`. The composer footer instead renders a **read-only** params row (mode · model · effort labels) plus a context-window usage figure (`pct% · ~used/~window`), all sourced from the session pointer; the full path is in `.docs/admin-webchat-native-channel.md`. The composer cannot re-seat a session, so the "no transcript" 400 on a brand-new chat is unreachable; the `/api/admin/session-reseat` + `/api/webchat/settings` routes and the dashboard re-seat form stay as off-composer surfaces. When the live session runs in `default` ("Ask permissions") mode, a tool the agent attempts that needs approval surfaces an Allow/Deny card in the composer (tool, description, argument preview); a click sends the verdict over Claude Code's channel permission relay and the tool runs or is refused — webchat is the only interactive ask surface (WhatsApp stays text-only; Telegram has no agent channel). Beyond the composer, the maxy admin UI keeps a single "New session" link (`https://claude.ai/code`, opens in a new tab) and no separate session list, viewer, controls, or model/mode picker. The daemon supervisor lives at [`platform/services/claude-session-manager/src/rc-daemon.ts`](../../../services/claude-session-manager/src/rc-daemon.ts). The `/session-defaults` route and `SpawnPreference` node were deleted with the picker. `/new-session-failure`, `/new-session-submit`, and `/claude-capabilities` are now orphaned (consumed only by the deleted NewSessionModal) — see [`.tasks/501`](../../../.tasks/) for their removal.
2330
+
2331
+ **Row title resolution.** Both the sidebar (`/sidebar-sessions`) and the manager's own row payload resolve a row's title in the same order: operator rename → Claude Code `ai-title` → first non-CLI user message → 8-char sessionId prefix. The operator-rename tier is the on-disk `<accountDir>/session-titles.json` (the manager's `UserTitleStore`), keyed by the CC sessionId — the sidebar reads that same file, so a write to the store lights up both surfaces with one write.
2332
+
2333
+ **`/chat` empty-state greeting panel.** While the admin webchat has no conversation JSONL yet (`GET /api/webchat/session` → `projectDir:null`), `app/chat/page.tsx` renders a "What's up next, {givenName}?" greeting (given name = first whitespace token of the admin session's `userName`) above two read-only lists from `GET /api/webchat/greeting` (`server/routes/webchat-greeting.ts`, `requireAdminSession`-gated, `accountId`-scoped): the next 5 upcoming `:Event` rows (`eventStatus IN ['scheduled','due']`, future `COALESCE(nextRun, startDate)`, soonest first) and the outstanding `:Task` rows (`status IN ['pending','active','running']`, 5 shown + `+N more`). Read failure returns HTTP 200 `{ ok: false }` and the page shows the headline alone — the panel never blocks the composer. A third section, **Your specialists**, shows the account's installed roster — every `*.md` under `data/accounts/<accountId>/specialists/agents/`, core and `--`-prefixed premium files alike — shown by frontmatter `name` + `summary` (fallback `description`), empty dir → "No specialists installed". The roster read (`app/lib/claude-agent/specialist-roster.ts`) is isolated from the graph fallback: malformed files are skipped (`op=specialist-skipped file=<name> reason=<…>`), a whole-roster failure degrades to `specialists: []` inside the `ok: true` payload (`op=specialists-read-failed`). Logs: `[webchat:greeting] op=read account=<id8> events=<n> tasks=<n> specialists=<n> ms=<n>` / `op=read-failed reason=…`; client warns `[admin-ui] greeting-unavailable …`. The full webchat architecture lives in `.docs/admin-webchat-native-channel.md`.
2334
+
2335
+ **`/chat` Claude-desktop transcript presentation.** The admin webchat keeps the shared `Transcript` shell (stream, follow-tail) but injects a /chat-only item renderer via the component's optional `renderItems` prop: `renderChatTimeline` in `app/chat/transcript-render.tsx`. Presentation: operator turns render as a right-aligned grey bubble showing the message text and, beneath it, a subtle always-visible time-of-day stamp (no label); delivered agent replies render as plain prose with the same time-of-day stamp beneath (the reply-document filename line stays, as prose); the stamp is HH:MM from the turn's `ts` (locale-formatted, right-aligned inside the operator bubble, left-aligned under agent prose), and a turn whose `ts` is null/unparseable shows no stamp, never an empty line — so only delivered operator and agent-reply turns are stamped, while tool runs, the collapsed "Thinking" block, and the agent-error banner stay time-free; a maximal consecutive run of `tool-call`/`tool-result` turns renders as one collapsed grey one-liner ("Used N tools ›") whose expansion shows every call and result payload — a lone call still gets the one-liner, and prose or a directive row ends a run. The WhatsApp reader (`/whatsapp`) omits the prop and keeps the default `renderTimeline`, so its rendering is unchanged; both presentations are test-pinned (`app/whatsapp/__tests__/Transcript-*.test.tsx`, `app/chat/__tests__/transcript-render.test.tsx`). **Day-divider:** both renderers insert a centered `.day-divider` row between two consecutive timeline items on different local calendar days (label `Today`/`Yesterday`, else `Sat 14 Jun 2026`), so a thread spanning midnight is never an ambiguous run of HH:MM; the first dated item gets a leading divider, a null/unparseable `ts` marks no boundary, dividers are computed over the filtered `visibleItems`, and in `/chat` a day crossover flushes any open tool/think run first so a collapsed run never spans it. Per-bubble HH:MM stamps are unchanged. Shared helpers `dayKey`/`dayLabel`/`itemTs`/`DayDivider` live in `app/whatsapp/Transcript.tsx`.
2336
+
2337
+ **maxy title for public sessions.** A `role=public` webchat spawn never produces a useful Claude Code `ai-title` (an anonymous one-line visitor turn), so every public row would otherwise read identically. The webchat route (`chat.ts`) composes a deterministic title — `Web · <senderId[:8]>[ · <personId>] · <UTC YYYY-MM-DD HH:mm>` (personId present only for gated visitors) — and threads it through the native webchat gateway's public spawn (`handleInbound` → `buildPublicWebchatSpawnRequest` → `managerSpawn`) to the manager `POST /public-spawn` body as `name`. `/spawn` validates it with `validateUserTitle` and, for `role=public` only, writes it into `UserTitleStore` so it occupies the operator-rename tier and wins over `ai-title`. Admin (`/rc-spawn`) and WhatsApp titling are unchanged. Observability: every public spawn logs `[spawn] role=public … title="…"` (or `title=missing`); the manager's row builder emits `[public-title] sessionId=… unexpected titleSource=<ai|null>` on the next list read for any public row that did not resolve from the user tier.
2338
+
2339
+ **Public visitor surface.** The public-host root (`GET /`), the `/:slug` agent routes, and the admin-host `/public` / `/public-chat` previews all serve one shell, `public.html` → [`app/public-entry.tsx`](../../../ui/app/public-entry.tsx) → `PublicChat`. `PublicChat` reuses `useSession` purely as the magic-link gatekeeper — it drives `AccessGate`, resolves the agent slug from the path, and handles `?token=` verification; once the grant is satisfied it mounts `ChatSurface variant="public"`, whose transcript reads the visitor-scoped, **delivered-only** stream `GET /api/public-reader/stream` ([`server/routes/public-reader.ts`](../../../ui/server/routes/public-reader.ts)) — the visitor sees the agent's delivered prose, never the tool/tool-result/directive bytes the legacy `/api/chat` SSE render exposed. The human visitor's branding is resolved client-side by `useSession`. For the head only, the server injects per-agent link-preview meta — `<title>`, `og:title`/`og:description`/`og:image`, `theme-color`, and a per-agent favicon, resolved from the same branding cache `useSession` reads — into the served shell, so a link-preview crawler (which never runs the client bundle) gets a branded card per agent instead of one generic shell; an agent with no branding cache gets the clean brand-default shell with no empty meta tags. There is exactly one public client surface and it is 1:1 visitor↔agent: the earlier `?surface=next` A/B handle is retired, group messaging is retired (not a supported product surface), and a former `/g/<slug>` group URL now serves the same 1:1 shell — a stale bookmark gets the 1:1 chat, never a broken render.
2340
+
2341
+ ### Graph
2342
+
2343
+ | Mount | Purpose |
2344
+ |---|---|
2345
+ | `/graph-search` | Filtered node search backing the `/graph` page filter chips. |
2346
+ | `/graph-subgraph` | Neighbourhood expansion around a focal node. |
2347
+ | `/graph-delete` | Soft-trash a node (sets `_trashed:true`). |
2348
+ | `/graph-restore` | Undo trash. |
2349
+ | `/graph-labels-in-graph` | Distinct label list for the filter dropdown. |
2350
+ | `/graph-default-view` | Account-scoped saved view (zoom, focal id, filters). |
2351
+
2352
+ ### Artefacts and files
2353
+
2354
+ | Mount | Purpose |
2355
+ |---|---|
2356
+ | `/sidebar-artefacts` | Lists the sidebar Artefacts rows: every `:FileArtifact` under this account's tree (`relativePath STARTS WITH 'accounts/'` — all file types, excluding the separate `uploads/<id>/` subtree) plus this account's IDENTITY / SOUL / KNOWLEDGE / specialist templates. |
2357
+ | `/sidebar-artefact-content` | Reads a single artefact's bytes for the artefact pane. |
2358
+ | `/sidebar-artefact-save` | Persists an artefact edit. |
2359
+ | `/attachment` | Per-attachment binary fetch (images, PDFs, etc.). |
2360
+ | `/files` | File browser CRUD (list, download, upload, delete). Listings put directories first, then files newest-first by `mtime` (name tie-break) so a just-changed file leads the panel. Upload is a raw-body stream (file bytes are the request body; `session_key`/`path`/`filename` in the query) written to disk without buffering — ceiling 2 GB (`MAX_DATA_UPLOAD_BYTES`), over-ceiling bodies abort mid-stream with `413`; the client shows a determinate progress bar. Distinct from the 50 MB in-memory chat-attachment cap. |
2361
+
2362
+ **Artefact download resolution.** Clicking a sidebar Artefacts row
2363
+ streams the `KnowledgeDocument`'s real backing file, which can live in one of
2364
+ three on-disk classes: the admin-UI upload store (`<DATA_ROOT>/uploads/<acc>/
2365
+ <attachmentId>/`), the agent-authored output dir (`<DATA_ROOT>/accounts/<acc>/
2366
+ output/<name>`), and the Claude-agent upload store
2367
+ (`<CLAUDE_CONFIG_DIR>/uploads/<attachmentId>/`, which is **outside** DATA_ROOT).
2368
+ `memory-ingest` persists the real path on the node as `KnowledgeDocument.sourcePath`
2369
+ (skipped for web docs, whose temp file is unlinked at ingest), so new ingests
2370
+ resolve deterministically; pre-existing rows fall back across the three classes.
2371
+ The download route (`/files/download`) accepts `root=data` (default) or
2372
+ `root=claude-uploads`; the config-dir root carries no accountId path segment, so
2373
+ it is account-scoped by a graph-ownership check (the attachmentId must map to a
2374
+ `KnowledgeDocument` carrying the caller's accountId) rather than by path
2375
+ partition. Resolution emits `[admin/sidebar-artefacts] download-resolved via=…`;
2376
+ a web/transient doc with no persisted file is `not-downloadable reason=no-persisted-file`.
2377
+
2378
+ **`/data` File panel — refresh and reload-survival.** The panel listing is a
2379
+ snapshot from its last fetch, so a file an agent writes (or an upload/delete
2380
+ elsewhere) leaves stale rows and timestamps until something re-fetches. A
2381
+ **Refresh** icon inside the search bar (beside Upload) re-fetches the current
2382
+ folder in place (fresh `mtime`s, no browser reload). The current directory is
2383
+ mirrored into the URL hash (`/data#path=<rel>`), so a browser reload restores
2384
+ that folder instead of snapping back to the data root; the hash never reaches
2385
+ the server and `/data` has no client router, so the channel is isolated.
2386
+ `path=` is cleared at the root for a clean URL.
2387
+
2388
+ **`/data` upload — button and drag-drop.** Besides the Upload button (one OS-picked
2389
+ file, stored under a timestamped name), files and whole folders can be dragged
2390
+ onto the file-browser body to upload into the open folder. A dropped folder's
2391
+ subtree is recreated under the open folder and every contained file uploaded,
2392
+ preserving source names and relative paths (a same-named file in an existing
2393
+ folder is overwritten; empty source subfolders are skipped). The drop region
2394
+ shows an active outline while a drag is over it and is inert wherever the open
2395
+ folder is not writable (outside the operator's own `accounts/<id>/…` subtree),
2396
+ rejecting the drop with the same "Open a folder inside your account to upload"
2397
+ guidance as the button. Each drop reports an uploaded/skipped summary; a file
2398
+ that fails the 50 MB limit, the MIME allowlist, or its HTTP write is skipped
2399
+ individually without aborting the rest, and every uploaded file is indexed for
2400
+ search exactly as the button path is. The server `/files/upload` endpoint takes
2401
+ an optional `relpath` form field (the file's path relative to the drop root); it
2402
+ recreates that path's directories under the open folder, scope-checked level by
2403
+ level, and writes the file under its original basename. A flat upload (no
2404
+ `relpath`) is unchanged.
2405
+
2406
+ **`/data` operator surface.** `/data` mounts the operator
2407
+ `HeaderMenu` (logo-left / name-centre / burger-right; flyout = Chat / Data /
2408
+ Log out) above the toolbar — the burger's Chat item returns to `/`, replacing
2409
+ the former standalone Home button. The search bar flexes to fill its toolbar
2410
+ row; the four file actions (Refresh, Upload, New folder and the list↔grid view
2411
+ toggle) sit beside it as one uniformly styled icon group, collapsing under a
2412
+ single `⋯` overflow menu at `≤640px`. File rows are two stacked full-width lines
2413
+ (name, then `size · modified`) with no file-type icon, no hover download icon,
2414
+ and no per-row delete button; a folder row keeps its glyph and navigates on tap,
2415
+ a file row downloads on tap. **Long-press** a file row to enter multi-select:
2416
+ every file row shows a selection indicator, the search bar becomes a Cancel
2417
+ control, and a fixed bottom bar offers **Share / Download / Delete** over the
2418
+ selection. Delete removes the non-protected files and keeps protected ones
2419
+ (`N protected file(s) kept`); the listing carries a per-entry `protected` flag
2420
+ from `isProtectedFromDeletion` so the UI never re-derives the rule. Share uses
2421
+ the Web Share API and is disabled where unavailable. Signals:
2422
+ `[data-ui] op=mount header=operator home=absent`, `op=select-enter`,
2423
+ `op=select-exit reason=<cancel|action>`, `op=share supported=<bool> count=<n>`.
2424
+
2425
+ **`/data` list ↔ grid view + image thumbnails.** A toolbar toggle switches the
2426
+ file browser between the two-line list and a **grid**. In grid view, image
2427
+ files render an inline thumbnail; folders render a folder tile (still navigate
2428
+ on tap); every other file renders a labelled tile (name + size) that downloads
2429
+ on tap. Tapping a thumbnail opens a full-size overlay (reusing the chat
2430
+ attachment overlay), not a download — download stays reachable via long-press →
2431
+ select → Download. The chosen view persists across reload and `/data` ↔ `/`
2432
+ navigation (`localStorage['maxy-data-view']`). A file counts as an image only
2433
+ when its **extension** is one the inline-serve route can serve
2434
+ (`png/jpg/jpeg/gif/webp/svg`, the server's `detectMimeType` image set) — the
2435
+ sidecar `mimeType` is not consulted, so the grid never promises a thumbnail the
2436
+ serve route would refuse. Thumbnails load from the same `/api/admin/files/download`
2437
+ route with `disposition=inline` (`inlineImageUrl`), which for an `image/*` file
2438
+ returns the bytes with **no** `Content-Disposition` and a cacheable header so the
2439
+ browser renders them in an `<img>`; a non-image inline request is refused `400`,
2440
+ and the account-scope guard is identical to the attachment path. Signals:
2441
+ `[data] op=view-mode mode=<grid|list>`, `[data] op=thumb-serve path=… mime=… size=… status=200`,
2442
+ `[data] op=thumb-refused path=… reason=not-image`, and client `[data] op=thumb-error path=…`
2443
+ from a thumbnail that fails to load.
2444
+
2445
+ **`/data` search — locate-in-files link and clear button.** Every
2446
+ search hit is a `:FileArtifact` backed by a physical file, so each result card
2447
+ whose `relativePath` is a non-empty string carries a **locate link** (folder
2448
+ icon + containing folder; root-level files show `data`). Clicking it clears the
2449
+ active search (query, results, error, chip) and navigates the file browser to
2450
+ that folder via the same `path` state + `#path=` hash contract above, so the
2451
+ file appears among its siblings and a reload restores the place. The link is a
2452
+ sibling of the clickable card, so it never triggers the row's download. Hits
2453
+ without a usable `relativePath` render no link; one
2454
+ `console.warn('[data-search] op=locate-link-missing nodeId=…')` per result set
2455
+ surfaces the index gap, and each click logs
2456
+ `[data-search] op=locate nodeId=… folder=…`. The search bar shows an **× clear
2457
+ button** while it holds text — clicking empties the input, clears results
2458
+ (restoring the file-browser body), and refocuses the input.
2459
+
2460
+ ### Browser / device-browser
2461
+
2462
+ | Mount | Purpose |
2463
+ |---|---|
2464
+ | `/browser` | `POST /launch` — launches Chromium on the resolved transport (native display or VNC) on demand. Backs the standalone `/browser` operator page. Lifeline tag `[admin/browser/launch]`. |
2465
+
2466
+ The in-chat / artefact-embedded brand-VNC iframe components and the
2467
+ `/browser-iframe` event-beacon route were retired and stay
2468
+ deleted; the `/device-browser` (navigate-the-device-tab) route was also
2469
+ removed and is not restored. The standalone `/browser` page is a
2470
+ sanctioned operator surface peer to `/graph` and `/data`: it embeds the live
2471
+ VNC viewer (`/vnc-viewer.html`, popout `/vnc-popout.html`) and calls
2472
+ `/api/admin/browser/launch`. On darwin (no noVNC asset) it shows a "VNC surface
2473
+ not available" state.
2474
+
2475
+ ### Diagnostics
2476
+
2477
+ | Mount | Purpose |
2478
+ |---|---|
2479
+ | `/logs` | Server log tail with `type=stream\|error\|sse` and `sessionId` filters; powers the in-chat **View logs** popover (see [`internals.md`](internals.md) "Conversations modal — View logs"). |
2480
+ | `/events` | Generic SSE event ingest from the UI client. |
2481
+ | `/log-ingest` | Loopback-only structured log ingest for MCP and PTY-spawn observability lines (see [`admin-session.md`](admin-session.md) "Memory MCP write-path outcome lines"). |
2482
+ | `/claude-info` | Returns Claude CLI binary path, version, and OAuth status. |
2483
+ | `/claude-capabilities` | Returns the resolved capability matrix the UI uses to gate features. |
2484
+ | `/agents` | Lists every installed agent template; supports `DELETE /:slug` for user-created public agents and `POST /:slug/project` for project assignment. |
2485
+ | `/cloudflare` | Tunnel setup surface — see [`cloudflare.md`](cloudflare.md) for the OAuth flow. |
2486
+ | `/linkedin-ingest` | LinkedIn Basic Data Export ingest entry point (see [`linkedin-extension.md`](linkedin-extension.md)). |
2487
+ | `/health-brand` | Brand-process liveness + 1 s Neo4j probe. Returns `{ok, processStartedAt, version, conversationDb: 'ok'\|'error', uptimeMs}`. The `processStartedAt` is captured at module load, so a stale value after an armed restart means the brand process never came back. |
2488
+ | `/system-stats` | Host CPU / RAM / load probe. See next section. |
2489
+
2490
+ The companion `/api/admin/version` and `/api/admin/actions` routes are
2491
+ served by `maxy-edge.service`, not this aggregator. The edge process
2492
+ keeps the upgrade view alive while the brand service restarts.
2493
+
2494
+ ## System-stats widget
2495
+
2496
+ Source:
2497
+ [`server/routes/admin/system-stats.ts`](../../../ui/server/routes/admin/system-stats.ts)
2498
+ (route) and `SystemStatsWidget` in
2499
+ [`platform/ui/app/Sidebar.tsx`](../../../ui/app/Sidebar.tsx)
2500
+ (consumer). CSS lives under `.system-stats*` in
2501
+ [`platform/ui/app/globals.css`](../../../ui/app/globals.css).
2502
+
2503
+ **What the widget shows.** A compact block at the foot of the sidebar
2504
+ with one row per metric: `CPU 73%` and `RAM 71%`, each followed by its
2505
+ own 4 px saturation bar. Bar fill colour is a smooth green → amber →
2506
+ red gradient computed as `hsl(140·(1−pct), 65%, 45%)` so the colour
2507
+ reflects each metric's own load. Hidden when the sidebar is collapsed
2508
+ to its 56 px icon rail.
2509
+
2510
+ **Where the numbers come from.** `GET /api/admin/system-stats` returns a
2511
+ snapshot for the host. On Linux the route reads `/proc/stat` twice 100 ms
2512
+ apart and computes `cpuPct = 1 - idleDelta / totalDelta`; `memUsedPct`
2513
+ comes from `(MemTotal - MemAvailable) / MemTotal` in `/proc/meminfo`; the
2514
+ three load averages come from `/proc/loadavg`. A single-flight module
2515
+ cache means concurrent callers share one in-flight pair of `/proc/stat`
2516
+ reads. On darwin and other non-Linux platforms the route falls back to
2517
+ `os.totalmem() / os.freemem() / os.loadavg()` and returns `cpuPct: null`
2518
+ — the widget renders a dash rather than fake a value.
2519
+
2520
+ **Refresh cadence.** The widget polls every 5 s
2521
+ (`SYSTEM_STATS_POLL_MS`). Polling pauses while `document.hidden` is true
2522
+ (tab in background) and resumes on `visibilitychange`. On unmount the
2523
+ interval is torn down and the visibility listener removed.
2524
+
2525
+ **Thresholds.**
2526
+
2527
+ | Class | Trigger | Visual |
2528
+ |---|---|---|
2529
+ | `.system-stats--warn` | `cpuPct >= 0.9` **or** `memUsedPct >= 0.9` | Widget text turns `--danger` red. Bar fill colour is independent (set by the per-bar hue gradient), so the figure text is what carries the warn signal at this band. |
2530
+ | `.system-stats--crit` | `cpuPct >= 0.98` **or** `memUsedPct >= 0.98` | Adds a 1.2 s pulsing background animation (`@keyframes system-stats-crit-pulse`) on top of the warn colour. |
2531
+ | `.system-stats__fig--warn` | Per-figure: applied to the specific CPU or RAM span that breached `0.9`. | Same red colour, lets the operator see which of the two figures crossed first. |
2532
+
2533
+ The warn threshold matches the threshold the operator most commonly
2534
+ cares about (a fully-loaded 4-core Pi at 16 GiB RAM crosses 0.9 long
2535
+ before anything else on the host notices). The crit threshold pulses
2536
+ because it is the band where a swap-thrash episode becomes likely.
2537
+
2538
+ **Failure handling.** Any read or parse error inside the route returns
2539
+ HTTP 200 with `{degraded: true, reason, sampledAtMs}` so the widget
2540
+ keeps showing its last-known value instead of flashing zeros. Failed
2541
+ fetches log `[admin-ui] system-stats-fetch-failed status=<code>` (or
2542
+ `reason=<message>`) to the browser console; successful polls are silent
2543
+ client-side. Server-side every poll logs one
2544
+ `[system-stats] poll cpuPct=<f3> memUsedPct=<f3> loadAvg1=<f2> swapUsedPct=<f3> platform=<linux|darwin|other> ms=<n>`
2545
+ line; errors emit
2546
+ `[system-stats] error file=<path|parse> reason=<message>`.
2547
+
2548
+ **Diagnostic grep.**
2549
+
2550
+ ```bash
2551
+ grep '\[system-stats\] poll' ~/.${brand}/logs/server.log | tail -20
2552
+ grep '\[system-stats\] error' ~/.${brand}/logs/server.log | tail
2553
+ ```
2554
+
2555
+ A 0.000 reading that persists across many polls while `top` shows load
2556
+ is the delta-cache regression signature (the single-flight promise was
2557
+ not released).
2558
+
2559
+ ## Sidebar surfaces
2560
+
2561
+ The sidebar is the entire left column of the admin UI. Its full layout,
2562
+ responsive breakpoints, drag-resize behaviour, and the
2563
+ new-session strip / nav rows / sessions list / footer ordering are
2564
+ documented in
2565
+ [`platform.md`](platform.md) "The Web Interface" — that paragraph is
2566
+ authoritative. This section names the surfaces and what backs each.
2567
+
2568
+ > **Admin variant only.** Every surface below belongs to the `admin` shell
2569
+ > variant. The **operator** variant (`operator.<host>`) mounts no sidebar at
2570
+ > all: its dashboard is the persistent admin webchat at `/` and the data
2571
+ > browser at `/data`, plus a read-only **Conversations** reader reached from a
2572
+ > dynamic burger item — header order Chat → Conversations → Data → Log out, in
2573
+ > a single-column `.platform.platform-operator` grid. The operator never sees
2574
+ > the sessions list or the nav rows; the Conversations reader lists the agent's
2575
+ > inbound channel conversations (WhatsApp, Telegram, public webchat) read-only
2576
+ > via the same admin-gated reader routes, never the operator's own session. The
2577
+ > operator surface is documented in full in the internal doc
2578
+ > `maxy-code/.docs/operator-dashboard.md`.
2579
+ >
2580
+ > **Width.** The operator header, the operator chat column, and the `/data`
2581
+ > header+toolbar+body all render in one centred column bounded to
2582
+ > `--chat-measure` (48rem). That token is a `:root` design token (beside
2583
+ > `--measure`/`--gutter`); the operator-header clamp
2584
+ > (`.admin-shell-root:has(> .platform-operator) > .admin-header`), the chat-column
2585
+ > clamp (`.platform-operator > .webchat-page`), and the `/data` clamp
2586
+ > (`.data-main`) all read it, so logo and burger align to the panel edges on both
2587
+ > surfaces. The admin shell carries no `--chat-measure` consumer and stays
2588
+ > edge-to-edge; the public webchat (`.public-surface`) inherits the same value.
2589
+ >
2590
+ > **Conversations item.** The dynamic Conversations burger item appears on
2591
+ > **both** the operator chat surface and `/data` whenever ≥1 reviewable
2592
+ > conversation exists (the count/channels are fetched per surface from
2593
+ > `/whatsapp-reader/conversations` with the operator's session key). On `/data`
2594
+ > selecting it renders the same read-only reader in place (the file browser is
2595
+ > swapped for it; Back returns). The flyout-open signal
2596
+ > `[operator-ui] op=conversations-menu present=<bool> channels=[…] count=<n>`
2597
+ > fires on `/data` too — `present=false` there while the chat surface shows the
2598
+ > item is the props-not-wired signature.
2599
+
2600
+ | Surface | What it does | Backed by |
2601
+ |---|---|---|
2602
+ | `+ New session` button | Opens `NewSessionModal`, which POSTs `{channel, permissionMode, model, initialMessage}` to `/api/admin/claude-sessions`. | `claude-sessions.ts` |
2603
+ | Mode trigger | Per-`(accountId, userId)` `SpawnPreference` for `permissionMode` and `model`; persists across reload, tab, device. | `session-defaults.ts` |
2604
+ | Nav rows (Chat / People / Agents / Projects / Tasks / Artefacts) | People, Agents, Tasks open the artefact-pane Graph filtered to the matching label. Chat selects the active conversation. Artefacts swaps the list to editable documents. **The "Projects" row is brand-aware:** its visible term and the graph label it filters to both come from the injected `window.__BRAND__.primaryContainer` (`brand.json` → `server/index.ts` inject → `brand.ts` `brandPrimaryContainer()`), so SiteDesk reads "Projects" → `:Project`, SiteDesk "Jobs" → `:Job`, Real Agent "Properties" → `:Property`. A brand JSON missing `primaryContainer` falls back to Project/Projects (server logs `[brand] op=primaryContainer-default reason=absent brand=<hostname>`; the populated case logs `[brand] op=inject primaryContainer=<label>/<term>`). | `graph-search.ts`, `graph-subgraph.ts`, `sidebar-artefacts.ts` |
2605
+ | Sessions list (Active / Archived / All) | Live row store driven by SSE; manual reconcile button on the segmented control re-fetches the full id set. Every listed row carries two launch actions: the claude.ai/code resume (`ExternalLink`) and a chat-launch (`MessageSquare`) that opens `/chat?session=<full sessionId>` — the admin webchat pointed at that exact session; sending there resumes a stopped session with the webchat channel bound to that id (see `admin-webchat-native-channel.md`, "Session-targeted mode"). At the ≤720 px drawer breakpoint each row stacks into two lines — dot + title + id/stamp, then the action icons — with a divider between rows and actions at full opacity (the desktop hover-gated 0.5 opacity never resolves on touch). Below a 400 px list width each row's action icons collapse to a single `MoreHorizontal` ellipsis trigger; its popover menu lists the same actions as the inline icons but labels them with concise verbs (`Resume in claude.ai/code`, `Open in webchat`, `Stop`, `Archive` / `Unarchive`, `Rename`, `Delete`, `Re-seat`) rather than the inline icon buttons' verbose per-session aria-labels — the inline buttons keep those verbose labels because an icon-only control needs the full descriptive accessible name. **Re-seat:** Re-seat is a member action of the one `SessionRowActions` cluster, not a separate sibling control — wide it is the sliders icon inline with the other icons (sharing the cluster geometry and alignment); collapsed it is the `Re-seat` menu item, which expands the model/mode/effort form inline inside the overflow menu. The form (`SessionReseatControl`) forks the session via `/api/admin/session-reseat` and navigates to the fork (the same fork mechanism `/chat`'s pickers drive); its model picker defaults to the row's current model (a `model` field on each row, read from the JSONL tail), and mode and effort each carry a "Keep" option that omits the field. The overflow menu and the Re-seat form render through a `document.body` portal, fixed-positioned from the trigger's rect (right-aligned, flipped above the trigger when there is no room below), so neither is clipped by `.side-list`'s `overflow-y:auto`; Escape, a pointerdown outside the trigger/popover, and any scroll or resize dismiss them. | `/claude-sessions/events`, `/claude-sessions`, `/session-reseat` |
2606
+ | Channel reader nav rows (WhatsApp / Telegram) | One conditional nav row **per interactive channel that has ≥1 admin session**. Each row carries its brand glyph (WhatsApp `#25D366`, Telegram `#229ED9`); a channel with no admin session shows no row, and no install ever shows an always-empty "No conversations" row. The channel list loads **once on sidebar mount** (the per-channel counts must be known before the nav renders), so a failed load shows one muted, non-clickable line instead of channel rows. Clicking a channel row lists that channel's admin conversations; each conversation row shows a **display name** resolved by precedence `operatorName ?? whatsappName ?? senderId ?? title`: the bound `Person givenName familyName` when a `senderId`→`userId` binding exists, else the persisted WhatsApp display name (`pushName`, read from the latest `:Message:WhatsAppMessage.senderName`), else the raw `senderId`, else the agent title; the agent session title is the hover tooltip only. Under the name each row shows a **last-message-time breadcrumb** (`conv-timestamp`, same markup as the Sessions rows) formatted from the row's `lastMessageAt` (the last parseable turn's `ts`); a session with no parseable turn shows no time, never "Invalid Date". **Re-seat:** each channel conversation row carries a `SessionRowActions` cluster whose sole action is Re-seat (the row is a `conv-with-actions` shell whose open click moved onto an inner button so the cluster can sit beside it), so a WhatsApp/Telegram session's model/mode/effort is re-seatable from the dashboard exactly like a webchat row — wide it is the inline sliders icon, and below the 400 px width it folds into the `…` overflow menu identically to the Sessions rows; the channel reader row carries the same `model` field for the picker default. A click on a conversation **opens its transcript on the home surface**: on `/` it selects in place, and from any other route (`/graph`, `/data`, `/browser`) it navigates to `/?wa=<sessionId>&projectDir=<dir>`, which the root shell hydrates on mount (then strips the query so a later refresh does not re-pin a closed conversation). Server logs `[wa-reader] op=operator-name-fallback senderId=… source=whatsapp-pushname` when the pushName fallback fires and `[wa-reader] op=conversations count=<n> withTimestamp=<m>` per list build; the client logs `[admin-ui] wa-open route=… via=<in-place\|navigate> …` and `[admin-ui] wa-hydrate route=/ …`. | `/whatsapp-reader/conversations` |
2607
+ | Channel transcript (`<Transcript>`) | Reads one session's JSONL over SSE (`/whatsapp-reader/stream`) and renders both sides plus tool calls — the turns claude.ai/code hides because channel inbound is stamped `isMeta`. Every turn shows its time-of-day (HH:MM from the turn's `ts`; a null/unparseable `ts` shows no time, never "Invalid Date"). `tool-call`/`tool-result` turns render as **collapsed cards** (chevron + label + time, default collapsed, expandable per card; one card's state never affects another) so the human↔agent text is not buried in JSON; the three conversation kinds always render in full. The thread **follows the tail**: it opens at the newest turn and pins to the bottom on each live append **only while the operator is already within 32 px of the bottom** — a scroll up suppresses the jump so reading history is never yanked. While the operator is scrolled up a **jump-to-bottom control** (`.wa-jump`, bottom-right of the viewport) appears; clicking it scrolls to the newest turn and re-arms follow-tail, and it hides again at the bottom. The thread scrolls inside its grid cell (header/sidebar/footer fixed). The stream sends a 20 s heartbeat so an idle Cloudflare tunnel does not idle-drop, tags each frame with a byte-offset `id:`, and resumes from the client's `Last-Event-ID` on reconnect (no duplicate backlog); the client clears the "Stream disconnected" banner on reopen and latches it only on a terminal CLOSED state. The thread also interleaves a collapsed `⚙ directive injected (N B)` row per turn, sorted by timestamp just before the turn it informed; expanding one fetches the exact stored `prompt-optimiser-directive` bytes for that turn. The entries are listed by `GET /whatsapp-reader/directives?sessionId=` and the bytes served by `GET /whatsapp-reader/directive?sessionId=&name=`, both admin-gated and account-scoped; a missing store degrades to no rows. A centered day-divider row (`.day-divider`) marks each local calendar-day crossover between consecutive turns so a thread spanning midnight is unambiguous. | `/whatsapp-reader/stream`, `/whatsapp-reader/directives`, `/whatsapp-reader/directive` |
2608
+ | Conversations row hover actions | Inline rename, archive, delete, JSONL view / download per row. The historical `.conversations-modal` CSS block exists in `globals.css` but is no longer mounted from any TSX — Sidebar.tsx now owns every per-row affordance directly. | `claude-sessions.ts` |
2609
+ | Artefacts list | Lists every `:FileArtifact` under this account's tree (`relativePath STARTS WITH 'accounts/'`, all file types, excluding the `uploads/<id>/` subtree) plus this account's IDENTITY / SOUL / KNOWLEDGE / specialist templates. Click downloads the row's backing file (`downloadPath` → `GET /api/admin/files/download`) so the operator opens it in their local app; rows whose file is outside `DATA_ROOT` (bundled-fallback templates) show a "can't be downloaded" pill. The in-app artefact pane is dead pending removal. | `sidebar-artefacts.ts`, `files.ts` |
2610
+ | System-stats widget | CPU / RAM widget at the foot of the sidebar. | `system-stats.ts` (see above) |
2611
+ | Footer | Operator avatar, name, role, and the actions popover. | `session.ts` |
2612
+
2613
+ ## Artefact pane
2614
+
2615
+ The right-hand pane that opens when the operator selects an artefact,
2616
+ clicks a project (Graph view), or opens Browser / Data / Graph from the
2617
+ menu. It holds the surface side-by-side with the conversation so the
2618
+ chat stays live.
2619
+
2620
+ - Editable artefacts (KnowledgeDocuments + the account's own IDENTITY /
2621
+ SOUL / KNOWLEDGE) auto-save on type via
2622
+ `POST /api/admin/sidebar-artefact-save`.
2623
+ - Read-only artefacts (specialist agent templates) cannot be edited
2624
+ because they ship with SiteDesk and would be overwritten on the next
2625
+ install.
2626
+ - PDF artefacts render inline; non-PDF binaries fall back to a Download
2627
+ button when the browser has no native viewer.
2628
+ - Orphan rows (no readable file on disk, unsupported content type) show
2629
+ a one-line banner explaining the skip instead of opening to a blank
2630
+ pane.
2631
+
2632
+ Below 1080 px the pane hides and Browser / Data / Graph open as
2633
+ full-window pages instead. The chat-and-pane divider is drag-resizable
2634
+ on every admin page; double-click resets to half the available width
2635
+ (viewport minus sidebar), clamped to the per-pane min-width floors. The
2636
+ chosen width is remembered across reloads.
2637
+
2638
+ ## Health vs version
2639
+
2640
+ Two endpoints, two surfaces, two restart-survival roles:
2641
+
2642
+ - `GET /api/admin/health-brand` (this aggregator) — brand-process
2643
+ liveness. `processStartedAt` resets on every brand-service restart;
2644
+ Neo4j probe is bounded to 1 s and reports
2645
+ `conversationDb: 'ok' | 'error'`. Use this to confirm the brand
2646
+ process came back after a Cloudflare-setup armed restart.
2647
+ - `GET /api/admin/version` (maxy-edge) — installer / brand version
2648
+ string. Hosted on `maxy-edge.service` so the Software Update modal
2649
+ can read it while the brand service is mid-restart.
2650
+
2651
+ ## Related references
2652
+
2653
+ - [`platform.md`](platform.md) — UI layout, session reconcile model,
2654
+ artefact pane behaviour in full detail, breakpoints.
2655
+ - [`admin-session.md`](admin-session.md) — admin session token, PIN-
2656
+ rebind, SDK-resume, structured log lines.
2657
+ - [`internals.md`](internals.md) — retrieval pipeline, end-turn auto-close
2658
+ auto-archive, graph-prune-denylist surface, conversation logs.
2659
+ - [`cloudflare.md`](cloudflare.md) — tunnel setup OAuth flow that
2660
+ `/api/admin/cloudflare/setup` drives.
2661
+ - [`deployment.md`](deployment.md) — Pi setup; the brand-service / edge-
2662
+ service split that the health-vs-version table above relies on.
2663
+
2664
+ ---
2665
+ # Graph View
2666
+ Source: https://docs.getmaxy.com/graph.md
2667
+
2668
+ # Graph View
2669
+
2670
+ The **Graph** admin page (`/graph`) renders a force-directed view of your
2671
+ account's Neo4j subgraph. Labels on the canvas follow the zoom level, so you
2672
+ see the most useful identity at every scale.
2673
+
2674
+ ## Search and pivot
2675
+
2676
+ Type a term in the search box to highlight matching nodes on the canvas. Hits get an amber border so you can pick them out of a busy view. Click any highlighted node to open its side panel and pivot into its neighbourhood — both clicks (hit and non-hit) behave identically.
2677
+
2678
+ When a search is active and you click a node, the neighbourhood you pivot into is **narrowed to the search-relevant subset**. For example: searching "david" with 175 matches and clicking yourself returns the Davids you're connected to, not your entire LinkedIn graph. The narrowing applies once per pivot — clearing the search and pivoting again returns the full neighbourhood.
2679
+
2680
+ Searches reach **every textual property** of every operator-meaningful label, including denormalised fields the platform writes specifically so search can reach them — for example, the current job title of each LinkedIn connection (originally stored on the connection edge, copied to the Person node so the fulltext index can match it).
2681
+
2682
+ Search behaves the same here, in the agent's own memory recall, and on the `/data` page: with **no filter chips selected** a search reaches **all** labels — the same scope the agent sees — and every surface applies the **same default relevance floor**, so the same query returns the same nodes everywhere. There is no longer a "select a chip first" gate; an empty chip set means "search everything". Selecting chips narrows the result to those labels.
2683
+
2684
+ ## Conversation label tiers
2685
+
2686
+ Conversation nodes carry the most operator-meaningful identity in the
2687
+ subgraph (the conversation name or summary, the date it started, the message
2688
+ count). They render in one of three tiers, switched by canvas scale:
2689
+
2690
+ | Zoom | Label shape | Example |
2691
+ |------|-------------|---------|
2692
+ | Zoomed out (< 0.7×) | Compact — one line, capped at 24 characters. Preserves the no-overlap contract that matters when nodes are tightly packed. | `Maxyfi branding conflict…` |
2693
+ | Mid zoom (0.7× to 1.3×) | Wrapped — up to two lines of 24 characters each, soft-ellipsis on overflow. Full name is visible without hover. | `Maxyfi branding conflict` / `with Rubytech` |
2694
+ | Zoomed in (≥ 1.3×) | Detailed — wrapped name plus a metadata line reading `YYYY-MM-DD · N msgs`. | `Maxyfi branding conflict` / `with Rubytech` / `2026-04-23 · 7 msgs` |
2695
+
2696
+ Non-Conversation nodes (People, Messages, Tasks, WorkflowRuns, etc.) keep
2697
+ their concise single-line labels at every zoom level — the canvas stays
2698
+ readable when you zoom out to see a large subgraph.
2699
+
2700
+ Tier transitions are debounced so spinning the scroll wheel does not cause
2701
+ label flicker; labels only rewrite once zoom settles on a new tier.
2702
+
2703
+ ## Cluster-expand on Conversation/Message clicks (cluster-integrity fix)
2704
+
2705
+ Clicking a Conversation node OR any Message node pulls the WHOLE
2706
+ conversation cluster onto the canvas: the Conversation node itself plus
2707
+ every Message belonging to it (via `PART_OF`), capped at 200 messages
2708
+ for layout reasons. The arrow chain along the conversation (the `NEXT`
2709
+ edges) renders for free because the inter-node relationship pass picks
2710
+ up edges where both endpoints are in the visible window.
2711
+
2712
+ Pre-fix, clicking a middle Message expanded only its prev+next
2713
+ neighbours; the head, tail, and Conversation node dropped off, visually
2714
+ disintegrating the conversation. The new behaviour keeps the cluster
2715
+ intact across click navigation. `PART_OF` edges are now rendered between
2716
+ visible Conversation/Message pairs (previously suppressed because they
2717
+ "added no information when the Conversation node wasn't on canvas" — an
2718
+ assumption that broke the moment the cluster-expand put it there).
2719
+
2720
+ The breadcrumb above the canvas tracks each pivot — every entry except
2721
+ the last is clickable to pop the view-stack back to that point.
2722
+
2723
+ ## Tooltips and side panel
2724
+
2725
+ Hovering a node still shows the full 5-line tooltip (display name, labels,
2726
+ id, created at, updated at). Clicking a Conversation opens the side panel
2727
+ with the full property table — zoom-tier changes never alter these paths.
2728
+
2729
+ The side panel carries a **Trash** button for live nodes and a **Restore**
2730
+ button for trashed nodes. Soft-delete is reversible: trashed nodes
2731
+ remain in the graph and reappear when **Show trashed** is on.
2732
+
2733
+ ## Deleting a node
2734
+
2735
+ Two surfaces, same outcome:
2736
+
2737
+ - **Mouse (desktop):** drag a node to the dashed Trash zone in the upper-
2738
+ right corner of the canvas.
2739
+ - **Touch (mobile/tablet):** the dashed Trash zone is hidden because
2740
+ vis-network's drag hit-test never fires on touch. Tap the node to open
2741
+ the side panel, then tap **Trash**.
2742
+
2743
+ Both paths POST to the same soft-delete endpoint; the operator-side
2744
+ behaviour is identical.
2745
+
2746
+ ## Mobile layout
2747
+
2748
+ Below 640px viewport width the toolbar wraps: the search input claims
2749
+ its own row, the search-result slider claims its own row (full-width with
2750
+ an enlarged thumb for touch), and the Filter button + node count share
2751
+ the bottom row. The "← Back" control collapses to a left-arrow icon to
2752
+ preserve toolbar space at depth.
2753
+
2754
+ ## Trashed conversations
2755
+
2756
+ Trashed Conversation nodes are hidden by default. Toggle **Show trashed** in
2757
+ the filter popover to surface them; they render with a faded fill and dashed
2758
+ border, with their zoom-tier labels intact. The `N msgs` count excludes
2759
+ trashed Messages, so the detailed-tier label reflects only live turns in the
2760
+ conversation.
2761
+
2762
+ ## Filtering by channel and message kind
2763
+
2764
+ When you select **AdminConversation** or **PublicConversation** in the
2765
+ filter popover, two extra rows appear underneath the chip list:
2766
+
2767
+ - **Channel** — Web / WhatsApp. Select one to scope the canvas to
2768
+ conversations that came in over that channel only. Selecting both is
2769
+ the same as selecting neither (all channels). After the migration that
2770
+ ships with this release, every conversation carries an explicit
2771
+ channel value — pre-existing conversations are backfilled to "Web"
2772
+ because only the WhatsApp and Telegram intake paths ever set non-Web
2773
+ values.
2774
+ - **Message** — User / Assistant / WhatsApp. When you've also pivoted
2775
+ into a conversation neighbourhood (or your search hits messages
2776
+ directly), this row scopes the messages on canvas to the chosen kind.
2777
+ WhatsApp messages persist with their own sublabel so you can isolate
2778
+ the live-channel cohort from the agent-path cohort within the same
2779
+ conversation.
2780
+
2781
+ These sub-facets compose with the chip selection. Searching with the
2782
+ AdminConversation chip selected now also reaches the body text of every
2783
+ admin message — typing a rare word like "ATM" returns every conversation
2784
+ that mentions it, not just conversations with that word in the title.
2785
+
2786
+ ## Sidebar conversations list
2787
+
2788
+ The Recents list above the chat sidebar carries a per-row marker:
2789
+ WhatsApp conversations show a small WhatsApp glyph next to the
2790
+ conversation name. The dropdown above the list filters Recents to a
2791
+ specific channel — flipping it to **WhatsApp** hides web-chat
2792
+ conversations and vice versa.
2793
+
2794
+ ## Agents in the graph
2795
+
2796
+ Both admin and public agents appear as `:Agent` nodes in the graph. Open
2797
+ the **Agents** entry from the sidebar to see them all. Each agent
2798
+ carries a `:HANDLED_BY` edge from every conversation it has handled, so
2799
+ you can pivot from an agent to the conversations it ran. The admin
2800
+ agent's IDENTITY, SOUL, KNOWLEDGE, and KNOWLEDGE-SUMMARY documents
2801
+ appear as :KnowledgeDocument nodes connected via `HAS_*` edges, the same
2802
+ projection shape used for public agents.
2803
+
2804
+ ## Agent-execution telemetry
2805
+
2806
+ `ToolCall`, `StepResult`, `WorkflowStep`, and `WorkflowRun` nodes are
2807
+ agent-execution telemetry — kept for audit but noisy for day-to-day graph
2808
+ navigation (they make up roughly 9% of a typical brand's live nodes).
2809
+ They are hidden from `/graph` by default. To see them — for audit, debug,
2810
+ or tracing a specific agent run — open the filter popover and tick
2811
+ **Include agent actions** (the checkbox directly below **Show trashed**).
2812
+ Flipping it on surfaces the four labels as chips in the popover roster AND
2813
+ keeps them on the canvas when you pivot into a neighbourhood. The toggle
2814
+ is session-scoped: every new session starts with agent actions hidden, so
2815
+ the 90% domain-navigation path stays clean without having to remember to
2816
+ switch them off. Flipping it off again also drops them from any already-
2817
+ expanded neighbourhood so a click near a `ToolCall` does not re-introduce
2818
+ it.
2819
+
2820
+ ## Direct edge management
2821
+
2822
+ `memory-edge` creates or deletes a typed directed edge between two nodes that already exist in the graph. Both nodes must belong to the same account — mismatched or foreign nodes are rejected with a structured error before any mutation runs.
2823
+
2824
+ **Create:** MERGE is idempotent. First call returns `{created: true}`; a repeated call with the same endpoints and type returns `{created: false}`. Properties supplied on the call are stamped onto the relationship on CREATE only; a subsequent idempotent hit does not overwrite them.
2825
+
2826
+ **Delete:** If the edge is present it is deleted and `{deleted: true}` is returned. If absent, the call is a no-op and returns `{deleted: false}`.
2827
+
2828
+ `relationshipType` is uppercase-coerced. Types that start with an underscore (e.g. `_SOFT_DELETE`) are reserved for platform internals and are rejected.
2829
+
2830
+ Typical flow: call `memory-search` for each endpoint to retrieve their `elementId` values, then call `memory-edge action=create relationshipType=RELATES_TO fromId=<id> toId=<id>`. The new edge appears when you hop-expand either endpoint on the `/graph` canvas.
2831
+
2832
+ ---
2833
+ # Neo4j Edge Types
2834
+ Source: https://docs.getmaxy.com/neo4j.md
2835
+
2836
+ # Neo4j edge types — operator reference
2837
+
2838
+ How SiteDesk's graph wires itself.
2839
+
2840
+ ## Typed-edge auto-extraction
2841
+
2842
+ When the operator types `/insight`, the admin agent delegates one pass to the `database-operator` specialist. That pass reads every prose-bearing node your account wrote since the last completed insight pass — messages, meetings, notes, pages, posts, reports, emails, ideas — and asks Claude Haiku to propose typed edges from the text. Only edges that match a closed allowlist of `(sourceLabel, EDGE_TYPE, targetLabel)` shapes are MERGEd into the graph. The graph wires itself; you do not have to ask for it.
2843
+
2844
+ If a session never runs an insight pass, its prose nodes are not lost — the next `/insight`, in that session or a later one, picks them up, because the pass is scoped by what changed since the last completed one rather than by which session wrote it. The cost of skipping is a delay, not lost extraction.
2845
+
2846
+ ## Typed-edge allowlist
2847
+
2848
+ <!-- TYPED-EDGE-TABLE:START -->
2849
+
2850
+ <!-- Generated by platform/plugins/memory/mcp/scripts/generate-edge-docs.ts from TYPED_EDGE_ALLOWLIST. Do not edit by hand. -->
2851
+
2852
+ | Source label | Edge type | Target label |
2853
+ |---|---|---|
2854
+ | Person | ATTENDED | Event |
2855
+ | Person | ATTENDED | Meeting |
2856
+ | Person | WORKS_AT | Organization |
2857
+ | Person | WORKS_AT | LocalBusiness |
2858
+ | Person | INVESTED_IN | Organization |
2859
+ | Person | INVESTED_IN | LocalBusiness |
2860
+ | Organization | INVESTED_IN | Organization |
2861
+ | Organization | INVESTED_IN | LocalBusiness |
2862
+ | Person | FOUNDED | Organization |
2863
+ | Person | FOUNDED | LocalBusiness |
2864
+ | Person | ADVISES | Organization |
2865
+ | Person | ADVISES | LocalBusiness |
2866
+ | Person | ADVISES | Person |
2867
+ | Message | MENTIONS | Person |
2868
+ | Message | MENTIONS | Organization |
2869
+ | Message | MENTIONS | LocalBusiness |
2870
+ | Message | MENTIONS | Event |
2871
+ | Page | MENTIONS | Person |
2872
+ | Page | MENTIONS | Organization |
2873
+ | Page | MENTIONS | LocalBusiness |
2874
+ | Page | MENTIONS | Event |
2875
+ | Meeting | MENTIONS | Person |
2876
+ | Meeting | MENTIONS | Organization |
2877
+ | KnowledgeDocument | MENTIONS | Person |
2878
+ | KnowledgeDocument | MENTIONS | Organization |
2879
+ | ConversationArchive | MENTIONS | Person |
2880
+ | ConversationArchive | MENTIONS | Organization |
2881
+ | Note | MENTIONS | Person |
2882
+ | Note | MENTIONS | Organization |
2883
+ | Idea | MENTIONS | Person |
2884
+ | Idea | MENTIONS | Organization |
2885
+ | Post | MENTIONS | Person |
2886
+ | Post | MENTIONS | Organization |
2887
+ | Report | MENTIONS | Person |
2888
+ | Report | MENTIONS | Organization |
2889
+ | Person | AUTHORED | Post |
2890
+ | Person | AUTHORED | Report |
2891
+ | Person | AUTHORED | Page |
2892
+ | Person | AUTHORED | Note |
2893
+ | KnowledgeDocument | ATTACHED_TO | Meeting |
2894
+ | Page | ATTACHED_TO | Project |
2895
+ | Note | ATTACHED_TO | Project |
2896
+ | Page | REFERENCES | Page |
2897
+ | Report | REFERENCES | Report |
2898
+ | Report | REFERENCES | Page |
2899
+ | Person | REPORTS_TO | Person |
2900
+ | Source | AUTHORED_BY | Person |
2901
+ | Project | ADVANCES | Objective |
2902
+ | Project | ADVANCES | KeyResult |
2903
+ | Task | ADVANCES | Objective |
2904
+ | Task | ADVANCES | KeyResult |
2905
+ | Task | DEPENDS_ON | Task |
2906
+
2907
+ <!-- TYPED-EDGE-TABLE:END -->
2908
+
2909
+ ---
2910
+ # Platform Internals
2911
+ Source: https://docs.getmaxy.com/internals.md
2912
+
2913
+ # Platform Internals — Retrieval Architecture
2914
+
2915
+ Technical architecture reference for the retrieval pipeline, knowledge delivery, and supporting infrastructure. This document covers how information moves from the Neo4j graph into an agent's context — the mechanics behind "SiteDesk searches this graph to retrieve relevant context."
2916
+
2917
+ Use this reference when assessing capabilities, diagnosing retrieval behaviour, or answering questions about how the platform works internally. When a question asks "does SiteDesk have X?" — check here before asserting a gap.
2918
+
2919
+ ---
2920
+
2921
+ ## Retrieval Pipeline Overview
2922
+
2923
+ Every knowledge query flows through a hybrid search pipeline that combines semantic similarity with keyword matching, applies layered access controls, expands results via graph traversal, and optionally re-ranks via LLM reasoning.
2924
+
2925
+ ```
2926
+ QUERY ── (retrievalClass from gateway-classifier)
2927
+
2928
+ ├── EXPAND (Haiku — 3-5 paraphrases, 1h cache) [flag: MAXY_GS_EXPANSION]
2929
+
2930
+ ├── ROUTE (per-class label filter + fusion weights) [flag: MAXY_GS_ROUTE]
2931
+
2932
+ ├── For each query ────► EMBED ──► VECTOR SEARCH ──┐
2933
+ │ ├─► FUSE (weighted-sum or RRF) [flag: MAXY_GS_RRF]
2934
+ │ └────► BM25 FULL-TEXT ──────────┘
2935
+ │ (entity_search — universal coverage)
2936
+
2937
+ ├── BOOST (compiledTruth +15%, backlinks log 5-25%) [flag: MAXY_GS_BOOSTS]
2938
+ ├── DEDUP (4 layers: nodeId, slug, canonicalName, hash) [flag: MAXY_GS_DEDUP]
2939
+ ├── THRESHOLD + SORT + SLICE
2940
+ └── GRAPH EXPAND ──► RESULTS
2941
+
2942
+ Fusion (default / weighted-sum): combined = 0.7 × vector + 0.3 × bm25_norm
2943
+ Fusion (RRF): score = Σ 1 / (60 + rank_i) across ranked lists
2944
+ Fallback: if the full-text index doesn't exist, vector-only results are returned (graceful degradation, no error).
2945
+ ```
2946
+
2947
+ Each enhancement is independently flagged. All flags default OFF — the unflagged pipeline is identical to the baseline weighted-sum + nodeId-only-dedup behaviour. Typed-edge backlinks and the compiledTruth property have landed, so the boost data is populated; flag activation, soak windows, and per-flag measurement remain pending.
2948
+
2949
+ ### Hybrid Search Detail
2950
+
2951
+ **Vector path:** The query is embedded via Ollama (model per `EMBED_MODEL` env var, default `nomic-embed-text`). The resulting vector is compared against Neo4j's HNSW cosine indexes — one per indexed label. Dimensions are configured at install time (default 768). The search runs against all discovered indexes (or a subset if the caller specifies label filters). Scores are in [0, 1] (cosine similarity).
2952
+
2953
+ **BM25 path:** The raw query text is escaped for Lucene special characters and run against the `entity_search` full-text index (earlier platform fixes — universal coverage), which spans every operator-meaningful label written by the platform on the canonical text-property union (~28 properties: `name`, `firstName`, `lastName`, `givenName`, `familyName`, `title`, `summary`, `body`, `content`, `description`, `headline`, `email`, `subject`, `bodyPreview`, etc.). Earlier the index was named `knowledge_fulltext` and covered only `KnowledgeDocument | Section | Chunk` — that gap silently hid Person/Organization/Task/Event/etc. from BM25 regardless of query. Raw BM25 scores are in [0, infinity) — they are normalised to [0, 1] via min-max scaling within the result set before merging. When all scores are equal (or a single result), all normalise to 1.0.
2954
+
2955
+ **Merge:** Results from both paths are collected in a single map keyed by `nodeId`. A node appearing in both paths accumulates the max vector score and max BM25 score independently. The combined score is `0.7 * vectorScore + 0.3 * bm25Score`. Results are sorted descending by combined score, then sliced to the requested limit (default 10).
2956
+
2957
+ ### Enhancements (flagged, default off)
2958
+
2959
+ | Stage | Module | Flag | What it does |
2960
+ |---|---|---|---|
2961
+ | Routing | `route.ts` | `MAXY_GS_ROUTE` | Picks per-class label filter + fusion weights from the `retrievalClass` hint produced by the gateway-classifier. `entity` → vector-heavy + Person/Company/Concept; `temporal` → BM25-heavy over Event; `event` → BM25-only over Event; `general` → balanced; `none` → skip the lookup. |
2962
+ | Multi-query expansion | `query-expansion.ts` | `MAXY_GS_EXPANSION` | Haiku generates 3-5 paraphrases per query; each runs through vector + BM25 in parallel, with results unioned before fusion. Per-call 1-hour cache keyed by (accountId, query, retrievalClass). Graceful degrade on Haiku failure — original query only. |
2963
+ | RRF fusion | `rrf-fusion.ts` | `MAXY_GS_RRF` | Replaces weighted-sum with Reciprocal Rank Fusion (k=60 by default). Sums `1 / (k + rank)` per node across the ranked lists each pass produces. More robust to score-distribution drift between indexes than weighted-sum. Weighted-sum stays as the fallback. |
2964
+ | compiledTruth boost | `boosts.ts` | `MAXY_GS_BOOSTS` | +15% to the combined score of any hit whose node carries a non-null `compiledTruth` property (populated on Person/Company/Concept). The property is in the `entity_search` index so BM25 hits against summary text are also matched. |
2965
+ | Backlink boost | `boosts.ts` | `MAXY_GS_BOOSTS` | `bump = clamp(0.05 + 0.05 × log10(backlinkCount), 0.05, 0.25)`. 1 backlink → +5%; 10 → +10%; 100 → +15%; 1000+ → +20%; capped at +25%. Reads `backlinkCount` populated by the typed-edge hook. |
2966
+ | 4-layer dedup | `dedup.ts` | `MAXY_GS_DEDUP` | Strict superset of nodeId-only dedup. Layers: `nodeId`, `slug`, `canonicalName` (case-insensitive, falls back to `name`), `contentHash` (sha256 of `compiledTruth || content`). Highest-score representative wins per collision class. Missing keys skip the layer, no false collision. |
2967
+
2968
+ A per-call log line lets the operator see which stages ran with which counts:
2969
+
2970
+ ```
2971
+ [graph-search:hybrid] accountId=<8c> retrievalClass=<c> expansions=<n> vector=<n> bm25=<n> fused=<n> boosted=<n> deduped=<n> final=<n> mode=<hybrid|rrf|bm25> ms=<ms> expand-ms=<ms>
2972
+ ```
2973
+
2974
+ ### What the hybrid approach catches
2975
+
2976
+ Vector search excels at semantic meaning — "how do I contact someone" finds nodes about communication even if the word "contact" doesn't appear. BM25 excels at exact terms — invoice numbers, product codes, proper nouns, technical identifiers. The hybrid combination ensures both modes contribute, with semantic similarity weighted higher (0.7) because most user queries are natural language.
2977
+
2978
+ ---
2979
+
2980
+ ## Embedding Infrastructure
2981
+
2982
+ | Property | Value |
2983
+ |---|---|
2984
+ | Model | Default `nomic-embed-text` (via Ollama at `localhost:11434`), configurable at install time via `--embed-model` |
2985
+ | Dimensions | Default 768, configurable at install time (resolved from model lookup table or `--embed-dimensions`) |
2986
+ | Similarity function | Cosine |
2987
+ | Index algorithm | HNSW (approximate nearest-neighbor) |
2988
+ | Configurable via | `EMBED_MODEL` and `EMBED_DIMENSIONS` env vars (set by installer in `~/{configDir}/.env`), `OLLAMA_URL` |
2989
+
2990
+ ### Indexed node labels
2991
+
2992
+ Every searchable node type has its own vector index. The `memory-search` tool discovers indexes at runtime via `SHOW INDEXES` and caches the label-to-index mapping. This means new index definitions in `schema.cypher` become searchable automatically without code changes.
2993
+
2994
+ Indexed labels: `Question`, `DefinedTerm`, `Review`, `Service`, `Person`, `LocalBusiness`, `PriceSpecification`, `Task`, `CreativeWork`, `DigitalDocument`, `KnowledgeDocument` (includes email threads via `source:'email'`), `Section`, `Chunk`, `Conversation`, `Message`, `Event`, `Workflow`, `Preference` (18 labels total).
2995
+
2996
+ ### Full-text index
2997
+
2998
+ | Index name | Labels | Properties | Purpose |
2999
+ |---|---|---|---|
3000
+ | `entity_search` | All operator-meaningful labels (~40, see [`schema.cypher`](../../../neo4j/schema.cypher)) | Canonical text-property union (~28) | Universal BM25 keyword matching across the whole graph |
3001
+
3002
+ ### Embedding lifecycle
3003
+
3004
+ Embeddings are computed at write time for **every** node of a vector-indexed label, on every write path — the per-node tools (`memory-write`, `memory-ingest`, `profile-update`, `project-create`), the bulk archive ingest (`memory-archive-write`: LinkedIn / Obsidian / Notion), the conversation-insight emitters, and the raw-Cypher admin/scheduling/UI paths. Small entities embed a bounded props representation; document/archive labels embed a bounded `summary` plus per-`:Section` body embeddings (the archive path uses a deterministic sectioniser since it has no LLM classifier). The authoritative indexed-label set is `VECTOR_INDEXED_LABELS` in `platform/lib/graph-write`, pinned to `schema.cypher` by a drift test.
3005
+
3006
+ If Ollama is unavailable at write time, the node is stored without an embedding (property-searchable, not vector-searchable) and a `[graph-write] warn reason=embed-failed` line is emitted — a failed embed never aborts the write. The two standing audits in the UI server's `graph-health` timer surface any backlog: `[embed-audit] null-embedding labels=… count=N` and `[account-audit] null-account labels=… count=N` (both healthy at 0).
3007
+
3008
+ The `memory-reindex` tool backfills missing embeddings by iterating nodes where `embedding IS NULL`. It uses the bounded representation (the `summary` for document/archive labels, never the raw body), embeds in batches with a per-node fallback on batch error, and **skips and continues** past a failing node — keeping skipped nodes out of the re-fetch via an exclude set — instead of aborting the whole run. `embed()`/`embedBatch()` cap oversized input (`EMBED_INPUT_MAX_CHARS`) before the Ollama POST, so a large body embeds truncated rather than throwing. Per-node `[reindex] op=embedded|skip-error` lines and a terminal `[reindex] op=done processed=N skipped=M`.
3009
+
3010
+ `embedBatch()` also paces large batches. A document's summary plus every section body in one `/api/embed` POST pins ollama's `llama-server` across all cores for the whole batch with no idle gaps; on a passively-cooled Pi the SoC climbs past its soft-temp limit and the board thermally hard-resets. `embedBatch` splits an input array longer than `EMBED_SUBBATCH_SIZE` (default 32) into sub-batches, waiting `EMBED_SUBBATCH_COOLDOWN_MS` (default 1000) between them so the SoC gets cooling gaps; vectors are concatenated in input order. Both knobs are env-overridable for on-device tuning. The load-bearing thermal protection is the installer's `CPUQuota` cap on `ollama.service` (every embed caller is bounded there regardless of batch shape); this pacing is defence-in-depth. The UI's file-index path uses its own single-input embed client in `platform/ui/app/lib/neo4j-store.ts` (one embed per file, not a batch), so it is covered by the CPU cap, not by `embedBatch` pacing.
3011
+
3012
+ ---
3013
+
3014
+ ## Knowledge Document Hierarchy
3015
+
3016
+ Large documents are decomposed into a three-level hierarchy for granular retrieval:
3017
+
3018
+ ```
3019
+ KnowledgeDocument
3020
+ ├── summary (embedded) — document-level semantic anchor
3021
+ ├── Section
3022
+ │ ├── summary (embedded) — section-level semantic anchor
3023
+ │ └── Chunk
3024
+ │ ├── summary (embedded) — chunk-level semantic anchor
3025
+ │ └── content (raw text, BM25-indexed) — full content for retrieval
3026
+ └── attachmentId — links back to the source file
3027
+ ```
3028
+
3029
+ All three levels are independently vector-indexed and BM25-indexed. A query may match at the document level (broad topic), section level (sub-topic), or chunk level (specific passage). Graph expansion from a matched chunk retrieves its parent section and document for context.
3030
+
3031
+ ### Semantic chunking
3032
+
3033
+ Documents are split by a semantic chunker that identifies topic boundaries rather than using fixed character counts. Each chunk gets a summary (used for embedding) and retains the raw content (used for BM25 and for returning to the agent).
3034
+
3035
+ ---
3036
+
3037
+ ## Response-side `fields` projection
3038
+
3039
+ `memory-search` accepts an optional `fields: string[]` that narrows the
3040
+ `properties` returned on each row to the caller-named keys. This is a
3041
+ read-side payload trim only — it runs **after** `hybrid()` returns, so
3042
+ vector search, BM25, keyword subscriptions, and graph expansion all see
3043
+ the full text. Ranking does not change.
3044
+
3045
+ - `fields` omitted → today's behaviour (every property except `embedding`).
3046
+ - `fields: ["name", "slug"]` → only those keys per row.
3047
+ - `fields: []` → empty `properties` object — explicit "no properties".
3048
+ - Unknown keys are silently skipped. Rows lacking a requested key omit it
3049
+ on that row.
3050
+ - `related[*].properties` is NOT projected (separate concern).
3051
+
3052
+ Use this when the caller knows which keys it needs (slug → name, Person →
3053
+ phoneNumber). It is the safe alternative to write-time summarisation,
3054
+ which is lossy: write-time pruning has no way to know which keys a future
3055
+ query will want.
3056
+
3057
+ Observability: when `fields` is set, `memory-search.ts` writes
3058
+ `[memory-search] accountId=… fields=… returnedProps=N droppedProps=N` to
3059
+ stderr. `droppedProps=0` across many calls with `fields` set is a
3060
+ diagnostic signal — either the schema has already been narrowed upstream,
3061
+ or callers are requesting every field and defeating the purpose.
3062
+
3063
+ ## Guard Layers
3064
+
3065
+ Every query path — vector search, BM25 search, keyword subscriptions, and graph expansion — applies a consistent set of access control filters. These are Cypher WHERE clauses, not middleware, so they cannot be bypassed by tool parameter manipulation.
3066
+
3067
+ ### Layer 1: Soft-delete filter
3068
+
3069
+ ```
3070
+ WHERE node.deletedAt IS NULL
3071
+ ```
3072
+
3073
+ Unconditional. No parameter controls it. Nodes with a `deletedAt` timestamp are excluded from all query paths. Soft-deleted `KnowledgeDocument` nodes cascade the timestamp to all child `Section` and `Chunk` nodes. Grace period before hard deletion: 7 days. Re-ingesting a soft-deleted document (same `attachmentId`) clears `deletedAt` and replaces the hierarchy.
3074
+
3075
+ ### Layer 2: Scope filter
3076
+
3077
+ ```
3078
+ WHERE (node.scope IS NULL OR node.scope IN $allowedScopes)
3079
+ ```
3080
+
3081
+ When `allowedScopes` is set (e.g., `["public", "shared"]` for public agents), only nodes with a matching `scope` property — or no scope at all (legacy transitional safety) — are returned. When `allowedScopes` is omitted (admin agent), no scope filtering is applied. Scope values: `public`, `shared`, `admin`.
3082
+
3083
+ ### Layer 3: Per-agent tag filter
3084
+
3085
+ ```
3086
+ WHERE node.agents IS NOT NULL AND $agentSlug IN node.agents
3087
+ ```
3088
+
3089
+ When `agentSlug` is set (public agent queries), only nodes explicitly tagged for that agent are returned. The `agents` property is a string array on each node — a node is visible to an agent only if the agent's slug appears in this array. No implicit "available to all" fallback. This is enforced at the MCP server level via the `AGENT_SLUG` environment variable — tool parameter overrides are rejected when the env var is set.
3090
+
3091
+ **Defense in depth:** Both scope and agent filters must pass. An admin-scoped node tagged for a public agent is still invisible to that agent because the scope filter rejects it first.
3092
+
3093
+ ### Layer 4: Graph expansion enforcement
3094
+
3095
+ Related nodes discovered during hop traversal are independently filtered:
3096
+
3097
+ ```
3098
+ WHERE (related.scope IS NULL OR related.scope IN $allowedScopes)
3099
+ AND (related.agents IS NULL OR $agentSlug IN related.agents)
3100
+ AND related.deletedAt IS NULL
3101
+ ```
3102
+
3103
+ This prevents cross-agent content leakage via graph traversal — a public agent cannot reach admin-scoped nodes by following relationships from a public node. Untagged related nodes (no `agents` property) pass through, allowing shared structural nodes (e.g., `PriceSpecification` linked to a `Service`) to be discoverable.
3104
+
3105
+ ### Layer 5: Account isolation
3106
+
3107
+ ```
3108
+ WHERE node.accountId = $accountId
3109
+ ```
3110
+
3111
+ Multi-tenancy boundary. Every query is scoped to the requesting account. The `ACCOUNT_ID` environment variable is set at MCP server startup — it is not a tool parameter and cannot be overridden by the agent.
3112
+
3113
+ The read filter alone is not sufficient — it correctly *hides* alien-account nodes from every UI but does not prevent them existing. A writer that misresolves `accountId` (literal, undefined, or inferred-from-the-wrong-context) leaks nodes into the graph with no downstream symptom; the read filter then keeps them invisible indefinitely. The write-side doctrine is documented in `.docs/neo4j.md` "Account isolation invariant" — every writer that stamps `n.accountId` must verify the value against `${DATA_ROOT}/accounts/<id>/account.json` before write. The live floor is `writeNodeWithEdges` — every doctrine-primitive write is gated by an `accountId == process.env.ACCOUNT_ID` check (the spawning process validates `ACCOUNT_ID` at boot against the on-disk account set via the `account-enumeration` lib), with `[graph-write] reject reason=invalid-account-id …` as the rejection signal.
3114
+
3115
+ **Two boot-time surfaces stamp + validate the env** (added 2026-05-07). The brand systemd unit emits `Environment=ACCOUNT_ID=<uuid>` (resolved by the installer from `INSTALL_DIR/data/accounts/<uuid>/account.json`); the Hono boot path then calls `validateAccountIdEnv` against the on-disk set and emits `[graph-health] account-id-env present=true id=<8> matches-on-disk=true` on success or `[graph-health] account-id-env FATAL reason=<missing|no-on-disk-account|mismatch>` + `process.exit(1)` on failure. No fallback — a misconfigured Pi cannot silently boot.
3116
+
3117
+ ---
3118
+
3119
+ ## Query Classification
3120
+
3121
+ Before searching, a Haiku classifier decides whether a query needs knowledge retrieval at all. This prevents meta-queries ("hello", "thanks", "continue") from polluting the system prompt with irrelevant search results.
3122
+
3123
+ | Property | Admin variant | Public variant |
3124
+ |---|---|---|
3125
+ | Model | `claude-haiku-4-5` | Same |
3126
+ | Timeout | 3 seconds | Same |
3127
+ | History window | Last 4 messages (2 user + 2 assistant) | Same |
3128
+ | Max tokens | 200 | 120 |
3129
+ | Query rewriting | Yes — resolves references from history into concrete search terms | Same |
3130
+ | Topic-change detection | Yes — detects shifts with confidence score | No (removed, earlier platform fixes) |
3131
+ | Fallback on failure | `search: true` (always search with raw message) | Same |
3132
+
3133
+ ### Classification output
3134
+
3135
+ The classifier returns a JSON object:
3136
+ - `search` (boolean) — whether a knowledge search should run
3137
+ - `query` (string or null) — a search-optimised rewrite of the user's message, or null to use the raw message
3138
+ - `reason` (string) — short explanation of the decision
3139
+
3140
+ When `search` is true and `query` is non-null, the rewritten query replaces the raw message for the memory-search call. This is important: the classifier resolves pronouns and references from conversation history into concrete terms, improving retrieval precision.
3141
+
3142
+ ### Knowledge retrieval gate
3143
+
3144
+ The public agent is toolless by construction: it has no `memory-search`, no graph access mid-turn, and no tools of any kind. KNOWLEDGE.md (when present) plus SOUL are assembled into the agent's system prompt at spawn time and are the entire knowledge surface. Every `role=public` spawn (webchat, whatsapp, telegram) resolves an empty allowlist and runs in `dontAsk` with a per-spawn `permissions.deny` covering every native, harness, and memory-MCP tool. The spawner anchors the empty allowlist with a single non-native deny-basis token (`mcp__none__deny-basis`) so `--allowed-tools` is always present and native-excluding — without it, `dontAsk` would have nothing to deny against and the brand `allow:["*"]` would re-open native tools.
3145
+
3146
+ ### The canonical public-agent locator
3147
+
3148
+ There is exactly one place each datum is read from, and every subsystem reads it the same way:
3149
+
3150
+ - **Default agent + account id** come from the canonical account config `data/accounts/<id>/account.json`, resolved via `resolveAccount` / `resolveDefaultAgentSlug` / `getDefaultAccountId` (`app/lib/claude-agent/account.ts`). The UI server's bare-root handler and branding loader read it through these helpers — never from `~/.<brand>/account.json`, which nothing writes. A `null` default means a genuinely unset `defaultAgent`; the root logs `[public-root] op=serve-default slug=<s>` on success and `op=no-default` only when the canonical default is truly empty.
3151
+ - **Identity files** (IDENTITY.md, SOUL.md, KNOWLEDGE.md) come from `agents/<slug>/` — keyed on the agent's slug, never the literal role. A public agent renamed to a slug `≠ "public"` (e.g. `maxy-info`) spawns from `agents/maxy-info/`. Admin reads `agents/admin/`. The spawn composer and the standing reachability audit resolve this directory through one shared function, `resolveAgentIdentityDir(accountDir, role, slug)` (`claude-session-manager/src/agent-identity-locator.ts`), so the path the audit vouches for is byte-identical to the path the spawn reads — the audit's `reachable=true` implies the spawn will find the files, and a slug whose files are misplaced is reported `reachable=false reason=files-missing file=<path>` without a visitor request.
3152
+
3153
+ ### Observability
3154
+
3155
+ Admin: `[admin-query-classifier]` log line with `topicChange`, `topicChangeConfidence`, `existingTopic`, `latencyMs`.
3156
+
3157
+ Public: `[public-query-classifier]` log line with `search`, `effectiveQuery`, `reason`, `latencyMs`. The intentional absence of topic-change fields in the public log is the on-disk evidence that the public path does less work.
3158
+
3159
+ ---
3160
+ ---
3161
+
3162
+ ## Reports — durable workflow output
3163
+
3164
+ The `:Report` label is the platform's durable shape for workflow output the operator may want back later — daily briefings, dream cycle runs, ad-hoc analyses. Three MCP tools own the surface, all on the memory plugin:
3165
+
3166
+ - `memory-report-write` — append-only writer. Validates body ≤ 10,000 chars, embeds title+body, and CREATEs a `:Report` node. Idempotent on `(accountId, title, occurredAt-within-same-minute)` — a second call with the same title in the same minute returns the existing node instead of duplicating. Parented to the active `:Conversation` via `:PRODUCED` when `SESSION_NODE_ID` is set (the chat-driven default); falls back to the account's `:AdminUser` so the graph-hierarchy doctrine holds even outside a conversation.
3167
+ - `memory-report-read-latest` — fetches the newest `:Report` (default `limit=1`) tagged with a given keyword. The expected route for any operator phrasing of "latest X", "last night's X", "show me X report".
3168
+ - `memory-report-list` — metadata-only paginated listing (newest first), with optional `keyword` and `sourceWorkflow` filters. Use to scan the catalogue without paying for full bodies.
3169
+
3170
+ Every operation emits one log line: `[reports] op=<write|read-latest|list> reportId=<short> keywords=<csv> ms=<n>` (with `idempotent=1` on a write that resolved to an existing node, `hits=<n>` on reads, `total=<n>` on list).
3171
+
3172
+ Routing is not classifier-side. The admin agent's `IDENTITY.md` carries the rule under **Recalling reports**: "latest <X>" / "last night's <X>" / "show me <X> report" → first tool call is `memory-report-read-latest`. The intent classifier (the `retrievalClass` hint) already differentiates temporal vs entity vs event reads; reports route off the literal phrase, not a new class.
3173
+
3174
+ The first caller is the `briefing` skill (`platform/plugins/scheduling/skills/briefing/SKILL.md`), which persists each run as a `:Report` with `title: "Daily briefing <YYYY-MM-DD>"`, `keywords: ["daily-briefing", "<YYYY-MM-DD>"]`, `sourceWorkflow: "daily-briefing"`. Dream-cycle and ad-hoc analyses are expected to follow the same pattern.
3175
+
3176
+ ---
3177
+
3178
+ ## Graph Expansion
3179
+
3180
+ After the top results are selected (by combined score or by LLM ranking), each result node is expanded by traversing its immediate relationships.
3181
+
3182
+ ### Traversal mechanics
3183
+
3184
+ ```cypher
3185
+ MATCH (n)-[r]-(related)
3186
+ WHERE elementId(n) = $nodeId
3187
+ AND related.deletedAt IS NULL
3188
+ AND (related.scope IS NULL OR related.scope IN $allowedScopes)
3189
+ AND (related.agents IS NULL OR $agentSlug IN related.agents)
3190
+ RETURN type(r), direction, labels(related), related
3191
+ LIMIT 20
3192
+ ```
3193
+
3194
+ - **Default hop depth:** 1 (immediate relationships only)
3195
+ - **Related nodes cap:** 20 per primary result
3196
+ - **Direction tracking:** Each relationship is labelled `outgoing` or `incoming`
3197
+ - **Scope enforcement:** All guard layers (soft-delete, scope, agent) apply to related nodes
3198
+ - **Configurable:** `expandHops: 0` produces compact output (properties only, no related nodes) — useful for listing/inventory queries
3199
+
3200
+ ### What expansion provides
3201
+
3202
+ A `Service` node matched by vector search will have its `PriceSpecification`, `Review` nodes, and parent `LocalBusiness` attached as related nodes. A `Chunk` matched by BM25 will have its parent `Section` and `KnowledgeDocument`. This context enrichment means the agent receives not just the matched node but its immediate neighbourhood in the graph.
3203
+
3204
+ ---
3205
+
3206
+ ## Keyword Subscriptions — Reactive Per-Agent Knowledge
3207
+
3208
+ Each public agent can subscribe to up to 5 keywords via `knowledgeKeywords` in its `config.json`. These subscriptions make the agent reactive to new graph content matching its topics — content added after the agent was created becomes discoverable without manual tag updates.
3209
+
3210
+ ### Dual search per keyword
3211
+
3212
+ For each subscription keyword, two complementary searches run:
3213
+
3214
+ 1. **BM25 full-text search** — queries the universal `entity_search` index with the keyword as the search term. Catches content that mentions the keyword in its text across every operator-meaningful label.
3215
+
3216
+ 2. **Property-based search** — finds nodes whose `keywords` array property contains the subscription keyword (case-insensitive). Catches nodes explicitly tagged with that keyword topic. These matches are boosted to maximum BM25 score (1.0) since they are exact tag matches.
3217
+
3218
+ Both searches run **without** the per-agent tag filter (`agentSlug`) — keyword subscriptions are scope-inclusive by design, meaning an agent's subscriptions can discover content not directly tagged for it. The scope filter (`allowedScopes`) still applies as defense in depth — admin-only content remains invisible to public agents regardless of keyword matches.
3219
+
3220
+ ### Union semantics
3221
+
3222
+ Results from keyword subscription searches are merged into the same scored map as the primary vector+BM25 results. Deduplication by `nodeId` with `Math.max` on scores means a node found by both direct search and keyword subscription keeps the highest score from each method.
3223
+
3224
+ ### Lifecycle
3225
+
3226
+ Keywords are consumed by the `update-knowledge` admin skill when regenerating KNOWLEDGE.md — the regeneration query broadens the operator-tagged set with keyword matches so newly-added graph content that shares a subscribed topic lands in the next baked snapshot. There is no runtime keyword-injection path on the public PTY surface.
3227
+
3228
+ ---
3229
+
3230
+ ## Conversation Search
3231
+
3232
+ Separate from the knowledge retrieval pipeline, `conversation-search` provides semantic search over past messages.
3233
+
3234
+ - **Index:** `message_embedding` (768-dim cosine HNSW on `Message` nodes)
3235
+ - **Scope:** When `SESSION_ID` is set (public agent), results are limited to that conversation. Admin searches all conversations.
3236
+ - **Output:** Messages with role, content, timestamp, and relevance score.
3237
+
3238
+ This tool is read-only and available to both public and admin agents.
3239
+
3240
+ ### When conversations are created
3241
+
3242
+ `:Conversation` nodes on webchat (admin login, "New conversation" in the burger, a new public visitor) are created lazily. Opening the chat or logging in does not write anything to the graph — SiteDesk only records the conversation once the user sends a second message. This keeps `conversation-search` and the Conversations modal free of one-turn abandoned threads. WhatsApp and Telegram take the opposite posture: every inbound — DM or group, allowed or activation-off, agent-invoked or gated — MERGEs the `:Conversation` and writes a forensic `:Message:WhatsAppMessage` row before any access-control decision. The graph is the durable record of every message the device received, not just the ones the agent replied to. See `.docs/web-chat.md` "Deferred conversation persistence" and `.docs/whatsapp.md` "Session continuity" for the full contract.
3243
+
3244
+ Each row in the Conversations modal exposes a `View logs` row-action that opens a popover with three links — **Stream**, **Errors**, **SSE** — each of which targets `/api/admin/logs?type={stream|error|sse}&sessionId={full-id}` in a new tab. The row's 8-char id chip is click-to-copy; hover reveals the full `sessionId` as a tooltip. See `.docs/web-chat.md` "In-chat retrieval" for the route contract and `console.debug` observability.
3245
+
3246
+ ### Static publish surface — `/sites/*`
3247
+
3248
+ SiteDesk hosts a generic per-account static-tree publish surface at `https://public.<brand>/sites/<...>/<file>`. The route serves files from `<accountDir>/sites/<...>` with URL=disk mirroring — operator drops the tree on disk, no upload API. Extended MIME covers HTML/CSS/JS/woff2/fonts on top of images. Path traversal (`..`, encoded `..`, segments failing `SAFE_SEG_RE`) returns 403; symlinks escaping the sites root are rejected via a `realpathSync` re-check. `.html` responses carry `Content-Security-Policy: default-src 'self' https: data:; script-src 'none'` and `Cache-Control: no-cache`; assets are cached for an hour; every response carries `X-Content-Type-Options: nosniff`. Per-account isolation comes from `resolveAccount` — every brand's install sees only its own tree.
3249
+
3250
+ **Directory canonicalisation.** A request whose disk target is a directory is `301`'d to the trailing-slash form (query string preserved) before any body is served — RFC 3986 §5.3 base resolution requires the trailing slash so relative refs in the served HTML resolve under the directory, not its parent. After the redirect the route serves `<dir>/index.html` if it exists on disk; otherwise `404`. There is **no** implicit-`index.html` invention for missing paths — the publisher owns canonical URLs. A brochure shipped without `index.html` is reached at `/sites/<slug>/<file>.html`, and the admin skill `publish-site` is the sanctioned surface that moves the extracted tree under `<accountDir>/sites/<slug>/` and emits the canonical path slug. Operator-side: drop a brochure at `<accountDir>/sites/properties/<id>/brochure/output/` and it serves at `<public-host>/sites/properties/<id>/brochure/output/brochure.html` (or `<public-host>/sites/properties/<id>/brochure/output/` if that directory contains an `index.html`). See `.docs/web-chat.md` `/sites/*` route entry for the wire contract and `[sites]` log lines (`serve|redirect-trailing-slash|not-found|path-traversal-rejected|symlink-escape-rejected|no-account`).
3251
+
3252
+ **Deterministic public-hostname surface.** The `<public-host>` half of the URL the operator pastes is resolved by the `mcp__plugin_admin_admin__public-hostname` MCP tool. It reads `<configDir>/cloudflared/config.yml` (ingress list) then falls back to `<configDir>/alias-domains.json` — the same two files `cloudflared` and `platform/ui/server/index.ts`'s `isPublicHost()` already trust to route. Returns `{hostname, isApex, source}` on hit (`source` is `"cloudflared-config.yml"` or `"alias-domains.json"`), or `{hostname:null, source:null, reason:"no-tunnel"}` on miss. Tiebreak: apex wins over subdomain (single-label, or `www.<apex>` stripped). `publish-site` step 6 calls it after the move and emits the full URL (`https://<hostname><path-slug>`) in the same turn. Graph queries are no longer involved — any earlier graph-backed resolver returned `(none)` on accounts bootstrapped without `cloudflare-task-tracker.ts` writes (laptop Real Agent, manual `cloudflared` setup), the `llm-framing-deterministic` recurrence class. The graph-mcp shim additionally runs a sequential envelope-warning probe on every read response — when Neo4j emits `gql_status` codes matching `^0[12]N5\d$` (e.g. `01N52` "property does not exist"), the shim stitches them into a prefix content block on the response so property-name misses surface to the agent inline instead of returning silent `[]`. Probe failure is best-effort: the upstream response forwards unchanged with `[mcp:graph] probe-error`.
3253
+
3254
+ ### Cross-tab session rotation
3255
+
3256
+ When you click "New conversation" in the chat tab, SiteDesk mints a fresh admin session key on the server and clears the old one. Sibling admin tabs (`/graph`, `/data`) opened in the same browser keep working without re-login: the chat tab broadcasts the new key on a same-origin channel so each sibling tab updates its captured key instantly, and any in-flight admin request that 401s with the rotation-orphan code retries once after re-reading the latest key from per-tab storage. If neither path recovers (browser locked down, second 401 after retry, session expired), the tab shows a single banner — "Your admin session was renewed in another tab. Click to reload." — and one click sends you back through login. No silent 401s; no re-clicking through the same trash icon hoping it sticks. See `.docs/web-chat.md` "Cross-tab rotation contract" for the wire-level `code` taxonomy and observability surfaces.
3257
+
3258
+ ---
3259
+
3260
+ ## Context Assembly — How Retrieved Knowledge Reaches the Agent
3261
+
3262
+ The final step in the retrieval pipeline is injecting retrieved content into the agent's system prompt. The path depends on agent configuration.
3263
+
3264
+ ### Channel spawn routing by role
3265
+
3266
+ The manager exposes three named spawn routes: `/rc-spawn` (a live `claude --remote-control` PTY — the operator sidebar, the channel admin, and the one-shot admin jobs), `/public-spawn` (the renamed `/spawn` — `spawnClaudeSession`, the zero-tool public surface), and the `rc-daemon` it drives. No route named `/spawn` remains; a manager boot line `[spawn-routes] live=[rc-spawn,public-spawn]` asserts this.
3267
+
3268
+ The channel PTY-bridge (`ensureEntry`) routes each inbound by role: an **admin** WhatsApp/Telegram inbound spawns on `/rc-spawn` (keyed by a deterministic per-sender sessionId so the thread resumes across restarts) and drives every turn via `/<id>/input`; a **non-admin** inbound spawns on `/public-spawn`. Each dispatch logs `[<channel>-adaptor] route role=<role> target=<rc-spawn|public-spawn> senderId=…`. LinkedIn ingest and the public session-end review also run on `/rc-spawn`, carrying their prompt as `initialMessage` with `closeAfterTurn` so the PTY stops after one assistant turn.
3269
+
3270
+ ### Public agent paths
3271
+
3272
+ Public agents run on the same native Claude Code PTY surface as the admin, dispatched through the channel PTY-bridge with `role: 'public'`. The agent's directory files (IDENTITY.md, SOUL.md, KNOWLEDGE.md, KNOWLEDGE-SUMMARY.md when present) are assembled into the system prompt at spawn time. There is no per-turn server-side knowledge injection.
3273
+
3274
+ The public agent is toolless by construction: `memory-search` and every other tool are excluded from the per-spawn `--allowed-tools` allowlist on every public channel, and a per-spawn `permissions.deny` blocks them outright. The agent has no graph access mid-conversation; KNOWLEDGE.md is the ceiling of factual knowledge.
3275
+
3276
+ ### KNOWLEDGE.md staleness guard
3277
+
3278
+ When both `KNOWLEDGE.md` and `KNOWLEDGE-SUMMARY.md` exist, the server compares modification times. If KNOWLEDGE.md is newer than the summary (summary is stale), the full KNOWLEDGE.md is used. Otherwise, the summary is preferred (smaller token footprint).
3279
+
3280
+ ### Admin agent path
3281
+
3282
+ The admin agent runs via Claude Code CLI, which manages its own system prompt assembly. Knowledge reaches the admin agent through MCP tools — `memory-search` is the read-path entry point (server-side LLM ranking was removed; the agent ranks in-turn against any criterion). The admin agent also receives session context via `loadSessionContext`, which injects:
3283
+
3284
+ - Recent review digest (last public chat or review digest `CreativeWork`)
3285
+ - Open tasks (priority-ordered, capped)
3286
+ - Active review alerts (unsuppressed, last 24 hours, capped at 5)
3287
+
3288
+ This is assembled as a `<previous-context>` block in the system prompt on each admin turn.
3289
+
3290
+ ### Public-agent memory context
3291
+
3292
+ Public agents historically had their memory context injected by a server-side bridge
3293
+ (`fetchMemoryContext`) that spawned the memory MCP server with `ALLOWED_SCOPES=public,shared`
3294
+ and ran a `memory-search` on the agent's behalf. That bridge was removed: public agents
3295
+ are toolless (`buildPublicDeny` denies `mcp__memory__*`), so neither the agent nor a
3296
+ server-side proxy runs a public-scope memory search, and the public-scope fulltext index that
3297
+ path ranked against was retired alongside it.
3298
+
3299
+ A gated visitor's per-visitor memory still reaches their next conversation, without any tool
3300
+ and without reopening the ringfence. The session-end reviewer writes per-visitor slice nodes
3301
+ (`{sliceToken, scope:'user'}`); at the next gated spawn the UI process fetches that visitor's
3302
+ own `scope:'user'` slice nodes (a slice-pinned read, not a public-scope search), renders them
3303
+ to a `<previous-context>` block, and threads it through the public spawn body so the manager
3304
+ appends it to the agent's system prompt. Only the visitor's own slice is read; open-mode
3305
+ visitors, admins, and first visits inject nothing.
3306
+
3307
+ ---
3308
+
3309
+ ## Output Formatting and Budget
3310
+
3311
+ The `memory-search` tool formats results as structured text with labels, properties, scores, and related nodes. An output character budget of 80,000 characters prevents results from exceeding Claude Code's tool result token limit (~100K chars). When results exceed the budget, related nodes are progressively dropped (compact mode) to fit within the limit.
3312
+
3313
+ Each result is formatted as:
3314
+ ```
3315
+ [Label1, Label2] (id: nodeId) (score: 0.XXX)
3316
+ property1: value
3317
+ property2: value
3318
+ Related:
3319
+ --[RELATIONSHIP]--> [RelatedLabel] {prop1: val, prop2: val}
3320
+ <--[RELATIONSHIP]-- [RelatedLabel] {prop1: val, prop2: val}
3321
+ ```
3322
+
3323
+ Results are separated by `---` dividers. The `embedding` and `accountId` properties are stripped from output (internal fields, not useful to the agent).
3324
+
3325
+ ---
3326
+
3327
+ ## Index Discovery and Schema Evolution
3328
+
3329
+ The memory MCP server does not hardcode index names. On first query, it runs `SHOW INDEXES YIELD name, labelsOrTypes, type WHERE type = 'VECTOR'` and builds a label-to-index-name map. This map is cached for the lifetime of the process.
3330
+
3331
+ This means:
3332
+ - Adding a new vector index in `schema.cypher` makes a new label searchable without code changes
3333
+ - The `memory-reindex` tool can backfill embeddings for newly indexed labels
3334
+ - Index renames are transparent — the server discovers the current index names at startup
3335
+
3336
+ The cache is cleared via `clearIndexCache` after schema changes (e.g., after `memory-reindex` detects new indexes).
3337
+
3338
+ ---
3339
+
3340
+ ## Inbound Message Gateway
3341
+
3342
+ Every inbound message — regardless of channel (web admin, web public, WhatsApp DM, WhatsApp group) — passes through a centralised screening and classification step before reaching the agent. One Haiku call per message produces:
3343
+
3344
+ - **Content screening** — CLEAN / SUSPICIOUS / DISCARD verdict plus a prompt injection flag. DISCARD verdicts on public channels return a polite refusal without invoking the agent. Admin messages receive advisory screening only — flagged in the log but never blocked or modified.
3345
+ - **Query rewriting** — retrieval-optimised reformulation of the message for memory-search (public channels only; admin text is unchanged).
3346
+ - **Intent classification** — question / instruction / complaint / greeting / follow-up.
3347
+ - **Language** — ISO 639-1 code.
3348
+ - **Complexity** — simple / complex.
3349
+
3350
+ Short messages (under 5 words) skip the Haiku call but still get local pattern matching against the shared prompt injection vocabulary — this prevents short injection payloads from bypassing screening.
3351
+
3352
+ On Haiku timeout, API error, or missing API key, the raw message passes through unmodified (graceful degradation). The gateway never blocks the user from reaching the agent due to its own failure.
3353
+
3354
+ Gateway results are injected into the agent's system prompt as structured metadata, giving the agent context about the message before it begins processing.
3355
+
3356
+ ### Diagnostics
3357
+
3358
+ Every gateway invocation logs to `server.log` with the `[inbound-gateway]` tag, including channel, verdict, intent, language, complexity, latency, and fallthrough status. Non-clean verdicts get an additional warning log.
3359
+
3360
+ To check recent screening activity:
3361
+ ```
3362
+ grep '[inbound-gateway]' server.log | tail -20
3363
+ ```
3364
+
3365
+ ---
3366
+
3367
+ ## Tool Eagerness — eager-load vs deferred
3368
+
3369
+ The Claude Code SDK marks every MCP tool as **deferred** by default. The model cannot invoke a deferred tool until it has first paid a `ToolSearch` round-trip to load the schema — one extra turn per unique schema. Built-in SDK tools (`Read`, `Write`, `Edit`, `Bash`, `Glob`, `Grep`, `Agent`, `WebSearch`, `WebFetch`) stay eager. There is no count threshold; the gate is per-tool.
3370
+
3371
+ The SDK's per-tool override is `_meta["anthropic/alwaysLoad"]: true` on each MCP tool's `tools/list` entry. Two surfaces apply it:
3372
+
3373
+ 1. **In-process plugins.** Every admin-eager tool is registered via `eagerTool(server, name, description, inputSchema, handler)` from `platform/lib/mcp-eager/` instead of `server.tool(...)`. The helper calls `server.registerTool` with the `_meta` flag set. Both `eagerTool` and the non-eager `lifelineTool` (from `platform/lib/mcp-lifeline/`) wrap the handler with `wrapWithLifeline`, which emits a structured `op=request`/`op=result` log pair per call including a holdings census — see `.docs/mcp-helper-observability.md` "Tool-call lifeline".
3374
+ 2. **Upstream graph proxy.** The upstream Python `mcp-neo4j-cypher` server has no `_meta` channel, so `platform/lib/graph-mcp/src/index.ts` intercepts every `tools/list` response on the wire and injects `_meta["anthropic/alwaysLoad"]: true` into each tool entry. The `[graph-mcp] tools/list eager-flagged count=<N>` stderr line confirms the injection fired.
3375
+
3376
+ **Curation rule.** Every MCP tool the admin agent calls routinely should be eager — registered via `eagerTool` (or arriving through the graph-mcp interceptor). Whether a tool is eager is decided at its registration site in the plugin's MCP `index.ts` (`eagerTool` vs `server.tool`); there is no separate allow-list constant. Admin-skill / specialist / public-agent tools that stay on `server.tool()` pay the ToolSearch tax only when their caller invokes them. The admin tool surface (`toolSurface.admin`, the `adminAllowlist: true` set) is the intended eager set; a routinely-called admin tool left on `server.tool()` is a gap to fix at the registration site.
3377
+
3378
+ **Observability.** Spawn-time emit: `[tool-surface] session=<convId> permission_allowed=N eager_intent=E eager_set_size=T`. Turn-end emit: `[admin-agent] turn-end ... toolsearch=N toolsearch_unique=U`. A non-zero `toolsearch` on a fresh turn for an eager-intended tool means a plugin reverted to `server.tool()` — fix at the plugin's MCP registration site, not the allow-list.
3379
+
3380
+ ## Spawn-time MCP and subagent registration
3381
+
3382
+ Each `claude` PTY spawn registers every callable MCP server and every dispatchable subagent before the operator's first turn. **Platform MCP servers come from one channel — installed plugins — for admin and specialist spawns.** Claude Code's plugin system serves every plugin MCP tool under the long prefix `mcp__plugin_<plugin>_<server>__<tool>` (for platform plugins `plugin == server == directory`), which is the canonical name the admin `--allowed-tools` argv and every specialist `tools:` frontmatter bind to. Admin spawns no longer write a per-spawn `.mcp.json` or pass `--mcp-config`; the per-account env (`ACCOUNT_ID`, `USER_ID`, `NEO4J_URI`, `NEO4J_PASSWORD`, `PLATFORM_ROOT`, `CLAUDE_CONFIG_DIR`) rides the PTY env block.
3383
+
3384
+ **Public agents are the one exception.** A public-facing web agent is toolless by construction, so public spawns retain the per-spawn `mcp-config.json` (`--mcp-config <path>`) but register **zero** servers in it — the file carries an empty `mcpServers`. Combined with the empty `--allowed-tools`, the `dontAsk` mode, and the per-spawn `permissions.deny`, no tool reaches an anonymous visitor on any channel. `--strict-mcp-config` (which only ever guarded auto-discovery of a project `.mcp.json`) is retained on the public per-spawn path so no project file is discovered either; it is dropped from admin spawns that no longer pass `--mcp-config`.
3385
+
3386
+ For subagents, the same spawn pushes `--add-dir` for every bundled plugin agents directory (`platform/plugins/*/agents/`, `premium-plugins/*/agents/`) — both roles — plus the per-account specialists directory `<accountDir>/specialists/agents/` (admin only). Claude Code's `subagent_type` dispatch reads the agent file off disk via the added directories; without `--add-dir` the dispatcher returns "no matching agent."
3387
+
3388
+ A boot gate refuses to start the manager when any admin-allowlisted tool `mcp__<plugin>__*` lacks a registered server. The signal is `boot-failed reason=mcp-allowlist-without-server plugin=<p> tool=<t>` followed by `process.exit(1)`. The remediation is a one-line edit to the named `PLUGIN.md`: add the `mcp:` block. The complementary observability emit `mcp-config-allowlist-coverage admin-tools=A admin-registered=R` (where `A === R`) confirms the invariant per boot.
3389
+
3390
+ A second boot gate walks every specialist `.md` under `platform/templates/specialists/agents/`, every bundled `<plugin>/agents/` directory, and the per-account `<accountDir>/specialists/agents/` directory, parses each file's `tools:` frontmatter line (canonical long-prefix names), and classifies every tool name as one of: CC-native (Read, Bash, …), a tool the loaded `PLUGIN.md` set actually serves (matched as the long canonical name in `toolSurface.all`), a third-party MCP bridge (a `mcp__plugin_*` name whose plugin segment is NOT a maxy platform plugin — Playwright etc., upstream-owned, passes unconditionally), `unknown-tool-in-plugin` (maxy plugin namespace served but tool name absent), `unknown-plugin-namespace` (namespace served by nothing), `brand-excluded-plugin` (namespace served by nothing on this brand, **but** the brand's `brand.json#plugins.excluded` list names it), or `malformed-name` (not CC-native and not `mcp__`-shaped). The first three pass. The next two refuse boot with one `boot-failed reason=specialist-tool-drift specialist=<name> tool=<t> drift=<class> path=<…>` line per defect, then `process.exit(1)`. A maxy-plugin `mcp__plugin_*` name is validated against `toolSurface.all`, so a typo or stale long-prefix tool name still refuses boot rather than passing as a bridge; the build-time `check-canonical-tool-names.mjs` gate catches the same drift in instruction files before publish. `brand-excluded-plugin` is a structural pass: it lands in a per-specialist strip-list, the manager continues to boot, and at spawn time `pty-spawner` removes those tool names from the `--agent <name>` spawn's `--allowed-tools` argv. The complementary observability emit `specialist-tool-strip specialist=<name> plugin=<p> tools=<csv> reason=brand-excluded` fires one line per stripped (specialist, plugin) pair so an operator who reads `server.log` sees the brand filter doing work without cross-referencing `brand.json` against the template. The startup-self-test line `startup-self-test specialist-tool-drift=ok inspected=<N> stripped-specialists=<M>` confirms the gate ran and how many specialists carry strip-lists.
3391
+
3392
+ The `brand-excluded` branch closes the recurring crash-restart loop on brands that ship without a plugin the shared `personal-assistant.md` template references (e.g. `realagent-code` excludes `telegram` while the template hard-codes `mcp__telegram__*`). The brand-agnostic template stays a single file; the brand-aware filter expresses what the specialist *may* do on this install while the template expresses what it *can* do across brands. Tool typos and renamed plugins still refuse to boot — only namespaces explicitly named in `plugins.excluded` are demoted to strip-and-warn.
3393
+
3394
+ **Brand-foreign premium bundles.** This closes the loop one layer up: the installer bundler at [`packages/create-maxy-code/scripts/bundle.js`](../../../../packages/create-maxy-code/scripts/bundle.js) now applies the same `brand.json#shipsPremiumBundles` gate at *payload assembly time*, so foreign bundles never reach disk on the device. The gate is shared with the test suite via [`scripts/premium-bundle-gate.mjs`](../../../../packages/create-maxy-code/scripts/premium-bundle-gate.mjs) and accepts only two shapes — `undefined` / missing → ships nothing; `string[]` → ships only the named bundles. The legacy boolean `true` form is **rejected**: bundle.js hard-fails with `FATAL: brand.shipsPremiumBundles must be a string[] (boolean 'true' no longer accepted; enumerate bundles in <brand.json>)`. An allowlist entry naming a bundle directory that is absent on disk is also FATAL — silent over-shipping is the failure mode this gate exists to prevent. Each build emits one `[bundler] premium-bundle-gate brand=<n> mode=<m> shipped=[…] skipped=[…]` line. The runtime gate `walkPremiumBundles` at [`plugin-manifest.ts`](../../../ui/app/lib/claude-agent/plugin-manifest.ts) keeps the same shape and stays as defence-in-depth — on a correctly bundled payload, it walks only allowlisted bundles because foreign ones are not present. The drift-gate's `agents-dir-skipped reason=brand-foreign-bundle` line therefore fires only when something has staged a foreign bundle out-of-band.
3395
+
3396
+ **Structured journald mirror for boot-failed.** Every `boot-failed reason=specialist-tool-drift …` line is mirrored to journald via `systemd-cat -t maxy-csm -p err` with the fields `specialist=`, `tool=`, `drift_reason=`, `agent_path=` so `journalctl --user -u <brand>-claude-session-manager.service -t maxy-csm` can filter by any of them without grep on `server.log`. The stdout line stays unchanged so the existing diagnostic one-liners keep working. `systemd-cat` absence (e.g. macOS dev box) is swallowed — the stdout line is the primary surface; the structured emit is auxiliary.
3397
+
3398
+ **Per-spawn signals (server.log).** Every spawn emits `pty-spawn-mcp-config servers=<N> tools=<M> bytes=<B> path=<…>` once, plus one `pty-spawn-agents-dir role=<admin|public> path=<…>` per added directory. Specialist spawns additionally emit `pty-spawn-allowlist specialist=<name> count=<N> stripped=<S> sourced-from=agent-frontmatter` where `stripped` is the count of brand-excluded tool names removed before argv emission. The diagnostic one-liner is `grep -E 'pty-spawn-mcp-config|pty-spawn-agents-dir|pty-spawn-allowlist|mcp-config-allowlist-coverage|specialist-tool-strip|boot-failed reason=' ~/.<brand>/logs/server.log | tail -50`.
3399
+
3400
+ **Channel follower cold-start retry.** Each `dispatchOnce`-based channel PTY session has one JSONL follower ([`platform/ui/app/lib/channel-pty-bridge/follower.ts`](../../../ui/app/lib/channel-pty-bridge/follower.ts)) reading `GET /<sessionId>/log?follow=1` and fanning each assistant `end_turn` out to the awaiting `dispatchOnce`. (WhatsApp and public webchat have since migrated to the native event channel — an MCP notification in, a `reply`-tool call out — and no longer use this follower; the remaining `dispatchOnce` channels are email and telegram. The webchat detail below is the historical record of the bug the retry fixed.) A freshly-spawned PTY has no JSONL on disk until claude flushes its first line; during that window the manager answers `202 {pending:true}`. The follower retries every `CHANNEL_PTY_FOLLOWER_RETRY_MS` (default 1000) until a 200 stream opens or `CHANNEL_PTY_FOLLOWER_PENDING_MAX_MS` elapses. The follower is shared across channels, so that window defaults to the longest channel turn window (whatsapp's `WHATSAPP_PTY_TURN_TIMEOUT_MS`, 300000 — longer than webchat's 120000) so it never abandons a turn the caller is still awaiting. Because public sessions idle-reap, every webchat greeting is the first turn of a fresh spawn and crosses this window — before the retry, a 202 (which satisfies `res.ok`) was consumed as a single non-event line, the stream ended, and the follower died silently, timing out every public turn. The lifecycle is greppable as `follower-connect status=<code>` → `follower-retry attempt=N reason=pending` → `follower-open` → `outbound bytes=N`; `follower-give-up reason=pending-timeout` marks the JSONL never appearing. A `reject reason=turn-timeout` with no preceding `follower-open` (and no manager `log-follow-open`) for that sessionId is the signature. See `.docs/gated-public-agents.md` "Webchat turn lifecycle" for the full tag list.
3401
+
3402
+ **Brand-process start counter.** `platform/ui/server-init.cjs` increments a persistent counter at `/tmp/server-init-<accountId>-restart.count` on every fresh start and emits `[server-init] start count=<N> account=<accountId> counter-path=<…>` to `server.log`. /tmp clears on reboot, so a clean reboot starts the count fresh; any value `>1` between operator-observed reboots means the brand process (driven by its `Requires=<brand>-claude-session-manager.service` clause) is restarting. The diagnostic one-liner is `grep '\[server-init\] start' ~/.<brand>/logs/server.log | tail -5` — the trailing `count=` value is the loop depth without counting SIGTERMs.
3403
+
3404
+ **Programmatic spawn entry point.** The Sidebar new-session-with-prompt click routes through the single cookie-auth wrapper (the recorder loopback caller was removed) at [`platform/ui/server/routes/admin/claude-sessions.ts`](../../../ui/server/routes/admin/claude-sessions.ts). The wrapper owns the per-spawn enrichment (owner profile, dormant/active plugins, specialist domains, tunnel URL) and the `senderId` resolution; it forwards a single `POST /public-spawn` to the session manager on `127.0.0.1`, with `initialMessage` inlined on that body. The manager appends `initialMessage` as the trailing positional argv to `claude`, so the CLI processes it as the session's first user turn at PTY startup — no separate `POST /<sessionId>/input` call, no bracketed-paste. See `admin-session.md` "Spawn-with-initialMessage wrapper" for the body schema and caller list.
3405
+
3406
+ **End-turn auto-close (lifecycle, not user-initiated).** The session manager's `attachEndTurnAutoClose` ([`platform/services/claude-session-manager/src/http-server.ts`](../../../services/claude-session-manager/src/http-server.ts)) wires a one-shot job's JSONL to a watcher: as soon as it contains `"stop_reason":"end_turn"`, the manager calls `stopSession`, the PTY exits, the PID file is removed, and `fs-watcher.ts` demotes the row to `state: 'archived'`. It fires for `/public-spawn` database-operator specialist spawns and for `/rc-spawn` jobs spawned with `closeAfterTurn` (LinkedIn ingest and the public session-end review). This is the lifecycle archive path — the row stays in place, the JSONL stays on disk, no directory move. It is structurally distinct from the user-initiated `POST /api/admin/claude-sessions/:id/archive` route, which actually `mv`s the JSONL between `<slugDir>` and `<slugDir>/archive/`.
3407
+
3408
+ ## Tool Call Audit Trail
3409
+
3410
+ Every tool invocation by the admin agent produces a durable `ToolCall` node in the knowledge graph, linked to the `Conversation` that triggered it. This covers all admin agent tool calls — the full history of what the agent did, when, and in what context.
3411
+
3412
+ Each ToolCall record contains:
3413
+
3414
+ | Field | Description |
3415
+ |-------|-------------|
3416
+ | toolName | The MCP tool that was invoked (e.g. `memory-search`, `workflow-execute`) |
3417
+ | pluginName | The plugin that owns the tool |
3418
+ | input | Truncated JSON of the tool's input arguments |
3419
+ | output | Truncated response text |
3420
+ | isError | Whether the tool call resulted in an error |
3421
+ | startedAt / completedAt | Timestamps for the invocation |
3422
+ | sessionId | Links back to the originating conversation |
3423
+
3424
+ Records persist indefinitely and are queryable by the admin agent. Ask SiteDesk "what tools ran in the last session?" or "show me all tool calls from today" to review the audit trail.
3425
+
3426
+ Workflow-dispatched tool calls are tracked separately via `StepResult` nodes (part of the workflow execution system) and are not duplicated as ToolCall nodes.
3427
+
3428
+ ### Diagnostics
3429
+
3430
+ Tool call persistence logs to `server.log` with the `[persist]` tag:
3431
+ ```
3432
+ grep '[persist] tool-call persisted' server.log | tail -10
3433
+ ```
3434
+
3435
+ Each log entry includes the tool name and a truncated conversation ID for correlation.
3436
+
3437
+ ## Process provenance — durable actions emit Tasks
3438
+
3439
+ Every durable action — cloudflare tunnel-login, brand publish, future deterministic flows — emits a `:Task {kind:"<flow>"}` node carrying the action's lifecycle and a `:PRODUCED` edge to every entity the action created. This makes the graph traversable from the originating Conversation to every entity created during it via `(c)<-[:RAISED_DURING]-(t:Task)-[:PRODUCED]->(e)` — answering "what did this turn produce" in one Cypher hop.
3440
+
3441
+ The doctrine is observed at the storage primitive: writes to `:Person`, `:UserProfile`, `:AdminUser`, `:Organization`, `:LocalBusiness`, `:CloudflareTunnel`, or `:CloudflareHostname` should carry an inbound `:PRODUCED` edge whose source is one of `:Task`, `:Conversation`, or `:Message`. Subtype labels like `:AdminConversation`, `:UserMessage`, `:AssistantMessage`, `:AdminMessage` qualify because the gate checks the full `labels()` array. Bootstrap writes (PIN-setup, schema migrations, lazy first-session UserProfile creation) are exempt via `createdBy.agent === 'system'`. When no qualifying edge resolves, the primitive emits a `[graph-write] warn reason=missing-provenance labels=<csv> agent=<agentLabel>` line and the write proceeds (this was relaxed from a hard reject — the composer-spawned admin path inherits a bare per-account env that never receives the `SESSION_NODE_ID` stamp, so the throw was failing every direct admin contact-create / memory-write for a gated label).
3442
+
3443
+ Two surfaces emit the lifecycle: agent-driven actions call `work-create`/`work-update`/`work-complete` over MCP (`work-create` accepts `kind`, the canonical `inputsProvided` call-shape record, `inputs` + `inputSchema` for the operator-meaningful form payload, and `raisedDuringConversationKey` to resolve the `RAISED_DURING` edge). Shell-driven actions wrap their script invocation in [platform/ui/app/lib/cloudflare-task-tracker.ts](../../../ui/app/lib/cloudflare-task-tracker.ts) (cloudflare is the first; installer / brand-publish / OAuth-login deferred). Both surfaces emit the same `[task] action-start|step|done` log lines so operators can grep one channel uniformly. Both also call the central `redactSecrets` primitive ([platform/lib/task-secrets/](../../../lib/task-secrets/)) to strip schema-tagged secret keys before persisting `inputs.<field>` props on the Task — see `.docs/neo4j.md § Audit Task input contract` for the contract that replaces per-kind allow-lists.
3444
+
3445
+ Two surfaces feed the gate. (1) **Workflow path:** `memory-write` accepts an optional `producedByTaskId` parameter. When set, an inbound `:PRODUCED` edge from that Task is composed into the write's relationships before the gate runs — the typical agent-side pattern is to call `work-create` at the start of an autonomous flow, capture `taskId`, and pass it as `producedByTaskId` on every subsequent `memory-write` for a gated label. The gate verifies Task and write share the same `accountId`; mismatch is rejected loud. (2) **Direct-ask path:** the admin server resolves the active `:AdminConversation`'s `sessionId` UUID and stamps it as `SESSION_NODE_ID` in the spawn env at PTY-spawn time. The same stamp propagates onto specialist subagent spawns the admin dispatches so listing-curator, content-producer, database-operator etc. inherit the same conversation anchor. The `contact-create` and `memory-write` wrappers call `injectConversationProvenance` (exported from [`@maxy/graph-write`](../../../lib/graph-write/src/conversation-provenance.ts)) which MATCHes `(c:Conversation {sessionId, accountId})` — account isolation is part of the natural key, not a separate gate — and prepends the synthetic `:PRODUCED` edge (composed by Neo4j elementId, which the helper reads off the MATCH). No agent-visible schema field changes. `memory-write` uses the env-stamp only as a fallback when `producedByTaskId` is unset; `contact-create` has no `producedByTaskId` parameter today and relies on the env-stamp alone. Autonomous (cron-driven) specialists with no parent conversation legitimately have no env-stamp; those must thread `producedByTaskId`.
3446
+
3447
+ Operator audit cyphers:
3448
+ - "What entities did this conversation's actions produce?" — `MATCH (c:AdminConversation {sessionId:$id})<-[:RAISED_DURING]-(t:Task)-[:PRODUCED]->(e) RETURN labels(e), e.name, t.kind, t.status`
3449
+ - "What cloudflare resources did this tunnel-login produce?" — `MATCH (t:Task {kind:'cloudflare-tunnel-login', status:'completed'})-[:PRODUCED]->(r) RETURN t.taskId, r.tunnelId, r.hostnameValue ORDER BY t.completedAt DESC`
3450
+
3451
+ See `.docs/neo4j.md § Process provenance doctrine` for the full enforcement contract, observability surface, and out-of-scope deferrals.
3452
+
3453
+ ## Context compaction
3454
+
3455
+ When an admin turn crosses 75% of the model's context window, SiteDesk runs a silent compaction turn that asks the agent to call the `session-compact` MCP tool with a structured briefing (what you asked for, what was done, decisions made, work-in-progress, things you've shared about yourself). The briefing is written to Neo4j; the next admin turn injects it back into the system prompt, so continuity survives across the compaction boundary without re-sending the full transcript.
3456
+
3457
+ The compaction runs against a transient one-shot pool entry separate from the long-lived admin Query. Operator-visible side effects:
3458
+ - Compaction logs land in `claude-agent-compaction-stream-YYYY-MM-DD.log` alongside the main stream log. Look for `[compaction-start]`, `[compaction-summary-captured]`, `[compaction-failed]`, `[compaction-timeout]`, `[compaction-crashed]`, or `[compaction-spawn-error]` to triage. Subprocess stderr is captured inline as `[subproc-stderr] <line>` — there is no longer a separate `claude-agent-compaction-stderr-…log` file.
3459
+ - The one-shot pool entry's lifecycle is greppable as `[client-cold-create] reason=compaction-one-shot …` paired with `[client-evict] reason=compaction-one-shot …`, distinguishable from the regular admin pool's lifecycle tags.
3460
+
3461
+ ---
3462
+ # Deployment Guide
3463
+ Source: https://docs.getmaxy.com/deployment.md
3464
+
3465
+ # Deployment Guide
3466
+
3467
+ ## Hardware Requirements
3468
+
3469
+ - Raspberry Pi 5 (16GB RAM minimum) with Raspberry Pi OS, **or**
3470
+ - Mac with macOS 14 (Sonoma) or newer — both Apple Silicon and Intel
3471
+ - 256GB storage minimum
3472
+ - Always-on power and network connection
3473
+ - **On a Pi 5: the official 27W USB-C power supply (5.1V / 5A) and a good cable.** This is not optional — see Power and recovery below.
3474
+
3475
+ ## Power and recovery (Raspberry Pi)
3476
+
3477
+ A Pi 5 running SiteDesk draws hard during document ingest: the embedding model runs the CPU flat-out in bursts. An underpowered supply or a thin/long USB-C cable cannot hold 5V under that current spike, the board *browns out*, and you get one of two failures:
3478
+
3479
+ - **A reset or freeze** — the board drops out mid-task and either reboots or hangs.
3480
+ - **A latched-off board** — the board goes dark and stays dark until you physically unplug and replug the power. No software can recover this, because there is no power to run any recovery.
3481
+
3482
+ **The cure is hardware.** Use the official Raspberry Pi 5 27W PSU (5.1V / 5A) and a short, good-quality USB-C cable. A marginal phone charger or a cheap cable is the usual cause. This is the only thing that *prevents* a brownout.
3483
+
3484
+ **Recovery seatbelts the installer sets up for you:**
3485
+
3486
+ - **A hardware watchdog.** If the board *hangs* (powered but stuck), it reboots itself automatically within about two minutes — no manual power cycle. This only helps a hung board; it cannot help a board that has gone dark.
3487
+ - **Power-health logging.** The admin server writes a `[power-health]` line to `server.log` at boot and every 15 minutes, so a brownout shows up without waiting for a crash. A healthy line reads `throttled=0x0 ... undervolt_occurred=false`. Any `undervolt`-flag set, or `reboots_unclean_24h` above zero, means the board is browning out — fix the power before trusting it with heavy work.
3488
+
3489
+ **For a board that latches off (the dark-board case):** put the Pi on a smart plug that you can power-cycle remotely, ideally one driven by a heartbeat (cut power and restore it when the box stops responding). This is the robust recovery for the dark-board failure and is an operator hardware choice, not something the installer can do.
3490
+
3491
+ **Keep one address.** After a reboot the Pi can pick up a different DHCP address and look like it vanished. Add a **DHCP reservation** on your router that pins the Pi's MAC to a fixed LAN IP, so the box is always reachable at the same address. The boot `[power-health] op=boot lan_ip=<ip>` line records the address each boot — if it changes across reboots, the reservation is not in place.
3492
+
3493
+ ## macOS install
3494
+
3495
+ On macOS the installer uses Homebrew + launchd instead of apt + systemd. No flags are required on a laptop:
3496
+
3497
+ ```bash
3498
+ npx -y @rubytech/create-maxy-code # default brand
3499
+ npx -y @rubytech/create-realagent-code # realagent brand
3500
+ ```
3501
+
3502
+ **Prerequisite:** Homebrew. If `brew` is missing, the installer refuses with `Homebrew not found. Install from https://brew.sh and re-run.` Install Homebrew once via the official one-liner, then re-run. The installer never installs Homebrew itself.
3503
+
3504
+ **Hostname / printed URL.** Without `--hostname`, the installer reads `scutil --get LocalHostName` and prints the completion URL as `http://<that-name>.local:<port>`. No sudo, no system change — your Mac's existing local network name is what mDNS will resolve. With `--hostname <h>`, the installer sets `HostName` / `LocalHostName` / `ComputerName` to `<h>` via `sudo scutil` (one password prompt, all-or-nothing rollback within the three-call batch) so the URL becomes `http://<h>.local:<port>`. Grep `~/.<brand>/logs/install-*.log` for `[create-maxy] darwin-hostname-mode=` to confirm which path ran (`scutil-get`, `scutil-set`, or `brand-fallback`).
3505
+
3506
+ **LaunchAgent.** The installer registers `SiteDesk` as a launchd LaunchAgent at `~/Library/LaunchAgents/com.rubytech.<brand-hostname>.plist` — for example `com.rubytech.maxy-code.plist`. Survives logout/login and reboot via `KeepAlive=true` and `RunAtLoad=true`. Two brands on the same Mac get two distinct plists (brand-hostname-keyed), so install order is independent. Use `launchctl print gui/$UID/com.rubytech.<brand-hostname>` for service state. The `[create-maxy] launchd-plist=<path> loaded=true` line in the install log confirms `launchctl bootstrap` accepted the plist; `loaded=false exit=<n>` is the failure signal (run `plutil -lint <path>` to diagnose).
3507
+
3508
+ **Cloudflare on darwin.** The installer brew-installs the `cloudflared` binary so it is on PATH, but does not invoke `cloudflared service install` or `cloudflared tunnel route dns` — public reach is opt-in. After install, the operator runs `cloudflared tunnel login` (browser-driven) followed by the existing tunnel-setup flow if they want a public address. Grep `[create-maxy] darwin-cloudflare-skip=true` in the install log to confirm the installer took the documented skip path.
3509
+
3510
+ **Uninstall.** `npx -y @rubytech/create-maxy-code uninstall` (or the realagent equivalent) bootsout the LaunchAgent, removes the plist, and deletes `~/.<brand>/`. Homebrew-installed dependencies (curl, git, unzip, jq, poppler, ffmpeg, node@22, neo4j, cloudflared) remain — remove them with `brew uninstall` if you want a clean slate.
3511
+
3512
+ **Pre-flight.** macOS < 14 is refused at pre-flight via `parseSwVers` (`sw_vers -productVersion` must be `≥ 14`).
3513
+
3514
+ **Diagnostic grep recipe.** After a Mac install, the canonical log path is `~/.<brand>/logs/install-*.log`. One pass tells you everything:
3515
+
3516
+ ```bash
3517
+ grep -E '^\[create-maxy\] (platform|darwin-hostname-mode|darwin-cloudflare-skip|launchd-plist|init-logging FAILED)=' \
3518
+ ~/.<brand>/logs/install-*.log
3519
+ ```
3520
+
3521
+ Every successful Mac install contains, in order: `platform=darwin`, `darwin-hostname-mode=…`, `darwin-cloudflare-skip=true`, every brew install/verify line, `launchd-plist=… loaded=true`. Absence of any of these is the failure signal.
3522
+
3523
+ ## Initial Setup
3524
+
3525
+ The SiteDesk installer handles the full setup. Run it on your Pi:
3526
+
3527
+ ```bash
3528
+ npx -y @rubytech/create-maxy
3529
+ ```
3530
+
3531
+ This installs all dependencies (Node.js, Neo4j, Cloudflare tunnel, Claude Code), configures the platform, and starts all services.
3532
+
3533
+ ## What the Installer Does
3534
+
3535
+ 1. Installs system dependencies
3536
+ 2. Installs Claude Code (the AI engine) and configures it
3537
+ 3. Installs and starts Neo4j (the memory database)
3538
+ 4. Installs and configures the Cloudflare tunnel for remote access
3539
+ 5. Creates your account and sets your PIN
3540
+ 6. Starts the SiteDesk web server on port 19200
3541
+ 7. Configures systemd so everything restarts automatically if the Pi reboots
3542
+
3543
+ ## First admin session — install-time defaults
3544
+
3545
+ There is no onboarding state machine. At install time the installer writes three defaults into `data/accounts/<accountId>/account.json` (`enabledPlugins` from the brand's default set, `outputStyle: "default"`, `thinkingView: "default"`) and stamps a minimal `agents/admin/SOUL.md`. Diagnostic lines on the Pi:
3546
+
3547
+ ```
3548
+ [install-defaults] account-json plugins=<n> outputStyle=default thinkingView=default
3549
+ [install-defaults] soul-md path=<path>
3550
+ ```
3551
+
3552
+ Grep for both in `~/.<brand>/logs/install-*.log`. Absence after a clean install is the failure signal.
3553
+
3554
+ ## Plugin cache refresh on upgrade
3555
+
3556
+ Claude Code loads each platform plugin's skills, commands, and MCP from a per-install snapshot under `~/.<brand>/.claude/plugins/cache/<marketplace>/<plugin>/<version>/`, recorded as `installPath` in `installed_plugins.json` — not from the live tree. The local marketplaces (`maxy-platform`, `maxy-premium-*`) are *directory sources*: an upgrade overwrites their tree in place with no version bump. `claude plugin install` and `claude plugin update` both short-circuit on the unchanged version, so the snapshot would otherwise freeze at first-install time and newly-shipped skills would never register.
3557
+
3558
+ The installer therefore **resyncs every directory-source plugin on every run**: `claude plugin uninstall` then `claude plugin install`, the only sequence that rebuilds the snapshot from the live tree. Remote marketplaces (the Anthropic ones, GitHub externals) keep version-pinned idempotence. Diagnostic lines on the Pi:
3559
+
3560
+ ```
3561
+ [plugin-install] recache <name>@<marketplace>
3562
+ [plugin-install] audit <name>@<marketplace> live-skills=<n> cache-skills=<m>
3563
+ [plugin-install] WARN cache-drift <name>@<marketplace> live-skills=<n> cache-skills=<m>
3564
+ ```
3565
+
3566
+ Grep `~/.<brand>/logs/install-*.log`. After an upgrade every directory-source plugin shows a `recache` line and an `audit` line whose `live-skills` and `cache-skills` counts are equal. A `WARN cache-drift` line — or unequal counts — means the snapshot did not fully rebuild and the running agent will see stale skills.
3567
+
3568
+ The first user-domain write the agent attempts (e.g. recording who the operator is) hits the graph-write gate's `Write blocked (no-admin-user)` or `Write blocked (no-local-business)` error. The agent then asks the persona question, persists the answer through the `business-profile` skill or `profile-update.personFields`, and proceeds. The error itself is the signal — grep `Write blocked` in `~/.<brand>/logs/server.log` to confirm.
3569
+
3570
+ Cloudflare, WhatsApp, Telegram, and any other dormant capability surfaces on owner request via the `<dormant-plugins>` sentinel the manager injects per-spawn. Execution is the existing plugin skill (`cloudflare:cloudflare`, etc.) — no banner, no per-step flag.
3571
+
3572
+ ### Per-spawn system-prompt sentinels
3573
+
3574
+ Every PTY spawn injects an `--append-system-prompt` block composed of these sentinel sections in fixed order:
3575
+
3576
+ | Sentinel | Source | Behaviour on resolve failure |
3577
+ |---|---|---|
3578
+ | `<host>` | brand.json + boot-time LAN resolution | spawn refuses with `host-context-unresolved` |
3579
+ | `<identity>` | `<accountDir>/agents/<role>/IDENTITY.md` | spawn refuses with `identity-unresolved` |
3580
+ | `<soul>` | `<accountDir>/agents/<role>/SOUL.md` | spawn refuses with `identity-unresolved` |
3581
+ | `<about-owner>` | upstream `loadUserProfile` + `formatProfileSummary` (UI process) | sentinel renders the prose body with `NOTHING (operator-data source unavailable: \`<reason>\`)` on line one; spawn proceeds |
3582
+ | `<specialist-domains>` | `<accountDir>/specialists/agents/*.md` frontmatter (UI process) | sentinel omitted when set is empty |
3583
+ | `<plugin-manifest>` | enabled plugins' PLUGIN.md frontmatter + skill SKILL.md frontmatter (UI process) | sentinel omitted when set is empty |
3584
+ | `<dormant-plugins>` | installed-minus-enabled set from `platform/plugins/` and `account.json`, excluding plugins whose PLUGIN.md frontmatter sets `surface: platform` (platform-shell — ships with every install, never opt-in). Absent `surface` field defaults to `feature` (dormant-eligible). | sentinel omitted when set is empty |
3585
+
3586
+ Diagnostic line per spawn (`~/.<brand>/logs/server.log`):
3587
+
3588
+ ```
3589
+ [pty-spawn] sessionId=<id> appendSystemPromptBytes=<n> identityBytes=<n> soulBytes=<n> aboutOwnerBytes=<n> dormantPluginsBytes=<n> pluginManifestBytes=<n> specialistDomainsBytes=<n> accountDir=<path> role=<admin|public> hostname=<h> lanIPv4=<ip> adminUrl=<url> tunnelUrl=<url|none>
3590
+ ```
3591
+
3592
+ The `pty-spawn-start` line additionally carries `hooksResolved=<event1,event2,…>` — the hook event names Claude Code would actually load for that PTY (resolved by walking the same `$CLAUDE_CONFIG_DIR/settings.json` plus the cwd-to-.git path Claude Code itself uses). A Stop hook registered in a settings file outside the loader's scope shows up as a missing event in this list.
3593
+
3594
+ Zero `aboutOwnerBytes` on any admin spawn is a regression: the upstream resolver dropped the field entirely. The prose body always carries the unconditional MAXIMISE imperative on line two, so the byte count is positive even on a fresh-account spawn whose line one is `NOTHING`. Zero `dormantPluginsBytes` on a SiteDesk install with `cloudflare` not enabled is likewise a regression. Zero `pluginManifestBytes` on any account with enabled plugins means the upstream walker failed silently.
3595
+
3596
+ The manager also runs a boot-time self-test that renders a fixture compose call against synthetic inputs and refuses to start if any sentinel is missing:
3597
+
3598
+ ```
3599
+ [claude-session-manager] startup-self-test system-prompt-sentinels=ok
3600
+ ```
3601
+
3602
+ LOUD-FAIL output is `startup-self-test system-prompt-sentinels=fail missing=<tag>` followed by an immediate process exit. Catches IDENTITY-promise-vs-emitter drift at boot rather than at the first real spawn.
3603
+
3604
+ ### Pre-publish boot smoke
3605
+
3606
+ `platform/scripts/smoke-boot-services.sh` runs inside `prepublishOnly` of the installer (`packages/create-maxy-code/`). For every service in its `SERVICES` list it builds a synthetic install dir that mirrors what `seed-neo4j.sh` writes on first boot — real templates copied from `platform/templates/agents/admin/*.md` and `platform/templates/specialists/agents/*.md` into both `<accountDir>/` and `<platformRoot>/templates/`, real plugin `PLUGIN.md` manifests, plus a `.claude/` dir for `CLAUDE_CONFIG_DIR`. The fixture stamps the same env shape the installer's systemd unit writes (dummy `NEO4J_URI`/`NEO4J_PASSWORD` — the manager only checks presence at boot; the live cypher gate runs separately). Then it spawns `node dist/index.js`, waits up to 10 s for the `startup-self-test identity-drift=` line (the last startup self-test the manager logs), SIGTERMs, and fails publish if any `boot-failed reason=` or `^\[.*\] fatal ` line appears. The script asserts each of the three startup self-tests (`specialist-tool-drift=ok`, `system-prompt-sentinels=ok`, `identity-drift=ok`) is present — the real-templates fixture is what makes the assertions non-trivial; it was added after the 0.1.143 / 0.1.147 / 0.1.155 / 0.1.156 install regressions slipped past an empty fixture. The original motivation still holds (module-load regressions tsc and vitest miss — e.g. a stray `require()` in an ESM-typed package).
3607
+
3608
+ Cypher schema gate: the same script applies `platform/neo4j/schema.cypher` to the maintainer's local Neo4j via `cypher-shell`, using `NEO4J_URI` / `NEO4J_USER` / `NEO4J_PASSWORD` env (same shape `seed-neo4j.sh` reads — falls back to `platform/config/.neo4j-password` for the password). The dev's database is the test surface; schema commands use `IF NOT EXISTS` / `IF EXISTS` so re-apply is idempotent. Catches Neo4j 4 → 5 syntax drift (e.g. 0.1.151's `DROP FULLTEXT INDEX`) at publish time, not on a real install. Absence of `cypher-shell` on PATH or unset `NEO4J_URI` fails the gate loudly — the same toolchain the installer requires on every device.
3609
+
3610
+ Companion lint: `platform/scripts/check-no-esm-require.mjs` rejects `require(` calls in any `.ts/.tsx/.js` file inside a package with `"type": "module"`, also wired into `prepublishOnly`. Allowlist lives at the top of the script.
3611
+
3612
+ ## Service Management
3613
+
3614
+ SiteDesk runs via systemd and starts automatically on boot. You don't need to start it manually. To check if it's running, ask SiteDesk "Check system status."
3615
+
3616
+ If you need to restart the service manually (rare), ask SiteDesk to do it for you.
3617
+
3618
+ ## Browsing the brand filesystem on your LAN (SMB)
3619
+
3620
+ Every install provisions a per-brand SMB share against the brand's install folder. See [Samba Share](./samba.md) for the share path, credentials, per-OS mount instructions, peer-brand lifecycle, and the interface-binding posture (LAN-only on a private-LAN host, loopback-only on a public-only cloud host).
3621
+
3622
+ ## Remote Access via Cloudflare
3623
+
3624
+ SiteDesk uses a Cloudflare tunnel to make your local Pi accessible from anywhere without opening router ports. The tunnel is configured during setup and runs as a background service.
3625
+
3626
+ Setting it up: say "Set up remote access." SiteDesk walks you through signing into Cloudflare, picking your domain (if you have more than one on your Cloudflare account), and then shows a form where you pick a short name that becomes your admin address. For example, entering `joel` gives you `https://joel.your-domain.com` for admin access. You can also pick a separate address for the public chat, or leave it blank to skip public access. The form only accepts valid address characters (lowercase letters, numbers, hyphens) — SiteDesk never asks you to type your full URL in chat.
3627
+
3628
+ Your admin URL looks like: `https://joel.maxy.chat` (the short name is whatever you picked in the form).
3629
+
3630
+ To check the tunnel status: ask SiteDesk "Check Cloudflare tunnel status."
3631
+
3632
+ To restart the tunnel: ask SiteDesk "Restart the Cloudflare tunnel."
3633
+
3634
+ ## Checking Service Status
3635
+
3636
+ Ask SiteDesk: "Check system status."
3637
+
3638
+ The `system-status` tool reports the health of all services: Neo4j, the web server, the Cloudflare tunnel, and all active MCP servers.
3639
+
3640
+ ## If SiteDesk Won't Start
3641
+
3642
+ From the Pi directly:
3643
+
3644
+ ```bash
3645
+ sudo systemctl status maxy
3646
+ sudo journalctl -u maxy -n 50
3647
+ ```
3648
+
3649
+ The logs will show which service failed to start and why. Common causes:
3650
+
3651
+ - **Neo4j not started** — run `sudo systemctl start neo4j` and retry
3652
+ - **Port 19200 already in use** — check for another process: `lsof -i:19200`
3653
+ - **Claude OAuth expired** — the next admin session will prompt you to re-authenticate
3654
+ - **NEO4J_URI guard throws** — the admin agent probes device reality at boot and fails closed on three shapes (earlier platform fixessucceeding earlier platform fixes):
3655
+ - `no Neo4j listening on [ports]` — nothing is bound; start `neo4j.service` or `neo4j-<brand>.service`, or edit `NEO4J_URI` to a port a Neo4j is actually running on.
3656
+ - `port:X not listening; only:Y is live` — single-brand device where `.env` names a port the local Neo4j isn't bound to; edit `NEO4J_URI` in `~/{configDir}/.env` to match the live port (shown in the `[neo4j-probe] listening=[…]` log line).
3657
+ - `port:X disagrees with brand.json neo4jPort:Y` — co-tenant device (2+ Neo4js listening) where `.env` names the other brand's port; edit `NEO4J_URI` to match `brand.neo4jPort`, or correct `neo4jPort` in `brand.json` and reinstall. Preserves the earlier platform fixes orphan-write protection on multi-brand devices.
3658
+
3659
+ ## Systemd units on each device
3660
+
3661
+ Each installed brand runs two per-brand `--user` systemd units (earlier platform fixes + — unit filenames are prefixed with the brand's `hostname` so two brands on the same device never share a unit file):
3662
+
3663
+ - `{hostname}.service` — the admin + public HTTP server on `127.0.0.1:19201` (public port + 1). Restarted by the upgrade flow; short downtime is expected during steps 8→11 of an upgrade. An earlier fix: the unit carries two port env vars — `PORT=<public>` (canonical public port, read by the upgrade detector) and `MAXY_UI_INTERNAL_PORT=<public+1>` (the port maxy-ui actually binds).
3664
+ - `{hostname}-edge.service` — the always-on public listener on the configured port (default 19200). Reverse-proxies HTTP to the main brand service and handles `/websockify` (VNC) WebSocket upgrades locally. An earlier fix: also hosts `/api/admin/actions/*` and `/api/admin/version*` — the Software Update modal's own routes — so the log stream survives the brand service's restart window. Does NOT restart during an upgrade — the browser WebSocket stays connected by construction. The operator views this VNC display in the admin UI via the standalone `/browser` page (peer to `/graph` and `/data`).
3665
+
3666
+ Upgrade and Cloudflare setup run as detached actions: `systemd-run --user` transient units per invocation with stdout+stderr persisted to `~/.maxy/logs/actions/<actionId>.log` and streamed to the UI via SSE. No boot-time service file exists for these.
3667
+
3668
+ If an action looks stuck, read `~/.maxy/logs/actions/<actionId>.log` directly for the full output, or `journalctl --user --identifier=maxy-action-<actionId>` for systemd's record.
3669
+
3670
+ ## Linux laptops: snap-confined Chromium replacement
3671
+
3672
+ On Ubuntu 24.04 (Noble) the system Chromium binary at `/usr/bin/chromium` is a symlink into the snap. Snap's AppArmor profile denies writes to hidden directories under your home folder, so the per-brand Chromium profile at `~/.{brand}/chromium-profile/` is unwritable and the VNC browser never starts. Pi installs (Debian Bookworm) are unaffected because Bookworm ships a real `.deb` chromium.
3673
+
3674
+ The installer detects this case during system-dependency setup and replaces the snap binary with Google Chrome stable, installed from Google's signed apt repo. The chosen binary's absolute path is recorded in `<INSTALL_DIR>/platform/config/chromium-binary.path` and read by the two call sites that launch Chromium — the VNC service and the in-page Chromium wrapper. (The `browser` plugin never launches its own Chromium; it attaches over CDP to the VNC Chromium that `vnc.sh` starts with `--remote-debugging-port`, so it doesn't consult this path.) If you ever see `chromium-binary.path missing` or `Chromium ... resolves to ... which is snap-confined` in `~/.{brand}/logs/vnc-boot.log`, re-run the installer to re-provision.
3675
+
3676
+ The post-install acceptance gate at `platform/scripts/test-laptop-vnc-boot.sh` runs four checks: the configured Chromium realpath is non-snap, the path is absolute and executable, the per-brand CDP port returns Chromium version JSON, and the VNC boot log ends with `VNC + browser stack running` with no preceding `Chromium failed to start`. The gate runs automatically at the end of every install on Linux; manual invocation is `MAXY_PLATFORM_ROOT=<install-dir>/platform <install-dir>/platform/scripts/test-laptop-vnc-boot.sh`.
3677
+
3678
+ A separate operator-side harness at `platform/scripts/installer-device-verify.sh <published-version>` runs after every npm publish to confirm the installer reaches a terminal-success marker on each device in the operator's manifest. Two markers are accepted because the installer's CDP probe behaves differently per `DISPLAY_MODE`: `Browser automation ready (CDP connected)` on Pi (virtual display, persistent Chromium) and `[cdp-check] skipped reason=native-display` on laptop (native display, on-demand Chromium). Either is a pass. The harness is operator-only — end users do not run it.
3679
+
3680
+ ## Plugin registration at install time
3681
+
3682
+ The installer registers Claude Code plugins on the device as the last step before the brand service starts. After registration, `claude plugin list` on the Pi shows every SiteDesk platform plugin shipped by the brand, every premium sub-plugin shipped by the brand, and any external plugins the brand declares (e.g. Telegram, Discord, iMessage from `claude-plugins-official`). Spawned `claude` sessions inherit those plugins from `~/.claude/` — the session manager passes no `--mcp-config` argv.
3683
+
3684
+ **Where the manifests come from.** The SiteDesk plugin source tree uses `PLUGIN.md` (YAML frontmatter) for plugin metadata, not Claude Code's native `.claude-plugin/plugin.json`. At bundle time, `scripts/generate-plugin-manifests.mjs` walks the payload and synthesises a Claude-Code-native `plugin.json` per plugin plus a `marketplace.json` at each tree root. The generator runs in `packages/create-maxy-code/scripts/bundle.js` after platform + premium plugins are copied into the payload, so the deployed install directory carries:
3685
+
3686
+ - `<INSTALL_DIR>/platform/plugins/<name>/.claude-plugin/plugin.json` per platform plugin
3687
+ - `<INSTALL_DIR>/platform/plugins/.claude-plugin/marketplace.json` (marketplace `maxy-platform`)
3688
+ - `<INSTALL_DIR>/premium-plugins/real-agent/plugins/<sub>/.claude-plugin/plugin.json` per sub-plugin
3689
+ - `<INSTALL_DIR>/premium-plugins/real-agent/plugins/.claude-plugin/marketplace.json` (`maxy-premium-real-agent`)
3690
+ - `<INSTALL_DIR>/premium-plugins/{teaching,writer-craft}/.claude-plugin/plugin.json` for bundle-root plugins
3691
+ - `<INSTALL_DIR>/premium-plugins/.claude-plugin/marketplace.json` (`maxy-premium`)
3692
+
3693
+ Generator schema:
3694
+
3695
+ | Field | Source | Notes |
3696
+ |---|---|---|
3697
+ | `name` | directory name (or `PLUGIN.md#name`) | Used as `<name>` in `plugin install` |
3698
+ | `description` | `PLUGIN.md` frontmatter `description` | Falls back to "{name} plugin" if absent |
3699
+ | `version` | `"0.1.0"` | Single version across all generated manifests |
3700
+ | `author` | `{ "name": "Rubytech LLC" }` | Object form required by Claude Code's validator |
3701
+ | `mcpServers["<name>"]` | only when `mcp/dist/index.js` exists | `{ "type": "stdio", "command": "node", "args": ["${CLAUDE_PLUGIN_ROOT}/mcp/dist/index.js"] }` |
3702
+
3703
+ Skills, agents, hooks, and commands directories at the plugin root are auto-discovered by Claude Code — no explicit field needed.
3704
+
3705
+ **Install flow** (`registerLocalAndExternalPlugins()` in `packages/create-maxy-code/src/index.ts`):
3706
+
3707
+ 1. Discover every `.claude-plugin/marketplace.json` under the install directory.
3708
+ 2. For each one not already in `claude plugin marketplace list`, run `claude plugin marketplace add <dir>`. Pre-existing entries log `[plugin-marketplace] added <name> idempotent=true`.
3709
+ 3. Snapshot `claude plugin list` once.
3710
+ 4. Build the desired plugin set = (every local marketplace's plugin entries) + (`brand.json#externalPlugins`).
3711
+ 5. For each desired plugin not in the snapshot, run `claude plugin install <name>@<marketplace> --scope user`. Already-installed plugins log `idempotent=true`. Failures log `[plugin-install] ERROR <name>@<src> exit=<n> stderr=<short>` but do not abort the installer — one plugin failing must not block the rest.
3712
+
3713
+ External channel plugins (telegram, discord) are installed but not configured at install time. The operator pairs a channel by running `/<name>:configure <token>` in a real session; no token is read from the install environment.
3714
+
3715
+ **Brand declaration** — `brands/<brand>/brand.json#externalPlugins`:
3716
+
3717
+ ```jsonc
3718
+ "externalPlugins": [
3719
+ { "name": "telegram", "marketplace": "claude-plugins-official", "channelPlugin": true },
3720
+ { "name": "discord", "marketplace": "claude-plugins-official", "channelPlugin": true },
3721
+ { "name": "imessage", "marketplace": "claude-plugins-official", "channelPlugin": true }
3722
+ ]
3723
+ ```
3724
+
3725
+ `channelPlugin: true` signals the session manager to include the entry in the spawn-time `--channels plugin:<name>@<marketplace>` argv. The session manager's `/public-spawn` and `/resume` HTTP routes accept an optional `channels: string[]` body field that maps directly to those argv flags. When the field is absent or empty, the spawn argv is byte-identical to today's `['--verbose', '--remote-control']` shape.
3726
+
3727
+ **Diagnostic path** — `grep "\[plugin-install\]" ~/.<brand>/logs/install-*.log | tail -50`; compare row count against `cat brand.json | jq '.externalPlugins | length'` plus the on-disk plugin count under `<INSTALL_DIR>/platform/plugins/` and `<INSTALL_DIR>/premium-plugins/`.
3728
+
3729
+ **Premium MCP dependency install** — Premium-plugin MCP servers ship `dist/` + `package.json` in the bundle but not `node_modules` (npm pack strips them, same as `server/`). `buildPlatform()` discovers every `<INSTALL_DIR>/premium-plugins/<bundle>/plugins/<plugin>/mcp/package.json` and runs `npm install --omit=dev` there, wiping any prior `node_modules` first. The summary log line `[install] premium-mcp-install dirs=<n>` is emitted before the loop runs, so `dirs=0` is itself a regression signal when a brand ships premium plugins.
3730
+
3731
+ ## Running multiple brands on one device
3732
+
3733
+ A single Pi or laptop can host more than one brand (for example SiteDesk and Real Agent) side by side. Each brand runs as its own service on its own port, with its own install directory and its own data. Installing one brand does not touch the other.
3734
+
3735
+ - **Separate:** each brand has its own install folder (`~/maxy/`, `~/realagent/`), its own config folder (`~/.maxy/`, `~/.realagent/`), its own web port, its own Cloudflare tunnel state, its own edge systemd unit (`maxy-edge.service` vs `realagent-edge.service`), and by default its own Neo4j database (SiteDesk on bolt port 7687, Real Agent on 7688). Action runner units are transient and per-invocation, not per-brand, so no naming conflict is possible.
3736
+ - **Brand-isolated Neo4j:** when a brand provisions a dedicated Neo4j instance (any port other than 7687), the installer stops and disables the apt-package's system `neo4j.service` after enabling the brand-dedicated unit, so only one Neo4j process holds the shared `/var/lib/neo4j/run/` PID file. The seed step receives the brand-correct `NEO4J_URI` and `NEO4J_PASSWORD` as explicit environment variables — the seed script no longer carries a `bolt://localhost:7687` default. A failed dedicated start aborts the install loudly with a journalctl tail; there is no silent fallback to the system instance. Stop/disable targets the literal `neo4j.service` only, so peer brands running their own `neo4j-{brand}.service` are unaffected.
3737
+ - **Peer-aware system-unit guard:** before stopping the system `neo4j.service`, the installer checks whether any other brand on the device still depends on it — that is, has `NEO4J_URI=bolt://localhost:7687` in its `~/.<peer>/.env`. If so, the system unit is left enabled and active, and the install log shows `[neo4j] system unit kept active — peer brand <name> depends on port 7687` instead of the usual `[neo4j] disabling system unit` line. This prevents a `create-realagent` install from disabling SiteDesk's database on a host where SiteDesk still uses the shared system instance (the earlier platform fixes reproducer on Neo's laptop, 2026-04-28). On single-brand hosts and on multi-brand hosts where every peer runs a dedicated port, behaviour is unchanged. The dedicated unit exports `NEO4J_HOME=<per-brand-data-dir>` alongside `NEO4J_CONF`, so `server.directories.run`, `server.directories.plugins`, and `server.directories.import` resolve per-brand — no collision with `/var/lib/neo4j/run/neo4j.pid`. The conf sed-overrides, mkdir-p, chown, and unit-write are idempotent and re-run on every install, so a host whose prior install left a broken unit recovers on retry.
3738
+ - **Shared:** both brands share the system Chromium/VNC stack, the Ollama model server, and the `cloudflared` command itself. Browser automation is serialised — one admin session at a time across both brands.
3739
+ - **Thermal cap on shared Ollama:** the installer writes a host-wide systemd `CPUQuota` drop-in (`/etc/systemd/system/ollama.service.d/10-maxy-cpuquota.conf`) bounding `ollama.service` to half the cores (200% on a 4-core Pi). An embedding burst — a document's summary plus every section body in one POST — otherwise pins `llama-server` across all cores with no idle gaps until a passively-cooled Pi crosses its soft-temp limit and hard-resets. The cap keeps peak temperature below the limit regardless of which brand or platform path issues the embeds. The drop-in has a neutral filename and is rewritten only when its content changes, so it is idempotent across brands and reinstalls. Applied only where the `ollama.service` system unit exists; a detached `ollama serve` has no unit to cap.
3740
+
3741
+ To install a second brand on a device that already runs the first, just run the other installer. No flags needed for isolation:
3742
+
3743
+ ```bash
3744
+ # Already running SiteDesk on port 20000. Install Real Agent on a different port:
3745
+ npx -y @rubytech/create-realagent --port 19500
3746
+ ```
3747
+
3748
+ Uninstalling one brand removes only that brand's state when the other brand is present: this brand's install folder, config folder, its own Neo4j data (if it runs a dedicated instance; shared data is left alone), its Cloudflare tunnel, and its systemd service. Shared binaries (Ollama, `cloudflared`), apt packages, and device-wide caches (`~/.claude`, `~/.ollama`) are left in place because the other brand is still using them. When no other brand is present, the uninstaller performs a full device decommission as before.
3749
+
3750
+ ## Version provenance
3751
+
3752
+ The version that the burger-menu badge displays is the same string the installer wrote to disk. Five links in the chain, each with its own log signal so a wrong badge can be traced to the broken hop in one grep:
3753
+
3754
+ 1. `packages/create-maxy-code/package.json` — `version` field. Bumped manually by the operator (`bin/publish-installers.sh:7`) before each publish. Single source of truth for every brand at a given release; the bundle script propagates one bump to every brand.
3755
+ 2. `packages/create-maxy-code/src/index.ts:3828-3830` — the installer reads its own `package.json` into the `PKG_VERSION` constant at start-up.
3756
+ 3. `packages/create-maxy-code/src/index.ts:2018` — the installer writes `PKG_VERSION` to `<configDir>/.${BRAND.hostname}-version` and logs `[install] version-marker written path=<absolute> version=<semver>`. Absence of that line in install.log means no marker was written for this run.
3757
+ 4. `platform/ui/server/routes/admin/version.ts` — the `/api/admin/version` route resolves `config/brand.json` per request, reads `config/.${brandHostname}-version`, and logs `[admin/version] outcome=<...> installed=<...> versionFile=<resolved-path> npmPackage=<resolved-name>`. On any brand.json defect (file missing, parse failure, or missing `hostname` / `npm.packageName` field) it emits one `[admin/version] brand-config-fallback reason=<file-missing|parse-failed|field-missing> field=<hostname|npm.packageName> using=<default>` per (reason, field) pair per process, then falls back to the defaults (`maxy` / `@rubytech/create-maxy`). No fallback line in the process log = brand.json resolved cleanly.
3758
+ 5. `platform/ui/app/components/header/HeaderMenu.tsx` — the menu renders `v${versionInfo.installed}` from the route's JSON response.
3759
+
3760
+ Diagnostic when the menu shows the wrong version:
3761
+
3762
+ ```bash
3763
+ # 1. Marker file actually on disk?
3764
+ ssh <device> 'cat ~/.<brand>-code/install/platform/config/.<brandHostname>-version'
3765
+
3766
+ # 2. What did the route resolve to?
3767
+ ssh <device> 'grep "\[admin/version\]" ~/.<brand>-code/logs/server.log | tail -5'
3768
+
3769
+ # 3. Any silent brand.json fallback?
3770
+ ssh <device> 'grep "brand-config-fallback" ~/.<brand>-code/logs/server.log'
3771
+ ```
3772
+
3773
+ Empty output from step 3 = brand.json resolved cleanly and the badge reflects the file from step 1.
3774
+
3775
+ ## Upgrading
3776
+
3777
+ To upgrade SiteDesk to the latest version, ask SiteDesk: "Upgrade SiteDesk." The platform checks the current device identity (hostname and port via `system-status`), then re-runs the installer with explicit `--hostname` and `--port` flags to preserve them across the upgrade.
3778
+
3779
+ The docs plugin (this plugin) is upgraded in the same step — you always have the documentation that matches your installed version.
3780
+
3781
+ ### Automatic upgrade alert
3782
+
3783
+ SiteDesk checks for new releases on every admin session start — whenever you log in, reload the page, or return to the admin chat. When a newer version is available, the Software Update window opens automatically showing your current and the latest version, with a one-click Upgrade button. Dismissing the window (click outside or the close button) defers the alert until your next login or reload; no alert is shown when you are already on the latest version.
3784
+
3785
+ The upgrade runs inside a live terminal embedded in the Software Update window — you see each installation step stream as it happens, and any password prompts from `sudo` appear directly in the terminal for you to answer. Closing the window does not cancel the upgrade; re-opening it reattaches to the same shell so you can see what happened while disconnected.
3786
+
3787
+ The header menu's version indicator still reflects real-time status: a green dot means you are up to date, and an accent-coloured dot means an upgrade is available. Opening the menu refreshes the version check, so a long-lived session can still surface an upgrade that became available after login without reloading the page.
3788
+
3789
+ ---
3790
+ # Samba Share
3791
+ Source: https://docs.getmaxy.com/samba.md
3792
+
3793
+ # Samba Share
3794
+
3795
+ Every SiteDesk install provisions a per-brand SMB network share so you can read and write the brand's install folder from Finder, File Explorer, the Files app on iOS, or any SMB-capable client on Android or Linux. No client install required — every modern OS speaks SMB natively.
3796
+
3797
+ The share lives next to the rest of the brand. On a device that runs more than one brand, each brand gets its own stanza, its own credentials, and its own lifecycle. Tearing one brand down never touches another brand's share.
3798
+
3799
+ ## What gets provisioned
3800
+
3801
+ The installer runs the same Samba step on every supported footprint — Raspberry Pi, Hetzner Cloud server, and self-hosted Linux laptop. Four sub-steps emit `[install-invariant] samba-provision-<step>` markers in order:
3802
+
3803
+ 1. **apt** — installs the `samba` package (skipped if `dpkg -s samba` already reports installed, so re-runs don't fight `unattended-upgrades` for the dpkg lock).
3804
+ 2. **conf** — writes `/etc/samba/smb.conf` with a `[global]` section plus a `[<brand>]` stanza pointing at the brand's install directory. The stanza is owned by the install owner (see below) and is marked `read only = no`, `browseable = yes`. The `[global]` bind posture depends on the host's interfaces (see "Interface binding" below); the marker records which posture fired — `bind=lan iface=<name>` or `bind=loopback-only`.
3805
+ 3. **user** — deferred at install time on a fresh Pi or Hetzner box because there is no PIN to hand to `smbpasswd` yet. The user is created the moment the operator sets a PIN in the admin UI (see "PIN rotation" below).
3806
+ 4. **units** — `systemctl enable --now smbd` so the share is reachable as soon as the install finishes. `nmbd` (NetBIOS name service) is never enabled: nothing mounts the share by NetBIOS name, and on a public-facing host it answers on `:137`/`:138` as a DDoS-reflection vector.
3807
+
3808
+ macOS install is a no-op for this step — the installer logs `samba-provision skipped: platform=darwin` and returns. Mac operators do not get an SMB share against their laptop.
3809
+
3810
+ ## Share path
3811
+
3812
+ | Client | Address |
3813
+ |---|---|
3814
+ | macOS Finder | `smb://<hostname>.local` then pick the `<brand>` share |
3815
+ | Windows Explorer | `\\<hostname>.local\<brand>` |
3816
+ | Linux (`mount.cifs`, Nautilus, KDE) | `//<hostname>.local/<brand>` |
3817
+ | iOS Files | `smb://<hostname>.local` |
3818
+ | Android (Solid Explorer, CX File Explorer) | Host `<hostname>.local`, share `<brand>` |
3819
+
3820
+ `<hostname>` is whatever the installer printed at the end of `npx @rubytech/create-<brand>-code install` — usually the brand name on a fresh Pi (`maxy-code.local`, `realagent-code.local`). `<brand>` is the same string — it is also the install folder name under the install owner's home.
3821
+
3822
+ If `<hostname>.local` does not resolve from your client (some networks do not route mDNS), fall back to the LAN IP: `smb://192.168.1.50` on macOS, `\\192.168.1.50\<brand>` on Windows.
3823
+
3824
+ ## Credentials
3825
+
3826
+ - **Username** — the Unix user that owns the install on the device. On a Pi or Hetzner box this is `admin`; on a self-hosted Linux laptop it is whatever Linux user ran the installer (for example `neo`). The installer persists this value to `~/.<brand>/.install-owner` so every later read uses the same identity the installer wrote.
3827
+ - **Password** — your current SiteDesk PIN. The same PIN that unlocks the admin UI unlocks the SMB share.
3828
+
3829
+ Both halves are required. SMB never accepts a guest connection; `map to guest = bad user` is set in the global stanza.
3830
+
3831
+ ## PIN rotation
3832
+
3833
+ There is no separate "SMB password." When you set or rotate the PIN in the admin UI, the platform's `set-pin` route runs `sudo -n smbpasswd -a -s <install-owner>` inline with the new PIN, behind a `NOPASSWD` sudoers grant written at install time and scoped to that exact command.
3834
+
3835
+ So:
3836
+
3837
+ - On a fresh Pi or Hetzner box, the share is reachable as soon as you set the first PIN. Before that point the `smbpasswd` entry does not exist and the mount fails with a logon error — that is expected.
3838
+ - Rotating the PIN re-syncs the SMB password to the new value on the next set-pin request. Mounts using the old PIN start failing immediately; remount with the new PIN.
3839
+ - If `set-pin` cannot read `~/.<brand>/.install-owner` (file missing or empty), it logs `[set-pin] smbpasswd sync failed owner=<unknown> rc=-1 reason=install-owner-file-missing` and skips the sync. The PIN still writes to the admin UI, but the SMB mount keeps refusing the new password until the install-owner file is restored.
3840
+
3841
+ ## Interface binding
3842
+
3843
+ `bind interfaces only = yes` is always set, which makes the `interfaces` line an allow-list rather than a hint. Smbd binds only to the interfaces named there. The installer classifies the host's interfaces and writes one of two postures:
3844
+
3845
+ - **Private LAN host (Raspberry Pi).** At least one non-loopback interface carries a private address — RFC1918 (`10/8`, `172.16/12`, `192.168/16`), CGNAT (`100.64/10`), or link-local (`169.254/16`). The installer binds loopback plus that interface (`wlan0` preferred, then `eth0`, then the first other private interface):
3846
+
3847
+ ```
3848
+ interfaces = lo <lan>
3849
+ bind interfaces only = yes
3850
+ ```
3851
+
3852
+ The share is reachable on the LAN and nowhere else.
3853
+
3854
+ - **Public-only host (Hetzner Cloud).** The only non-loopback interface carries a routable public address (typically `eth0` with a `/32`, no private LAN). Binding `lo eth0` here would put smbd directly on the public internet, so the installer binds **loopback only**:
3855
+
3856
+ ```
3857
+ interfaces = lo
3858
+ bind interfaces only = yes
3859
+ ```
3860
+
3861
+ The share is reachable solely from the box itself. Operators reach it by forwarding loopback over SSH — `ssh -L 4445:localhost:445 admin@<tunnel-host>` and then mounting `smb://localhost:4445` — or by joining the box to a private network and re-installing, which makes the private interface the chosen LAN bind.
3862
+
3863
+ If the device has no non-loopback IPv4 interface at all, the installer refuses to provision and exits — there is nothing safe to bind to. This is distinct from the public-only case, which still provisions a working (host-local) share.
3864
+
3865
+ This classification is the structural guarantee that SMB never leaves the box (loopback-only) or the LAN (LAN-only), even if upstream firewall rules are misconfigured. The Cloudflare tunnel that fronts the admin UI carries HTTPS only; it does not route SMB.
3866
+
3867
+ ## Peer-brand lifecycle
3868
+
3869
+ A device that hosts more than one brand carries one stanza per brand in `/etc/samba/smb.conf`. The provisioner is idempotent and peer-safe:
3870
+
3871
+ - **Install a second brand** — the new brand's stanza is appended next to the existing one. The shared `[global]` section is rewritten to keep the LAN-only directives current but is otherwise unchanged. Peer-brand stanzas are preserved byte-for-byte.
3872
+ - **Re-run the installer on an existing brand** — the brand's own stanza is replaced in place. Peer stanzas are not touched.
3873
+ - **Uninstall one brand** — only that brand's stanza is stripped. `smbd` is then `reload`ed so the brand share disappears from the running config without dropping connections to peer shares.
3874
+ - **Uninstall the last brand** — after the stanza is removed, the uninstaller checks `hasAnyBrandStanza()` and, if false, stops and disables `smbd`/`nmbd`, runs `smbpasswd -x <install-owner>` to drop the smbpasswd entry, and `apt-purge samba`. If any peer stanza remains, the units stay running and the package stays installed — the uninstaller logs `Leaving smbd/nmbd + samba package in place — other brand stanza remains`.
3875
+
3876
+ The brand-stanza name is the only identifier the uninstaller matches on, so two brands with different `BRAND.hostname` values cannot collide.
3877
+
3878
+ ## Troubleshooting
3879
+
3880
+ - **"Logon failure" on mount.** The PIN you typed does not match the current `smbpasswd` entry. Set a new PIN in the admin UI and remount. If the PIN was just rotated and the mount still fails, check `~/.<brand>/.install-owner` exists and is non-empty.
3881
+ - **Share does not show up in Finder / network browser.** mDNS may not be routed on your network. Mount by LAN IP instead of `<hostname>.local`.
3882
+ - **`smbd` not running after install.** Check the install log for the four `[install-invariant] samba-provision-<step>` markers. The `units` step running `systemctl enable --now smbd` is the last to fire; if it failed the marker prints `fail: <reason>`.
3883
+ - **Hetzner share not reachable from outside the box.** This is by design — see "Interface binding" above. A public-only host binds loopback only; use SSH port forwarding (`ssh -L 4445:localhost:445 …`).
3884
+
3885
+ Also see [Deployment Guide](./deployment.md) for the surrounding install flow, and [Access Control](./access-control.md) for how the brand isolation extends from the admin UI to the SMB share.
3886
+
3887
+ ---
3888
+ # Troubleshooting
3889
+ Source: https://docs.getmaxy.com/troubleshooting.md
3890
+
3891
+ # Troubleshooting
3892
+
3893
+ ## Stream-log file for a fresh session is absent or empty
3894
+
3895
+ **Symptom:** Operator opens a new admin session, sends one turn, sees the agent reply, then `logs-read sessionKey=<…>` returns `file-not-found` or zero bytes.
3896
+
3897
+ **Invariant:** For every new session, the stream-log file exists on disk iff at least one token byte has been emitted, and contains the token bytes from the moment the first token returns to the operator. The single-writer mandate (2026-05-14) mechanically enforces both halves of the contract: the single writer module at `platform/ui/app/lib/claude-agent/stream-log-writer.ts` opens the file lazily on `streamLog.writeToken` (the SDK first-byte site at [`stream-parser.ts:296`](../../../ui/app/lib/claude-agent/stream-parser.ts#L296)), and the build gate `platform/ui/scripts/check-stream-log-writer.mjs` rejects every external `appendFileSync`/`createWriteStream` against the `claude-agent-stream-*` pattern at CI time. The first-token invariant is bound by `platform/scripts/__tests__/first-token-creates-stream-log.test.sh`: one operator turn, one token, `claude-agent-stream-<sessionKey>.log` exists and contains the token bytes — pass iff file present and bytes present. The hourly adherence runner `platform/scripts/log-adherence-check.sh` extends the device-side check with a duplicate-basename diagnostic (`dup-basenames=N` in the `[log-tee] adherence-check` line); `dup>0` is a P0 page meaning the writer collapse regressed.
3898
+
3899
+ **Diagnose if it ever recurs:** run `bash platform/scripts/__tests__/first-token-creates-stream-log.test.sh` from the install. Pass = invariant holds; any other exit = the writer-side existence contract is broken and one `[log-tee] missing-on-resolve sessionKey=<8> surface=<…>` line on `server.log` is the operator-visible signal (P0). For the duplicate-file class specifically (the 2026-05-14 recurrence trigger), `bash platform/scripts/log-adherence-check.sh` returns non-zero whenever any sessionKey has more than one `claude-agent-stream-<sk>.log` across account dirs.
3900
+
3901
+ ## Retrieving evidence from an rc-spawn session
3902
+
3903
+ rc-spawn sessions (those started via the sidebar or the `claude rc --spawn` daemon) do not write a per-account stream log under `data/accounts/<id>/logs/`. Their evidence is the Claude Code JSONL transcript in the configDir:
3904
+
3905
+ ```
3906
+ <CLAUDE_CONFIG_DIR>/projects/<slug>/<uuid>.jsonl # parent session
3907
+ <…>/projects/<slug>/<uuid>.meta.json # bridgeIds persistent map
3908
+ <…>/projects/<slug>/<uuid>/subagents/agent-<hex>.jsonl # each subagent
3909
+ <…>/projects/<slug>/<uuid>/subagents/agent-<hex>.meta.json # {"agentType",…}
3910
+ ```
3911
+
3912
+ **Retrieve a session's merged timeline:** `logs-read.sh <key>` with a bare key (no second argument) maps the key to the local `<uuid>` and prints one timestamp-ordered timeline merging the parent transcript with every subagent transcript. The key is resolved in order: a matching `<uuid>.jsonl` on disk; a `sessions/<pid>.json` whose `bridgeSessionId` matches; a `<uuid>.meta.json` whose `bridgeIds` carries the suffix (persistent — survives PID-file cleanup on clean exit); and finally a content scan of the top-level transcripts as last resort. Any accepted key form works: the `claude.ai` `session_<id>`, its bare suffix, or the `<uuid>` (or a unique uuid prefix).
3913
+
3914
+ Every subagent `is_error` tool_result is flagged inline as `‼ SUBAGENT ERROR` with the agent type, the failing tool, and the error text. The parent session's own tool errors appear as `‼ tool error`. The two are never conflated.
3915
+
3916
+ **Audit all silently-failed subagents:** `logs-read.sh --scan-subagent-errors [N]` walks every `subagents/agent-*.jsonl` under the configDir and lists each one carrying an `is_error` result — agent type, parent session, failing tool, error text. Optional `N` limits the scan to the `N` most-recently-modified transcripts. Use this when a delivery failure was reported but no reproduction is available.
3917
+
3918
+ **Quick recipes:**
3919
+
3920
+ ```bash
3921
+ # A session's merged parent+subagent timeline (subagent errors flagged inline)
3922
+ ~/maxy-code/platform/scripts/logs-read.sh session_<id>
3923
+
3924
+ # Standing audit: every subagent transcript that failed silently
3925
+ ~/maxy-code/platform/scripts/logs-read.sh --scan-subagent-errors
3926
+
3927
+ # Limit audit to the 50 most-recent transcripts
3928
+ ~/maxy-code/platform/scripts/logs-read.sh --scan-subagent-errors 50
3929
+ ```
3930
+
3931
+ Note: passing an explicit second argument (e.g. `logs-read.sh <key> agent-stream`) still reads the legacy per-account stream log — the bare-key JSONL path is the default when no type is given.
3932
+
3933
+ ## A JavaScript-rendered page comes back empty from WebFetch or `url-get`
3934
+
3935
+ **Symptom:** A page that needs JavaScript to show its content returns empty or a shell document from `WebFetch` (summary) or `url-get` (verbatim, server-rendered).
3936
+
3937
+ **Resolution:** Use the `browser` core plugin's `browser-render` tool. It renders the page in the device's per-brand Chromium over the Chrome DevTools Protocol (the same browser the VNC viewer shows) and returns the rendered HTML plus visible text. It attaches to the already-running Chromium on `127.0.0.1:${CDP_PORT}` — nothing is downloaded or installed mid-session.
3938
+
3939
+ **Diagnose if it ever recurs:** grep the per-conversation stream log for `[browser-render]`. `rendered=true domBytes=<n>` is the healthy signal. `rendered=false outcome=cdp-unreachable` means no Chromium is listening on the brand's CDP port — confirm with `curl 127.0.0.1:<cdpPort>/json/version`. Other outcomes (`navigate-failed`, `load-timeout`, `evaluate-failed`) name the failed CDP step.
3940
+
3941
+ ## First user-domain write rejected by `[graph-write-gate] reject reason=no-admin-user`
3942
+
3943
+ **Symptom:** Admin chat reports "couldn't save that — set up your business profile first" or `[graph-write-gate] reject reason=no-admin-user` appears in `server.log` on the operator's first non-bootstrap write (a website, service, opening hours, etc.). Reproduces on Minimal-onboarded installs from before the seed-stamping fix shipped.
3944
+
3945
+ **Diagnose:** Tail the gate reject and self-heal lines together:
3946
+
3947
+ ```
3948
+ grep -E "adminuser-self-heal|graph-write-gate.*reject" <server.log>
3949
+ ```
3950
+
3951
+ - `[adminuser-self-heal] healed=1 …` followed by no `[graph-write-gate] reject` lines on subsequent writes — heal fired, the gate is now passing. Operator can retry.
3952
+ - `[adminuser-self-heal] healed=0 …` + `[graph-write-gate] reject … subReason=admin-user-no-accountid` — heal couldn't reach the broken node. Most likely cause: the env-side `ACCOUNT_ID` doesn't match any `:AdminUser.userId`. Cross-check `users.json[0].userId` against `MATCH (au:AdminUser) RETURN au.userId, au.accountId` — if the userId mismatches, the `[admin-invariant]` line in the same log will show `direction=users-without-account` and the repair is to align the stores per `.docs/agents.md` § "Three-store admin auth invariant", not to retry the heal.
3953
+ - `[graph-write-gate] reject … subReason=no-admin-user-node` — the graph has no `:AdminUser` at all. Re-run the seed (`platform/scripts/seed-neo4j.sh`) under the install's env vars; the boot self-heal won't help because there's nothing to heal.
3954
+
3955
+ The `subReason=admin-user-no-accountid` path should be impossible on any install whose admin server has booted at least once after the boot self-heal shipped — if it fires, the diagnostic recipe is the cross-check above, not "rerun the heal."
3956
+
3957
+ ## Fresh install opens to "Set your remote password" on the LAN URL
3958
+
3959
+ **Symptom:** On a brand-new device, the LAN URL printed by `create-maxy` (e.g. `http://maxy.local:19200`) opens to a remote-password setup page instead of admin onboarding. This was an earlier regression and should not occur on any install built.
3960
+
3961
+ **Diagnose:** On the Pi, grep the UI server log for the gate's disambiguation fields:
3962
+
3963
+ ```
3964
+ tail -200 ~/.maxy/logs/maxy-ui.log | rg '\[remote-auth\].*resolvedKind='
3965
+ ```
3966
+
3967
+ - `resolvedKind=lan` on a `login required` or `not configured` line means the classifier sees the request as local — if the browser is still on the remote-auth page, something cached the older page before the fix shipped (hard-refresh the tab).
3968
+ - `resolvedKind=external` means the request chain presents as remote (routable IP in the first `x-forwarded-for` hop). On a LAN-only browser this points to a proxy or VPN rewriting headers between the browser and the Pi.
3969
+ - `resolvedKind=unknown` is a defect — the classifier could not identify the TCP peer. Capture the log line and file it; do not work around it.
3970
+
3971
+ **Fix:** If all three fields confirm the LAN shape and the gate still refuses, upgrade the platform (`Software Update` from admin chat) to pick up the updated classifier.
3972
+
3973
+ ---
3974
+
3975
+ ## Remote sign-in is rejected with "Remote access requires TLS"
3976
+
3977
+ **Symptom:** Posting the remote-auth password returns a plain-text `400 Remote access requires TLS` response instead of completing sign-in.
3978
+
3979
+ **What this means:** The login endpoint will only issue a session cookie when the request arrived over HTTPS (via the Cloudflare tunnel). Browsers silently drop `Set-Cookie: Secure` on plain-HTTP responses, so minting a cookie there would produce a dead-end redirect. An earlier fix replaced that silent failure with this loud one.
3980
+
3981
+ **Fix:** Reach the admin surface through the tunnel hostname (e.g. `https://admin.<your-domain>`), not an IP or plain-HTTP URL. If you need LAN access, use the LAN URL (`http://<hostname>.local:<port>`) — LAN never hits the remote-auth endpoint.
3982
+
3983
+ ---
3984
+
3985
+ ## Agent Not Responding
3986
+
3987
+ **Symptom:** You send a message and nothing comes back, or the response never arrives.
3988
+
3989
+ **Check:**
3990
+ 1. Ask SiteDesk: "Check system status" — the `system-status` tool will report whether all services are running
3991
+ 2. Check the platform logs: ask SiteDesk "Show me the recent logs"
3992
+ 3. If the admin agent itself won't start: restart the platform (see below)
3993
+
3994
+ **Common causes:**
3995
+ - Claude API connectivity issue — check your Claude OAuth connection is still valid
3996
+ - Platform process has stopped — restart it
3997
+ - Network issue if accessing remotely — check your Cloudflare tunnel is running
3998
+
3999
+ **If the chat shows a single `[agent-loop-stop] same error twice — aborting` line and stops:** SiteDesk hit the same structured tool failure twice in a row inside one turn (e.g. a permission gate refused the same write twice, or two `Read` calls hit the same missing file). The runtime aborted the turn after the second occurrence to save tokens instead of running until the SDK turn budget exhausted. The blocker text names the tool and the first line of the error. Resolve the underlying cause (re-run the named skill, fix the missing prerequisite, etc.) and tap "Continue" — the next turn truly resumes the prior SDK session via the synthetic-tool-result contract, so SiteDesk picks up where it aborted instead of cold-querying its own session list. To see the diagnostic, ask SiteDesk: "Show me the most recent stall-recovery log line." Greppable post-deploy invariants: `[agent-loop-stop] reason=identical-tool-failure tool=<name> errorSignature=<sha8> toolInputDigest=<sha8>` followed by `[stall-recovery] kind=agent_loop_stop … handoff=resume-first` and on the next turn `[stall-resume] consumed kind=agent_loop_stop toolUseId=<8> priorSessionId=<8>`. The fallback path (when the SDK session id was lost) emits `handoff=metadata-only` + `[recovery-handoff] generated/consumed reason=agent-loop-stop` and the chat button reads "Start over" instead of "Continue". A `[recovery-handoff] WARN missing-on-cold-create` line means the fallback briefing wasn't persisted — surface to support.
4000
+
4001
+ **If a background task goes silent and the chat shows "A background task went silent — K of M completed":** SiteDesk's subagent stopped emitting progress for over 2 minutes. Tap "Continue" — the next turn resumes the prior session and reads a synthetic tool_result describing what completed before the pause, so the agent re-plans without losing the work it had done. Most stalls are upstream API latency rather than the subagent's approach failing — the resume-first path treats both correctly. Greppable post-deploy invariants: `[stall-recovery] kind=subagent_stalled … completed=<K>/? handoff=resume-first` followed by `[stall-resume] consumed kind=subagent_stalled toolUseId=<8>` on the next turn. If the button reads "Start over" instead, the parent's pending tool_use_id was not captured — the fallback path took over; the prior conversation is preserved as a `<recovery-context>` block in the cold-started session.
4002
+
4003
+ **Agent searches the filesystem after uploading a zip.** If you uploaded a zip and the agent burns several turns running `find` / `Glob` instead of unzipping, that is the symptom of the recovery-retry attachment-context regression (now closed by the recovery context preservation contract in `.docs/agents.md`). Greppable confirmation is the `[context-overflow-recovery] retry … attachmentsCarried=<n>` line in the conversation stream log. If you see `[context-overflow-recovery] WARN attachment-context-lost`, the regression has returned — surface to support.
4004
+
4005
+ **Turn budget exhausted with a horizontal rule separating two assistant turns.** When SiteDesk reaches its turn budget and the doubled retry also runs out, the chat now shows a one-paragraph assistant message that opens with `error_max_turns turns=A→B` (initial budget → final budget) followed by the recovery copy: "I reached my turn budget of N before I could finish this request. Try sending a smaller or more focused request, or ask me to use higher effort." That message is persisted to the graph, so the next page-refresh still shows it. The thin horizontal rule labelled "Session restored after timeout." that appears above your following turn signals that the prior turn forced a cold SDK-session restart inside the same conversation (pool eviction) — the agent's response after the rule is from a fresh SDK session even though the conversation thread is unchanged. Greppable post-deploy invariants: `[context-overflow-recovery] exhausted cause=max-turns-interrupted` count equals `[admin-persist] writer=persistMessageExhaust outcome=ok` count for the same sessionId window, and one `[session-store] storeAgentSessionId` line marks the cold-restart that drove the on-screen rule.
4006
+
4007
+
4008
+ **A turn rendered in chat is missing on next page-refresh.** Pre-the 2026-05-07 mandate this was a class of silent failure — Neo4j persists were wrapped in a no-op error catch and a write that threw left the artefact "rendered then disappeared on resume". The 2026-05-07 mandate makes JSONL canonical: the resume route reads the SDK transcript file at `~/.claude/projects/<project-key>/<sessionId>.jsonl` first, supplements from Neo4j, and triggers async heal-on-resume writes for any turn the JSONL has but Neo4j does not. So a refreshed conversation always renders what the SDK saw, regardless of write outcome. If a heal write itself fails, the chat shows a top-of-conversation banner naming the count; if every heal succeeds the resume is silent and the missing rows are quietly restored to Neo4j. Greppable post-deploy invariants in the per-session stream log (`logs/claude-agent-stream-<sessionKey>.log`): `[admin-resume] reason=<…> source=<jsonl|jsonl-missing|neo4j-only>` (one per resume), `[admin-persist] convId=<8> writer=<…> outcome=<ok|fail|skip>` (per persist site), `[admin-persist-heal] convId=<8> turnIndex=<n> outcome=<ok|fail>` (per heal write). To force-audit a specific conversation against its Neo4j projection without re-executing it, run `tsx platform/scripts/admin-persist-audit.ts --conversation-id=<uuid> --account-id=<uuid> --session-id=<uuid>` — non-zero exit + per-divergence `[admin-persist-audit] expected=<message|component> missing reason=neo4j-row-absent` lines name what would have been silently lost pre-mandate.
4009
+ **Wrong Claude account answering on a multi-brand device.** On a host running both SiteDesk and Real Agent, each brand's admin agent reads its own `~/${brand.configDir}/.claude/.credentials.json`; there is no longer a shared `~/.claude/` thrashing them against one another. If a brand reports auth failures or appears to be operating against the wrong subscription, check three things:
4010
+ 1. `grep "\[claude-auth\] init" ~/.${brand}/logs/server.log | tail -1` — the resolved path must end with `~/.${brand}/.claude/.credentials.json`. If a `[claude-auth] WARN cross-brand-path-detected` line is present, the runtime is still pointing at `~/.claude/`; the brand main service did not pick up the `Environment=CLAUDE_CONFIG_DIR=` setting (re-run the brand installer to refresh the unit file).
4011
+ 2. `diff <(jq .claudeAiOauth.accessToken ~/.maxy/.claude/.credentials.json) <(jq .claudeAiOauth.accessToken ~/.realagent/.claude/.credentials.json)` — must be non-empty after each brand's operator has run `claude /login` against distinct Anthropic accounts; if it's empty, both brands are still logged in to the same account (operator action, not a code bug).
4012
+ 3. `grep "\[install\] claude-creds pickup" ~/.${brand}/logs/install-*.log` — fires once on the first install of any brand and moves the legacy `~/.claude/.credentials.json` into that brand's path. Subsequent brands install with no credentials and require a fresh `claude /login` inside that brand's chat (which writes to the brand-scoped path because the systemd unit env is in scope).
4013
+
4014
+ To deliberately disconnect the wrong account, use the header menu's **Disconnect Claude** item (the supported path; no SSH or manual file deletion needed). It runs `claude auth logout`, then verifies the brand's `~/${brand.configDir}/.claude/.credentials.json` is actually gone before reporting success — a disconnect that left the credential in place reports failure in the menu rather than false-confirming. The server logs one line per attempt: `grep '\[onboarding\] op=claude-logout' ~/.${brand}/logs/server.log` — `credentialsPresent=true` after the call is a failed disconnect the operator may believe succeeded.
4015
+
4016
+ **All sessions on the brand stopped responding after a token expiry.** Symptom on the operator side: every spawn dies at `pid-file-timeout` and the dashboard health probe reports auth dead. Diagnose the OAuth refresh path before anything else:
4017
+
4018
+ 1. `tail -n 300 ~/.${brand}/logs/server.log | grep -E 'auth-refresh|auth-health|invalid_grant'` — `op=lock-acquired` proves the cross-process lock is in play. `op=skipped-fresh` means a sibling process (the admin server or a `claude` binary) already rotated the tokens during the lock wait — expected, healthy. `op=renewed expiresAt=…` is the only line that means a network refresh actually ran.
4019
+ 2. `outcome=fail-token` or `invalid_grant` lines mean Anthropic rejected the refresh token itself (revoked or expired beyond the rotation window). The brand needs a fresh `claude /login`. Pre-576 the most common cause was the admin server and a spawned `claude` racing to rotate the same single-use refresh token; that race is now serialised by the file lock at `~/.${brand}/.claude/.credentials.json.lock` and a re-read after the lock skips redundant refreshes.
4020
+ 3. `grep '\[auth-health\]' ~/.${brand}/logs/server.log | tail -n 5` — the heartbeat fires every five minutes. `status=dead expiresIn=...` means the refresh token is gone; only a re-login fixes it. `status=ok` heartbeats with no spawns in between mean the credentials file is healthy and the failure lives elsewhere.
4021
+ 4. The spawn-failure surface now carries `reason=auth-refresh-failed` (with `authStatus` in the JSON body) instead of generic `pid-file-timeout` whenever the credentials file is in `dead` or `expired` state at the moment of failure — visible in `grep '\[spawn-failed\]'` on server.log.
4022
+
4023
+ ---
4024
+
4025
+ ## Memory Not Working
4026
+
4027
+ **Symptom:** SiteDesk doesn't remember things you've told it, or search returns nothing.
4028
+
4029
+ **Check:**
4030
+ 1. Ask SiteDesk: "Check the Neo4j connection"
4031
+ 2. Ask SiteDesk: "Search memory for [something you know was stored]"
4032
+
4033
+ **Common causes:**
4034
+ - Neo4j service stopped — restart the platform, which restarts Neo4j
4035
+ - Memory index is stale — ask SiteDesk: "Reindex memory"
4036
+
4037
+ ---
4038
+
4039
+ ## Telegram Bot Not Receiving Messages
4040
+
4041
+ **Symptom:** You send a message to the bot and nothing happens.
4042
+
4043
+ **Check:**
4044
+ 1. Confirm the bot token is correct: ask SiteDesk "What Telegram bot token is configured?"
4045
+ 2. Verify the bot is running: send `/start` to the bot in Telegram
4046
+ 3. Check the MCP server logs: ask SiteDesk "Show Telegram plugin logs"
4047
+
4048
+ **Common causes:**
4049
+ - Bot token changed (if you regenerated it in BotFather) — update it by telling SiteDesk "Update my Telegram bot token"
4050
+ - Webhook not connected — restart the platform
4051
+
4052
+ ---
4053
+
4054
+ ## Plugin Errors
4055
+
4056
+ **Symptom:** A tool fails with an error, or a plugin says it can't connect.
4057
+
4058
+ **Check:**
4059
+ 1. Ask SiteDesk: "Show me recent errors"
4060
+ 2. Ask SiteDesk: "Restart the [plugin name] plugin"
4061
+
4062
+ **Common causes:**
4063
+ - Missing environment variable (API key, token) — the error message will name it; ask SiteDesk to help configure it
4064
+ - MCP server crashed — restarting the platform restarts all MCP servers
4065
+
4066
+ ---
4067
+
4068
+ ## Cannot Mount the SMB Share
4069
+
4070
+ **Symptom:** Mounting `smb://<hostname>.local` (or `\\<hostname>.local\<brand>`) fails with a "logon failure" or the share does not appear in your network browser.
4071
+
4072
+ **Check:**
4073
+ 1. Confirm you have set a PIN in the admin UI at least once. On a fresh Pi or Hetzner box the `smbpasswd` entry does not exist until the first set-pin runs — mounts before that point always fail.
4074
+ 2. Use the install owner as the username (`admin` on a Pi or Hetzner box; the Linux user that ran the installer on a self-hosted laptop) and the current SiteDesk PIN as the password. The SMB password is not stored separately — it is the PIN.
4075
+ 3. If `<hostname>.local` does not resolve from your client, mount by LAN IP instead (`smb://192.168.1.50` on macOS, `\\192.168.1.50\<brand>` on Windows).
4076
+ 4. Rotate the PIN in the admin UI. That re-triggers the `smbpasswd` sync on the device. If the resync log line reads `[set-pin] smbpasswd sync failed owner=<unknown> rc=-1 reason=install-owner-file-missing`, restore `~/.<brand>/.install-owner` from the installer log.
4077
+
4078
+ See [Samba Share](./samba.md) for the full credential model and per-OS mount syntax.
4079
+
4080
+ ---
4081
+
4082
+ ## Restarting the Platform
4083
+
4084
+ From the admin interface, ask SiteDesk: "Restart the platform."
4085
+
4086
+ If SiteDesk itself isn't responding (the page loads but the agent won't connect), try refreshing the browser. If the page itself won't load, the platform process may have stopped — power-cycle the Raspberry Pi by unplugging and reconnecting power, then wait a minute for services to restart automatically.
4087
+
4088
+ ---
4089
+
4090
+ ## Checking Logs
4091
+
4092
+ Ask SiteDesk: "Show me the logs" or "Show errors from the last hour."
4093
+
4094
+ For specific plugin logs: "Show Telegram logs" or "Show contacts plugin logs."
4095
+
4096
+ SiteDesk has access to all platform logs and can filter them for you.
4097
+
4098
+ ---
4099
+
4100
+ ## Cloudflare Tunnel Down (Remote Access Broken)
4101
+
4102
+ **Symptom:** You can reach SiteDesk on your local network but not via your public domain.
4103
+
4104
+ **Check:** Ask SiteDesk "Check the Cloudflare tunnel status."
4105
+
4106
+ **Fix:** Ask SiteDesk "Restart the Cloudflare tunnel."
4107
+
4108
+ If the tunnel won't reconnect, re-run the Cloudflare setup: ask SiteDesk "Reconnect Cloudflare."
4109
+
4110
+ If the initial Cloudflare login fails during setup, SiteDesk will fall back to asking you for a connection key. You can create one in the Cloudflare dashboard (SiteDesk will guide you through this in the browser).
4111
+
4112
+ **If you switched Cloudflare accounts or are stuck on the wrong one:** ask SiteDesk "Reset my Cloudflare login and start over." This is a clean reset — SiteDesk clears every stored credential, then opens a fresh browser sign-in. The next sign-in binds to whichever Cloudflare account you choose, with no risk of the previous account's stored credentials silently coming back.
4113
+
4114
+ ---
4115
+
4116
+ ## "Bad Gateway" or holding page during an upgrade
4117
+
4118
+ `maxy-edge.service` (always-on front door) classifies upstream errors and serves a brand-aware response. There are two distinct user-visible shapes; the right one depends on what failed.
4119
+
4120
+ **Branded holding page (brand logo + "Starting") for ~10 s during an upgrade — this is expected and self-healing.** The edge process binds the public port immediately, but `maxy.service` (the upstream UI) takes ~10 s after restart to apply the neo4j schema and mount its 11 routes. Any browser navigation that lands during that window gets a self-contained HTML holding page that polls `/api/health` and reloads automatically once the upstream binds. The page renders the brand logo (inlined as a base64 data URI at edge boot from `<install>/server/public/brand/<assets.logo>`) and the brand display/body fonts (loaded from fonts.googleapis.com) — both paths bypass the unavailable upstream so the page never makes a same-origin asset fetch. When `brand.logoContainsName` is true the logo replaces the productName text; otherwise the page falls back to "SiteDesk is starting". No operator action required. The diagnostic line in `~/.maxy/logs/edge.log` is `[edge] upstream http error path=… err=connect ECONNREFUSED 127.0.0.1:<UPSTREAM_PORT> err-class=econnrefused-coldstart upstream=…` and disappears as soon as upstream binds. Boot-time confirmation that the logo resolved: `[edge] brand=<name> holding-logo=inlined assets-dir=<path>` — `holding-logo=missing` means the logo file wasn't found at `assets-dir`, the page degrades to text-only.
4121
+
4122
+ **Branded plain-text 502 ("Bad Gateway (SiteDesk unavailable)") — real upstream failure, not cold-start.** Any error class other than `ECONNREFUSED` (timeouts, resets, host-unreachable) returns the existing 502 path. The diagnostic line carries `err-class=other`. Read the log with `tail -200 ~/.maxy/logs/edge.log | rg 'err-class=other'` and check `~/.maxy/logs/server.log` for upstream stack traces — the upstream itself is the source.
4123
+
4124
+ **Continuous `err-class=econnrefused-coldstart` for >30 s past the last `[edge] listening` line** indicates the upstream never binds — the upgrade or boot has stalled. Recover via `sudo systemctl --user status maxy.service` and check the action runner log per the next section. Permanent-failure UI escalation (turning the holding page into an error after N seconds) is intentionally deferred.
4125
+
4126
+ **The literal string `maxy-ui` should never appear in `edge.log` or in any user-visible 502 body**, regardless of brand. If it does, the edge is running stale code — re-bundle and re-publish.
4127
+
4128
+ **Verifying the holding page locally:** `curl -sS -H 'Accept: text/html' http://127.0.0.1:<EDGE_PORT>/` while `maxy.service` is stopped should return HTML containing the brand `productName`. The `Accept: text/html` header is required — non-html clients (default `curl`, `fetch`, XHR) get the branded plain-text 502 instead, so the holding page's own `/api/health` polls don't break themselves during cold-start.
4129
+
4130
+ ---
4131
+
4132
+
4133
+ ## Software update and Cloudflare setup
4134
+
4135
+ Both flows run on the native Claude Code PTY surface in admin chat. The retired action-runner / terminal-modal troubleshooting sections that lived here have been removed because those surfaces no longer exist; failures now manifest as plain stderr from the agent-invoked Bash command, visible in chat.
4136
+
4137
+ - **Software update.** Re-run `npx -y @rubytech/create-<brand>@latest` from a shell; if the installer fails, its stdout is the diagnostic record. HeaderMenu turns sage when `installed === latest`.
4138
+ - **Cloudflare setup.** The agent invokes `cloudflared` directly via Bash, following the cloudflare plugin's `plugins/cloudflare/references/manual-setup.md`. Failures surface as cloudflared's literal stderr plus a non-zero exit. Recovery paths live in `plugins/cloudflare/references/reset-guide.md` and `plugins/cloudflare/references/manual-setup.md`.
4139
+
4140
+ ## Orphan Account Directory Archived to `.trash/`
4141
+
4142
+ **What happened:** During upgrade, the installer detected multiple account directories under `~/maxy/data/accounts/` and identified one as live (its `admins` list matches the device's `users.json`). Non-matching siblings are archived — not deleted — under `~/maxy/data/accounts/.trash/<uuid>-<ISO8601-ts>/`.
4143
+
4144
+ **Installer signal:** Look for these lines in the installer log or admin terminal output:
4145
+
4146
+ ```
4147
+ ==> [seed] identity-match: kept=<uuid-short> via userId=<first-8>
4148
+ ==> [seed] swept orphan: <uuid-short> →.trash/<uuid-short>-<ts>
4149
+ ==> [seed] orphan sweep: moved N → ~/maxy/data/accounts/.trash/
4150
+ ```
4151
+
4152
+ **Rollback (if the wrong account was kept):** The archive is preserved verbatim. Stop the platform, move the desired directory back, restart:
4153
+
4154
+ ```bash
4155
+ sudo systemctl --user stop maxy-ui
4156
+ mv ~/maxy/data/accounts/<live-uuid> ~/maxy/data/accounts/.trash/<live-uuid>-$(date -u +%Y%m%dT%H%M%SZ)
4157
+ mv ~/maxy/data/accounts/.trash/<archived-uuid>-<ts> ~/maxy/data/accounts/<archived-uuid>
4158
+ sudo systemctl --user start maxy-ui
4159
+ ```
4160
+
4161
+ **`.trash/` retention:** Archived directories are kept indefinitely. The platform never auto-empties `.trash/`. When you're confident the archived orphans are truly obsolete, remove the directory manually: `rm -rf ~/maxy/data/accounts/.trash/<uuid>-<ts>/`.
4162
+
4163
+ **Installer aborted with "identity-match FAILED":** Multi-account installs where no sibling matches `users.json[0].userId` abort loud — the installer refuses to pick one and refuses to sweep. Resolution: inspect `account.json` in each candidate dir (listed in the abort output), identify the correct owner, move the other(s) aside manually, then re-run the installer.
4164
+
4165
+ **A chat turn looks broken — assistant bubble never rendered:** Open `claude-agent-stream-<sessionKey>.log` and grep for `[sse-client]`. The five phases (`connected`, `event_received`, `render_complete`, `error`, `close`) tell the story in order. Missing `connected` = the chat fetch never returned 200; missing `event_received` = the server emitted nothing or the client lost the stream before the first frame; missing `render_complete` = the reducer never committed the assistant bubble (persist_ack never arrived).
4166
+
4167
+ ## Admin DevTools console floods with `onboarding-banner-mount` or `sessions-poll` lines
4168
+
4169
+ **Regression symptom.** Open DevTools on the admin shell at `/` with `onboardingComplete=false`, leave the page idle for a minute, then scroll back through the console. Thousands of `[admin-ui] onboarding-banner-mount onboardingComplete=false` lines (one per AdminShell render, ~40/min driven by the 3s sessions poll) with no per-tick poll telemetry indicates the banner-mount log has regressed back into the render body.
4170
+
4171
+ **Steady-state invariants at `/`:**
4172
+
4173
+ - `grep -c '\[admin-ui\] onboarding-banner-mount' ~/.maxy/logs/admin-ui-console.log` equals page-load count plus onboarding-flip count, not the render count. Sustained climb at idle means the banner mount log regressed back into the render body (fix).
4174
+ - `grep -c '\[admin-ui\] sessions-poll' ~/.maxy/logs/admin-ui-console.log` over a 60-minute idle window equals zero. The hook no longer installs a `setInterval`; every `sessions-poll` line is operator-triggered (initial mount, refresh button, post-mutation refetch). One or more lines during operator idle means `setInterval` was reinstated.
4175
+ - `outcome=error` lines name a real fetch failure on an operator-triggered refetch, set the `error` field, and surface in the sidebar.
4176
+
4177
+ **Reconcile signal:**
4178
+
4179
+ - `grep -c '\[admin-ui\] sidebar-meta-pane-reconcile' ~/.maxy/logs/admin-ui-console.log` should equal the count of End / Resume / Purge clicks while the metadata pane was open. A `to=gone` line without a paired Close click means the pane's auto-close logic regressed.
4180
+
4181
+ **Why this matters.** The render-body log was misleading: it read as "the admin agent is checking onboarding state continuously", when in fact `onboardingComplete` had not changed at all. The fix moved the log into `useEffect(…, [])` then dropped the per-tick poll entirely, so a quiet console is now the steady state. With both fixes in place, console output is a faithful record of what the page actually did each operator click.