@bevel-software/platform-core-backend 0.7.5 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. package/LICENSE +202 -202
  2. package/THIRD-PARTY-NOTICES.md +428 -454
  3. package/dist/core/core-ports.d.ts +1 -1
  4. package/dist/core/create-core-server.d.ts.map +1 -1
  5. package/dist/core/create-core-server.js +51 -7
  6. package/dist/core/create-core-server.js.map +1 -1
  7. package/dist/core/create-core-services.d.ts +5 -3
  8. package/dist/core/create-core-services.d.ts.map +1 -1
  9. package/dist/core/create-core-services.js +30 -18
  10. package/dist/core/create-core-services.js.map +1 -1
  11. package/dist/modules/access/access-control.interface.d.ts +8 -7
  12. package/dist/modules/access/access-control.interface.d.ts.map +1 -1
  13. package/dist/modules/access/access-control.service.d.ts +1 -1
  14. package/dist/modules/access/access-control.service.d.ts.map +1 -1
  15. package/dist/modules/access/access-control.service.js +6 -6
  16. package/dist/modules/access/access-control.service.js.map +1 -1
  17. package/dist/modules/access/access-declarations.d.ts +5 -5
  18. package/dist/modules/access/access-declarations.js +3 -3
  19. package/dist/modules/access/access-mutation.service.d.ts +3 -3
  20. package/dist/modules/access/access-mutation.service.d.ts.map +1 -1
  21. package/dist/modules/access/access-mutation.service.js +3 -3
  22. package/dist/modules/access/access-mutation.service.js.map +1 -1
  23. package/dist/modules/access/access-splice.js +4 -4
  24. package/dist/modules/access/access-splice.js.map +1 -1
  25. package/dist/modules/access/access.routes.js +19 -19
  26. package/dist/modules/access/access.routes.js.map +1 -1
  27. package/dist/modules/access/creator-access.d.ts +2 -2
  28. package/dist/modules/access/creator-access.js +5 -5
  29. package/dist/modules/access/creator-access.js.map +1 -1
  30. package/dist/modules/access/roles-admin.service.d.ts +18 -4
  31. package/dist/modules/access/roles-admin.service.d.ts.map +1 -1
  32. package/dist/modules/access/roles-admin.service.js +14 -4
  33. package/dist/modules/access/roles-admin.service.js.map +1 -1
  34. package/dist/modules/code-mode/code-mode-names.d.ts +5 -13
  35. package/dist/modules/code-mode/code-mode-names.d.ts.map +1 -1
  36. package/dist/modules/code-mode/code-mode-names.js +5 -27
  37. package/dist/modules/code-mode/code-mode-names.js.map +1 -1
  38. package/dist/modules/code-mode/code-mode.tool.d.ts.map +1 -1
  39. package/dist/modules/code-mode/code-mode.tool.js +29 -7
  40. package/dist/modules/code-mode/code-mode.tool.js.map +1 -1
  41. package/dist/modules/mcp/mcp.service.d.ts +11 -52
  42. package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
  43. package/dist/modules/mcp/mcp.service.js +33 -395
  44. package/dist/modules/mcp/mcp.service.js.map +1 -1
  45. package/dist/modules/plugins/index.d.ts +7 -0
  46. package/dist/modules/plugins/index.d.ts.map +1 -0
  47. package/dist/modules/plugins/index.js +6 -0
  48. package/dist/modules/plugins/index.js.map +1 -0
  49. package/dist/modules/plugins/join-proposals.d.ts +53 -0
  50. package/dist/modules/plugins/join-proposals.d.ts.map +1 -0
  51. package/dist/modules/plugins/join-proposals.js +67 -0
  52. package/dist/modules/plugins/join-proposals.js.map +1 -0
  53. package/dist/modules/plugins/join-requests.service.d.ts +81 -0
  54. package/dist/modules/plugins/join-requests.service.d.ts.map +1 -0
  55. package/dist/modules/plugins/join-requests.service.js +135 -0
  56. package/dist/modules/plugins/join-requests.service.js.map +1 -0
  57. package/dist/modules/plugins/plugin-provision.service.d.ts +134 -0
  58. package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -0
  59. package/dist/modules/plugins/plugin-provision.service.js +344 -0
  60. package/dist/modules/plugins/plugin-provision.service.js.map +1 -0
  61. package/dist/modules/plugins/plugins.contract.d.ts +106 -0
  62. package/dist/modules/plugins/plugins.contract.d.ts.map +1 -0
  63. package/dist/modules/plugins/plugins.contract.js +36 -0
  64. package/dist/modules/plugins/plugins.contract.js.map +1 -0
  65. package/dist/modules/plugins/plugins.routes.d.ts +42 -0
  66. package/dist/modules/plugins/plugins.routes.d.ts.map +1 -0
  67. package/dist/modules/plugins/plugins.routes.js +379 -0
  68. package/dist/modules/plugins/plugins.routes.js.map +1 -0
  69. package/dist/modules/plugins/plugins.service.d.ts +60 -0
  70. package/dist/modules/plugins/plugins.service.d.ts.map +1 -0
  71. package/dist/modules/plugins/plugins.service.js +172 -0
  72. package/dist/modules/plugins/plugins.service.js.map +1 -0
  73. package/dist/modules/skills/pending-skills.service.d.ts +2 -2
  74. package/dist/modules/skills/pending-skills.service.js +7 -7
  75. package/dist/modules/skills/pending-skills.service.js.map +1 -1
  76. package/dist/modules/skills/skills.contract.d.ts +4 -4
  77. package/dist/modules/skills/skills.contract.d.ts.map +1 -1
  78. package/dist/modules/skills/skills.contract.js +1 -1
  79. package/dist/modules/skills/skills.service.js +5 -5
  80. package/dist/modules/skills/skills.service.js.map +1 -1
  81. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts +65 -0
  82. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -0
  83. package/dist/modules/tool-manuals/mcp-json-discovery.js +276 -0
  84. package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -0
  85. package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts +92 -0
  86. package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts.map +1 -0
  87. package/dist/modules/tool-manuals/mcp-server-edit.service.js +328 -0
  88. package/dist/modules/tool-manuals/mcp-server-edit.service.js.map +1 -0
  89. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +38 -12
  90. package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
  91. package/dist/modules/tool-manuals/tool-manuals.contract.js +1 -1
  92. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +13 -2
  93. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
  94. package/dist/modules/tool-manuals/tool-manuals.routes.js +233 -2
  95. package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
  96. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
  97. package/dist/modules/tool-manuals/tool-manuals.service.js +74 -37
  98. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
  99. package/dist/modules/tool-manuals/tool-manuals.tools.js +6 -3
  100. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
  101. package/dist/modules/workflow/git/git.service.js +2 -2
  102. package/dist/modules/workflow/git/git.service.js.map +1 -1
  103. package/dist/modules/workspace/kb-seed.service.d.ts +2 -2
  104. package/dist/modules/workspace/kb-seed.service.d.ts.map +1 -1
  105. package/dist/modules/workspace/kb-seed.service.js +43 -10
  106. package/dist/modules/workspace/kb-seed.service.js.map +1 -1
  107. package/dist/modules/workspace/plugins-migration.d.ts +50 -0
  108. package/dist/modules/workspace/plugins-migration.d.ts.map +1 -0
  109. package/dist/modules/workspace/plugins-migration.js +379 -0
  110. package/dist/modules/workspace/plugins-migration.js.map +1 -0
  111. package/dist/modules/workspace/workspace.routes.js +3 -3
  112. package/dist/modules/workspace/workspace.routes.js.map +1 -1
  113. package/dist/modules/workspace/workspace.service.d.ts +26 -0
  114. package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
  115. package/dist/modules/workspace/workspace.service.js +83 -12
  116. package/dist/modules/workspace/workspace.service.js.map +1 -1
  117. package/dist/shared/kb-layout.test.js +3 -3
  118. package/dist/shared/kb-layout.test.js.map +1 -1
  119. package/dist/shared/utcp-namespace.d.ts +6 -27
  120. package/dist/shared/utcp-namespace.d.ts.map +1 -1
  121. package/dist/shared/utcp-namespace.js +6 -63
  122. package/dist/shared/utcp-namespace.js.map +1 -1
  123. package/dist/shared/variable-refs.d.ts +42 -0
  124. package/dist/shared/variable-refs.d.ts.map +1 -0
  125. package/dist/shared/variable-refs.js +60 -0
  126. package/dist/shared/variable-refs.js.map +1 -0
  127. package/kb-template/.bevelignore +1 -1
  128. package/kb-template/AGENTS.md +88 -35
  129. package/kb-template/KnowledgeBase/How to get started.md +10 -10
  130. package/kb-template/access.md +36 -36
  131. package/migrations/meta/0000_snapshot.json +1479 -1479
  132. package/package.json +5 -4
  133. package/src/assets.ts +25 -25
  134. package/src/core/core-ports.ts +106 -106
  135. package/src/core/create-core-server.ts +55 -9
  136. package/src/core/create-core-services.ts +40 -20
  137. package/src/index.ts +69 -69
  138. package/src/modules/access/__tests__/access-control.atref-batch.test.ts +98 -98
  139. package/src/modules/access/__tests__/access-declarations.test.ts +28 -28
  140. package/src/modules/access/__tests__/access-md-format.test.ts +18 -18
  141. package/src/modules/access/__tests__/access-mutation.service.test.ts +5 -5
  142. package/src/modules/access/__tests__/access-splice.test.ts +2 -2
  143. package/src/modules/access/__tests__/access.routes.overrides.test.ts +16 -16
  144. package/src/modules/access/__tests__/grant-sources.test.ts +12 -12
  145. package/src/modules/access/__tests__/roles-admin.service.test.ts +13 -1
  146. package/src/modules/access/access-control.interface.ts +8 -7
  147. package/src/modules/access/access-control.service.ts +7 -7
  148. package/src/modules/access/access-declarations.ts +5 -5
  149. package/src/modules/access/access-mutation.service.ts +3 -3
  150. package/src/modules/access/access-splice.ts +4 -4
  151. package/src/modules/access/access.routes.ts +20 -20
  152. package/src/modules/access/creator-access.ts +5 -5
  153. package/src/modules/access/roles-admin.service.ts +13 -2
  154. package/src/modules/admin/admin-access.routes.ts +29 -29
  155. package/src/modules/auth/__tests__/auth.routes.test.ts +91 -91
  156. package/src/modules/auth/__tests__/rate-limit.test.ts +36 -36
  157. package/src/modules/auth/rate-limit.ts +45 -45
  158. package/src/modules/code-mode/__tests__/code-mode.tool.test.ts +67 -0
  159. package/src/modules/code-mode/code-mode-names.ts +10 -36
  160. package/src/modules/code-mode/code-mode.tool.ts +27 -7
  161. package/src/modules/database/connection.ts +15 -15
  162. package/src/modules/database/schema.ts +11 -11
  163. package/src/modules/diff/__tests__/diff.routes.rejectPathsLocked.test.ts +150 -150
  164. package/src/modules/mcp/mcp.service.ts +57 -435
  165. package/src/modules/{groups → plugins}/__tests__/join-proposals.test.ts +1 -1
  166. package/src/modules/{groups → plugins}/__tests__/join-requests.service.test.ts +7 -7
  167. package/src/modules/{groups/__tests__/group-index.service.test.ts → plugins/__tests__/plugin-index.service.test.ts} +41 -41
  168. package/src/modules/plugins/__tests__/plugin-provision.service.test.ts +312 -0
  169. package/src/modules/{groups/__tests__/groups.routes.test.ts → plugins/__tests__/plugins.routes.test.ts} +100 -100
  170. package/src/modules/plugins/index.ts +17 -0
  171. package/src/modules/{groups → plugins}/join-proposals.ts +2 -2
  172. package/src/modules/{groups → plugins}/join-requests.service.ts +8 -8
  173. package/src/modules/{groups/group-provision.service.ts → plugins/plugin-provision.service.ts} +139 -69
  174. package/src/modules/{groups/groups.contract.ts → plugins/plugins.contract.ts} +26 -26
  175. package/src/modules/{groups/groups.routes.ts → plugins/plugins.routes.ts} +102 -102
  176. package/src/modules/{groups/groups.service.ts → plugins/plugins.service.ts} +43 -43
  177. package/src/modules/secrets-vault/__tests__/tool-owner-gate.route.test.ts +143 -143
  178. package/src/modules/skills/__tests__/pending-skills.service.test.ts +14 -14
  179. package/src/modules/skills/__tests__/skills.service.test.ts +13 -13
  180. package/src/modules/skills/pending-skills.service.ts +7 -7
  181. package/src/modules/skills/skills.contract.ts +4 -4
  182. package/src/modules/skills/skills.service.ts +5 -5
  183. package/src/modules/tool-auth/llm-usage-meter.ts +19 -19
  184. package/src/modules/tool-manuals/__tests__/mcp-json-discovery.test.ts +198 -0
  185. package/src/modules/tool-manuals/__tests__/mcp-server-edit.service.test.ts +346 -0
  186. package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +101 -0
  187. package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +3 -3
  188. package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +2 -2
  189. package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +27 -27
  190. package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +3 -3
  191. package/src/modules/tool-manuals/mcp-json-discovery.ts +328 -0
  192. package/src/modules/tool-manuals/mcp-server-edit.service.ts +434 -0
  193. package/src/modules/tool-manuals/tool-manuals.contract.ts +35 -12
  194. package/src/modules/tool-manuals/tool-manuals.routes.ts +222 -1
  195. package/src/modules/tool-manuals/tool-manuals.service.ts +82 -42
  196. package/src/modules/tool-manuals/tool-manuals.tools.ts +6 -3
  197. package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +1 -1
  198. package/src/modules/workflow/git/__tests__/branch-name.test.ts +3 -3
  199. package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +3 -3
  200. package/src/modules/workflow/git/__tests__/git.service.commitFile.test.ts +13 -8
  201. package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +1 -1
  202. package/src/modules/workflow/git/__tests__/pull-request.service.test.ts +1 -1
  203. package/src/modules/workflow/git/git.service.ts +2 -2
  204. package/src/modules/workflow/review-workflow/__tests__/approval-states.test.ts +1 -1
  205. package/src/modules/workflow/review-workflow/__tests__/cancel-pr.test.ts +1 -1
  206. package/src/modules/workflow/workflow-hooks.ts +101 -101
  207. package/src/modules/workspace/__tests__/kb-seed.service.test.ts +81 -13
  208. package/src/modules/workspace/__tests__/plugins-migration.test.ts +427 -0
  209. package/src/modules/workspace/__tests__/session-ontology.gate.test.ts +237 -237
  210. package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +236 -236
  211. package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +179 -179
  212. package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +320 -320
  213. package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +337 -337
  214. package/src/modules/workspace/__tests__/workspace.service.test.ts +116 -0
  215. package/src/modules/workspace/bevel-ignore.ts +66 -66
  216. package/src/modules/workspace/kb-seed.service.ts +38 -9
  217. package/src/modules/workspace/plugins-migration.ts +479 -0
  218. package/src/modules/workspace/session-sink.ts +25 -25
  219. package/src/modules/workspace/workspace.routes.ts +3 -3
  220. package/src/modules/workspace/workspace.service.ts +85 -14
  221. package/src/modules/workspace/workspace.tools.ts +922 -922
  222. package/src/shared/__tests__/join-request.test.ts +13 -13
  223. package/src/shared/__tests__/kb-layout.plugin.test.ts +45 -0
  224. package/src/shared/kb-layout.test.ts +3 -3
  225. package/src/shared/utcp-namespace.ts +10 -68
  226. package/src/shared/variable-refs.ts +64 -0
  227. package/src/modules/groups/__tests__/group-provision.service.test.ts +0 -247
  228. package/src/modules/groups/index.ts +0 -17
  229. package/src/shared/__tests__/kb-layout.group.test.ts +0 -45
  230. /package/kb-template/{Groups → Plugins}/.gitkeep +0 -0
