@synap-core/cli 1.7.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.d.ts +47 -0
- package/dist/commands/agent-run.js +301 -0
- package/dist/commands/agent-run.js.map +1 -0
- package/dist/commands/agents.js +85 -46
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/artifact.d.ts +26 -0
- package/dist/commands/artifact.js +76 -0
- package/dist/commands/artifact.js.map +1 -0
- package/dist/commands/automation.d.ts +47 -0
- package/dist/commands/automation.js +601 -0
- package/dist/commands/automation.js.map +1 -0
- 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/cell.d.ts +55 -0
- package/dist/commands/cell.js +277 -0
- package/dist/commands/cell.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 +25 -10
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/connections.js +0 -16
- package/dist/commands/connections.js.map +1 -1
- package/dist/commands/context.d.ts +22 -0
- package/dist/commands/context.js +149 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/data-extra.d.ts +14 -0
- package/dist/commands/data-extra.js +185 -0
- package/dist/commands/data-extra.js.map +1 -0
- package/dist/commands/data.d.ts +14 -10
- package/dist/commands/data.js +353 -192
- 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/doc.d.ts +39 -0
- package/dist/commands/doc.js +130 -0
- package/dist/commands/doc.js.map +1 -0
- package/dist/commands/events.d.ts +26 -0
- package/dist/commands/events.js +69 -0
- package/dist/commands/events.js.map +1 -0
- package/dist/commands/explain.d.ts +21 -0
- package/dist/commands/explain.js +251 -0
- package/dist/commands/explain.js.map +1 -0
- 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.d.ts +18 -0
- package/dist/commands/graph.js +74 -0
- package/dist/commands/graph.js.map +1 -0
- package/dist/commands/home.d.ts +12 -0
- package/dist/commands/home.js +54 -0
- package/dist/commands/home.js.map +1 -0
- 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.d.ts +0 -2
- package/dist/commands/init.js +97 -118
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/keys.d.ts +9 -0
- package/dist/commands/keys.js +78 -0
- package/dist/commands/keys.js.map +1 -0
- package/dist/commands/knowledge.d.ts +34 -18
- package/dist/commands/knowledge.js +355 -57
- 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.d.ts +9 -0
- package/dist/commands/observe.js +93 -0
- package/dist/commands/observe.js.map +1 -0
- package/dist/commands/open.d.ts +32 -0
- package/dist/commands/open.js +85 -0
- package/dist/commands/open.js.map +1 -0
- 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 +6 -0
- package/dist/commands/pods.js +160 -50
- package/dist/commands/pods.js.map +1 -1
- package/dist/commands/proposals-actions.d.ts +7 -0
- package/dist/commands/proposals-actions.js +77 -0
- package/dist/commands/proposals-actions.js.map +1 -0
- package/dist/commands/providers.d.ts +38 -0
- package/dist/commands/providers.js +170 -0
- package/dist/commands/providers.js.map +1 -0
- 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.d.ts +31 -0
- package/dist/commands/sessions.js +248 -0
- package/dist/commands/sessions.js.map +1 -0
- 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.d.ts +26 -0
- package/dist/commands/skills-commands.js +187 -0
- package/dist/commands/skills-commands.js.map +1 -0
- package/dist/commands/skills.d.ts +26 -0
- package/dist/commands/skills.js +196 -0
- package/dist/commands/skills.js.map +1 -0
- package/dist/commands/status.d.ts +3 -1
- package/dist/commands/status.js +231 -41
- 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.d.ts +19 -0
- package/dist/commands/subscribe.js +91 -0
- package/dist/commands/subscribe.js.map +1 -0
- 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.d.ts +57 -0
- package/dist/commands/view.js +195 -0
- package/dist/commands/view.js.map +1 -0
- 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.d.ts +3 -4
- package/dist/index.js +1524 -202
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-templates.d.ts +25 -0
- package/dist/lib/agent-templates.js +148 -0
- package/dist/lib/agent-templates.js.map +1 -0
- package/dist/lib/agents-config.d.ts +4 -1
- package/dist/lib/agents-config.js +19 -2
- package/dist/lib/agents-config.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 +67 -0
- package/dist/lib/capture-lane.js +136 -0
- package/dist/lib/capture-lane.js.map +1 -0
- 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 +84 -1
- package/dist/lib/hub-client.js +502 -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 +104 -19
- package/dist/lib/pod.js +245 -57
- 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 +16 -5
- package/dist/lib/skills-installer.js +132 -18
- 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 +66 -2
- package/dist/lib/targets.js +914 -132
- 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 +10 -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 +1524 -104
- 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 +38 -11
- 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/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/dist/lib/templates.d.ts +0 -11
- package/dist/lib/templates.js +0 -13
- package/dist/lib/templates.js.map +0 -1
- package/dist/templates/agent-os.json +0 -3090
- 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,290 @@
|
|
|
1
|
+
## ViewFrame Cells — Custom View Generation
|
|
2
|
+
|
|
3
|
+
ViewFrame is the standard way to create custom data visualizations in Synap. Use it whenever an existing cell (table, kanban, list, chart) does not cover the needed chart type, 3D layout, map, or bespoke AI-generated UI.
|
|
4
|
+
|
|
5
|
+
### When to Use ViewFrame
|
|
6
|
+
|
|
7
|
+
| Situation | Action |
|
|
8
|
+
| ---------------------------------------------------------------------- | ----------------------------- |
|
|
9
|
+
| An existing cell or view type covers the need | Use the existing cell or view |
|
|
10
|
+
| User asks for a specific chart type, map, 3D scene, or custom layout | Generate a ViewFrame widget |
|
|
11
|
+
| User says "show X as a [funnel / heatmap / treemap / scatter / globe]" | Generate a ViewFrame widget |
|
|
12
|
+
|
|
13
|
+
### What ViewFrame Is
|
|
14
|
+
|
|
15
|
+
- A sandboxed iframe that renders **one ES module** that default-exports a React component (or plain JS)
|
|
16
|
+
- Keep generated cells self-contained. The CLI can analyse bare imports into a
|
|
17
|
+
`deps` map, but the current Hub `cells/define` persistence path does not yet
|
|
18
|
+
retain that map, so external runtime dependencies are not a reliable contract.
|
|
19
|
+
- The host injects a `SynapWidget` bridge for data access and shell actions
|
|
20
|
+
- Security: `sandbox="allow-scripts allow-modals allow-popups"`, no `allow-same-origin`, no cookies, no pod token
|
|
21
|
+
|
|
22
|
+
### Authoring contract
|
|
23
|
+
|
|
24
|
+
A ViewFrame cell is **one self-contained ES module** (inline in `rendererSource`):
|
|
25
|
+
|
|
26
|
+
- The module **default-exports a React component** (or calls `SynapWidget.onInit()` for plain JS).
|
|
27
|
+
- Bare imports (`"react"`, `"recharts"`, etc.) are resolved via the esm.sh import map generated from `deps`.
|
|
28
|
+
- **No bundler, no `import` of local files** — everything is either inlined or declared in `deps`.
|
|
29
|
+
- External CSS is not supported; inline `<style>` tags or CSS-in-JS only.
|
|
30
|
+
|
|
31
|
+
### Register a Cell via the Hub Protocol (canonical path)
|
|
32
|
+
|
|
33
|
+
**Use `POST /api/hub/cells/define` — this is the canonical Hub Protocol path for AI-generated cells.**
|
|
34
|
+
|
|
35
|
+
It is idempotent (upserts on typeKey), pod-global by default (no workspaceId needed), and immediately available across all of the user's workspaces without any proposal step.
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
POST /api/hub/cells/define
|
|
39
|
+
Authorization: Bearer {SYNAP_HUB_API_KEY}
|
|
40
|
+
Content-Type: application/json
|
|
41
|
+
|
|
42
|
+
{
|
|
43
|
+
"name": "Deal Stage Funnel",
|
|
44
|
+
"rendererSource": "<!DOCTYPE html>…</html>",
|
|
45
|
+
"typeKey": "deal-stage-funnel", // optional — derived from name if omitted
|
|
46
|
+
"description": "Funnel chart of deal pipeline stages", // optional
|
|
47
|
+
"defaultSize": { "w": 8, "h": 6 }, // optional
|
|
48
|
+
"deps": { "recharts": "2.12.0" } // accepted for forward compatibility; not persisted yet
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**`deps` status:** the CLI accepts a JSON map for forward compatibility, but
|
|
53
|
+
the current server stores `{}`. Do not make a generated cell depend on an
|
|
54
|
+
external package until the persistence contract is upgraded and verified.
|
|
55
|
+
|
|
56
|
+
**`workspaceId` is intentionally omitted** — cells defined without it are pod-global (`workspaceId IS NULL`), visible in every workspace the user owns. Pass `workspaceId` only when you explicitly want a cell scoped to a single workspace.
|
|
57
|
+
|
|
58
|
+
Response: `{ "success": true, "typeKey": "generated:deal-stage-funnel" }`
|
|
59
|
+
|
|
60
|
+
The typeKey is auto-prefixed `generated:` when not explicitly provided.
|
|
61
|
+
|
|
62
|
+
**List cells (all pod-global + optionally workspace-specific):**
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
GET /api/hub/cells — pod-global only
|
|
66
|
+
GET /api/hub/cells?workspaceId={id} — pod-global + workspace-scoped
|
|
67
|
+
Authorization: Bearer {SYNAP_HUB_API_KEY}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Delete a cell:**
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
DELETE /api/hub/cells/{typeKey} — pod-global row
|
|
74
|
+
DELETE /api/hub/cells/{typeKey}?workspaceId={id} — workspace-scoped row
|
|
75
|
+
Authorization: Bearer {SYNAP_HUB_API_KEY}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Open the cell in the browser (deep link):**
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
synap://open/cell/{typeKey}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The browser receives this deep link, looks the typeKey up in the cell registry (which polls `widget_definitions` every 10s), and opens it as a side panel tab with the cell's registered `meta.name` as the tab title.
|
|
85
|
+
|
|
86
|
+
**Full AI artifact workflow:**
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
// 1. Generate the HTML/React cell
|
|
90
|
+
POST /api/hub/cells/define
|
|
91
|
+
{ "name": "Q2 Revenue Report", "rendererSource": "<!DOCTYPE html>…</html>",
|
|
92
|
+
"deps": { "recharts": "2.12.0" } }
|
|
93
|
+
// → { "success": true, "typeKey": "generated:q2-revenue-report" }
|
|
94
|
+
|
|
95
|
+
// 2. Open it in the user's browser
|
|
96
|
+
synap://open/cell/generated:q2-revenue-report
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The cell appears immediately in the side panel with "Q2 Revenue Report" as the tab title. It persists across sessions and is available from any workspace.
|
|
100
|
+
|
|
101
|
+
> **Note:** `POST /api/hub/widget-definitions` (tRPC path) still works but is the internal/admin path. Use `POST /api/hub/cells/define` for all agent-generated cells.
|
|
102
|
+
|
|
103
|
+
### CLI commands (when running as Claude Code / OpenClaw agent)
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Build a multi-file cell source into a single ES module bundle
|
|
107
|
+
synap cell build <entry> --out ./dist/my-chart.js
|
|
108
|
+
# → writes the bundle and prints the inferred deps JSON
|
|
109
|
+
|
|
110
|
+
# Push a built cell (source + deps) to the pod
|
|
111
|
+
synap cell define \
|
|
112
|
+
--name "My Chart" \
|
|
113
|
+
--file ./dist/my-chart.js \
|
|
114
|
+
--deps '{"recharts":"2.12.0"}' \
|
|
115
|
+
[--type-key my-chart] \
|
|
116
|
+
[--workspace <id>]
|
|
117
|
+
|
|
118
|
+
# Document operations
|
|
119
|
+
synap doc create --title "Q2 Report" --file ./report.md
|
|
120
|
+
synap doc update <docId> --file ./updated-report.md
|
|
121
|
+
|
|
122
|
+
# Arrange widgets on an existing bento view
|
|
123
|
+
synap view arrange <viewId> --blocks '[{"id":"b1","kind":"widget","widgetKind":"generated:my-chart","layout":{"x":0,"y":0,"w":8,"h":6}}]'
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### The SynapWidget Bridge (inside the iframe)
|
|
127
|
+
|
|
128
|
+
`window.SynapWidget` is injected automatically — do NOT import or `<script>` it.
|
|
129
|
+
|
|
130
|
+
#### Queries (read-only, always approved)
|
|
131
|
+
|
|
132
|
+
```js
|
|
133
|
+
SynapWidget.onInit(async ({ config, context }) => {
|
|
134
|
+
// context: { workspaceId, viewId?, entityId?, sdkVersion }
|
|
135
|
+
|
|
136
|
+
// List entities
|
|
137
|
+
const deals = await SynapWidget.query("entities.list", {
|
|
138
|
+
profileSlug: "deal",
|
|
139
|
+
limit: 200,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Get a single entity
|
|
143
|
+
const entity = await SynapWidget.query("entities.get", { id: "uuid" });
|
|
144
|
+
|
|
145
|
+
// List views
|
|
146
|
+
const views = await SynapWidget.query("views.list", {
|
|
147
|
+
workspaceId: context.workspaceId,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// List profiles
|
|
151
|
+
const profiles = await SynapWidget.query("profiles.list", {});
|
|
152
|
+
|
|
153
|
+
render(deals ?? []);
|
|
154
|
+
SynapWidget.resize(document.body.scrollHeight);
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
All `query()` calls return a Promise. Entity shape: `{ id, title, profileSlug, properties, createdAt, … }`.
|
|
159
|
+
|
|
160
|
+
#### Mutations (governance-gated — return `{ status: "approved" | "proposed" | "denied" }`)
|
|
161
|
+
|
|
162
|
+
```js
|
|
163
|
+
// Create an entity
|
|
164
|
+
const result = await SynapWidget.mutate("create_entity", {
|
|
165
|
+
profileSlug: "task",
|
|
166
|
+
title: "Follow up",
|
|
167
|
+
properties: { status: "todo" },
|
|
168
|
+
});
|
|
169
|
+
// result.status === "approved" → result.id is the new entity id
|
|
170
|
+
// result.status === "proposed" → result.proposalId, result.reviewUrl
|
|
171
|
+
|
|
172
|
+
// Update an entity
|
|
173
|
+
await SynapWidget.mutate("update_entity", {
|
|
174
|
+
id: "uuid",
|
|
175
|
+
properties: { status: "done" },
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// Delete an entity (always proposed for agent-generated cells)
|
|
179
|
+
await SynapWidget.mutate("delete_entity", { id: "uuid" });
|
|
180
|
+
|
|
181
|
+
// Create a relation
|
|
182
|
+
await SynapWidget.mutate("create_relation", {
|
|
183
|
+
sourceEntityId: "uuid-a",
|
|
184
|
+
targetEntityId: "uuid-b",
|
|
185
|
+
type: "related_to",
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Always check `result.status`.** `"proposed"` is not an error — surface `result.reviewUrl` to the user.
|
|
190
|
+
|
|
191
|
+
#### Shell actions
|
|
192
|
+
|
|
193
|
+
```js
|
|
194
|
+
SynapWidget.navigate({ entityId: "entity-uuid" }); // open entity detail in side panel
|
|
195
|
+
SynapWidget.openPanel("entity-detail", { entityId: "uuid" }); // explicit panel open
|
|
196
|
+
SynapWidget.toast("Saved!", "success"); // 'success' | 'error' | 'info'
|
|
197
|
+
SynapWidget.resize(document.body.scrollHeight); // resize the iframe to content height
|
|
198
|
+
SynapWidget.updateContext({ viewId: "uuid" }); // update ambient context
|
|
199
|
+
|
|
200
|
+
// Subscribe to live entity changes
|
|
201
|
+
SynapWidget.subscribe("entity:changed", ({ entityId }) => {
|
|
202
|
+
// re-fetch and re-render when any entity in the pod changes
|
|
203
|
+
});
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Common Dependency Patterns (esm.sh import map)
|
|
207
|
+
|
|
208
|
+
The `deps` map in `/cells/define` drives the import map. Each key becomes a bare specifier in the `<script type="importmap">`, resolved to `https://esm.sh/<pkg>@<version>`.
|
|
209
|
+
|
|
210
|
+
```json
|
|
211
|
+
// deps in the define call:
|
|
212
|
+
{ "recharts": "2.12.0", "d3": "7" }
|
|
213
|
+
|
|
214
|
+
// → generates this importmap inside the frame:
|
|
215
|
+
{
|
|
216
|
+
"imports": {
|
|
217
|
+
"react": "https://esm.sh/react@19",
|
|
218
|
+
"react-dom/client": "https://esm.sh/react-dom@19/client",
|
|
219
|
+
"react/jsx-runtime": "https://esm.sh/react@19/jsx-runtime",
|
|
220
|
+
"recharts": "https://esm.sh/recharts@2.12.0",
|
|
221
|
+
"d3": "https://esm.sh/d3@7"
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
React 19 core entries are always injected by the host — never put them in `deps`.
|
|
227
|
+
|
|
228
|
+
Common library choices:
|
|
229
|
+
|
|
230
|
+
| Category | Packages (put in `deps`) |
|
|
231
|
+
| -------- | -------------------------------------------------------------- |
|
|
232
|
+
| Data viz | `recharts@2.12.0`, `d3@7`, `chart.js@4`, `observable-plot@0.6` |
|
|
233
|
+
| Tables | `@tanstack/react-table@8` |
|
|
234
|
+
| 3D | `three@0.165.0`, `@react-three/fiber@8`, `@react-three/drei@9` |
|
|
235
|
+
| Maps | `leaflet@1.9.4`, `react-leaflet@4` |
|
|
236
|
+
|
|
237
|
+
### Minimal Widget Template
|
|
238
|
+
|
|
239
|
+
```html
|
|
240
|
+
<!DOCTYPE html>
|
|
241
|
+
<html>
|
|
242
|
+
<head>
|
|
243
|
+
<meta charset="utf-8" />
|
|
244
|
+
<style>
|
|
245
|
+
* {
|
|
246
|
+
box-sizing: border-box;
|
|
247
|
+
margin: 0;
|
|
248
|
+
}
|
|
249
|
+
body {
|
|
250
|
+
font-family: -apple-system, sans-serif;
|
|
251
|
+
padding: 16px;
|
|
252
|
+
background: transparent;
|
|
253
|
+
}
|
|
254
|
+
</style>
|
|
255
|
+
<!-- importmap is injected by the host from deps — do not write one manually -->
|
|
256
|
+
</head>
|
|
257
|
+
<body>
|
|
258
|
+
<div id="root"></div>
|
|
259
|
+
<script type="module">
|
|
260
|
+
import { createRoot } from "react-dom/client";
|
|
261
|
+
import { createElement as h, useState } from "react";
|
|
262
|
+
|
|
263
|
+
SynapWidget.onInit(async ({ context }) => {
|
|
264
|
+
const items = await SynapWidget.query("entities.list", {
|
|
265
|
+
profileSlug: "deal",
|
|
266
|
+
limit: 200,
|
|
267
|
+
}).catch(() => []);
|
|
268
|
+
|
|
269
|
+
createRoot(document.getElementById("root")).render(
|
|
270
|
+
h("p", null, `Loaded ${(items ?? []).length} deals`)
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
SynapWidget.resize(document.body.scrollHeight);
|
|
274
|
+
});
|
|
275
|
+
</script>
|
|
276
|
+
</body>
|
|
277
|
+
</html>
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Rules
|
|
281
|
+
|
|
282
|
+
- **Always call `SynapWidget.onInit()`** — the host will not send data until you register this handler.
|
|
283
|
+
- **Call `SynapWidget.resize()`** after rendering to prevent clipping.
|
|
284
|
+
- **Handle errors** — `query()` and `mutate()` can fail; always `.catch()`.
|
|
285
|
+
- **Check `result.status` on mutations** — `"proposed"` is governance, not an error; surface `reviewUrl`.
|
|
286
|
+
- **Transparent background** — `background: transparent` on `body` inherits the host surface color.
|
|
287
|
+
- **No external fetch** — the sandbox has no cross-origin access; all data must go through `SynapWidget`.
|
|
288
|
+
- **Declare all non-React imports in `deps`** — the host generates the import map from that field.
|
|
289
|
+
|
|
290
|
+
---
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
## The work flow — question → research → decision → action
|
|
2
|
+
|
|
3
|
+
AI-assisted work has a shape. When the user is actually _thinking about something_, it flows through four structural nodes. Each is a first-class entity. None of these are optional "nice-to-have" labels — they're the graph that makes the work _durable_ and transferrable between AIs.
|
|
4
|
+
|
|
5
|
+
| Stage | Entity | What it captures | Typical trigger |
|
|
6
|
+
| ----------- | ---------- | -------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
7
|
+
| Inquiry | `question` | What the user is trying to figure out | "I'm wondering about X" / "Should we Y or Z?" / "What's the best…" |
|
|
8
|
+
| Exploration | `research` | Investigation: sources consulted, conclusion, confidence | Reading articles, comparing options, summarizing findings |
|
|
9
|
+
| Resolution | `decision` | What was chosen + rationale + alternatives | "We decided to…" / "Let's go with…" / "I'm going with…" |
|
|
10
|
+
| Execution | `task` | Concrete action items that follow the decision | "Now I need to…" / "TODO: ship Y by…" |
|
|
11
|
+
|
|
12
|
+
**Link each stage to the next:**
|
|
13
|
+
|
|
14
|
+
- `question.answeredByDecisionId` → the decision that closed it
|
|
15
|
+
- `research.questionId` → the question it investigates
|
|
16
|
+
- `decision.projectId` → the project it affects (same for question / research)
|
|
17
|
+
- Use `POST /relations type=source` to link research to its sources (articles, websites, documents)
|
|
18
|
+
|
|
19
|
+
Traversing in either direction gives the user answers like:
|
|
20
|
+
|
|
21
|
+
- "What am I currently exploring about Project Eve?" → `GET /entities?profileSlug=question&…` filtered by open
|
|
22
|
+
- "What decisions have we made on this project?" → filtered by `projectId`
|
|
23
|
+
- "What was the research behind this decision?" → reverse-lookup from `decision` via the research entities that reference the same `projectId` and question
|
|
24
|
+
|
|
25
|
+
### When to create each
|
|
26
|
+
|
|
27
|
+
**`question` — substantive inquiries only.** The test: _would the user want to find this later?_ "What's the weather" = no, don't create. "Should we use LangGraph or CrewAI?" = yes, create. Casual chitchat never becomes a question.
|
|
28
|
+
|
|
29
|
+
**`research` — when you investigate.** Any time you go off and read articles / websites / past notes to answer something, that's research. Create the entity upfront (`status: "ongoing"`), link sources as you pull them (`POST /relations type=source`), set `conclusion` when you're done (`status: "concluded"`).
|
|
30
|
+
|
|
31
|
+
**`decision` — when the user picks a path.** Already covered in the memory-vs-entity section above. Link back to the question it answers (set `question.answeredByDecisionId`).
|
|
32
|
+
|
|
33
|
+
**`task` — when the decision implies concrete work.** Link with `projectId` if not already inferred.
|
|
34
|
+
|
|
35
|
+
### Worked example
|
|
36
|
+
|
|
37
|
+
User: _"I'm trying to figure out whether we should build our own orchestrator or standardize on OpenClaude's. Can you help me think through it?"_
|
|
38
|
+
|
|
39
|
+
1. Create the question:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
POST /api/hub/entities
|
|
43
|
+
{ "profileSlug": "question",
|
|
44
|
+
"title": "Build custom orchestrator or use OpenClaude native?",
|
|
45
|
+
"properties": {
|
|
46
|
+
"questionStatus": "exploring",
|
|
47
|
+
"askedAt": "2026-04-20",
|
|
48
|
+
"projectId": "ent_project_eve",
|
|
49
|
+
"description": "Weighing separation-of-concerns vs. out-of-the-box capability."
|
|
50
|
+
} }
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
2. As you investigate, create a research entity and link sources:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
POST /api/hub/entities
|
|
57
|
+
{ "profileSlug": "research",
|
|
58
|
+
"title": "LangGraph vs CrewAI capability survey",
|
|
59
|
+
"properties": {
|
|
60
|
+
"researchStatus": "ongoing",
|
|
61
|
+
"questionId": "ent_question_1",
|
|
62
|
+
"projectId": "ent_project_eve"
|
|
63
|
+
} }
|
|
64
|
+
|
|
65
|
+
POST /api/hub/relations
|
|
66
|
+
{ "sourceEntityId": "ent_research_1", "targetEntityId": "ent_article_langgraph_docs", "type": "source" }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
3. When you reach a conclusion, update the research:
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
PATCH /api/hub/entities/ent_research_1
|
|
73
|
+
{ "properties": {
|
|
74
|
+
"researchStatus": "concluded",
|
|
75
|
+
"conclusion": "LangGraph separates orchestration brain from UX. CrewAI adds agent abstractions but couples to its runtime.",
|
|
76
|
+
"researchConfidence": "high"
|
|
77
|
+
} }
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
4. When the user picks, create a decision linked to the question:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
POST /api/hub/entities
|
|
84
|
+
{ "profileSlug": "decision",
|
|
85
|
+
"title": "Use LangGraph orchestrator over OpenClaude native",
|
|
86
|
+
"properties": {
|
|
87
|
+
"decisionStatus": "accepted",
|
|
88
|
+
"decidedAt": "2026-04-22",
|
|
89
|
+
"rationale": "Separates Orchestration Brain from UX.",
|
|
90
|
+
"alternatives": "Standardize on OpenClaude's multi-agent logic.",
|
|
91
|
+
"projectId": "ent_project_eve"
|
|
92
|
+
} }
|
|
93
|
+
|
|
94
|
+
PATCH /api/hub/entities/ent_question_1
|
|
95
|
+
{ "properties": {
|
|
96
|
+
"questionStatus": "answered",
|
|
97
|
+
"answeredByDecisionId": "ent_decision_1"
|
|
98
|
+
} }
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
5. Tasks follow as usual, linked to the project.
|
|
102
|
+
|
|
103
|
+
**The payoff:** six months later, any AI (or the user alone) can reconstruct the reasoning by traversing from the project → question → research → decision → tasks. That's the durability Synap provides on top of chat.
|
|
104
|
+
|
|
105
|
+
### Creation is silent by default
|
|
106
|
+
|
|
107
|
+
Don't interrupt the conversation to ask "should I log this as a question?" — just do it and add a one-line trailer at the end of your response:
|
|
108
|
+
|
|
109
|
+
> (Logged as question on Project Eve. Review: synap://open/proposal/…)
|
|
110
|
+
|
|
111
|
+
If the creation was auto-approved (entity.create is on the whitelist), there's no proposal; just show a link to the entity:
|
|
112
|
+
|
|
113
|
+
> (Logged as question → synap://open/entity/ent_question_1)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
## Worked examples
|
|
2
|
+
|
|
3
|
+
### Example 1 — "Remind me to send the proposal to Acme on Friday"
|
|
4
|
+
|
|
5
|
+
1. Search for the Acme entity: `GET /entities?q=Acme&profileSlug=company` → got `ent_acme`
|
|
6
|
+
2. Search for an existing task: `GET /entities?q=proposal&profileSlug=task&workspaceId=…` → none
|
|
7
|
+
3. Create the task with links:
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
POST /api/hub/entities
|
|
11
|
+
{ "userId": "{userId}", "workspaceId": "{wsId}",
|
|
12
|
+
"profileSlug": "task",
|
|
13
|
+
"title": "Send proposal to Acme",
|
|
14
|
+
"properties": {
|
|
15
|
+
"status": "todo", "priority": "high",
|
|
16
|
+
"dueDate": "2026-04-24"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
4. Link to Acme (Acme is not an entity_id property on task — use Way 2):
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
POST /api/hub/relations
|
|
25
|
+
{ "userId": "{userId}",
|
|
26
|
+
"sourceEntityId": "ent_new_task",
|
|
27
|
+
"targetEntityId": "ent_acme",
|
|
28
|
+
"type": "related_to" }
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
5. Confirm: "Task created and linked to Acme, due Friday."
|
|
32
|
+
|
|
33
|
+
### Example 2 — "Who's Sarah at Acme?"
|
|
34
|
+
|
|
35
|
+
1. Search person: `GET /entities?q=Sarah&profileSlug=person` → `ent_sarah`
|
|
36
|
+
2. Pull her connections: `GET /entities/ent_sarah/connections` → company=Acme, 3 recent emails, 1 meeting
|
|
37
|
+
3. Answer from the returned data, not from your own context.
|
|
38
|
+
|
|
39
|
+
### Example 3 — "Save this article for later: https://…"
|
|
40
|
+
|
|
41
|
+
1. Search for existing bookmark: `GET /entities?q=<url>&profileSlug=article` → none
|
|
42
|
+
2. Create an article entity:
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
POST /api/hub/entities
|
|
46
|
+
{ "userId": "{userId}", "workspaceId": "{wsId}",
|
|
47
|
+
"profileSlug": "article",
|
|
48
|
+
"title": "<page title>",
|
|
49
|
+
"properties": { "url": "<url>", "domain": "<host>" }
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
3. If the user said why ("interesting for the onboarding project"), also create a relation to that project — never drop the reason as a plain comment, turn it into a link.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
## Workspace design — is this concern a WORKSPACE, or something smaller?
|
|
2
|
+
|
|
3
|
+
Before you create a workspace, run the decision rule. A workspace (an operational **domain**) is the heaviest structure in the pod — it owns kinds, confers roles, carries its own team and automations. Most new concerns are NOT domains; they are a **hat**, an **initiative**, or a **stage**. Creating a workspace for one of those is the anti-pattern that fragments the graph. Decide first, then create.
|
|
4
|
+
|
|
5
|
+
## The decision rule — a concern earns a workspace ONLY if ALL FOUR hold
|
|
6
|
+
|
|
7
|
+
1. **Owns kinds** — it is source-of-truth for a noun nothing else owns (CRM owns `person`/`company`; Operations owns `engagement`/`deliverable`). If it only _reads_ or _annotates_ another domain's kinds, it is not a domain.
|
|
8
|
+
2. **Own team** — a distinct set of operators/collaborators works it (separation of _who_, not just _what_).
|
|
9
|
+
3. **Native automations/tools** — it runs behavior its neighbors don't (its own capabilities, playbooks, triggers).
|
|
10
|
+
4. **Stable** — it persists across clients and campaigns. If it is per-client or per-campaign, it is time-bound, not a domain.
|
|
11
|
+
|
|
12
|
+
**All four, or it is not a workspace.** Then fork it to the right lighter structure:
|
|
13
|
+
|
|
14
|
+
| If the concern is… | It is a… | Substrate | Example |
|
|
15
|
+
| ----------------------------------------------------------- | -------------- | -------------------------------------- | ------------------------------------------- |
|
|
16
|
+
| a **role/hat** an existing entity wears in a domain | **Facet** | `attach_facet` (`profileKind: "role"`) | `client`, `sponsor`, `prospect`, `investor` |
|
|
17
|
+
| a **cross-cutting, time-bound initiative** spanning domains | **Project** | `create_project` (a lens) | a campaign, an engagement, a launch |
|
|
18
|
+
| a **stage/filter WITHIN a domain** | **State/View** | a `status` property def + a view | pipeline stage, "active"/"archived" |
|
|
19
|
+
|
|
20
|
+
## The decision procedure (follow in order)
|
|
21
|
+
|
|
22
|
+
1. **Name the source-of-truth noun.** What kind would this workspace _own_ that no existing workspace owns? Run `list_profiles` — if the noun already lives in another domain, you have a facet or a project, not a domain. STOP.
|
|
23
|
+
2. **Test all four conditions.** Owns kinds AND own team AND native automations AND stable. Any one fails → fork below.
|
|
24
|
+
3. **If it's a hat** (a status/role on an entity that already exists elsewhere) → resolve the entity, `attach_facet`. Never a workspace, never a second entity.
|
|
25
|
+
4. **If it's time-bound work across domains** → `create_project` and set it as the lens; the work files into it from whatever workspace holds the data. **A project is a COMMITMENT WITH GRAVITY** — a real initiative that ties work together (a campaign, an engagement, a client, a launch). Tasks, plans, repos, themes, and topics are **entities**, never projects. Before you create one: (a) **search existing projects first** (`synap orient` / `GET /api/hub/projects`) and prefer **linking into an existing project** via `belongs_to_project` — near-duplicate names are rejected with the existing candidates; (b) an agent-created project must cite **≥5 existing entities** that would belong to it as `evidenceEntityIds` — the backend rejects a project with no gravity and tells you to store it as an entity or reuse an existing project instead; (c) **never create a project for the pod owner's own company** — the company _is_ the pod, not a project inside it.
|
|
26
|
+
5. **If it's a stage inside a domain** → add a `status` property def (`create_property_def`) and a view; don't split the stage into its own space.
|
|
27
|
+
6. **Only if all four held** → **template first** (escalation ladder L3):
|
|
28
|
+
`market.search({query, kind: "template"})` and propose install of a matching
|
|
29
|
+
template before freehand `create_workspace`. Freehand create is last resort
|
|
30
|
+
and always proposed — a deliberate move, offer it to the user (see
|
|
31
|
+
`lenses.md`). Then declare how it lives in the graph (see `workspace-edges.md`).
|
|
32
|
+
|
|
33
|
+
## The CRM corollary — the load-bearing example
|
|
34
|
+
|
|
35
|
+
Operational state — **prospect → client → delivered** — is a **FLOW across domains**, expressed as **facets + a triggered project**, NEVER as workspaces and NEVER by bolting delivery onto the identity domain.
|
|
36
|
+
|
|
37
|
+
- CRM = **who** (owns `person`/`company`, confers the `lead`/`client` facets).
|
|
38
|
+
- Operations = **what we do for them** (owns `engagement`/`contract`/`deliverable`).
|
|
39
|
+
- The bridge: attaching the `client` facet in CRM **triggers** an engagement project in Operations (see the _triggers_ edge in `workspace-edges.md`).
|
|
40
|
+
|
|
41
|
+
Bolting delivery-ops onto CRM was the anti-pattern: it made one workspace own two unrelated source-of-truth concerns and blurred _who_ the entity is with _what work_ is happening. Split by ownership; bridge by facet + trigger.
|
|
42
|
+
|
|
43
|
+
## Why this matters
|
|
44
|
+
|
|
45
|
+
A workspace is a boundary; a facet/project/state is a connection. Boundaries fragment the graph — they should be rare and earned. When you catch yourself about to create a workspace, check the four conditions: nine times out of ten the honest answer is a facet on an entity that already exists, a project that spans what's already there, or a status field on a kind you already own.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
## Workspace edges — how a domain LIVES IN THE GRAPH
|
|
2
|
+
|
|
3
|
+
A workspace is never an island. Before you create one (or reason about an existing one), map its **edges**: what it consumes, what it provides, what it triggers, what subject it shares, what spans it. Domains are wired together by a small, fixed taxonomy — and each edge type maps to a specific substrate. Knowing the taxonomy is what lets you reason about a new domain's _position_ instead of dropping it in disconnected.
|
|
4
|
+
|
|
5
|
+
> The two graphs are orthogonal. This is the **data-flow graph** (what reads/writes/triggers what) — the one we model. The **org graph** (who owns/operates a domain) is workspace membership only. "Comms contains Marketing" is org; the _data_ edge is "Marketing **consumes** Comms' brand." Keep them separate so a team reorg never rewires the data graph.
|
|
6
|
+
|
|
7
|
+
## The four edge types (and their substrate)
|
|
8
|
+
|
|
9
|
+
| Edge | Meaning | Direction | Substrate | Example |
|
|
10
|
+
| ----------------------- | ------------------------------------------------ | --------- | ------------------------------------------------------------- | ----------------------------------------------------- |
|
|
11
|
+
| **Provides / Consumes** | a domain _reads_ another's data (read redirect) | A ← B | `defaultSources` / `sourceRoles` on the consuming workspace | Content **consumes** Comms' voice/ICP |
|
|
12
|
+
| **Triggers** | an event in A causes _work written_ into B | A ⇒ B | automation + `resolveWorkspacePlacement` (run-in-A → write-B) | a `client` facet in CRM ⇒ an engagement in Operations |
|
|
13
|
+
| **Shares subject** | the same atom wears a different facet per domain | A ⟷ B | `entity_facets` (one entity, per-domain roles) | one company is `lead` in CRM, `client` in Ops |
|
|
14
|
+
| **Spans** | a time-bound initiative crosses domains | A—B—C | `projects` (a cross-cutting lens) | one campaign spans Marketing + Content + Social |
|
|
15
|
+
|
|
16
|
+
Read the whole graph as: **Provides/Consumes** = the read wiring · **Triggers** = the write/event wiring · **Shares subject** = shared identity · **Spans** = shared initiative.
|
|
17
|
+
|
|
18
|
+
## Reason about position BEFORE you create
|
|
19
|
+
|
|
20
|
+
When `workspace-design.md`'s rule says "yes, this is a domain," don't stop at creating it — place it in the graph:
|
|
21
|
+
|
|
22
|
+
1. **What does it consume?** Which existing domains' data does it read? Those become its `defaultSources` (provides/consumes edges).
|
|
23
|
+
2. **What does it provide?** Which domains will read _its_ output? (Declared on the consumer's side, but know the answer.)
|
|
24
|
+
3. **What does it trigger — and what triggers it?** Which facet/event in a neighbor should spin up work here, or here into a neighbor? That's the automation + placement wiring (Wave 2 processor behavior).
|
|
25
|
+
4. **What subject does it share?** Which atoms already exist elsewhere that this domain will confer a new facet on? (Resolve identity first, `attach_facet` — never a duplicate.)
|
|
26
|
+
5. **What projects span it?** Which cross-cutting initiatives will pull its data alongside other domains'?
|
|
27
|
+
|
|
28
|
+
A domain that consumes nothing and provides nothing is a smell — re-check the decision rule; it may be a facet or a project after all.
|
|
29
|
+
|
|
30
|
+
## Declaring provides/consumes on an existing workspace
|
|
31
|
+
|
|
32
|
+
Edges used to be settable only at template-authoring time or through the tRPC UI. The agnostic door for setting them on a live workspace is the governed MCP tool **`synap_declare_workspace_source`** (Hub REST: `PATCH /workspaces/:id/source-edges`): it merges `defaultSources` / `sourceRoles` on an existing workspace so the generic edge-resolver can redirect its reads to the providing domain, and it materializes the `feeds` link the placement ladder reads.
|
|
33
|
+
|
|
34
|
+
- Use it when a domain should start reading another's data (e.g. point Marketing at Comms for brand/ICP).
|
|
35
|
+
- It is a **governed write** — a `{ status: "proposed", proposalId }` response is NORMAL, not an error. Because declaring an edge rewires where the pod's cross-workspace reads land, it goes through review: when you (an agent) call it, it is **proposed for a human to approve**, and the edge only goes live on approval (the `workspace/declare_source` proposal executor then runs the same merge). Tell the user it's **proposed for review** and share the review link — don't claim the edge is already live. (An operator calling it directly with their own authority applies immediately and gets `{ status: "updated" }`.)
|
|
36
|
+
- Setting the edge is what makes cross-workspace reads resolve generically, instead of each domain re-deriving its sources by hand.
|
|
37
|
+
|
|
38
|
+
## The reference wiring (worked example)
|
|
39
|
+
|
|
40
|
+
The 6-domain reference enterprise, read as edges:
|
|
41
|
+
|
|
42
|
+
- **Communication** owns voice/narrative/ICP/assets — _provides_ → Marketing, Content.
|
|
43
|
+
- **Content** owns asset/carousel/video — _consumes_ Comms; _provides_ → Social, Marketing.
|
|
44
|
+
- **Marketing** owns campaign/funnel — _consumes_ Comms + Content; _provides_ brief → Social; ⇒ _triggers_ leads → CRM.
|
|
45
|
+
- **Social** owns channel/post/schedule — _consumes_ Content + Marketing; _provides_ signals → Marketing/CRM.
|
|
46
|
+
- **CRM** owns person/company, confers `lead`/`client` — _consumes_ Social signals; `client` facet ⇒ _triggers_ → Operations.
|
|
47
|
+
- **Operations** owns engagement/contract/deliverable — _consumes_ CRM; delivery proof ⇒ _feeds_ → Content/Marketing.
|
|
48
|
+
|
|
49
|
+
Every arrow above is one of the four edge types. That is the whole model: name the arrows, pick the substrate, wire it — then the domain is a citizen of the graph, not an island.
|