@synap-core/cli 1.8.0 → 1.10.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 (332) hide show
  1. package/dist/commands/agent-chat.d.ts +47 -0
  2. package/dist/commands/agent-chat.js +250 -0
  3. package/dist/commands/agent-chat.js.map +1 -0
  4. package/dist/commands/agent-run.js +3 -4
  5. package/dist/commands/agent-run.js.map +1 -1
  6. package/dist/commands/agents.js +85 -46
  7. package/dist/commands/agents.js.map +1 -1
  8. package/dist/commands/automation.js +2 -1
  9. package/dist/commands/automation.js.map +1 -1
  10. package/dist/commands/bridge-setup.d.ts +66 -0
  11. package/dist/commands/bridge-setup.js +1112 -0
  12. package/dist/commands/bridge-setup.js.map +1 -0
  13. package/dist/commands/cap-connections.d.ts +28 -0
  14. package/dist/commands/cap-connections.js +224 -0
  15. package/dist/commands/cap-connections.js.map +1 -0
  16. package/dist/commands/capability.d.ts +89 -0
  17. package/dist/commands/capability.js +1523 -0
  18. package/dist/commands/capability.js.map +1 -0
  19. package/dist/commands/centrality.d.ts +20 -0
  20. package/dist/commands/centrality.js +94 -0
  21. package/dist/commands/centrality.js.map +1 -0
  22. package/dist/commands/connect.d.ts +2 -0
  23. package/dist/commands/connect.js +16 -35
  24. package/dist/commands/connect.js.map +1 -1
  25. package/dist/commands/context.js +4 -6
  26. package/dist/commands/context.js.map +1 -1
  27. package/dist/commands/data-extra.d.ts +1 -0
  28. package/dist/commands/data-extra.js +34 -10
  29. package/dist/commands/data-extra.js.map +1 -1
  30. package/dist/commands/data.d.ts +4 -4
  31. package/dist/commands/data.js +241 -184
  32. package/dist/commands/data.js.map +1 -1
  33. package/dist/commands/diagnose.d.ts +20 -0
  34. package/dist/commands/diagnose.js +143 -0
  35. package/dist/commands/diagnose.js.map +1 -0
  36. package/dist/commands/digest.d.ts +17 -0
  37. package/dist/commands/digest.js +121 -0
  38. package/dist/commands/digest.js.map +1 -0
  39. package/dist/commands/discover.d.ts +2 -0
  40. package/dist/commands/discover.js +25 -8
  41. package/dist/commands/discover.js.map +1 -1
  42. package/dist/commands/events.js +2 -1
  43. package/dist/commands/events.js.map +1 -1
  44. package/dist/commands/explain.d.ts +1 -1
  45. package/dist/commands/explain.js +18 -15
  46. package/dist/commands/explain.js.map +1 -1
  47. package/dist/commands/facet.d.ts +29 -0
  48. package/dist/commands/facet.js +113 -0
  49. package/dist/commands/facet.js.map +1 -0
  50. package/dist/commands/graph.js +2 -1
  51. package/dist/commands/graph.js.map +1 -1
  52. package/dist/commands/import.d.ts +38 -0
  53. package/dist/commands/import.js +440 -0
  54. package/dist/commands/import.js.map +1 -0
  55. package/dist/commands/init.js +35 -16
  56. package/dist/commands/init.js.map +1 -1
  57. package/dist/commands/keys.js +3 -4
  58. package/dist/commands/keys.js.map +1 -1
  59. package/dist/commands/knowledge.d.ts +2 -0
  60. package/dist/commands/knowledge.js +61 -9
  61. package/dist/commands/knowledge.js.map +1 -1
  62. package/dist/commands/launch.d.ts +50 -0
  63. package/dist/commands/launch.js +790 -0
  64. package/dist/commands/launch.js.map +1 -0
  65. package/dist/commands/lens.d.ts +45 -0
  66. package/dist/commands/lens.js +386 -0
  67. package/dist/commands/lens.js.map +1 -0
  68. package/dist/commands/market.d.ts +209 -0
  69. package/dist/commands/market.js +1368 -0
  70. package/dist/commands/market.js.map +1 -0
  71. package/dist/commands/mcp.d.ts +42 -0
  72. package/dist/commands/mcp.js +184 -0
  73. package/dist/commands/mcp.js.map +1 -0
  74. package/dist/commands/observe.js +14 -11
  75. package/dist/commands/observe.js.map +1 -1
  76. package/dist/commands/open.d.ts +21 -4
  77. package/dist/commands/open.js +45 -4
  78. package/dist/commands/open.js.map +1 -1
  79. package/dist/commands/pod.d.ts +100 -0
  80. package/dist/commands/pod.js +359 -0
  81. package/dist/commands/pod.js.map +1 -0
  82. package/dist/commands/pods.d.ts +1 -0
  83. package/dist/commands/pods.js +77 -15
  84. package/dist/commands/pods.js.map +1 -1
  85. package/dist/commands/proposals-actions.js +40 -3
  86. package/dist/commands/proposals-actions.js.map +1 -1
  87. package/dist/commands/purge.d.ts +23 -0
  88. package/dist/commands/purge.js +148 -0
  89. package/dist/commands/purge.js.map +1 -0
  90. package/dist/commands/raycast.d.ts +15 -0
  91. package/dist/commands/raycast.js +153 -0
  92. package/dist/commands/raycast.js.map +1 -0
  93. package/dist/commands/sessions.js +45 -21
  94. package/dist/commands/sessions.js.map +1 -1
  95. package/dist/commands/skill-manage.d.ts +21 -0
  96. package/dist/commands/skill-manage.js +195 -0
  97. package/dist/commands/skill-manage.js.map +1 -0
  98. package/dist/commands/skills-commands.js +2 -1
  99. package/dist/commands/skills-commands.js.map +1 -1
  100. package/dist/commands/skills.js +4 -3
  101. package/dist/commands/skills.js.map +1 -1
  102. package/dist/commands/status.d.ts +3 -1
  103. package/dist/commands/status.js +166 -14
  104. package/dist/commands/status.js.map +1 -1
  105. package/dist/commands/statusline.d.ts +24 -0
  106. package/dist/commands/statusline.js +450 -0
  107. package/dist/commands/statusline.js.map +1 -0
  108. package/dist/commands/subscribe.js +2 -2
  109. package/dist/commands/subscribe.js.map +1 -1
  110. package/dist/commands/tools.d.ts +30 -0
  111. package/dist/commands/tools.js +315 -0
  112. package/dist/commands/tools.js.map +1 -0
  113. package/dist/commands/versions.d.ts +27 -0
  114. package/dist/commands/versions.js +277 -0
  115. package/dist/commands/versions.js.map +1 -0
  116. package/dist/commands/view.js +3 -2
  117. package/dist/commands/view.js.map +1 -1
  118. package/dist/commands/whoami.d.ts +21 -0
  119. package/dist/commands/whoami.js +129 -0
  120. package/dist/commands/whoami.js.map +1 -0
  121. package/dist/index.js +776 -60
  122. package/dist/index.js.map +1 -1
  123. package/dist/lib/approval-poll.d.ts +42 -0
  124. package/dist/lib/approval-poll.js +52 -0
  125. package/dist/lib/approval-poll.js.map +1 -0
  126. package/dist/lib/auth.d.ts +29 -6
  127. package/dist/lib/auth.js +105 -94
  128. package/dist/lib/auth.js.map +1 -1
  129. package/dist/lib/bundle-version.d.ts +11 -0
  130. package/dist/lib/bundle-version.js +33 -0
  131. package/dist/lib/bundle-version.js.map +1 -0
  132. package/dist/lib/capture-lane.d.ts +30 -12
  133. package/dist/lib/capture-lane.js +71 -14
  134. package/dist/lib/capture-lane.js.map +1 -1
  135. package/dist/lib/cp-packages.d.ts +121 -0
  136. package/dist/lib/cp-packages.js +218 -0
  137. package/dist/lib/cp-packages.js.map +1 -0
  138. package/dist/lib/describe-lens.d.ts +46 -0
  139. package/dist/lib/describe-lens.js +33 -0
  140. package/dist/lib/describe-lens.js.map +1 -0
  141. package/dist/lib/hub-client.d.ts +78 -1
  142. package/dist/lib/hub-client.js +474 -22
  143. package/dist/lib/hub-client.js.map +1 -1
  144. package/dist/lib/installed.d.ts +51 -0
  145. package/dist/lib/installed.js +70 -0
  146. package/dist/lib/installed.js.map +1 -0
  147. package/dist/lib/next-steps.d.ts +61 -0
  148. package/dist/lib/next-steps.js +146 -0
  149. package/dist/lib/next-steps.js.map +1 -0
  150. package/dist/lib/pod.d.ts +91 -19
  151. package/dist/lib/pod.js +222 -56
  152. package/dist/lib/pod.js.map +1 -1
  153. package/dist/lib/project-ref.d.ts +95 -0
  154. package/dist/lib/project-ref.js +144 -0
  155. package/dist/lib/project-ref.js.map +1 -0
  156. package/dist/lib/project.d.ts +35 -0
  157. package/dist/lib/project.js +39 -0
  158. package/dist/lib/project.js.map +1 -0
  159. package/dist/lib/session-lens.d.ts +33 -0
  160. package/dist/lib/session-lens.js +76 -0
  161. package/dist/lib/session-lens.js.map +1 -0
  162. package/dist/lib/skill-import.d.ts +40 -0
  163. package/dist/lib/skill-import.js +203 -0
  164. package/dist/lib/skill-import.js.map +1 -0
  165. package/dist/lib/skills-installer.d.ts +17 -6
  166. package/dist/lib/skills-installer.js +133 -19
  167. package/dist/lib/skills-installer.js.map +1 -1
  168. package/dist/lib/suite.d.ts +28 -0
  169. package/dist/lib/suite.js +29 -0
  170. package/dist/lib/suite.js.map +1 -0
  171. package/dist/lib/superwhisper-import.d.ts +40 -0
  172. package/dist/lib/superwhisper-import.js +389 -0
  173. package/dist/lib/superwhisper-import.js.map +1 -0
  174. package/dist/lib/targets.d.ts +49 -1
  175. package/dist/lib/targets.js +420 -288
  176. package/dist/lib/targets.js.map +1 -1
  177. package/dist/lib/unwrapList.d.ts +1 -0
  178. package/dist/lib/unwrapList.js +20 -0
  179. package/dist/lib/unwrapList.js.map +1 -0
  180. package/dist/utils/logger.d.ts +2 -0
  181. package/dist/utils/logger.js +10 -2
  182. package/dist/utils/logger.js.map +1 -1
  183. package/package.json +9 -4
  184. package/skills/agent-os/SKILL.md +212 -0
  185. package/skills/manifest.json +5 -0
  186. package/skills/onboard/SKILL.md +186 -0
  187. package/skills/synap/SKILL.md +1182 -37
  188. package/skills/synap/_order.txt +37 -0
  189. package/skills/synap/_skill.yaml +24 -0
  190. package/skills/synap/authentication.md +10 -0
  191. package/skills/synap/automations.md +264 -0
  192. package/skills/synap/capabilities.md +107 -0
  193. package/skills/synap/capture.md +10 -0
  194. package/skills/synap/cli-operations.md +107 -0
  195. package/skills/synap/common-mistakes.md +12 -0
  196. package/skills/synap/creative-loop.md +43 -0
  197. package/skills/synap/crm.md +117 -0
  198. package/skills/synap/diagnostics.md +35 -0
  199. package/skills/synap/digesting-a-channel.md +38 -0
  200. package/skills/synap/document-embeds.md +123 -0
  201. package/skills/synap/escalation-ladder.md +71 -0
  202. package/skills/synap/focus-sessions.md +47 -0
  203. package/skills/synap/governance-rules.md +64 -0
  204. package/skills/synap/governance.md +6 -6
  205. package/skills/synap/graph-gardening.md +21 -0
  206. package/skills/synap/inline-patterns.md +38 -0
  207. package/skills/synap/lenses.md +38 -0
  208. package/skills/synap/linking-principle.md +39 -0
  209. package/skills/synap/linking.md +1 -0
  210. package/skills/synap/mental-model.md +45 -0
  211. package/skills/synap/more.md +7 -0
  212. package/skills/synap/multi-entity-capture.md +10 -0
  213. package/skills/synap/next-action.md +37 -0
  214. package/skills/synap/north-star.md +17 -0
  215. package/skills/synap/operating-mode-rules.md +45 -0
  216. package/skills/synap/operating-mode.md +9 -0
  217. package/skills/synap/quick-reference.md +67 -0
  218. package/skills/synap/reading.md +43 -0
  219. package/skills/synap/recap.md +21 -0
  220. package/skills/synap/reflexes.md +46 -0
  221. package/skills/synap/response-style.md +21 -0
  222. package/skills/synap/scope.md +13 -0
  223. package/skills/synap/showing.md +17 -0
  224. package/skills/synap/user-model.md +25 -0
  225. package/skills/synap/viewframe-cells.md +290 -0
  226. package/skills/synap/work-flow.md +113 -0
  227. package/skills/synap/worked-examples.md +53 -0
  228. package/skills/synap/workspace-design.md +45 -0
  229. package/skills/synap/workspace-edges.md +49 -0
  230. package/skills/synap/writes.md +156 -0
  231. package/skills/synap-schema/SKILL.md +97 -6
  232. package/skills/synap-schema/_order.txt +13 -0
  233. package/skills/synap-schema/_skill.yaml +22 -0
  234. package/skills/synap-schema/before-you-touch.md +14 -0
  235. package/skills/synap-schema/common-mistakes.md +9 -0
  236. package/skills/synap-schema/creating-profiles.md +17 -0
  237. package/skills/synap-schema/discover-profiles.md +24 -0
  238. package/skills/synap-schema/entity-scope.md +8 -0
  239. package/skills/synap-schema/extend-vs-create.md +31 -0
  240. package/skills/synap-schema/more.md +6 -0
  241. package/skills/synap-schema/overlay-properties.md +22 -0
  242. package/skills/synap-schema/profiles.md +3 -0
  243. package/skills/synap-schema/property-defs.md +29 -0
  244. package/skills/synap-schema/read-before-write.md +50 -0
  245. package/skills/synap-schema/relations.md +18 -0
  246. package/skills/synap-schema/worked-example.md +30 -0
  247. package/skills/synap-ui/SKILL.md +26 -2
  248. package/skills/synap-ui/_order.txt +13 -0
  249. package/skills/synap-ui/_skill.yaml +23 -0
  250. package/skills/synap-ui/ai-companion.md +27 -0
  251. package/skills/synap-ui/arranging-bento.md +8 -0
  252. package/skills/synap-ui/before-you-build.md +20 -0
  253. package/skills/synap-ui/bento-layouts.md +35 -0
  254. package/skills/synap-ui/common-mistakes.md +10 -0
  255. package/skills/synap-ui/creating-views.md +26 -0
  256. package/skills/synap-ui/four-builds.md +24 -0
  257. package/skills/synap-ui/more.md +7 -0
  258. package/skills/synap-ui/proposing-vs-extending.md +11 -0
  259. package/skills/synap-ui/view-list.md +24 -0
  260. package/skills/synap-ui/views.md +3 -0
  261. package/skills/synap-ui/worked-example.md +18 -0
  262. package/skills/synap-ui/workspaces.md +47 -0
  263. package/templates/automations/bookmark-enrichment.automation.json +44 -0
  264. package/templates/automations/mail-feed.automation.json +86 -0
  265. package/templates/automations/url-bookmark-capture.automation.json +70 -0
  266. package/templates/skills/README.md +21 -0
  267. package/templates/skills/authoring-automations/SKILL.md +95 -0
  268. package/templates/skills/authoring-automations/reference/node-matrix.md +49 -0
  269. package/templates/skills/authoring-capabilities/SKILL.md +93 -0
  270. package/templates/skills/authoring-capabilities/reference/template-anatomy.md +70 -0
  271. package/templates/skills/authoring-playbooks/SKILL.md +102 -0
  272. package/templates/skills/authoring-playbooks/reference/stages-contract.md +35 -0
  273. package/templates/skills/authoring-playbooks/reference/worked-example.md +64 -0
  274. package/templates/skills/bookmark-enrichment/SKILL.md +40 -0
  275. package/templates/skills/coordinating-agents/SKILL.md +32 -0
  276. package/templates/skills/coordinating-branches/SKILL.md +27 -0
  277. package/templates/skills/mapping-the-server/SKILL.md +54 -0
  278. package/templates/skills/reading-client-progress/SKILL.md +65 -0
  279. package/templates/skills/routing-to-channels/SKILL.md +54 -0
  280. package/templates/skills/stellar-scf-grants-advisor/ASSOCIATE-CHEATSHEET.md +133 -0
  281. package/templates/skills/stellar-scf-grants-advisor/ASSOCIATE-ONBOARDING-GUIDE.md +761 -0
  282. package/templates/skills/stellar-scf-grants-advisor/CLIENT-FAQ.md +181 -0
  283. package/templates/skills/stellar-scf-grants-advisor/PARTNER-HANDOVER.md +130 -0
  284. package/templates/skills/stellar-scf-grants-advisor/SKILL.md +102 -0
  285. package/templates/skills/stellar-scf-grants-advisor/examples/README.md +43 -0
  286. package/templates/skills/stellar-scf-grants-advisor/examples/chat-summary-templates.md +158 -0
  287. package/templates/skills/stellar-scf-grants-advisor/examples/corpus-comparable-rows.md +136 -0
  288. package/templates/skills/stellar-scf-grants-advisor/examples/q10-team-rewrites.md +109 -0
  289. package/templates/skills/stellar-scf-grants-advisor/examples/q2-description-rewrites.md +88 -0
  290. package/templates/skills/stellar-scf-grants-advisor/examples/q6-integration-rewrites.md +107 -0
  291. package/templates/skills/stellar-scf-grants-advisor/examples/tranche-structures.md +176 -0
  292. package/templates/skills/stellar-scf-grants-advisor/reference/01-methodology.md +96 -0
  293. package/templates/skills/stellar-scf-grants-advisor/reference/02-scoring-framework.md +199 -0
  294. package/templates/skills/stellar-scf-grants-advisor/reference/03-rejection-patterns.md +241 -0
  295. package/templates/skills/stellar-scf-grants-advisor/reference/04-winner-patterns.md +120 -0
  296. package/templates/skills/stellar-scf-grants-advisor/reference/05-comeback-patterns.md +92 -0
  297. package/templates/skills/stellar-scf-grants-advisor/reference/06-budget-benchmarks.md +125 -0
  298. package/templates/skills/stellar-scf-grants-advisor/reference/07-integration-list.md +147 -0
  299. package/templates/skills/stellar-scf-grants-advisor/reference/08-abstract-fields.md +258 -0
  300. package/templates/skills/stellar-scf-grants-advisor/reference/09-build-fields.md +259 -0
  301. package/templates/skills/stellar-scf-grants-advisor/reference/10-corpus-winners.md +135 -0
  302. package/templates/skills/stellar-scf-grants-advisor/reference/11-corpus-rejects.md +267 -0
  303. package/templates/skills/stellar-scf-grants-advisor/reference/12-client-communication.md +131 -0
  304. package/templates/skills/stellar-scf-grants-advisor/reference/13-excel-output-spec.md +199 -0
  305. package/templates/skills/stellar-scf-grants-advisor/reference/14-worked-examples.md +160 -0
  306. package/templates/skills/stellar-scf-grants-advisor/templates/abstract-review-builder.py +253 -0
  307. package/templates/skills/stellar-scf-grants-advisor/templates/build-review-builder.py +213 -0
  308. package/dist/commands/connectors.d.ts +0 -31
  309. package/dist/commands/connectors.js +0 -276
  310. package/dist/commands/connectors.js.map +0 -1
  311. package/dist/commands/finish.d.ts +0 -25
  312. package/dist/commands/finish.js +0 -274
  313. package/dist/commands/finish.js.map +0 -1
  314. package/dist/commands/openclaw.d.ts +0 -40
  315. package/dist/commands/openclaw.js +0 -1148
  316. package/dist/commands/openclaw.js.map +0 -1
  317. package/dist/commands/security-audit.d.ts +0 -12
  318. package/dist/commands/security-audit.js +0 -100
  319. package/dist/commands/security-audit.js.map +0 -1
  320. package/dist/lib/hardening.d.ts +0 -18
  321. package/dist/lib/hardening.js +0 -214
  322. package/dist/lib/hardening.js.map +0 -1
  323. package/node_modules/@synap/hub-rest-client/dist/index.cjs +0 -881
  324. package/node_modules/@synap/hub-rest-client/dist/index.d.cts +0 -907
  325. package/node_modules/@synap/hub-rest-client/dist/index.d.ts +0 -907
  326. package/node_modules/@synap/hub-rest-client/dist/index.js +0 -851
  327. package/node_modules/@synap/hub-rest-client/package.json +0 -45
  328. package/node_modules/@synap/hub-rest-client/src/client.ts +0 -1143
  329. package/node_modules/@synap/hub-rest-client/src/errors.ts +0 -30
  330. package/node_modules/@synap/hub-rest-client/src/index.ts +0 -111
  331. package/node_modules/@synap/hub-rest-client/src/setup.ts +0 -77
  332. package/node_modules/@synap/hub-rest-client/src/types.ts +0 -639