@@ -0,0 +1,60 @@
1
+ /**
2
+ * The ONE variable-reference grammar, shared by every boundary that has to
3
+ * decide "would the substitutor expand this?" — `.tool` parsing, `mcp.json`
4
+ * discovery, the server editor's header split, and the Groups→Plugins
5
+ * migration. The decision has credential stakes on both sides (a reference
6
+ * mis-read as prose is a `${VAR}` written into portable, world-readable
7
+ * `mcp.json`; prose mis-read as a reference is a header that stops working),
8
+ * so the classifiers must not each keep their own approximation of it.
9
+ */
10
+ /**
11
+ * The SDK substitutor's reference grammar, exactly: `${VAR}` or `$VAR`, names
12
+ * `[a-zA-Z0-9_]+`. Note a LEADING DIGIT is legal — `$5TOKEN` (and `$5` in
13
+ * prose) is a reference as far as substitution is concerned, and classifying
14
+ * it as anything else here would diverge from what actually expands.
15
+ */
16
+ export const VARIABLE_REFERENCE_RE = /\$\{([a-zA-Z0-9_]+)\}|\$([a-zA-Z0-9_]+)/g;
17
+ // `.test()` on a global regex is stateful (lastIndex persists across calls) —
18
+ // the predicate gets its own non-global compilation of the same source.
19
+ const VARIABLE_REFERENCE_ONCE = new RegExp(VARIABLE_REFERENCE_RE.source);
20
+ /** True when any substring of `text` is a substitutor reference. */
21
+ export function containsVariableReference(text) {
22
+ return VARIABLE_REFERENCE_ONCE.test(text);
23
+ }
24
+ /**
25
+ * Variable names the platform seeds for its own (Bevel-hosted) manuals:
26
+ * `<ns>_API_URL` points a manual at the backend and `<ns>_CONNECTION_KEY`
27
+ * carries the platform bearer. User-declared variables may not take these
28
+ * names, and user content may not reference them (bare or namespaced).
29
+ */
30
+ export const RESERVED_VARIABLE_NAMES = ['API_URL', 'CONNECTION_KEY'];
31
+ /**
32
+ * A NAME is reserved by SUFFIX, not by exact match: the substitutor looks a
33
+ * variable up under the manual's UTCP namespace first, so `${<ns>_CONNECTION_KEY}`
34
+ * resolves the very same seeded value the bare `${CONNECTION_KEY}` does.
35
+ * Suffix matching also refuses harmless-looking near-misses (`MY_API_URL`) —
36
+ * deliberately fail-closed.
37
+ */
38
+ export function isReservedVariableName(varName) {
39
+ return RESERVED_VARIABLE_NAMES.some((reserved) => varName.endsWith(reserved));
40
+ }
41
+ /**
42
+ * The first reserved REFERENCE anywhere in `doc` (scanned as JSON text), or
43
+ * null. Built on the shared grammar above, so what counts as a reference here
44
+ * is exactly what counts everywhere else — `${ API_URL }` with spaces is not
45
+ * expandable, so it is a literal to every boundary, not reserved to one and
46
+ * portable to another.
47
+ */
48
+ export function findReservedVariableRef(doc) {
49
+ const text = JSON.stringify(doc) ?? '';
50
+ // A fresh instance per scan: `matchAll` COPIES the source regex's
51
+ // `lastIndex` (spec), and the exported one is mutable module state — any
52
+ // future `.exec`/`.test` on it would make this scan start mid-string.
53
+ for (const match of text.matchAll(new RegExp(VARIABLE_REFERENCE_RE.source, VARIABLE_REFERENCE_RE.flags))) {
54
+ const varName = match[1] ?? match[2] ?? '';
55
+ if (isReservedVariableName(varName))
56
+ return match[0];
57
+ }
58
+ return null;
59
+ }
60
+ //# sourceMappingURL=variable-refs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"variable-refs.js","sourceRoot":"","sources":["../../src/shared/variable-refs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,0CAA0C,CAAC;AAEhF,8EAA8E;AAC9E,wEAAwE;AACxE,MAAM,uBAAuB,GAAG,IAAI,MAAM,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAEzE,oEAAoE;AACpE,MAAM,UAAU,yBAAyB,CAAC,IAAY;IACpD,OAAO,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC5C,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAsB,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;AAExF;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAe;IACpD,OAAO,uBAAuB,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AAChF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CAAC,GAAY;IAClD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IACvC,kEAAkE;IAClE,yEAAyE;IACzE,sEAAsE;IACtE,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QACzG,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3C,IAAI,sBAAsB,CAAC,OAAO,CAAC;YAAE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -22,4 +22,4 @@ CLAUDE.md
22
22
  **/access.md
