@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.
- package/dist/commands/agent-chat.d.ts +47 -0
- package/dist/commands/agent-chat.js +250 -0
- package/dist/commands/agent-chat.js.map +1 -0
- package/dist/commands/agent-run.js +3 -4
- package/dist/commands/agent-run.js.map +1 -1
- package/dist/commands/agents.js +85 -46
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/automation.js +2 -1
- package/dist/commands/automation.js.map +1 -1
- package/dist/commands/bridge-setup.d.ts +66 -0
- package/dist/commands/bridge-setup.js +1112 -0
- package/dist/commands/bridge-setup.js.map +1 -0
- package/dist/commands/cap-connections.d.ts +28 -0
- package/dist/commands/cap-connections.js +224 -0
- package/dist/commands/cap-connections.js.map +1 -0
- package/dist/commands/capability.d.ts +89 -0
- package/dist/commands/capability.js +1523 -0
- package/dist/commands/capability.js.map +1 -0
- package/dist/commands/centrality.d.ts +20 -0
- package/dist/commands/centrality.js +94 -0
- package/dist/commands/centrality.js.map +1 -0
- package/dist/commands/connect.d.ts +2 -0
- package/dist/commands/connect.js +16 -35
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/context.js +4 -6
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/data-extra.d.ts +1 -0
- package/dist/commands/data-extra.js +34 -10
- package/dist/commands/data-extra.js.map +1 -1
- package/dist/commands/data.d.ts +4 -4
- package/dist/commands/data.js +241 -184
- package/dist/commands/data.js.map +1 -1
- package/dist/commands/diagnose.d.ts +20 -0
- package/dist/commands/diagnose.js +143 -0
- package/dist/commands/diagnose.js.map +1 -0
- package/dist/commands/digest.d.ts +17 -0
- package/dist/commands/digest.js +121 -0
- package/dist/commands/digest.js.map +1 -0
- package/dist/commands/discover.d.ts +2 -0
- package/dist/commands/discover.js +25 -8
- package/dist/commands/discover.js.map +1 -1
- package/dist/commands/events.js +2 -1
- package/dist/commands/events.js.map +1 -1
- package/dist/commands/explain.d.ts +1 -1
- package/dist/commands/explain.js +18 -15
- package/dist/commands/explain.js.map +1 -1
- package/dist/commands/facet.d.ts +29 -0
- package/dist/commands/facet.js +113 -0
- package/dist/commands/facet.js.map +1 -0
- package/dist/commands/graph.js +2 -1
- package/dist/commands/graph.js.map +1 -1
- package/dist/commands/import.d.ts +38 -0
- package/dist/commands/import.js +440 -0
- package/dist/commands/import.js.map +1 -0
- package/dist/commands/init.js +35 -16
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/keys.js +3 -4
- package/dist/commands/keys.js.map +1 -1
- package/dist/commands/knowledge.d.ts +2 -0
- package/dist/commands/knowledge.js +61 -9
- package/dist/commands/knowledge.js.map +1 -1
- package/dist/commands/launch.d.ts +50 -0
- package/dist/commands/launch.js +790 -0
- package/dist/commands/launch.js.map +1 -0
- package/dist/commands/lens.d.ts +45 -0
- package/dist/commands/lens.js +386 -0
- package/dist/commands/lens.js.map +1 -0
- package/dist/commands/market.d.ts +209 -0
- package/dist/commands/market.js +1368 -0
- package/dist/commands/market.js.map +1 -0
- package/dist/commands/mcp.d.ts +42 -0
- package/dist/commands/mcp.js +184 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/observe.js +14 -11
- package/dist/commands/observe.js.map +1 -1
- package/dist/commands/open.d.ts +21 -4
- package/dist/commands/open.js +45 -4
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/pod.d.ts +100 -0
- package/dist/commands/pod.js +359 -0
- package/dist/commands/pod.js.map +1 -0
- package/dist/commands/pods.d.ts +1 -0
- package/dist/commands/pods.js +77 -15
- package/dist/commands/pods.js.map +1 -1
- package/dist/commands/proposals-actions.js +40 -3
- package/dist/commands/proposals-actions.js.map +1 -1
- package/dist/commands/purge.d.ts +23 -0
- package/dist/commands/purge.js +148 -0
- package/dist/commands/purge.js.map +1 -0
- package/dist/commands/raycast.d.ts +15 -0
- package/dist/commands/raycast.js +153 -0
- package/dist/commands/raycast.js.map +1 -0
- package/dist/commands/sessions.js +45 -21
- package/dist/commands/sessions.js.map +1 -1
- package/dist/commands/skill-manage.d.ts +21 -0
- package/dist/commands/skill-manage.js +195 -0
- package/dist/commands/skill-manage.js.map +1 -0
- package/dist/commands/skills-commands.js +2 -1
- package/dist/commands/skills-commands.js.map +1 -1
- package/dist/commands/skills.js +4 -3
- package/dist/commands/skills.js.map +1 -1
- package/dist/commands/status.d.ts +3 -1
- package/dist/commands/status.js +166 -14
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/statusline.d.ts +24 -0
- package/dist/commands/statusline.js +450 -0
- package/dist/commands/statusline.js.map +1 -0
- package/dist/commands/subscribe.js +2 -2
- package/dist/commands/subscribe.js.map +1 -1
- package/dist/commands/tools.d.ts +30 -0
- package/dist/commands/tools.js +315 -0
- package/dist/commands/tools.js.map +1 -0
- package/dist/commands/versions.d.ts +27 -0
- package/dist/commands/versions.js +277 -0
- package/dist/commands/versions.js.map +1 -0
- package/dist/commands/view.js +3 -2
- package/dist/commands/view.js.map +1 -1
- package/dist/commands/whoami.d.ts +21 -0
- package/dist/commands/whoami.js +129 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/index.js +776 -60
- package/dist/index.js.map +1 -1
- package/dist/lib/approval-poll.d.ts +42 -0
- package/dist/lib/approval-poll.js +52 -0
- package/dist/lib/approval-poll.js.map +1 -0
- package/dist/lib/auth.d.ts +29 -6
- package/dist/lib/auth.js +105 -94
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/bundle-version.d.ts +11 -0
- package/dist/lib/bundle-version.js +33 -0
- package/dist/lib/bundle-version.js.map +1 -0
- package/dist/lib/capture-lane.d.ts +30 -12
- package/dist/lib/capture-lane.js +71 -14
- package/dist/lib/capture-lane.js.map +1 -1
- package/dist/lib/cp-packages.d.ts +121 -0
- package/dist/lib/cp-packages.js +218 -0
- package/dist/lib/cp-packages.js.map +1 -0
- package/dist/lib/describe-lens.d.ts +46 -0
- package/dist/lib/describe-lens.js +33 -0
- package/dist/lib/describe-lens.js.map +1 -0
- package/dist/lib/hub-client.d.ts +78 -1
- package/dist/lib/hub-client.js +474 -22
- package/dist/lib/hub-client.js.map +1 -1
- package/dist/lib/installed.d.ts +51 -0
- package/dist/lib/installed.js +70 -0
- package/dist/lib/installed.js.map +1 -0
- package/dist/lib/next-steps.d.ts +61 -0
- package/dist/lib/next-steps.js +146 -0
- package/dist/lib/next-steps.js.map +1 -0
- package/dist/lib/pod.d.ts +91 -19
- package/dist/lib/pod.js +222 -56
- package/dist/lib/pod.js.map +1 -1
- package/dist/lib/project-ref.d.ts +95 -0
- package/dist/lib/project-ref.js +144 -0
- package/dist/lib/project-ref.js.map +1 -0
- package/dist/lib/project.d.ts +35 -0
- package/dist/lib/project.js +39 -0
- package/dist/lib/project.js.map +1 -0
- package/dist/lib/session-lens.d.ts +33 -0
- package/dist/lib/session-lens.js +76 -0
- package/dist/lib/session-lens.js.map +1 -0
- package/dist/lib/skill-import.d.ts +40 -0
- package/dist/lib/skill-import.js +203 -0
- package/dist/lib/skill-import.js.map +1 -0
- package/dist/lib/skills-installer.d.ts +17 -6
- package/dist/lib/skills-installer.js +133 -19
- package/dist/lib/skills-installer.js.map +1 -1
- package/dist/lib/suite.d.ts +28 -0
- package/dist/lib/suite.js +29 -0
- package/dist/lib/suite.js.map +1 -0
- package/dist/lib/superwhisper-import.d.ts +40 -0
- package/dist/lib/superwhisper-import.js +389 -0
- package/dist/lib/superwhisper-import.js.map +1 -0
- package/dist/lib/targets.d.ts +49 -1
- package/dist/lib/targets.js +420 -288
- package/dist/lib/targets.js.map +1 -1
- package/dist/lib/unwrapList.d.ts +1 -0
- package/dist/lib/unwrapList.js +20 -0
- package/dist/lib/unwrapList.js.map +1 -0
- package/dist/utils/logger.d.ts +2 -0
- package/dist/utils/logger.js +10 -2
- package/dist/utils/logger.js.map +1 -1
- package/package.json +9 -4
- package/skills/agent-os/SKILL.md +212 -0
- package/skills/manifest.json +5 -0
- package/skills/onboard/SKILL.md +186 -0
- package/skills/synap/SKILL.md +1182 -37
- package/skills/synap/_order.txt +37 -0
- package/skills/synap/_skill.yaml +24 -0
- package/skills/synap/authentication.md +10 -0
- package/skills/synap/automations.md +264 -0
- package/skills/synap/capabilities.md +107 -0
- package/skills/synap/capture.md +10 -0
- package/skills/synap/cli-operations.md +107 -0
- package/skills/synap/common-mistakes.md +12 -0
- package/skills/synap/creative-loop.md +43 -0
- package/skills/synap/crm.md +117 -0
- package/skills/synap/diagnostics.md +35 -0
- package/skills/synap/digesting-a-channel.md +38 -0
- package/skills/synap/document-embeds.md +123 -0
- package/skills/synap/escalation-ladder.md +71 -0
- package/skills/synap/focus-sessions.md +47 -0
- package/skills/synap/governance-rules.md +64 -0
- package/skills/synap/governance.md +6 -6
- package/skills/synap/graph-gardening.md +21 -0
- package/skills/synap/inline-patterns.md +38 -0
- package/skills/synap/lenses.md +38 -0
- package/skills/synap/linking-principle.md +39 -0
- package/skills/synap/linking.md +1 -0
- package/skills/synap/mental-model.md +45 -0
- package/skills/synap/more.md +7 -0
- package/skills/synap/multi-entity-capture.md +10 -0
- package/skills/synap/next-action.md +37 -0
- package/skills/synap/north-star.md +17 -0
- package/skills/synap/operating-mode-rules.md +45 -0
- package/skills/synap/operating-mode.md +9 -0
- package/skills/synap/quick-reference.md +67 -0
- package/skills/synap/reading.md +43 -0
- package/skills/synap/recap.md +21 -0
- package/skills/synap/reflexes.md +46 -0
- package/skills/synap/response-style.md +21 -0
- package/skills/synap/scope.md +13 -0
- package/skills/synap/showing.md +17 -0
- package/skills/synap/user-model.md +25 -0
- package/skills/synap/viewframe-cells.md +290 -0
- package/skills/synap/work-flow.md +113 -0
- package/skills/synap/worked-examples.md +53 -0
- package/skills/synap/workspace-design.md +45 -0
- package/skills/synap/workspace-edges.md +49 -0
- package/skills/synap/writes.md +156 -0
- package/skills/synap-schema/SKILL.md +97 -6
- package/skills/synap-schema/_order.txt +13 -0
- package/skills/synap-schema/_skill.yaml +22 -0
- package/skills/synap-schema/before-you-touch.md +14 -0
- package/skills/synap-schema/common-mistakes.md +9 -0
- package/skills/synap-schema/creating-profiles.md +17 -0
- package/skills/synap-schema/discover-profiles.md +24 -0
- package/skills/synap-schema/entity-scope.md +8 -0
- package/skills/synap-schema/extend-vs-create.md +31 -0
- package/skills/synap-schema/more.md +6 -0
- package/skills/synap-schema/overlay-properties.md +22 -0
- package/skills/synap-schema/profiles.md +3 -0
- package/skills/synap-schema/property-defs.md +29 -0
- package/skills/synap-schema/read-before-write.md +50 -0
- package/skills/synap-schema/relations.md +18 -0
- package/skills/synap-schema/worked-example.md +30 -0
- package/skills/synap-ui/SKILL.md +26 -2
- package/skills/synap-ui/_order.txt +13 -0
- package/skills/synap-ui/_skill.yaml +23 -0
- package/skills/synap-ui/ai-companion.md +27 -0
- package/skills/synap-ui/arranging-bento.md +8 -0
- package/skills/synap-ui/before-you-build.md +20 -0
- package/skills/synap-ui/bento-layouts.md +35 -0
- package/skills/synap-ui/common-mistakes.md +10 -0
- package/skills/synap-ui/creating-views.md +26 -0
- package/skills/synap-ui/four-builds.md +24 -0
- package/skills/synap-ui/more.md +7 -0
- package/skills/synap-ui/proposing-vs-extending.md +11 -0
- package/skills/synap-ui/view-list.md +24 -0
- package/skills/synap-ui/views.md +3 -0
- package/skills/synap-ui/worked-example.md +18 -0
- package/skills/synap-ui/workspaces.md +47 -0
- package/templates/automations/bookmark-enrichment.automation.json +44 -0
- package/templates/automations/mail-feed.automation.json +86 -0
- package/templates/automations/url-bookmark-capture.automation.json +70 -0
- package/templates/skills/README.md +21 -0
- package/templates/skills/authoring-automations/SKILL.md +95 -0
- package/templates/skills/authoring-automations/reference/node-matrix.md +49 -0
- package/templates/skills/authoring-capabilities/SKILL.md +93 -0
- package/templates/skills/authoring-capabilities/reference/template-anatomy.md +70 -0
- package/templates/skills/authoring-playbooks/SKILL.md +102 -0
- package/templates/skills/authoring-playbooks/reference/stages-contract.md +35 -0
- package/templates/skills/authoring-playbooks/reference/worked-example.md +64 -0
- package/templates/skills/bookmark-enrichment/SKILL.md +40 -0
- package/templates/skills/coordinating-agents/SKILL.md +32 -0
- package/templates/skills/coordinating-branches/SKILL.md +27 -0
- package/templates/skills/mapping-the-server/SKILL.md +54 -0
- package/templates/skills/reading-client-progress/SKILL.md +65 -0
- package/templates/skills/routing-to-channels/SKILL.md +54 -0
- package/templates/skills/stellar-scf-grants-advisor/ASSOCIATE-CHEATSHEET.md +133 -0
- package/templates/skills/stellar-scf-grants-advisor/ASSOCIATE-ONBOARDING-GUIDE.md +761 -0
- package/templates/skills/stellar-scf-grants-advisor/CLIENT-FAQ.md +181 -0
- package/templates/skills/stellar-scf-grants-advisor/PARTNER-HANDOVER.md +130 -0
- package/templates/skills/stellar-scf-grants-advisor/SKILL.md +102 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/README.md +43 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/chat-summary-templates.md +158 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/corpus-comparable-rows.md +136 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/q10-team-rewrites.md +109 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/q2-description-rewrites.md +88 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/q6-integration-rewrites.md +107 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/tranche-structures.md +176 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/01-methodology.md +96 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/02-scoring-framework.md +199 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/03-rejection-patterns.md +241 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/04-winner-patterns.md +120 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/05-comeback-patterns.md +92 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/06-budget-benchmarks.md +125 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/07-integration-list.md +147 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/08-abstract-fields.md +258 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/09-build-fields.md +259 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/10-corpus-winners.md +135 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/11-corpus-rejects.md +267 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/12-client-communication.md +131 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/13-excel-output-spec.md +199 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/14-worked-examples.md +160 -0
- package/templates/skills/stellar-scf-grants-advisor/templates/abstract-review-builder.py +253 -0
- package/templates/skills/stellar-scf-grants-advisor/templates/build-review-builder.py +213 -0
- package/dist/commands/connectors.d.ts +0 -31
- package/dist/commands/connectors.js +0 -276
- package/dist/commands/connectors.js.map +0 -1
- package/dist/commands/finish.d.ts +0 -25
- package/dist/commands/finish.js +0 -274
- package/dist/commands/finish.js.map +0 -1
- package/dist/commands/openclaw.d.ts +0 -40
- package/dist/commands/openclaw.js +0 -1148
- package/dist/commands/openclaw.js.map +0 -1
- package/dist/commands/security-audit.d.ts +0 -12
- package/dist/commands/security-audit.js +0 -100
- package/dist/commands/security-audit.js.map +0 -1
- package/dist/lib/hardening.d.ts +0 -18
- package/dist/lib/hardening.js +0 -214
- package/dist/lib/hardening.js.map +0 -1
- package/node_modules/@synap/hub-rest-client/dist/index.cjs +0 -881
- package/node_modules/@synap/hub-rest-client/dist/index.d.cts +0 -907
- package/node_modules/@synap/hub-rest-client/dist/index.d.ts +0 -907
- package/node_modules/@synap/hub-rest-client/dist/index.js +0 -851
- package/node_modules/@synap/hub-rest-client/package.json +0 -45
- package/node_modules/@synap/hub-rest-client/src/client.ts +0 -1143
- package/node_modules/@synap/hub-rest-client/src/errors.ts +0 -30
- package/node_modules/@synap/hub-rest-client/src/index.ts +0 -111
- package/node_modules/@synap/hub-rest-client/src/setup.ts +0 -77
- 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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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,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).
|