@@ -0,0 +1,156 @@
1
+ ## Core writes
2
+
3
+ ### Create an entity (schema-first, complete intent)
4
+
5
+ Before this call, use `/discover?userId=…&profileSlugs=<kind>` to read the
6
+ real fields, required/default values, constraints and reference targets. Omit
7
+ `workspaceId` for the pod/base schema and normal profile placement; pass it
8
+ only when the user or routing decision explicitly selected that workspace.
9
+
10
+ ```json
11
+ POST /api/hub/entities
12
+ {
13
+ "userId": "{userId}",
14
+ "profileSlug": "task", // from /discover — never guess
15
+ "title": "Weekly team sync",
16
+ "description": "Recurring planning sync",
17
+ "properties": { "status": "todo", "dueDate": "2026-07-21" },
18
+ "content": "# Agenda\n- Priorities\n- Risks",
19
+ "projectId": "{existingProjectId}",
20
+ "source": "agent"
21
+ }
22
+ ```
23
+
24
+ The response has legacy `status`/`id` fields plus `writeReceipt`:
25
+ `pending` means a proposal exists and no entity is live; `applied` means the
26
+ reported direct write completed; `partial` means a follow-up (for example a
27
+ facet) failed after the entity applied. Never claim completion from `pending`,
28
+ and only enrich again when the receipt identifies a real missing fact.
29
+
30
+ For several entities, creation-time roles/facets, or relations that need one
31
+ review, submit one `POST /api/hub/capture/graph` plan instead of sequencing
32
+ independent creates. It returns a pending receipt and materializes on human
33
+ approval.
34
+
35
+ ### Update an entity
36
+
37
+ ```json
38
+ PATCH /api/hub/entities/{entityId}
39
+ { "userId": "{userId}", "title": "…", "properties": { "status": "done" } }
40
+ ```
41
+
42
+ **Properties are deep-merged — send only the keys you want to change.** An update with `{ "status": "done" }` leaves all other properties untouched. You never need to re-send the full properties object.
43
+
44
+ ### Create a document (attach to an entity)
45
+
46
+ ```json
47
+ POST /api/hub/documents
48
+ {
49
+ "userId": "{userId}",
50
+ "workspaceId": "{workspaceId}",
51
+ "title": "Meeting notes — 2026-04-20",
52
+ "content": "# Attendees\n- …\n\n# Decisions\n- …",
53
+ "type": "markdown", // "markdown" | "html" | "text" | "code"
54
+ "entityId": "ent_event_..." // attach to an entity for context
55
+ }
56
+ ```
57
+
58
+ `type: "html"` stores self-contained HTML. The browser renders it via the `html-doc` cell in a sandboxed iframe. Use for AI-generated reports, rich visualisations, custom charts, or anything beyond markdown.
59
+
60
+ **Full HTML cell workflow** (AI → visible custom UI in any bento):
61
+
62
+ ```json
63
+ // 1. Create the HTML document
64
+ POST /api/hub/documents
65
+ { "userId": "{userId}", "workspaceId": "{workspaceId}",
66
+ "title": "Q2 Revenue Report", "type": "html",
67
+ "content": "<!DOCTYPE html><html>…</html>",
68
+ "entityId": "ent_project_..." }
69
+ // → { "document": { "id": "doc_abc" }, ... }
70
+
71
+ // 2. Place the html-doc cell in any bento view
72
+ POST /api/hub/views/{bentoViewId}/arrange
73
+ { "userId": "{userId}", "workspaceId": "{workspaceId}",
74
+ "widgets": [
75
+ { "id": "b1", "kind": "html-doc", "config": { "documentId": "doc_abc" },
76
+ "layout": { "x": 0, "y": 0, "w": 8, "h": 6 } }
77
+ ] }
78
+
79
+ // 3. Update the HTML (cell auto-refreshes)
80
+ PATCH /api/hub/documents/doc_abc
81
+ { "userId": "{userId}", "content": "<!DOCTYPE html>…updated…</html>" }
82
+ ```
83
+
84
+ The iframe uses `sandbox="allow-scripts"` — scripts run but have no same-origin access to the parent app. The HTML is fully isolated.
85
+
86
+ ### Update a document (title and/or content)
87
+
88
+ ```json
89
+ PATCH /api/hub/documents/{documentId}
90
+ {
91
+ "userId": "{userId}",
92
+ "title": "Updated title", // optional
93
+ "content": "# Full replacement\n…" // full string — not a diff
94
+ }
95
+ ```
96
+
97
+ Content is a **full replacement**, not a patch. Fetch the current content first if you want to append: `GET /api/hub/documents/{id}?userId={userId}` → `.content`, append, then PATCH.
98
+
99
+ The reverse lookup is `entities WHERE documentId = ?`. Always attach the document to a meaningful entity (the meeting event, the project, the person) — a floating document is another orphan.
100
+
101
+ ### Store a fact (memory) — use sparingly
102
+
103
+ ```json
104
+ POST /api/hub/memory
105
+ { "userId": "{userId}", "fact": "User prefers async communication over meetings" }
106
+ ```
107
+
108
+ Always auto-approved. **Memory is for loose, unstructured, hard-to-title facts only.** The seductive thing about memory is it has zero friction — no dedup, no linking, no proposals. That makes it easy to misuse.
109
+
110
+ **The test:** if the user later asked "show me all X," can memory answer? Memory can only keyword-match — it has no structure. So:
111
+
112
+ | Input | Use |
113
+ | ------------------------------------------------------- | --------------------------------------------------------------- |
114
+ | "User prefers async communication" | memory — it's a preference |
115
+ | "Garage code is 4321" | memory — throwaway fact |
116
+ | "Should we use LangGraph or CrewAI for Eve?" | **entity `question`** — substantive inquiry, start of flow |
117
+ | "Here's what I found comparing LangGraph and CrewAI…" | **entity `research`** — investigation with sources + conclusion |
118
+ | "We decided to use LangGraph over OpenClaude's native…" | **entity `decision`** — has title, rationale, project |
119
+ | "Key insight: tasks need better retry logic" | **entity `note` with tag "insight"** + link to project |
120
+ | "John is now head of engineering at Acme" | **update `contact` entity** — that's a property change |
121
+ | "Launch date moved to May 15" | **update `project` entity** — change the startDate |
122
+ | "Action item from meeting: ship MVP by Friday" | **entity `task`** linked to the `event` (meeting) |
123
+ | "Agreed with Sarah: we'll split backend & frontend" | **entity `decision`** linked to Sarah + the project |
124
+
125
+ **Rule of thumb:** if it has a title-worthy noun OR context to link to (a project, a person, a meeting) OR a lifecycle (status/supersession) — it's an entity, not memory. Memory is the fallback, not the default.
126
+
127
+ **For decisions specifically** — use the `decision` system profile:
128
+
129
+ ```json
130
+ POST /api/hub/entities
131
+ {
132
+ "userId": "{userId}",
133
+ "profileSlug": "decision",
134
+ "title": "Use LangGraph orchestrator over OpenClaude native",
135
+ "properties": {
136
+ "decisionStatus": "accepted",
137
+ "decidedAt": "2026-04-20",
138
+ "summary": "Dedicated orchestrator service; OpenClaude CLI as UX",
139
+ "rationale": "Separates the Orchestration Brain (LangGraph) from the UX (OpenClaude CLI).",
140
+ "alternatives": "Standardize entirely on OpenClaude's multi-agent logic.",
141
+ "projectId": "ent_project_eve"
142
+ }
143
+ }
144
+ ```
145
+
146
+ This creates a first-class decision entity linked to Project Eve. It shows up in traversals, can be superseded later (`supersededBy: newDecisionId`), and survives governance. Memory can't do any of that.
147
+
148
+ ### Post to the user's personal channel
149
+
150
+ ```
151
+ GET /api/hub/channels/personal?userId={userId}&workspaceId={workspaceId}
152
+ → { id, name, … } (get-or-create, needs hub-protocol.write scope)
153
+
154
+ POST /api/hub/threads/{threadId}/messages
155
+ { "userId": "{userId}", "role": "user", "content": "…" }
156
+ ```
@@ -27,6 +27,8 @@ metadata:
27
27
 