23
23
  roles.yaml
24
24
 
25
- Groups/
25
+ Plugins/
@@ -21,36 +21,77 @@ change them.
21
21
  ```text
22
22
  knowledge-base/
23
23
  ├── KnowledgeBase/ ← the knowledge itself; organise it however suits you
24
- ├── Groups/ ← one folder per group: its skills AND its tools
24
+ ├── Plugins/ ← one folder per plugin: its skills AND its tools
25
25
  ├── roles.yaml ← identity → role mapping (Admin-only edits)
26
26
  └── access.md ← repo-root access-control rules
27
27
  ```
28
28
 
29
- Only those two folders are structural, and only `Groups/` has a layout the
29
+ Only those two folders are structural, and only `Plugins/` has a layout the
30
30
  platform reads:
31
31
 
32
32
  ```text
33
- Groups/<Group>/<skill>/SKILL.md a skill
34
- Groups/<Group>/<name>.tool a tool manual
35
- Groups/<Group>/access.md who can read/write the whole group
36
- Groups/personal-<user-id>/… one per person: their own skills, private
33
+ Plugins/<Plugin>/plugin.json the manifest (Agent Plugins)
34
+ Plugins/<Plugin>/skills/<skill>/SKILL.md a skill
35
+ Plugins/<Plugin>/mcp.json MCP servers (authoritative)
36
+ Plugins/<Plugin>/software.bevel.hexis/tools/ `.tool` manuals
37
+ Plugins/<Plugin>/access.md who can read/write the plugin
38
+ Plugins/personal-<user-id>/… one per person: private
37
39
  ```