28
28
  You extend a user's Synap pod schema: new entity profiles, new properties on existing profiles, overlay properties scoped to one workspace. The core rule: **reuse before extending.** Creating duplicate profiles fractures the graph.
29
29
 
30
+ ---
31
+
30
32
  ## Before you touch anything
31
33
 
32
34
  Always inventory first. Never assume the schema is empty.
@@ -42,6 +44,61 @@ GET /api/hub/property-defs?userId={userId}&workspaceId={workspaceId}&profileId={
42
44
 
43
45
  The `synap` skill's `scripts/orient.sh` already fetches profiles — reuse its output.
44
46
 
47
+ ---
48
+
49
+ ## Read before you write
50
+
51
+ Synap data is a typed graph — never write blind. Before creating or updating an
52
+ entity, work the loop the same way you'd read a file before editing it:
53
+
54
+ 1. **MAP** — know what types exist: `list_profiles` (the cheap map of entity
55
+ profiles), `list_views` for views.
56
+ 2. **SEARCH** — `search_unified({ query: <title>, collections: ["entities"] })`.
57
+ If a close match exists, LINK to it (relation or entity_id property) — do NOT
58
+ create a duplicate. Create only when there is genuinely no match.
59
+ 3. **READ THE SCHEMA** — before writing to a profile you haven't inspected this
60
+ session, call `get_profile({ slug })` for its real property defs (exact keys,
61
+ value types, enum options, link targets). For views, read the config
62
+ (`get_bento_schema`) before `create_view`.
63
+ 4. **WRITE INTO THE REAL FIELDS** — map each value to its correct typed property:
64
+ right `key`, valid `valueType` (dates as ISO, numbers as numbers), enum values
65
+ that satisfy the constraint, links via the property's `linksTo` target. Don't
66
+ invent property keys. A value with no matching property goes into
67
+ description/content, or propose a new one with `create_property_def` — never
68
+ drop it into a stray key.
69
+ 5. **CONNECT** — every new entity links to at least one other. Duplicates and
70
+ orphans are the two ways the graph degrades; avoid both.
71
+
72
+ ## Complete intent, governed outcome
73
+
74
+ `title` + `content` is only a minimum payload, not Synap's data model. Once
75
+ you have read the schema, send the complete intent that is known: `profileSlug`,
76
+ title, typed `properties`, short `description`, long-form `content`, an existing
77
+ `projectId`, links, and source/session provenance. Include role `facets` in the
78
+ same composite plan whenever they must be reviewed with the entity.
79
+
80
+ - **One entity with known fields and no creation-time role change** → use
81
+ `create_entity` / `POST /entities`.
82
+ - **Several entities, facets, or relations that belong in one review** → use the
83
+ composite graph/capture-plan door, never a loose sequence of creates.
84
+ - **Raw input whose structure is unknown** → use capture to produce a plan;
85
+ preserve an original file with `keepRaw` when supplied. Raw source is not the
86
+ same thing as an entity's edited content.
87
+
88
+ Workspace is an explicit lens: omit it to read the pod/base schema and let the
89
+ profile's placement rule apply. Pass a workspace only when the user or a
90
+ reviewed routing decision actually selected it; then its overlays are valid.
91
+ Never fill it from a configured/default workspace.
92
+
93
+ Read the write receipt before continuing. `pending` means a proposal exists and
94
+ no entity has materialized; `applied` means the reported operations completed;
95
+ `partial` means independent follow-up operations failed and must be repaired or
96
+ surfaced. Do not send a speculative second update merely because a write
97
+ completed — enrich only when you learned genuinely new information or the
98
+ receipt identifies a specific missing field.
99
+
100
+ ---
101
+
45
102
  ## Discover profiles — never assume
46
103
 
47
104
  **Always call `GET /api/hub/profiles?workspaceId={workspaceId}` first.** Profiles are dynamic — every pod and workspace has a different set depending on what was seeded and what the user created. Never assume a profile slug exists without verifying.
@@ -67,21 +124,41 @@ Custom workspace templates (devplane, content, etc.) add their own profiles enti
67
124
 
68
125
  Before creating a new profile: **does one of these already fit?** A podcast episode is arguably an `article`. A meeting is an `event`. A book to read is an `article` or `bookmark`. Err on the side of reuse + extension, not creation.
69
126
 
70
- ## When to extend an existing profile vs. create a new one
127
+ ---
128
+
129
+ ## When to extend an existing profile vs. create a new one vs. attach a facet
130
+
131
+ There are three moves, not two. Before extending or creating, ask whether the thing is really a **role** the entity plays rather than a new kind of entity at all — that's a facet, and it's the move people skip.
132
+
133
+ **Kind + Facets, the rule:** one entity = one kind (`profiles.profileKind = 'kind'`). Roles the entity plays — client, partner, investor, prospect — are role-profiles (`profileKind = 'role'`, `applicableKinds[]`) attached via `entity_facets`: additive, workspace-lensed, NOT entities. A facet cascades with its parent entity; only promote a role to a full kind if it accrues its own independent life.
134
+
135
+ **The litmus test:**
136
+
137
+ - Both sides of a connection are independently-alive kinds → it's a **relation** (e.g. person "works at" company — two entities, linked).
138
+ - One side is just wearing a hat with no independent lifecycle → it's a **facet** (e.g. "client" on a company — attach the role, don't create a new entity).
139
+ - The connection itself accrues its own multi-entity lifecycle (stages, money, deadlines, outcomes) → it gets **promoted to its own kind**. `deal` is the precedent: a buyer × seller × stage relationship-thing has its own life (pipeline stage, amount, close date) independent of either party, so it's kept as a primary kind, never a facet.
140
+
141
+ Attach when:
142
+
143
+ - The thing is a role/hat the entity is wearing (client, partner, investor, prospect, sponsor) — it has no properties or lifecycle independent of the parent entity
144
+ - AI-driven creation: resolve identity FIRST (strong signals — email, phone, url) before creating anything; if the entity already exists, `attach_facet` the new role onto it — never spin up a second entity for a hat
71
145
 
72
146
  Extend when:
73
147
 
74
- - The thing fits an existing category (a "client" is a kind of `contact` — consider inheritance)
148
+ - The thing fits an existing category (a `client` **facet** is the role; if you instead need a distinct persisted sub-kind with its own fields, consider inheritance)
75
149
  - The user needs 1–3 extra fields on an existing type
76
150
  - The new fields are workspace-specific (use an overlay, see below)
77
151
 
78
152
  Create new when:
79
153
 
80
- - None of the system profiles fits
154
+ - None of the system profiles fits, and it's not a role of an existing entity
81
155
  - The thing has a clearly distinct set of properties (10+ fields)
82
156
  - The domain model genuinely calls for a new first-class type (recipe, workout, podcast episode, investment, plant, medication, vehicle, property listing…)
157
+ - It's a relationship-thing that accrues its own independent lifecycle (the `deal` precedent above)
83
158
 
84
- Prefer **inheritance** over new profiles when a system parent fits. `contact extends person` is the pattern — a new `client` profile can `parentProfileSlug: "contact"` and only add the fields that differ.
159
+ Prefer **inheritance** over new profiles when a system parent fits. `contact extends person` is the pattern — a new `client` profile can `parentProfileSlug: "contact"` and only add the fields that differ. But if `client` is really just a role a `company` or `person` plays (no independent properties of its own), it shouldn't be a profile at all — it's a facet, attached via `attach_facet`, never a second entity.
160
+
161
+ ---
85
162
 