38
40
 
39
- Skills and tools live TOGETHER in a group because they share one access
40
- boundary: a tool a group cannot read is a skill that group cannot run.
41
-
42
- **Group folders are made through the app, not by writing files.** A group
41
+ Skills and tools live TOGETHER in a plugin because they share one access
42
+ boundary: a tool a plugin cannot read is a skill that plugin cannot run.
43
+
44
+ **Symlinks are not supported anywhere under `Plugins/`.** Access control
45
+ resolves rules by path, and a symlink is a second path to the same content —
46
+ the two can disagree about who may read what. The platform never creates
47
+ them and ignores any it finds (they can only arrive via a direct git push).
48
+
49
+ **A plugin follows the [Agent Plugins](https://agent-plugins.org) specification**
50
+ (v1.0.0), so another conformant client can load one: it reads `plugin.json`, the
51
+ skills under `skills/`, and the servers in `mcp.json`, and ignores everything
52
+ else. Two things here are ours and sit outside that portable core. `access.md`
53
+ stays at the plugin root because access resolution walks root → file, so the
54
+ same rules one level down would govern only that subtree. And `http`/`inline` `.tool`
55
+ manuals live under the reverse-DNS `software.bevel.hexis/` namespace, because
56
+ the specification describes MCP servers only and has no way to express them.
57
+
58
+ **MCP servers belong in `mcp.json` — do not write `.tool` files for them.**
59
+ Each `mcpServers` key is the server's identity: it is the namespace its vault
60
+ secrets bind to (`<name>_<VAR>`), so renaming a key unbinds every configured
61
+ secret and sign-in. The portable entry carries only where the server is
62
+ (`type`, `url`, literal headers). Anything this platform needs beyond that —
63
+ auth headers carrying `${VAR}` vault references, `variables` declarations,
64
+ a `description`, or `local: true` for a server only reachable from a user's
65
+ machine — goes in `plugin.json` under
66
+ `extensions["software.bevel.hexis"].mcpServers[<name>]`, which other clients
67
+ ignore by design. A `type: "stdio"` entry (a command run on the user's own
68
+ machine) is always local: the hosted endpoint never spawns it; the local
69
+ `hexis-mcp` server fetches the plugin's files to a local directory and runs it
70
+ per the Agent Plugins runtime contract (`PLUGIN_ROOT`/`PLUGIN_DATA`, `./`
71
+ commands contained to the plugin).
72
+
73
+ **Secrets are never written into a plugin's portable files.** The specification
74
+ defines no portable credential mechanism on purpose: authorization and
75
+ credential storage are the client's business, header and `env` values are
76
+ "visible package data", and a client must not expand anything except
77
+ `${PLUGIN_ROOT}` and `${PLUGIN_DATA}`. So the Secrets Vault IS this platform's
78
+ answer to that — and `mcp.json` carries only where a server is, never a
79
+ `${VAR}` reference to how to authenticate with it. Those live in `plugin.json`
80
+ under `extensions["software.bevel.hexis"].mcpServers[<name>]`, which is ours
81
+ to interpret and which other clients ignore by design.
82
+
83
+ **Plugin folders are made through the app, not by writing files.** A plugin
43
84
  exists exactly when its folder carries an `access.md` — a bare directory
44
- under `Groups/` is not a group and is never listed. A new
45
- direct child of `Groups/` needs an `access.md` naming who runs it, and the
85
+ under `Plugins/` is not a plugin and is never listed. A new
86
+ direct child of `Plugins/` needs an `access.md` naming who runs it, and the
46
87
  write gate refuses a plain write into an unused name there — so do not try to
47
- create a group by writing a skill into `Groups/<new-name>/…`; it will be
48
- denied. Send the user to the app's **New group** button (or its
49
- `POST /api/groups` endpoint), then write into the folder it made. Names
88
+ create a plugin by writing a skill into `Plugins/<new-name>/…`; it will be
89
+ denied. Send the user to the app's **New plugin** button (or its
90
+ `POST /api/plugins` endpoint), then write into the folder it made. Names
50
91
  starting with `personal-` are reserved: one such folder exists per person,