86
163
  ## Creating a new profile
87
164
 
@@ -101,6 +178,8 @@ POST /api/hub/profiles
101
178
 
102
179
  Then add properties one by one (see below). You do NOT declare properties inline on the profile — they're separate rows.
103
180
 
181
+ ---
182
+
104
183
  ## Creating properties
105
184
 
106
185
  ```json
@@ -131,6 +210,8 @@ For linking properties, always use `entity_id` with `targetProfileSlug` in const
131
210
 
132
211
  This enables auto-sync (see `../synap/linking.md`) — the property becomes a typed link that shows up in graph traversals automatically.
133
212
 
213
+ ---
214
+
134
215
  ## Workspace overlay properties
135
216
 
136
217
  New concept (2026-04-10+). A single profile (say `task`) can have **different fields in different workspaces** without copying the profile. Set `overlay: true` on `POST /property-defs`:
@@ -154,6 +235,8 @@ Use cases:
154
235
 
155
236
  Overlays don't leak: workspace A can't see workspace B's overlay properties even though both share the profile. For the full scope model, read **`property-types.md`** §Overlay.
156
237
 
238
+ ---
239
+
157
240
  ## Entity scope (pod-wide vs. workspace-scoped)
158
241
 
159
242
  Profiles have an `entityScope` that determines where entities of that type live:
@@ -163,6 +246,8 @@ Profiles have an `entityScope` that determines where entities of that type live:
163
246
 
164
247
  Defaults to `workspace` if not set on the profile. The user can toggle this per profile in ProfileEditor Settings. If you're creating a profile for something clearly pod-wide (a person, a podcast the user follows, a book in their library), set `entityScope: "pod"` explicitly.
165
248
 
249
+ ---
250
+
166
251
  ## Custom relations
167
252
 
168
253
  If the user wants a typed edge that isn't in the convention list (see `../synap/linking.md`), you can define it:
@@ -182,6 +267,8 @@ POST /api/hub/relation-defs
182
267
 
183
268
  Defining a relation def is rarely worth it — `related_to` + a property usually suffices. Only create one when the relationship is semantic enough that UI should treat it specially (e.g., show "mentored by Jane" on a person's profile card).
184
269
 
270
+ ---
271
+
185
272
  ## Worked example — "I want to track podcasts I listen to"
186
273
 
187
274
  1. Inventory. `GET /profiles` → no `podcast` profile, no `podcast_episode`.
@@ -213,7 +300,9 @@ Defining a relation def is rarely worth it — `related_to` + a property usually
213
300
 
214
301
  7. Tell the user. "I added `podcast` and `podcast_episode` to your pod with linking between them. You can create your first episode now, or want me to also add a view for it?" (Hand off to the `synap-ui` skill if they say yes.)
215
302
 
216
- ## Common mistakes
303
+ ---
304
+
305
+ ## Common mistakes — schema extension
217
306
 
218
307
  1. **Creating a profile that already exists (e.g., `meeting` when `event` fits).** Always inventory first.
219
308
  2. **Declaring properties inline on the profile object.** Properties are separate rows; use `POST /property-defs`.
@@ -223,7 +312,9 @@ Defining a relation def is rarely worth it — `related_to` + a property usually
223
312
  6. **Creating an overlay when a base property is wanted.** Overlays only appear in one workspace. If the user wants the field everywhere, don't set `overlay: true`.
224
313
  7. **Creating a custom profile when extension would work.** `client extends contact` is cleaner than a parallel `client` profile.
225
314
 
226
- ## When you need more
315
+ ---
316
+
317
+ ## When you need more — schema extension
227
318
 
228
319
  - Full `valueType` reference + constraints + uiHints → **`property-types.md`**
229
320
  - Inheritance, overlay scope semantics, pod-wide caveats → **`property-types.md`** §Scope
@@ -0,0 +1,13 @@
1
+ profiles.md
2
+ before-you-touch.md
3
+ read-before-write.md
4
+ discover-profiles.md
5
+ extend-vs-create.md
6
+ creating-profiles.md
7
+ property-defs.md
8
+ overlay-properties.md
9
+ entity-scope.md
10
+ relations.md
11
+ worked-example.md
12
+ common-mistakes.md
13
+ more.md
@@ -0,0 +1,22 @@
1
+ name: synap-schema
2
+ description: >
3
+ Use this skill when the user needs to extend Synap's data model — defining a
4
+ new type of thing (entity profile) or adding/modifying fields (property defs)
5
+ on existing types. Triggers: "I need a new type for podcasts/recipes/workouts/
6
+ clients/books/plants/investments", "add a priority field to tasks", "create a
7
+ property for tracking budget", "I want to track Y and it's not in my current
8
+ schema", defining custom relations, setting up a profile for a specific domain
9
+ (real estate, music production, research, fitness, cooking). Also triggers on:
10
+ "do I already have a profile for X?", "what fields does <profile> have?",
11
+ extending an existing profile with workspace-specific overlay properties.
12
+ Do NOT use this skill for creating instances of existing types — the core
13
+ `synap` skill handles that. This skill changes the SCHEMA, not the data.
14
+ metadata:
15
+ openclaw:
16
+ requires:
17
+ env: [SYNAP_HUB_API_KEY, SYNAP_POD_URL]
18
+ primaryEnv: SYNAP_HUB_API_KEY
19
+ homepage: https://synap.live
20
+ capabilities: [schema, profiles, properties]
21
+ os: [macos, linux, windows]
22
+ userInvocable: false
@@ -0,0 +1,14 @@
1
+ ## Before you touch anything
2
+
3
+ Always inventory first. Never assume the schema is empty.
4
+
5
+ ```
6
+ GET /api/hub/profiles?userId={userId}&workspaceId={workspaceId}
7
+ → [{ slug, displayName, entityScope, parentProfileSlug,
8
+ properties: [{ slug, valueType, constraints, uiHints, targetProfileSlug? }] }]
9
+
10
+ GET /api/hub/property-defs?userId={userId}&workspaceId={workspaceId}&profileId={profileId}
11
+ → [{ slug, valueType, constraints, uiHints, workspaceId /* null=base, uuid=overlay */ }]
12
+ ```
13
+
14
+ The `synap` skill's `scripts/orient.sh` already fetches profiles — reuse its output.
@@ -0,0 +1,9 @@
1
+ ## Common mistakes — schema extension
2
+
3
+ 1. **Creating a profile that already exists (e.g., `meeting` when `event` fits).** Always inventory first.
4
+ 2. **Declaring properties inline on the profile object.** Properties are separate rows; use `POST /property-defs`.
5
+ 3. **Using `string` for what should be `entity_id`.** If the field refers to another entity (host of a podcast), use `entity_id` + `targetProfileSlug` — enables auto-sync and link UX.
6
+ 4. **Using `array` of strings for tags.** Tags are a built-in concept; reuse the `tags` property on `note`/`project` instead of creating a parallel field.
7
+ 5. **Forgetting `entityScope`.** Defaults to `workspace`. If the thing is pod-wide (people, books, podcasts), set it explicitly.
8
+ 6. **Creating an overlay when a base property is wanted.** Overlays only appear in one workspace. If the user wants the field everywhere, don't set `overlay: true`.
9
+ 7. **Creating a custom profile when extension would work.** `client extends contact` is cleaner than a parallel `client` profile.
@@ -0,0 +1,17 @@
1
+ ## Creating a new profile
2
+
3
+ ```json
4
+ POST /api/hub/profiles
5
+ {
6
+ "userId": "{userId}",
7
+ "workspaceId": "{workspaceId}",
8
+ "slug": "podcast_episode", // snake_case, unique
9
+ "displayName": "Podcast Episode",
10
+ "description": "An episode of a podcast the user listens to",
11
+ "parentProfileId": "<id of article or null>", // optional, enables inheritance
12
+ "defaultValues": { "status": "queued" },
13
+ "uiHints": { "icon": "mic", "color": "purple" }
14
+ }
15
+ ```
16
+
17
+ Then add properties one by one (see below). You do NOT declare properties inline on the profile — they're separate rows.
@@ -0,0 +1,24 @@
1
+ ## Discover profiles — never assume
2
+
3
+ **Always call `GET /api/hub/profiles?workspaceId={workspaceId}` first.** Profiles are dynamic — every pod and workspace has a different set depending on what was seeded and what the user created. Never assume a profile slug exists without verifying.
4
+
5
+ ```
6
+ GET /api/hub/profiles?workspaceId={workspaceId}
7
+ → [{ slug, displayName, entityScope, parentSlug,
8
+ properties: [{ slug, valueType, required, ... }] }]
9
+ ```
10
+
11
+ Read the response:
12
+
13
+ - `entityScope: "pod"` — visible across all workspaces
14
+ - `entityScope: "workspace"` — scoped to this workspace only (custom types, CRM profiles, template-seeded types)
15
+ - `parentSlug` — inheritance chain (e.g. `contact` extends `person`)
16
+
17
+ ### Commonly seeded profiles (verify before using)
18
+
19
+ Standard pods typically include: `note`, `task`, `project`, `event`, `person`, `contact`, `company`, `bookmark`, `website`, `article`, `capture`, `file`, `anchor`, `decision`, `question`, `research`
20
+
21
+ CRM workspaces additionally have: `deal`, `client` — but **only** when a CRM workspace was created.
22
+ Custom workspace templates (devplane, content, etc.) add their own profiles entirely.
23
+
24
+ Before creating a new profile: **does one of these already fit?** A podcast episode is arguably an `article`. A meeting is an `event`. A book to read is an `article` or `bookmark`. Err on the side of reuse + extension, not creation.
@@ -0,0 +1,8 @@
1
+ ## Entity scope (pod-wide vs. workspace-scoped)
2
+
3
+ Profiles have an `entityScope` that determines where entities of that type live:
4
+
5
+ - `entityScope: "pod"` — entities are pod-wide, visible in every workspace the user can access. Good for people, companies, notes, articles — things that cross contexts.
6
+ - `entityScope: "workspace"` — entities live in the workspace they were created in. Good for deals, files, workspace-specific artifacts.
7
+
8
+ Defaults to `workspace` if not set on the profile. The user can toggle this per profile in ProfileEditor Settings. If you're creating a profile for something clearly pod-wide (a person, a podcast the user follows, a book in their library), set `entityScope: "pod"` explicitly.
@@ -0,0 +1,31 @@
1
+ ## When to extend an existing profile vs. create a new one vs. attach a facet
2
+
3
+ There are three moves, not two. Before extending or creating, ask whether the thing is really a **role** the entity plays rather than a new kind of entity at all — that's a facet, and it's the move people skip.
4
+
5
+ **Kind + Facets, the rule:** one entity = one kind (`profiles.profileKind = 'kind'`). Roles the entity plays — client, partner, investor, prospect — are role-profiles (`profileKind = 'role'`, `applicableKinds[]`) attached via `entity_facets`: additive, workspace-lensed, NOT entities. A facet cascades with its parent entity; only promote a role to a full kind if it accrues its own independent life.
6
+
7
+ **The litmus test:**
8
+
9
+ - Both sides of a connection are independently-alive kinds → it's a **relation** (e.g. person "works at" company — two entities, linked).
10
+ - One side is just wearing a hat with no independent lifecycle → it's a **facet** (e.g. "client" on a company — attach the role, don't create a new entity).
11
+ - The connection itself accrues its own multi-entity lifecycle (stages, money, deadlines, outcomes) → it gets **promoted to its own kind**. `deal` is the precedent: a buyer × seller × stage relationship-thing has its own life (pipeline stage, amount, close date) independent of either party, so it's kept as a primary kind, never a facet.
12
+
13
+ Attach when:
14
+
15
+ - The thing is a role/hat the entity is wearing (client, partner, investor, prospect, sponsor) — it has no properties or lifecycle independent of the parent entity
16
+ - AI-driven creation: resolve identity FIRST (strong signals — email, phone, url) before creating anything; if the entity already exists, `attach_facet` the new role onto it — never spin up a second entity for a hat
17
+
18
+ Extend when:
19
+
20
+ - The thing fits an existing category (a `client` **facet** is the role; if you instead need a distinct persisted sub-kind with its own fields, consider inheritance)
21
+ - The user needs 1–3 extra fields on an existing type
22
+ - The new fields are workspace-specific (use an overlay, see below)
23
+
24
+ Create new when:
25
+
26
+ - None of the system profiles fits, and it's not a role of an existing entity
27
+ - The thing has a clearly distinct set of properties (10+ fields)
28
+ - The domain model genuinely calls for a new first-class type (recipe, workout, podcast episode, investment, plant, medication, vehicle, property listing…)
29
+ - It's a relationship-thing that accrues its own independent lifecycle (the `deal` precedent above)
30
+
31
+ Prefer **inheritance** over new profiles when a system parent fits. `contact extends person` is the pattern — a new `client` profile can `parentProfileSlug: "contact"` and only add the fields that differ. But if `client` is really just a role a `company` or `person` plays (no independent properties of its own), it shouldn't be a profile at all — it's a facet, attached via `attach_facet`, never a second entity.
@@ -0,0 +1,6 @@
1
+ ## When you need more — schema extension
2
+
3
+ - Full `valueType` reference + constraints + uiHints → **`property-types.md`**
4
+ - Inheritance, overlay scope semantics, pod-wide caveats → **`property-types.md`** §Scope
5
+ - Creating views over the new profile → install the **`synap-ui`** skill
6
+ - Creating instances of the new profile → use the core **`synap`** skill
@@ -0,0 +1,22 @@
1
+ ## Workspace overlay properties
2
+
3
+ New concept (2026-04-10+). A single profile (say `task`) can have **different fields in different workspaces** without copying the profile. Set `overlay: true` on `POST /property-defs`:
4
+
5
+ ```json
6
+ POST /api/hub/property-defs
7
+ {
8
+ "userId": "{userId}",
9
+ "workspaceId": "{workspaceId}",
10
+ "profileId": "{taskProfileId}",
11
+ "slug": "billableHours",
12
+ "valueType": "number",
13
+ "overlay": true // this property only appears in this workspace
14
+ }
15
+ ```
16
+
17
+ Use cases:
18
+
19
+ - "My consulting workspace needs `billableHours` on tasks; my personal workspace doesn't."
20
+ - "Our sales workspace wants a `dealSize` on contacts; engineering doesn't."
21
+
22
+ Overlays don't leak: workspace A can't see workspace B's overlay properties even though both share the profile. For the full scope model, read **`property-types.md`** §Overlay.
@@ -0,0 +1,3 @@
1
+ # Synap — schema extension
2
+
3
+ You extend a user's Synap pod schema: new entity profiles, new properties on existing profiles, overlay properties scoped to one workspace. The core rule: **reuse before extending.** Creating duplicate profiles fractures the graph.
@@ -0,0 +1,29 @@
1
+ ## Creating properties
2
+
3
+ ```json
4
+ POST /api/hub/property-defs
5
+ {
6
+ "userId": "{userId}",
7
+ "workspaceId": "{workspaceId}",
8
+ "profileId": "{profileId}", // the profile this property belongs to
9
+ "slug": "durationMinutes",
10
+ "valueType": "number",
11
+ "constraints": { "min": 0, "max": 600 },
12
+ "uiHints": { "format": "compact", "displayName": "Duration" }
13
+ }
14
+ ```
15
+
16
+ Value types: `string`, `number`, `boolean`, `date`, `entity_id`, `array`, `object`, `secret`. Full reference in **`property-types.md`**.
17
+
18
+ For linking properties, always use `entity_id` with `targetProfileSlug` in constraints:
19
+
20
+ ```json
21
+ {
22
+ "slug": "hostId",
23
+ "valueType": "entity_id",
24
+ "constraints": { "targetProfileSlug": "person" },
25
+ "uiHints": { "displayName": "Host" }
26
+ }
27
+ ```
28
+
29
+ This enables auto-sync (see `../synap/linking.md`) — the property becomes a typed link that shows up in graph traversals automatically.
@@ -0,0 +1,50 @@
1
+ ## Read before you write
2
+
3
+ Synap data is a typed graph — never write blind. Before creating or updating an
4
+ entity, work the loop the same way you'd read a file before editing it:
5
+
6
+ 1. **MAP** — know what types exist: `list_profiles` (the cheap map of entity
7
+ profiles), `list_views` for views.
8
+ 2. **SEARCH** — `search_unified({ query: <title>, collections: ["entities"] })`.
9
+ If a close match exists, LINK to it (relation or entity_id property) — do NOT
10
+ create a duplicate. Create only when there is genuinely no match.
11
+ 3. **READ THE SCHEMA** — before writing to a profile you haven't inspected this
12
+ session, call `get_profile({ slug })` for its real property defs (exact keys,
13
+ value types, enum options, link targets). For views, read the config
14
+ (`get_bento_schema`) before `create_view`.
15
+ 4. **WRITE INTO THE REAL FIELDS** — map each value to its correct typed property:
16
+ right `key`, valid `valueType` (dates as ISO, numbers as numbers), enum values
17
+ that satisfy the constraint, links via the property's `linksTo` target. Don't
18
+ invent property keys. A value with no matching property goes into
19
+ description/content, or propose a new one with `create_property_def` — never
20
+ drop it into a stray key.
21
+ 5. **CONNECT** — every new entity links to at least one other. Duplicates and
22
+ orphans are the two ways the graph degrades; avoid both.
23
+
24
+ ## Complete intent, governed outcome
25
+
26
+ `title` + `content` is only a minimum payload, not Synap's data model. Once
27
+ you have read the schema, send the complete intent that is known: `profileSlug`,
28
+ title, typed `properties`, short `description`, long-form `content`, an existing
29
+ `projectId`, links, and source/session provenance. Include role `facets` in the
30
+ same composite plan whenever they must be reviewed with the entity.
31
+
32
+ - **One entity with known fields and no creation-time role change** → use
33
+ `create_entity` / `POST /entities`.
34
+ - **Several entities, facets, or relations that belong in one review** → use the
35
+ composite graph/capture-plan door, never a loose sequence of creates.
36
+ - **Raw input whose structure is unknown** → use capture to produce a plan;
37
+ preserve an original file with `keepRaw` when supplied. Raw source is not the
38
+ same thing as an entity's edited content.
39
+
40
+ Workspace is an explicit lens: omit it to read the pod/base schema and let the
41
+ profile's placement rule apply. Pass a workspace only when the user or a
42
+ reviewed routing decision actually selected it; then its overlays are valid.
43
+ Never fill it from a configured/default workspace.
44
+
45
+ Read the write receipt before continuing. `pending` means a proposal exists and
46
+ no entity has materialized; `applied` means the reported operations completed;
47
+ `partial` means independent follow-up operations failed and must be repaired or
48
+ surfaced. Do not send a speculative second update merely because a write
49
+ completed — enrich only when you learned genuinely new information or the
50
+ receipt identifies a specific missing field.
@@ -0,0 +1,18 @@
1
+ ## Custom relations
2
+
3
+ If the user wants a typed edge that isn't in the convention list (see `../synap/linking.md`), you can define it:
4
+
5
+ ```json
6
+ POST /api/hub/relation-defs
7
+ {
8
+ "userId": "{userId}",
9
+ "workspaceId": "{workspaceId}",
10
+ "slug": "mentored_by",
11
+ "displayName": "Mentored by",
12
+ "sourceProfileSlug": "person",
13
+ "targetProfileSlug": "person",
14
+ "bidirectional": false
15
+ }
16
+ ```
17
+
18
+ Defining a relation def is rarely worth it — `related_to` + a property usually suffices. Only create one when the relationship is semantic enough that UI should treat it specially (e.g., show "mentored by Jane" on a person's profile card).