51
92
  created automatically with their first personal skill, readable only by its
52
- owner and never listed as a group — a signed-in user's own skills belong
53
- there, and move into a group by moving the skill's folder.
93
+ owner and never listed as a plugin — a signed-in user's own skills belong
94
+ there, and move into a plugin by moving the skill's folder.
54
95
 
55
96
  Everything under `KnowledgeBase/` is yours to arrange. Subfolders, naming,
56
97
  whether a topic is one file or twenty — all of it is a judgement call about
@@ -99,7 +140,7 @@ File-level write access decides how a change lands on the default branch:
99
140
  review flow — and prefer a change request when in doubt, when the change is
100
141
  large, or when it touches content the user does not own.
101
142
 
102
- ## Skills (`Groups/<Group>/<skill>/SKILL.md`)
143
+ ## Skills (`Plugins/<Plugin>/skills/<skill>/SKILL.md`)
103
144
 
104
145
  A skill is a folder holding a `SKILL.md` and whatever files it needs. The
105
146
  frontmatter names it and declares which tools it may use:
@@ -113,21 +154,25 @@ allowed-tools: [slack_post_message]
113
154
  ```
114
155
 
115
156
  The body is the instructions, in plain markdown. `allowed-tools` entries are
116
- tool names from the `.tool` manuals in the same group — a skill can only reach
117
- tools its group can read.
157
+ tool names from the `.tool` manuals in the same plugin — a skill can only reach
158
+ tools its plugin can read.
118
159
 
119
- ## Tool Manuals (`Groups/<Group>/*.tool`)
160
+ ## Tool Manuals (`Plugins/<Plugin>/software.bevel.hexis/tools/*.tool`)
120
161
 
121
- Each group folder holds `*.tool` files — reusable **tool manuals** that let agents call external APIs. They are **not part of the knowledge graph** (never modelled as nodes) and are access-controlled like any other file via `access.md`. Any user who can *read* a `.tool` can use its tools; anyone who can *write* it sets its shared (admin) secrets (see below). Put each manual directly in the group folder whose skills use it. The same
122
- integration may exist in several groups as separate files (`Everyone/notion.tool`
123
- and `Finance/notion.tool`), each with its own credentials and access rule —
124
- a group is a folder, not a registry of unique names.
162
+ Each plugin folder holds `*.tool` files — reusable **tool manuals** that let agents call external APIs. They are **not part of the knowledge graph** (never modelled as nodes) and are access-controlled like any other file via `access.md`. Any user who can *read* a `.tool` can use its tools; anyone who can *write* it sets its shared (admin) secrets (see below). Put each manual in the plugin's `software.bevel.hexis/tools/` directory, beside
163
+ the skills that use it. The same integration may exist in several plugins as
164
+ separate files (`Everyone/…/serper.tool` and `Finance/…/serper.tool`), each
165
+ with its own credentials and access rule — a plugin is a folder, not a registry
166
+ of unique names. Remember: `.tool` files are for `http` and `inline` manuals
167
+ only; MCP servers belong in `mcp.json`.
125
168
 
126
169
  A `.tool` file is JSON or YAML. Its `type` decides how tools are discovered:
127
170
 
128
171
  - **`inline`** — the tools are embedded in the file (no network round-trip to list them).
129
172
  - **`http`** — `url` points to an endpoint that returns a UTCP manual.
130
- - **`mcp`** — `url` is a remote MCP server whose tools are discovered over MCP.
173
+
174
+ (`type: mcp` is the LEGACY spelling of an MCP server as a `.tool`. The boot
175
+ migration converts such files into `mcp.json` entries; do not write new ones.)
131
176
 
132
177
  **The tool is the frontmatter.** A `.tool` is one `---` YAML block holding *everything* — its `id`, its access verbs (`read:`/`write:`/`owner:`/`download:`), and its config (`type`/`url`/`variables`/…) — all in the same object. Anything after the closing `---` is free-form notes the parser ignores (like a `SKILL.md` body):
133
178
 
@@ -138,8 +183,8 @@ write:
138
183
  - Product Team
139
184
  owner:
140
185
  - Jane Doe <jane@x.com>
141
- type: mcp
142
- url: https://mcp.example.com
186
+ type: http
187
+ url: https://api.example.com/utcp
143
188
  ---
144
189
  ```
145
190
 
@@ -149,7 +194,15 @@ url: https://mcp.example.com
149
194
 
150
195
  **Frontmatter `id` = address.** This is generic, not tool-specific: ANY `.md` or `.tool` file whose frontmatter declares an `id` (or a lowercase snake_case/kebab `name`) is addressable at `/workspace/<branch>/<id>` in the app, exactly like a knowledge node — tools, skills (`SKILL.md`), and plain notes alike. Graph nodes win an id collision; files without frontmatter stay path-addressed.
151
196
 
152
- **Remote vs local (`remote`).** A tool is available to remote agents by default. Add `remote: false` for a tool that only works on the user's own machine (e.g. an mcp/http `url` on `localhost`): the hosted remote MCP endpoint then skips it and instead advertises it through the `list_local_tools` tool, which returns the `.tool`'s path so a local agent can read it and self-configure (e.g. add the MCP server to its own client).
197
+ **Remote vs local (`remote`).** A tool is available to remote agents by default. Add `remote: false` for a tool that only works on the user's own machine (e.g. an `http` manual whose `url` is on `localhost`): the hosted remote MCP endpoint cannot reach it, so it skips the tool and advertises it through the `list_local_tools` tool instead. (An MCP server that is local-only declares `local: true` in the plugin.json extensions block instead — see above.)
198
+
199
+ To actually USE those tools, run the workspace as a local MCP server:
200
+
201
+ ```
202
+ npx @bevel-software/hexis-mcp --url <workspace-url> --key <connection-key>
203
+ ```
204
+
205
+ It serves everything the hosted endpoint serves **plus** the local-only tools, because it runs on the machine where they exist. Remote tools still execute on the server, so their shared keys and OAuth sign-ins keep working untouched; a local-only tool's own `${VAR}`s come from the environment of whatever launched the command (your MCP client's config), since the Secrets Vault never leaves the server. Reading the `.tool` and wiring the server into your client by hand still works and is the fallback when the command is unavailable.
153
206
 
154
207
  ### Referencing secrets — `${VAR}` and the `variables` block
155
208
 
@@ -207,21 +260,21 @@ An `inline` manual with one tool:
207
260
  When asked to add/integrate a product as a tool (e.g. "add Notion", "wire up Linear"), **never invent an endpoint or write a placeholder URL** — a `.tool` pointing at a made-up host is useless:
208
261
 
209
262
  1. **Find the real endpoint from the vendor's own docs.** Prefer the vendor's official **remote MCP server** if one exists; otherwise fall back to their **REST API** base. No endpoint is named here on purpose — a URL copied into this file would be asserted long after it stopped being true, which is the failure this step exists to prevent. Use web search/extract to confirm the exact URL, transport, and auth scheme — don't answer from memory. If you have no web access or genuinely can't find it, **ask the user** for the endpoint URL and auth instead of guessing.
210
- 2. **Pick the type from what you found.** An MCP server → `type: mcp` with the official `url` (the MCP transport is HTTP/streamable — use the `https://…` URL, **never** `ws://`/`wss://`). A plain REST/HTTP endpoint → `type: http`. Use `type: inline` only when hand-authoring the individual HTTP calls.
211
- 3. **An OAuth-protected MCP server usually needs NOTHING beyond `type: mcp` + `url`.** Write just those two and let the app probe the server: it discovers the sign-in provider (MCP authorization spec), registers itself, and surfaces a per-user sign-in on the Connect page. That is the `oauth-auto` case, and for it you must NOT declare `variables` or `headers`.
263
+ 2. **Pick the home from what you found.** An MCP server → an entry in the plugin's `mcp.json` (`type: "streamable-http"` with the official `url` — use the `https://…` URL, **never** `ws://`/`wss://`). A plain REST/HTTP endpoint → a `.tool` with `type: http`. Use `type: inline` only when hand-authoring the individual HTTP calls.
264
+ 3. **An OAuth-protected MCP server usually needs NOTHING beyond its `mcp.json` entry.** Write just those two and let the app probe the server: it discovers the sign-in provider (MCP authorization spec), registers itself, and surfaces a per-user sign-in on the Connect page. That is the `oauth-auto` case, and for it you must NOT declare `variables` or `headers`.
212
265
 
213
266
  Some providers do not support automatic registration (`oauth-manual` — see the walkthrough below). Those DO need a sign-in variable to hold the client id, and an admin pastes the client secret on the tool's page. You do not have to guess which kind you are facing: write the two lines, then run `list_tool_setup` and read `setup.kind`.
214
267
  4. **For key-based auth, wire it as `variables`, never a hard-coded secret.** Reference credentials as `${VAR}` in `headers` (e.g. `Authorization: Bearer ${NOTION_TOKEN}`) and declare each in the `variables` block with a scope (`admin` = one shared value; `user` = per-user). Users fill the values in the Secrets Vault.
215
- 5. **Set `remote: false`** only when the tool is reachable ONLY from the user's own machine (e.g. a `localhost` MCP server); otherwise leave it remote-capable.
268
+ 5. **Say so when a tool is reachable ONLY from the user's own machine.** For an MCP server (e.g. one on `localhost`), declare `local: true` on its entry in the plugin.json extensions block — `remote: false` is a `.tool` frontmatter field and means nothing in `mcp.json`. For an `http`/`inline` `.tool`, set `remote: false`. Otherwise leave the tool remote-capable.
216
269
 
217
270
  ### Checking what an admin still needs to configure
218
271
 
219
- Call the **`list_tool_setup`** tool to see, for every accessible `.tool`, what is configured and what is still missing. Use it whenever a tool isn't working, after adding a tool, or when asked "what do I need to set up?" — then EXPLAIN the remaining steps to the user rather than guessing. Per tool it reports:
272
+ Call the **`list_tool_setup`** tool to see, for every accessible tool — `.tool` manuals and `mcp.json` servers alike — what is configured and what is still missing. Use it whenever a tool isn't working, after adding a tool, or when asked "what do I need to set up?" — then EXPLAIN the remaining steps to the user rather than guessing. Per tool it reports:
220
273
 
221
- - **`setup.kind`** (for `type: mcp`): `open` = no credentials needed; `oauth-auto` = the platform registered itself with the server automatically and users just authorize on the **Connect page**; `oauth-manual` = the provider does not support automatic registration, so a tool writer must configure it by hand (below).
274
+ - **`setup.kind`** (for MCP servers): `open` = no credentials needed; `oauth-auto` = the platform registered itself with the server automatically and users just authorize on the **Connect page**; `oauth-manual` = the provider does not support automatic registration, so a tool writer must configure it by hand (below).
222
275
  - **Per variable**: `adminConfigured` (the shared value — or, for a sign-in, the owner-side provider setup — is done), `userConfigured` / `authorized` (the CURRENT user's own value / sign-in), and `canWrite` (whether the current user may set the tool's shared config).
223
276
 
224
- The listing is scoped by the same access controls as everything else: a `.tool` the caller can't READ doesn't appear at all, and `canWrite` means write access **on that `.tool` file itself** — granted by its frontmatter `write:`/`owner:` verbs or the `access.md` chain, NOT by any platform role. The people who manage a `.tool` file are exactly the people who configure its shared secrets. To delegate a tool to someone, add them to the file's `write:` or `owner:` list (an edit you can make via change request); that alone lets them configure it.
277
+ The listing is scoped by the same access controls as everything else: a tool the caller can't READ doesn't appear at all, and `canWrite` means write access **on the file that declares it** — the `.tool` file itself (via its frontmatter `write:`/`owner:` verbs or the `access.md` chain), or the plugin's `mcp.json` for an MCP server (via the plugin's `access.md` chain — `mcp.json` carries no verb list of its own) — NOT any platform role. The people who manage that file are exactly the people who configure its shared secrets. To delegate a `.tool` to someone, add them to that file's `write:`/`owner:` list; to delegate an MCP server, grant them `write` on the plugin in its `access.md` (both are edits you can make via change request). That alone lets them configure it.
225
278
 
226
279
  **Agents never handle secret VALUES.** Never ask for an API key, token, or client secret in the conversation, and there is no tool to set one. Point the right person at the right surface instead:
227
280
 
@@ -17,7 +17,7 @@ Use the app switcher in the top-left corner to move between the two views:
17
17
 
18
18
  - **Knowledge** is the reading and writing surface: a file tree on the left,
19
19
  the document on the right.
20
- - **Skills & Tools** is the library: groups of skills and tools, who runs
20
+ - **Skills & Tools** is the library: plugins holding skills and tools, who runs
21
21
  them, and what still needs setting up.
22
22
 
23
23
  ## Write your first document
@@ -29,22 +29,22 @@ someone else, you get **Propose changes** instead. A proposal becomes a
29
29
  nothing moves until they approve it. That is the whole safety model, and it
30
30
  applies to agents exactly as it applies to people.
31
31
 
32
- ## Set up your group
32
+ ## Set up your plugin
33
33
 
34
- In Skills & Tools, use **New group** to make a place for your team. Creating
35
- a group makes you the one who runs it: you approve its change requests,
34
+ In Skills & Tools, use **New plugin** to make a place for your team. Creating
35
+ a plugin makes you the one who runs it: you approve its change requests,
36
36
  answer join requests, and manage who can see what (the **Share** button on
37
- the group page). Skills you create outside any group land in your own private
38
- space and can move into a group later.
37
+ the plugin page). Skills you create outside any plugin land in your own private
38
+ space and can move into a plugin later.
39
39
 
40
40
  ## Give your agents skills and tools
41
41
 
42
- - On a group page, **+** adds a skill: name it and an empty skill file opens,
42
+ - On a plugin page, **+** adds a skill: name it and an empty skill file opens,
43
43
  ready for instructions. Write it the way you would brief a careful new
44
44
  colleague: what to load, what to do, what to record.
45
- - Tools are added as small manual files in the group. Sign-ins and keys are
46
- entered on the **Connect** page or the tool's own page, never written into
47
- files.
45
+ - Tools live in the plugin too: most are small manual files, and MCP servers
46
+ go in the plugin's `mcp.json`. Sign-ins and keys are entered on the
47
+ **Connect** page or the tool's own page, never written into files.
48
48
 
49
49
  ## Connect your AI agent
50
50
 
@@ -1,36 +1,36 @@
1
- ---
2
- write:
3
- - Admin
4
- download:
5
- - Admin
6
- owner: []
7
- ---
8
-
9
- # Repository access
10
-
11
- This file is the root of the access-control tree for this knowledge base. It grants
12
- write access only to the `Admin` role by default. Subfolders can broaden or narrow
13
- access by adding their own `access.md`.
14
-
15
- See [roles.yaml](roles.yaml) for the identity → role mapping. Access resolution and validation
16
- run in the Bevel platform.
17
-
18
- ## Adding a folder-level rule
19
-
20
- Drop an `access.md` into any folder, at any depth. Frontmatter
21
- only — the body is ignored. Example:
22
-
23
- ```yaml
24
- ---
25
- write:
26
- - Admin
27
- - Editor
28
- - Jane Doe <jane.doe@example.com>
29
- - deny Mallory Bad <mallory@example.com>
30
- ---
31
- ```
32
-
33
- Each entry is either a grant (bare principal) or a denial (`deny <principal>` —
34
- **lowercase `deny` only**; capitalised forms like `Deny` are treated as part of a
35
- name). A principal is either a role name (matched case-insensitively against
36
- `roles.yaml`) or a user reference in `Name <email>` form.
1
+ ---
2
+ write:
3
+ - Admin
4
+ download:
5
+ - Admin
6
+ owner: []
7
+ ---
8
+
9
+ # Repository access
10
+
11
+ This file is the root of the access-control tree for this knowledge base. It grants
12
+ write access only to the `Admin` role by default. Subfolders can broaden or narrow
13
+ access by adding their own `access.md`.
14
+
15
+ See [roles.yaml](roles.yaml) for the identity → role mapping. Access resolution and validation
16
+ run in the Bevel platform.
17
+
18
+ ## Adding a folder-level rule
19
+
20
+ Drop an `access.md` into any folder, at any depth. Frontmatter
21
+ only — the body is ignored. Example:
22
+
23
+ ```yaml
24
+ ---
25
+ write:
26
+ - Admin
27
+ - Editor
28
+ - Jane Doe <jane.doe@example.com>
29
+ - deny Mallory Bad <mallory@example.com>
30
+ ---
31
+ ```
32
+
33
+ Each entry is either a grant (bare principal) or a denial (`deny <principal>` —
34
+ **lowercase `deny` only**; capitalised forms like `Deny` are treated as part of a
35
+ name). A principal is either a role name (matched case-insensitively against
36
+ `roles.yaml`) or a user reference in `Name <email>` form.