@synap-core/workspace-templates 0.12.0 → 0.24.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/README.md +509 -0
- package/automations/bookmark-enrichment.automation.json +321 -0
- package/automations/github-pr-events.automation.json +505 -0
- package/automations/mail-feed.automation.json +86 -0
- package/automations/ship-a-change-checks-green.automation.json +106 -0
- package/automations/ship-a-change-checks-red.automation.json +106 -0
- package/automations/ship-a-change-deployed.automation.json +56 -0
- package/automations/ship-a-change-pr-merged.automation.json +110 -0
- package/automations/ship-a-change-pr-opened.automation.json +104 -0
- package/automations/url-bookmark-capture.automation.json +132 -0
- package/capabilities/agency-skills.capability.json +157 -0
- package/capabilities/apify.capability.json +265 -0
- package/capabilities/apollo.capability.json +120 -0
- package/capabilities/arch-backend.capability.json +97 -0
- package/capabilities/arch-client-intelligence.capability.json +401 -0
- package/capabilities/backblaze-b2.capability.json +205 -0
- package/capabilities/cal-com.capability.json +266 -0
- package/capabilities/canva.capability.json +274 -0
- package/capabilities/claude-code-routines.capability.json +172 -0
- package/capabilities/claude-managed-agents.capability.json +215 -0
- package/capabilities/client-comms-report.capability.json +246 -0
- package/capabilities/content-idea-to-production.capability.json +29 -0
- package/capabilities/datagouv.capability.json +315 -0
- package/capabilities/discord-bot.capability.json +157 -0
- package/capabilities/dropbox.capability.json +281 -0
- package/capabilities/exa.capability.json +109 -0
- package/capabilities/fal-ai.capability.json +83 -0
- package/capabilities/fal-media-lab.capability.json +158 -0
- package/capabilities/fireflies.capability.json +191 -0
- package/capabilities/freellmapi.capability.json +114 -0
- package/capabilities/generic-apikey.capability.json +92 -0
- package/capabilities/github-merge.capability.json +99 -0
- package/capabilities/github-read.capability.json +325 -0
- package/capabilities/governance-tighten-recommender.capability.json +81 -0
- package/capabilities/jev.capability.json +226 -0
- package/capabilities/lead-conversion-enrollment.capability.json +246 -0
- package/capabilities/mail-feed.capability.json +277 -0
- package/capabilities/mailgun.capability.json +52 -0
- package/capabilities/nango-google.capability.json +639 -0
- package/capabilities/notion.capability.json +417 -0
- package/capabilities/omniroute.capability.json +137 -0
- package/capabilities/posthog-analytics.capability.json +258 -0
- package/capabilities/postiz.capability.json +467 -0
- package/capabilities/proactive-digest.capability.json +190 -0
- package/capabilities/proton.capability.json +288 -0
- package/capabilities/replicate-rvm.capability.json +97 -0
- package/capabilities/research-methods.capability.json +57 -0
- package/capabilities/shopify.capability.json +395 -0
- package/capabilities/slack.capability.json +369 -0
- package/capabilities/stripe.capability.json +1496 -0
- package/capabilities/telegram-bridge.capability.json +56 -0
- package/capabilities/treg.capability.json +102 -0
- package/capabilities/unipile-linkedin.capability.json +494 -0
- package/capabilities/vercel.capability.json +424 -0
- package/dist/define-DqoItRiR.d.ts +1370 -0
- package/dist/index.d.ts +174 -900
- package/dist/index.js +26447 -24075
- package/dist/index.js.map +1 -1
- package/dist/wire.d.ts +222 -0
- package/dist/wire.js +77 -0
- package/dist/wire.js.map +1 -0
- package/package.json +27 -4
- package/retired.yaml +136 -0
- package/skills/app-factory-build-slice/SKILL.md +70 -0
- package/skills/app-factory-build-slice.catalog.json +17 -0
- package/skills/app-factory-design-canvas/SKILL.md +96 -0
- package/skills/app-factory-design-canvas.catalog.json +17 -0
- package/skills/app-factory-design-review/SKILL.md +105 -0
- package/skills/app-factory-design-review.catalog.json +18 -0
- package/skills/app-factory-research/SKILL.md +123 -0
- package/skills/app-factory-research.catalog.json +17 -0
- package/skills/bookmark-enrichment/SKILL.md +40 -0
- package/skills/carousel-format/carousel-format.skill.json +18 -0
- package/skills/collage-broll/collage-broll.skill.json +20 -0
- package/skills/content-taste/content-taste.skill.json +18 -0
- package/skills/creative-director/creative-director.skill.json +18 -0
- package/skills/design-critique/SKILL.md +138 -0
- package/skills/design-critique.catalog.json +12 -0
- package/skills/designing-with-real-components/SKILL.md +140 -0
- package/skills/designing-with-real-components.catalog.json +12 -0
- package/skills/edit-loop/edit-loop.skill.json +25 -0
- package/skills/facecam-edit/facecam-edit.skill.json +24 -0
- package/skills/mapping-the-server/SKILL.md +54 -0
- package/skills/math-explainer-manimgx/math-explainer-manimgx.skill.json +20 -0
- package/skills/motion-quality-gates/motion-quality-gates.skill.json +20 -0
- package/skills/open-design-edit/open-design-edit.skill.json +24 -0
- package/skills/reading-client-progress/SKILL.md +65 -0
- package/skills/routing-to-channels/SKILL.md +54 -0
- package/skills/stellar-scf-grants-advisor/ASSOCIATE-CHEATSHEET.md +133 -0
- package/skills/stellar-scf-grants-advisor/ASSOCIATE-ONBOARDING-GUIDE.md +761 -0
- package/skills/stellar-scf-grants-advisor/CLIENT-FAQ.md +181 -0
- package/skills/stellar-scf-grants-advisor/PARTNER-HANDOVER.md +130 -0
- package/skills/stellar-scf-grants-advisor/SKILL.md +102 -0
- package/skills/stellar-scf-grants-advisor/examples/README.md +43 -0
- package/skills/stellar-scf-grants-advisor/examples/chat-summary-templates.md +158 -0
- package/skills/stellar-scf-grants-advisor/examples/corpus-comparable-rows.md +136 -0
- package/skills/stellar-scf-grants-advisor/examples/q10-team-rewrites.md +109 -0
- package/skills/stellar-scf-grants-advisor/examples/q2-description-rewrites.md +88 -0
- package/skills/stellar-scf-grants-advisor/examples/q6-integration-rewrites.md +107 -0
- package/skills/stellar-scf-grants-advisor/examples/tranche-structures.md +176 -0
- package/skills/stellar-scf-grants-advisor/reference/01-methodology.md +96 -0
- package/skills/stellar-scf-grants-advisor/reference/02-scoring-framework.md +199 -0
- package/skills/stellar-scf-grants-advisor/reference/03-rejection-patterns.md +241 -0
- package/skills/stellar-scf-grants-advisor/reference/04-winner-patterns.md +120 -0
- package/skills/stellar-scf-grants-advisor/reference/05-comeback-patterns.md +92 -0
- package/skills/stellar-scf-grants-advisor/reference/06-budget-benchmarks.md +125 -0
- package/skills/stellar-scf-grants-advisor/reference/07-integration-list.md +147 -0
- package/skills/stellar-scf-grants-advisor/reference/08-abstract-fields.md +258 -0
- package/skills/stellar-scf-grants-advisor/reference/09-build-fields.md +259 -0
- package/skills/stellar-scf-grants-advisor/reference/10-corpus-winners.md +135 -0
- package/skills/stellar-scf-grants-advisor/reference/11-corpus-rejects.md +267 -0
- package/skills/stellar-scf-grants-advisor/reference/12-client-communication.md +131 -0
- package/skills/stellar-scf-grants-advisor/reference/13-excel-output-spec.md +199 -0
- package/skills/stellar-scf-grants-advisor/reference/14-worked-examples.md +160 -0
- package/skills/stellar-scf-grants-advisor/templates/abstract-review-builder.py +253 -0
- package/skills/stellar-scf-grants-advisor/templates/build-review-builder.py +213 -0
- package/skills/video-direction/video-direction.skill.json +20 -0
- package/skills/video-style-vocabulary/video-style-vocabulary.skill.json +20 -0
- package/skills/video-toolbox/video-toolbox.skill.json +20 -0
- package/src/__fixtures__/lifecycle-presets.flat-before.json +205 -0
- package/src/agency-os.yaml +122 -0
- package/src/agent-os-skill-slugs.test.ts +65 -0
- package/src/apify-social-reader.test.ts +317 -0
- package/src/base.yaml +85 -39
- package/src/blockchain-ecosystem.yaml +1 -0
- package/src/brand-library.yaml +525 -14
- package/src/builder-dev-fold.template.test.ts +113 -0
- package/src/builder.yaml +779 -91
- package/src/business-model-catalog-description.test.ts +47 -0
- package/src/business-model-grp.template.test.ts +214 -0
- package/src/business-model.yaml +296 -49
- package/src/catalog-safety.test.ts +198 -0
- package/src/catalog.template-items.test.ts +75 -0
- package/src/catalog.ts +66 -2
- package/src/concept-guard.test.ts +28 -8
- package/src/concept-guard.ts +2 -2
- package/src/content-creation.template.test.ts +52 -0
- package/src/content-creation.yaml +192 -0
- package/src/content-os.edit-loop.template.test.ts +210 -0
- package/src/content-os.publish-due-posts.template.test.ts +261 -0
- package/src/content-os.template.test.ts +349 -0
- package/src/content-os.video-takes.template.test.ts +338 -0
- package/src/content-os.work-a-take.template.test.ts +125 -0
- package/src/content-os.yaml +1873 -39
- package/src/content-studio-retired.template.test.ts +82 -0
- package/src/corpus-flow-validity.test.ts +4 -5
- package/src/crm-absorbs-outreach.template.test.ts +117 -0
- package/src/crm-build-plan.template.test.ts +128 -0
- package/src/crm-lists.template.test.ts +96 -0
- package/src/crm-messages-cadence.template.test.ts +246 -0
- package/src/crm-one-send-door.template.test.ts +65 -0
- package/src/crm.yaml +1563 -181
- package/src/decisions-wave.template.test.ts +186 -0
- package/src/define.ts +146 -17
- package/src/design-to-implementation.template.test.ts +94 -0
- package/src/domain-template-type.test.ts +75 -0
- package/src/ecosystem.yaml +27 -66
- package/src/enterprise-os.yaml +10 -134
- package/src/facecam-edit.audio-studio.test.ts +188 -0
- package/src/fal-generate-image.test.ts +200 -0
- package/src/fal-media-lab-pod-files.test.ts +180 -0
- package/src/finance.yaml +254 -1
- package/src/foundation.yaml +78 -38
- package/src/frame-host-modules.d.mts +6 -0
- package/src/frame-host-modules.mjs +58 -0
- package/src/generate.mjs +9 -3
- package/src/github-merge.test.ts +210 -0
- package/src/grants.yaml +46 -17
- package/src/hr.yaml +39 -6
- package/src/index.ts +36 -1
- package/src/intent.test.ts +161 -0
- package/src/internal-runbook.yaml +19 -1
- package/src/jev.test.ts +356 -0
- package/src/legal.yaml +33 -1
- package/src/life-os.yaml +51 -240
- package/src/lifecycle-coverage.test.ts +124 -0
- package/src/lifecycle-declarations.test.ts +252 -0
- package/src/lifecycle-presets.test.ts +468 -0
- package/src/lifecycle-presets.ts +494 -0
- package/src/lifecycle-stuck.test.ts +46 -0
- package/src/lifecycle-waits.parity.test.ts +319 -0
- package/src/marketing.yaml +108 -4
- package/src/meetings-knowledge.yaml +18 -0
- package/src/networking.yaml +23 -2
- package/src/operations.yaml +304 -4
- package/src/pipeline-views.template.test.ts +88 -0
- package/src/playbook-goal-placeholders.test.ts +57 -0
- package/src/postiz-contract.test.ts +134 -0
- package/src/presentation-declarations.test.ts +174 -0
- package/src/process-contract.validate.test.ts +352 -0
- package/src/project-management.yaml +39 -740
- package/src/publish-body.d.mts +29 -0
- package/src/publish-body.mjs +74 -0
- package/src/publish-body.test.ts +74 -0
- package/src/publish-official-lib.test.ts +176 -0
- package/src/replicate-rvm.test.ts +504 -0
- package/src/research-base.yaml +119 -20
- package/src/research-decision.yaml +60 -3
- package/src/reserved-profile-slugs.test.ts +81 -0
- package/src/retired-goal-kinds.test.ts +52 -0
- package/src/role-reference-and-step-domain.test.ts +192 -0
- package/src/seed-obligation.test.ts +1 -6
- package/src/send-message-maps.test.ts +227 -0
- package/src/shared-role-ssot.test.ts +40 -2
- package/src/ship-a-change.template.test.ts +177 -0
- package/src/skills.test.ts +170 -0
- package/src/social.yaml +85 -27
- package/src/space-packages.freshness.test.ts +97 -0
- package/src/space-packages.generated.ts +40 -0
- package/src/space-packages.test.ts +125 -0
- package/src/space-packages.ts +73 -0
- package/src/start.test.ts +188 -0
- package/src/stripe-capability.test.ts +192 -0
- package/src/task-intents.test.ts +293 -0
- package/src/template-documents.test.ts +158 -0
- package/src/templates.ts +20907 -21464
- package/src/types.ts +475 -61
- package/src/unipile-linkedin-find-profile.test.ts +183 -0
- package/src/unipile-publish-post.test.ts +162 -0
- package/src/validate-flow.drift.test.ts +2 -3
- package/src/validate-flow.ts +22 -2
- package/src/validate-onboarding.test.ts +59 -0
- package/src/validate.test.ts +71 -4
- package/src/validate.ts +1416 -7
- package/src/wire-core.ts +231 -0
- package/src/wire.test.ts +159 -0
- package/src/wire.ts +107 -0
- package/views/bookmark-views-pack.view.json +39 -0
- package/views/event-views-pack.view.json +45 -0
- package/views/task-views-pack.view.json +53 -0
- package/src/agent-fleet.yaml +0 -1645
- package/src/business-developer.template.test.ts +0 -351
- package/src/business-developer.yaml +0 -860
- package/src/content-studio.yaml +0 -361
- package/src/dev-dashboard.yaml +0 -990
- package/src/outreach-comms.yaml +0 -486
- package/src/the-arch.yaml +0 -201
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
{
|
|
2
|
+
"apiVersion": "synap/v1",
|
|
3
|
+
"kind": "capability",
|
|
4
|
+
"meta": {
|
|
5
|
+
"slug": "arch-backend",
|
|
6
|
+
"name": "The Arch — Backend Agents",
|
|
7
|
+
"description": "List and run The Arch's backend agents from Synap. The agents you can reach depend on your Arch key's scope, and results arrive in The Arch. Needs an Arch A2A API key.",
|
|
8
|
+
"tags": [
|
|
9
|
+
"capability",
|
|
10
|
+
"arch",
|
|
11
|
+
"a2a",
|
|
12
|
+
"private",
|
|
13
|
+
"opt-in"
|
|
14
|
+
],
|
|
15
|
+
"isPublic": false,
|
|
16
|
+
"syncByDefault": false,
|
|
17
|
+
"owner": "template-owner"
|
|
18
|
+
},
|
|
19
|
+
"spec": {
|
|
20
|
+
"key": "arch-backend",
|
|
21
|
+
"name": "The Arch — Backend Agents",
|
|
22
|
+
"description": "Invoke The Arch's own backend agents from Synap over the A2A (agent-to-agent) protocol — the REVERSE of the consume-a-service connectors (Exa/Apify/Unipile call OUT to third parties; this calls IN to The Arch's product). The Arch exposes 15 agents at POST https://thearch.so/api/a2a/rpc (Google A2A v0.3 JSON-RPC 2.0); this capability wraps the two safe entry points: discover the agents this key may invoke, and dispatch one. WHICH agents are reachable is governed SERVER-SIDE by the A2A key's own scope (A2A_KEY_SCOPES) — the recommended key is scoped to the read-only intelligence agents only (market-intelligence, radar-discovery, onchain-discovery, competitor-watch), never the money/outbound agents (cold-outreach, autonomous-bd-agent, content-generator). So the reachable surface is the intersection of these verbs and that key scope; there is no way to widen it from the pod side. PRECONDITION: an Arch A2A API key issued by The Arch (set in its A2A_API_KEYS + scoped in A2A_KEY_SCOPES), pasted into this capability's connection. Dispatch is asynchronous: message/send returns a task { id, state } that the Arch runs via its own Inngest fleet — the durable result lands in The Arch, not inline.",
|
|
23
|
+
"params": [
|
|
24
|
+
{
|
|
25
|
+
"name": "archA2aApiKey",
|
|
26
|
+
"label": "Arch A2A API key",
|
|
27
|
+
"type": "text",
|
|
28
|
+
"required": true,
|
|
29
|
+
"description": "The Arch A2A key (a value present in The Arch's A2A_API_KEYS and scoped in A2A_KEY_SCOPES). Stored server-encrypted in the vault; never persisted in the template."
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"vault": [
|
|
33
|
+
{
|
|
34
|
+
"ref": "archA2aApiKeySecret",
|
|
35
|
+
"name": "{{name}} Arch A2A key",
|
|
36
|
+
"value": "{{archA2aApiKey}}",
|
|
37
|
+
"type": "api_key",
|
|
38
|
+
"description": "Arch A2A API key for the arch_a2a connector (sent as the X-API-Key header)."
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"tools": [
|
|
42
|
+
{
|
|
43
|
+
"name": "arch_a2a",
|
|
44
|
+
"kind": "api",
|
|
45
|
+
"description": "Authenticated HTTP access to The Arch's A2A surface (https://thearch.so). The applier injects the vaulted key into the `X-API-Key` header (raw key, no prefix — The Arch's auth scheme); its credentialRef is remapped to the runtime vault://<id> at apply time. Discovery is GET /api/a2a/agents; dispatch is POST /api/a2a/rpc (JSON-RPC 2.0).",
|
|
46
|
+
"credentialRef": "archA2aApiKeySecret",
|
|
47
|
+
"executor": "is-agent",
|
|
48
|
+
"config": {
|
|
49
|
+
"baseUrl": "https://thearch.so",
|
|
50
|
+
"auth": {
|
|
51
|
+
"in": "header",
|
|
52
|
+
"name": "X-API-Key",
|
|
53
|
+
"prefix": ""
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"skills": [
|
|
59
|
+
{
|
|
60
|
+
"name": "arch_list_agents",
|
|
61
|
+
"intent": "list_records",
|
|
62
|
+
"kind": "code",
|
|
63
|
+
"scope": "pod",
|
|
64
|
+
"description": "Discover the Arch backend agents THIS key may invoke — the A2A discovery endpoint (GET /api/a2a/agents), already filtered server-side to the key's capability scope, so it returns only the agents `arch_run_agent` is actually allowed to dispatch. Read-only, no side effects. Returns { count, agents: [{ id, name, description, capabilities }] }. Run this first to see the reachable surface before dispatching.",
|
|
65
|
+
"requires": [
|
|
66
|
+
"arch_a2a"
|
|
67
|
+
],
|
|
68
|
+
"executionMode": "sync",
|
|
69
|
+
"timeoutSeconds": 30,
|
|
70
|
+
"parameters": {},
|
|
71
|
+
"code": "// Discover the Arch agents this key may invoke. Executor wraps this body as\n// (async (args, context) => { <code> }); use args directly and `return`.\n// callProvider('arch_a2a','GET','/api/a2a/agents') injects the vaulted key as\n// `X-API-Key: <key>` (config.auth). The endpoint filters the list to this key's\n// A2A_KEY_SCOPES, so it never reveals agents this key cannot invoke.\nconst res = await callProvider('arch_a2a', 'GET', '/api/a2a/agents');\nconst payload = res?.body ?? res;\nconst rows = Array.isArray(payload?.agents) ? payload.agents : [];\nconst agents = rows.map((a) => ({\n id: a?.id ?? null,\n name: a?.name ?? null,\n description: a?.description ?? null,\n capabilities: Array.isArray(a?.capabilities) ? a.capabilities.map((c) => c?.name ?? c) : null,\n}));\nreturn { count: agents.length, agents };"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "arch_run_agent",
|
|
75
|
+
"intent": "run_external_job",
|
|
76
|
+
"kind": "code",
|
|
77
|
+
"scope": "pod",
|
|
78
|
+
"description": "Dispatch one Arch backend agent over A2A (POST /api/a2a/rpc, method message/send). ASYNCHRONOUS: The Arch accepts the task and runs it on its own Inngest fleet — this returns { agentId, taskId, state } (state is typically 'submitted'), NOT the finished analysis. The durable output lands inside The Arch (its Mongo + channels), by design. Named as an ACTION verb because it triggers real work; the reachable agentId set is bounded server-side by this key's scope, so a request for an out-of-scope agent is rejected 403. Args: { agentId: string (e.g. 'market-intelligence'), prompt: string (the natural-language brief for the agent) }.",
|
|
79
|
+
"requires": [
|
|
80
|
+
"arch_a2a"
|
|
81
|
+
],
|
|
82
|
+
"executionMode": "sync",
|
|
83
|
+
"timeoutSeconds": 60,
|
|
84
|
+
"parameters": {
|
|
85
|
+
"agentId": "string",
|
|
86
|
+
"prompt": "string"
|
|
87
|
+
},
|
|
88
|
+
"code": "// Dispatch an Arch agent over A2A JSON-RPC. Executor wraps this body as\n// (async (args, context) => { <code> }); use args directly and `return`.\n// callProvider('arch_a2a','POST','/api/a2a/rpc',rpc) injects `X-API-Key` via\n// config.auth. message/send is async: it returns a task descriptor, not the\n// finished result — The Arch runs the agent on its own fleet.\nconst agentId = String(args?.agentId ?? '').trim();\nif (!agentId) throw new Error('arch_run_agent: agentId is required');\nconst prompt = String(args?.prompt ?? '').trim();\nif (!prompt) throw new Error('arch_run_agent: prompt is required');\n\nconst rpc = {\n jsonrpc: '2.0',\n id: 'synap-' + agentId,\n method: 'message/send',\n params: {\n agentId,\n message: { role: 'user', parts: [{ type: 'text', text: prompt }] },\n },\n};\n\nconst res = await callProvider('arch_a2a', 'POST', '/api/a2a/rpc', rpc);\nconst payload = res?.body ?? res;\nif (payload?.error) {\n throw new Error('arch_run_agent: A2A error ' + (payload.error.code ?? '') + ' ' + (payload.error.message ?? ''));\n}\nconst result = payload?.result ?? payload;\nreturn {\n agentId,\n taskId: result?.id ?? null,\n state: result?.status?.state ?? null,\n metadata: result?.metadata ?? null,\n};"
|
|
89
|
+
}
|
|
90
|
+
],
|
|
91
|
+
"provides": [
|
|
92
|
+
"list_records",
|
|
93
|
+
"run_external_job"
|
|
94
|
+
]
|
|
95
|
+
},
|
|
96
|
+
"dependencies": []
|
|
97
|
+
}
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
{
|
|
2
|
+
"apiVersion": "synap/v1",
|
|
3
|
+
"kind": "capability",
|
|
4
|
+
"meta": {
|
|
5
|
+
"slug": "arch-client-intelligence",
|
|
6
|
+
"name": "Arch Client Intelligence",
|
|
7
|
+
"description": "When a client message or transcript arrives, refreshes that client's context summary and proposes a grant-submission card if grant work is detected. On a new Cal.com booking, prepares a call brief. Needs the Grants pipeline; automations ship turned off.",
|
|
8
|
+
"tags": [
|
|
9
|
+
"capability"
|
|
10
|
+
],
|
|
11
|
+
"isPublic": true,
|
|
12
|
+
"syncByDefault": true
|
|
13
|
+
},
|
|
14
|
+
"spec": {
|
|
15
|
+
"key": "arch-client-intelligence",
|
|
16
|
+
"name": "Arch Client Intelligence",
|
|
17
|
+
"description": "The Arch's PROACTIVE client-intelligence layer (Waves 3+4), expressed entirely as config — automations + playbooks, zero backend code. EVENT-DRIVEN, not a daily fleet pass (the Stellar 'Client Sync' + 'Client Comms — Daily Report' crons already do the daily whole-fleet read; a third would be redundant, so everything here is triggered by a real event and gated by a filter). Three moves: (1) on a NEW client message/transcript (external_message.received — Fireflies transcripts + Discord/email all land via recordInboundMessage and fire this event), re-synthesize THAT ONE client's whole context across every bound channel + linked docs and refresh its derived `contextSummary` (governed self-update — proposes); (2) when that synthesis DETECTS grant-work (the client is discussing/pursuing a grant program), launch an is-agent playbook that PROPOSES a `grant_submission` pipeline card (never auto-creates — a mis-detection must never spawn a junk card, so this goes through the propose door, not an automation entity_create output); (3) on a NEW cal.com booking (an `event` entity created by cal-com's cal_create_booking, source:'cal.com'), run an is-agent call-prep-brief playbook for the upcoming call. Pairs with the grants workspace-template (reuses their `grant_submission` kind + `contextSummary` slug). Install into a workspace that has the grant spine (grant_submission / grant-program) composed.",
|
|
18
|
+
"params": [],
|
|
19
|
+
"vault": [],
|
|
20
|
+
"tools": [],
|
|
21
|
+
"skills": [
|
|
22
|
+
{
|
|
23
|
+
"name": "arch-client-intelligence-method",
|
|
24
|
+
"kind": "instruction",
|
|
25
|
+
"scope": "pod",
|
|
26
|
+
"description": "How to re-synthesize a single client's context on a new message, detect grant-work, and prep a call — the methodology behind the Arch proactivity automations/playbooks.",
|
|
27
|
+
"code": "# Arch client intelligence — methodology\n\nThis is the PROACTIVE, event-driven client-intelligence layer. It fires on a real signal (a new client message/transcript, or a new cal.com booking) and works ONE client at a time — never a whole-fleet sweep. Follow these rules on every run.\n\n## 1. Re-synthesis on a new message (external_message.received)\n- Only act on a MATCHED client: a message whose channel is bound to a client entity (the trigger carries `data.entityId`). An unbound / internal message is skipped — never fire on every message.\n- Gather the client's WHOLE context, not just the one message: read EVERY bound channel (Discord + email + Fireflies transcripts + team thread) and the client's linked documents. This is the `messages_query` gathering primitive with `scope: \"all-channels\"` + `includeDocuments: true`.\n- Produce a durable `contextSummary` — 1-3 plain-language sentences a teammate would want at a glance: where the client stands and what just happened. Never empty; if nothing material happened, say so in one line. Write it back via the GOVERNED self-update (it PROPOSES for a non-owner — that is correct, a human approves the refresh). REUSE the existing `contextSummary` property slug — never invent a new field.\n\n## 2. Grant-work detection → PROPOSE (never auto-create)\n- Grant-work = the client is discussing, scoping, or pursuing a grant PROGRAM (e.g. Stellar SCF, Optimism RetroPGF, Arbitrum) — a real application intent, not a passing mention.\n- When detected, the pipeline card is a `grant_submission`. It is PROPOSED, never auto-created: a mis-detected grant must never silently spawn a junk pipeline card, not even on the owner's pod. Proposing routes it to human review (a 'proposed' result is success, not failure).\n- Resolve identity FIRST: the grant PROGRAM is (or should become) its own `grant-program` entity — match before creating; the client is ALREADY an entity (the message's channel is bound to it), so you never create a company. Link the proposed submission `submitted_by` → the client and `submitted_to` → the round/program AFTER approval.\n\n## 3. Call prep on a new booking (cal.com event)\n- A cal.com booking lands as an `event` entity (`properties.source == \"cal.com\"`). Only prep cal.com events — a plain calendar-sync event is skipped.\n- Resolve the attendee (name/email on the booking) to an EXISTING client entity via identity resolution — do NOT create a person/company from a booking.\n- If a client resolves, gather their context (all channels + linked docs) and write a concise prep brief: who they are, where things stand, open needs, and 3 talking points for the call.\n\n## Firewall (never bend)\n- Any brief/report is for the INTERNAL TEAM channel only — resolve it via `channel.resolve` with `branchPurpose: \"team\"` and post there and only there. NEVER post an AI synthesis into a client-facing channel."
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "propose_grant_submission",
|
|
31
|
+
"kind": "code",
|
|
32
|
+
"scope": "pod",
|
|
33
|
+
"description": "Propose (never auto-create) a `grant_submission` pipeline card for a client the synthesis detected is pursuing a grant program. Governed: routes through the propose door for human review. Args: { clientId: string (the ALREADY-resolved client entity id), clientName?: string, programName?: string (the detected grant program), evidence?: string (a short verbatim quote evidencing the grant-work) }.",
|
|
34
|
+
"executionMode": "async",
|
|
35
|
+
"timeoutSeconds": 60,
|
|
36
|
+
"parameters": {
|
|
37
|
+
"clientId": "string",
|
|
38
|
+
"clientName": "string?",
|
|
39
|
+
"programName": "string?",
|
|
40
|
+
"evidence": "string?"
|
|
41
|
+
},
|
|
42
|
+
"code": "// Propose a grant_submission card (governed — the propose door files it for\n// human review; it is NEVER auto-created). Executor wraps this body as\n// (async (args, context) => { <code> }); use args directly and `return`.\n// Identity firewall: the client is ALREADY an entity (its channel is bound) —\n// we NEVER create a company here; we only propose the non-company submission\n// card and key it to the client via sourceRecordId so a human/later sync can\n// link submitted_by -> client and submitted_to -> the round after approval.\nconst clientId = String(args?.clientId ?? '').trim();\nif (!clientId) throw new Error('propose_grant_submission: clientId is required');\nconst clientName = String(args?.clientName ?? '').trim();\nconst programName = String(args?.programName ?? '').trim();\nconst evidence = String(args?.evidence ?? '').trim();\n\nconst title = (clientName || 'Client') + ' \\u2014 grant submission' + (programName ? ' (' + programName + ')' : '');\nconst summary = programName\n ? ('Detected grant-work: the client is pursuing ' + programName + '.' + (evidence ? ' Evidence: \"' + evidence + '\"' : ''))\n : 'Detected grant-work in the client\\u2019s recent context.';\n\n// stage/status use grant_submission’s OWN enum vocab (grants.yaml): a fresh\n// pursuit starts at stage \"scope\", status \"waiting-client\". sourceRecordId =\n// the client entity id (the same stable per-client key the Stellar spine uses),\n// so a later sync/human can dedupe + advance the one card.\nconst res = await propose.entity({\n profileSlug: 'grant_submission',\n title: title,\n properties: { stage: 'scope', status: 'waiting-client', summary: summary, sourceRecordId: clientId },\n reasoning: 'AI detected grant-work in the client\\u2019s context. Proposing a grant_submission pipeline card for review (never auto-created). After approval, link submitted_by \\u2192 the client and submitted_to \\u2192 the round/program.'\n});\nreturn { proposed: res?.proposed ?? true, proposalId: res?.proposalId ?? null, clientId: clientId, programName: programName };"
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"provides": [],
|
|
46
|
+
"playbooks": [
|
|
47
|
+
{
|
|
48
|
+
"name": "Arch — Propose Grant Submission",
|
|
49
|
+
"description": "On detected grant-work for a client, PROPOSE a `grant_submission` pipeline card (never auto-create). Identity-resolves the grant program first, proposes the card via the `propose_grant_submission` skill, and (after approval) links it to the client + round. Launched by the 'Arch — Client Re-Synthesis' automation when its synthesis detects grant-work; also runnable on demand for any client.",
|
|
50
|
+
"goalTemplate": "The client {client} is pursuing a grant program — detected from their recent context: {programName} (evidence: {evidence}). PROPOSE a grant_submission pipeline card for this client — never auto-create it; a 'proposed' result is success, awaiting human review.\n\n1. Resolve identity first: match the grant program ({programName}) against an existing `grant-program` entity before treating it as new; the client is ALREADY an entity, so never create a company.\n2. Propose the card by running the `propose_grant_submission` skill with the client id, the client name, the program name, and the short evidence quote. It keys the card to the client via sourceRecordId and starts it at stage 'scope'.\n3. After the proposal is approved, link the submission `submitted_by` → the client and `submitted_to` → the program's round. Leave any field you cannot verify blank — never fabricate.",
|
|
51
|
+
"params": [
|
|
52
|
+
{
|
|
53
|
+
"name": "client",
|
|
54
|
+
"label": "Client",
|
|
55
|
+
"type": "entity",
|
|
56
|
+
"required": true,
|
|
57
|
+
"description": "The client entity pursuing the grant (the session subject). Already resolved — never created here."
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"name": "programName",
|
|
61
|
+
"label": "Grant program",
|
|
62
|
+
"type": "text",
|
|
63
|
+
"required": false,
|
|
64
|
+
"description": "The grant program the synthesis detected the client is pursuing (e.g. Stellar SCF)."
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"name": "evidence",
|
|
68
|
+
"label": "Evidence",
|
|
69
|
+
"type": "text",
|
|
70
|
+
"required": false,
|
|
71
|
+
"description": "A short verbatim quote from the client's context evidencing the grant-work."
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
"subjectProfile": {
|
|
75
|
+
"profileSlug": "company"
|
|
76
|
+
},
|
|
77
|
+
"channelSpec": {
|
|
78
|
+
"type": "THREAD",
|
|
79
|
+
"aiReactionMode": "only_mentioned"
|
|
80
|
+
},
|
|
81
|
+
"executor": "is-agent",
|
|
82
|
+
"status": "active",
|
|
83
|
+
"stages": [
|
|
84
|
+
{
|
|
85
|
+
"key": "propose",
|
|
86
|
+
"name": "Propose submission",
|
|
87
|
+
"category": "started",
|
|
88
|
+
"description": "Identity-resolve the grant program, then propose (never auto-create) the grant_submission card for the client via the propose_grant_submission skill.",
|
|
89
|
+
"goal": "A grant_submission card is PROPOSED for the client (stage 'scope'), keyed to the client via sourceRecordId, awaiting human review — never auto-created.",
|
|
90
|
+
"grants": [
|
|
91
|
+
{
|
|
92
|
+
"kind": "skill",
|
|
93
|
+
"id": "propose_grant_submission"
|
|
94
|
+
}
|
|
95
|
+
],
|
|
96
|
+
"expectedOutputs": [
|
|
97
|
+
{
|
|
98
|
+
"kind": "note",
|
|
99
|
+
"label": "Proposed grant submission"
|
|
100
|
+
}
|
|
101
|
+
],
|
|
102
|
+
"suggestedTasks": [
|
|
103
|
+
"Resolve the grant program identity",
|
|
104
|
+
"Propose the grant_submission card (never auto-create)",
|
|
105
|
+
"Note the client + program to link after approval"
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"name": "Arch — Call Prep Brief",
|
|
112
|
+
"description": "On a new cal.com booking, prep the upcoming call: resolve the attendee to an existing client, gather that client's context across every bound channel + linked docs, and post a concise prep brief to the client's INTERNAL TEAM channel (firewall — never client-facing). Launched by the 'Arch — Call Prep on New Booking' automation; also runnable on demand for any booking event.",
|
|
113
|
+
"goalTemplate": "A new cal.com booking landed as the event {booking}. Prepare a brief for this upcoming call, following the `arch-client-intelligence-method` methodology.\n\n1. Read the booking event's details — attendee name/email, start time, and meeting link.\n2. Resolve the attendee to an EXISTING client entity via identity resolution (match on email/name). Do NOT create a person or company from a booking.\n3. If a client resolves, gather their context across ALL bound channels + linked documents, then write a concise prep brief: who they are, where the relationship stands, any open needs, and 3 talking points for the call. If no client resolves, write a lightweight brief from the booking details alone.\n4. FIREWALL: resolve the client's TEAM channel via channel.resolve { branchPurpose: \"team\" } and post the brief there and only there — never a client-facing channel. If no team channel exists, stop and say so rather than posting anywhere else.",
|
|
114
|
+
"params": [
|
|
115
|
+
{
|
|
116
|
+
"name": "booking",
|
|
117
|
+
"label": "Booking",
|
|
118
|
+
"type": "entity",
|
|
119
|
+
"required": true,
|
|
120
|
+
"description": "The cal.com booking `event` entity to prep for (the session subject)."
|
|
121
|
+
}
|
|
122
|
+
],
|
|
123
|
+
"subjectProfile": {
|
|
124
|
+
"profileSlug": "event"
|
|
125
|
+
},
|
|
126
|
+
"channelSpec": {
|
|
127
|
+
"type": "THREAD",
|
|
128
|
+
"aiReactionMode": "only_mentioned"
|
|
129
|
+
},
|
|
130
|
+
"executor": "is-agent",
|
|
131
|
+
"status": "active"
|
|
132
|
+
}
|
|
133
|
+
],
|
|
134
|
+
"automations": [
|
|
135
|
+
{
|
|
136
|
+
"name": "Arch — Client Re-Synthesis on New Message",
|
|
137
|
+
"description": "EVENT-DRIVEN, one client at a time. When a new client message/transcript lands (external_message.received — Fireflies transcripts, Discord, email all fire this), re-synthesize THAT client's whole context (all bound channels + linked docs) and refresh its derived `contextSummary` (governed self-update — proposes). If the synthesis detects grant-work, launch the 'Arch — Propose Grant Submission' playbook (which PROPOSES a grant_submission — never auto-creates). Gated to MATCHED clients only (a bound channel) so it never fires on internal/unmatched messages — the anti-over-automation guardrail. Seeded DRAFT: it runs a paid AI pass per matched client message, so activate it after a dogfood run (same convention as the Stellar/CRM AI automations).",
|
|
138
|
+
"triggerType": "event",
|
|
139
|
+
"triggerConfig": {
|
|
140
|
+
"eventPattern": "external_message.received.completed"
|
|
141
|
+
},
|
|
142
|
+
"status": "draft",
|
|
143
|
+
"metadata": {
|
|
144
|
+
"kind": "arch-client-resynthesis"
|
|
145
|
+
},
|
|
146
|
+
"flowDefinition": {
|
|
147
|
+
"nodes": [
|
|
148
|
+
{
|
|
149
|
+
"id": "trigger",
|
|
150
|
+
"type": "trigger",
|
|
151
|
+
"position": {
|
|
152
|
+
"x": 0,
|
|
153
|
+
"y": 0
|
|
154
|
+
},
|
|
155
|
+
"data": {
|
|
156
|
+
"triggerType": "event",
|
|
157
|
+
"label": "New client message / transcript",
|
|
158
|
+
"config": {
|
|
159
|
+
"eventPattern": "external_message.received.completed"
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"id": "matched-client-gate",
|
|
165
|
+
"type": "condition",
|
|
166
|
+
"position": {
|
|
167
|
+
"x": 0,
|
|
168
|
+
"y": 120
|
|
169
|
+
},
|
|
170
|
+
"data": {
|
|
171
|
+
"label": "Only a MATCHED client (channel bound to an entity)",
|
|
172
|
+
"expression": "trigger.payload.data.entityId !== \"\"",
|
|
173
|
+
"_note": "The `external_message.received` event fires for EVERY inbound external message; its `data.entityId` is the bound client entity (null when the channel isn't client-bound). matchFilters (triggerConfig) is equality-only and cannot express 'entityId is present', so the matched-client gate lives here in-flow, BEFORE any paid AI pass — this is the anti-over-automation filter (gate by matched-client, never fire-on-every-message). Bare-path + operator + quoted literal is the correct condition grammar: resolveTemplate renders an absent path to \"\" (=> \"\" !== \"\" => false, skip) and a present id to the id (=> true, proceed). external_message events are inbound EXTERNAL messages only (not team-thread chatter), so this is inherently external-attendee-gated too."
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"id": "gather",
|
|
178
|
+
"type": "messages_query",
|
|
179
|
+
"position": {
|
|
180
|
+
"x": 0,
|
|
181
|
+
"y": 240
|
|
182
|
+
},
|
|
183
|
+
"data": {
|
|
184
|
+
"label": "Gather the client's WHOLE context (all channels + linked docs)",
|
|
185
|
+
"subjectEntityId": "{{trigger.payload.data.entityId}}",
|
|
186
|
+
"scope": "all-channels",
|
|
187
|
+
"includeDocuments": true,
|
|
188
|
+
"limit": 40,
|
|
189
|
+
"_note": "W2's messages_query fan-out: scope 'all-channels' merges every channel bound to the client (Discord + email + Fireflies transcripts + team thread) chronologically, and includeDocuments adds the client's linked-document previews. Output: { messages, documents, channels, truncated }. The access floor (workspace OR pod-wide) is enforced inside the node — the fan-out never widens it."
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"id": "assess",
|
|
194
|
+
"type": "capability",
|
|
195
|
+
"position": {
|
|
196
|
+
"x": 0,
|
|
197
|
+
"y": 360
|
|
198
|
+
},
|
|
199
|
+
"data": {
|
|
200
|
+
"label": "Re-synthesize context + detect grant-work → JSON",
|
|
201
|
+
"verbId": "ai.generate",
|
|
202
|
+
"inputMapping": {
|
|
203
|
+
"json": "true",
|
|
204
|
+
"maxTokens": "600",
|
|
205
|
+
"system": "You are a strict data-extraction function that re-synthesizes ONE client's context from their recent communications and detects whether they are pursuing a grant program. Respond with STRICT JSON and NOTHING else. Never fabricate.",
|
|
206
|
+
"prompt": "The client entity id is {{trigger.payload.data.entityId}}. Below is their recent context gathered across every bound channel (chronological) and their linked documents.\n\nMessages:\n{{steps.gather.output.messages}}\n\nLinked documents:\n{{steps.gather.output.documents}}\n\nReturn STRICT JSON with EXACTLY these keys and nothing else:\n{\n \"contextSummary\": \"1-3 plain-language sentences on where this client stands and what just happened; never empty (say 'no material activity' in one line if nothing happened)\",\n \"grantDetected\": \"true\" or \"false\" (a STRING, not a boolean): 'true' ONLY when the client is clearly discussing / scoping / pursuing a specific grant PROGRAM (e.g. Stellar SCF, Optimism RetroPGF, Arbitrum), not a passing mention,\n \"grantProgram\": \"the grant program name when grantDetected is 'true', else an empty string\",\n \"grantEvidence\": \"a short VERBATIM quote from the context evidencing the grant-work when grantDetected is 'true', else an empty string\"\n}\nAlways return ALL keys. Use conservative defaults (grantDetected 'false', empty strings) when unsure."
|
|
207
|
+
},
|
|
208
|
+
"_note": "ONE assess pass (mirrors Stellar 'Client Sync' + grants.yaml 'grant-submission-sync'): re-synthesizes contextSummary AND detects grant-work in the same read. This flow is SINGLE-SUBJECT from the event — there is no loop node, so the prompt must not reference a loop item (an earlier draft did, and it would have rendered empty at run time). The client is identified by the trigger's entityId, the same handle every other node here uses; the client's display title is not separately available, so the prompt leans on the gathered messages/documents (each message carries its source). grantDetected is a STRING ('true'/'false') so the string-based `condition` gate downstream can test it with an explicit `=== \"true\"` (a bare truthiness check would read 'false' as truthy — the documented gate-fail-open trap)."
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"id": "enrich-context",
|
|
213
|
+
"type": "output",
|
|
214
|
+
"position": {
|
|
215
|
+
"x": -220,
|
|
216
|
+
"y": 480
|
|
217
|
+
},
|
|
218
|
+
"data": {
|
|
219
|
+
"label": "Refresh the client's contextSummary (governed self-update — PROPOSES)",
|
|
220
|
+
"outputType": "entity_update",
|
|
221
|
+
"config": {
|
|
222
|
+
"entityId": "{{trigger.payload.data.entityId}}",
|
|
223
|
+
"properties": {
|
|
224
|
+
"contextSummary": "{{steps.assess.output.contextSummary}}"
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
"_note": "GOVERNED SELF-UPDATE of a DERIVED field, REUSING the existing `contextSummary` slug (defined on company/client via foundation/CRM — the SAME slug Stellar 'Client Sync' writes; never invent a new property). Routes through checkAutomationWriteOrPropose: for a non-owner / non-auto-approved automation it PROPOSES (correct — a human approves the refresh); for an owner/auto-approved workspace it direct-writes. entity_update on the EXISTING client ({{trigger.payload.data.entityId}}) — it NEVER creates an entity."
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"id": "grant-gate",
|
|
232
|
+
"type": "condition",
|
|
233
|
+
"position": {
|
|
234
|
+
"x": 220,
|
|
235
|
+
"y": 480
|
|
236
|
+
},
|
|
237
|
+
"data": {
|
|
238
|
+
"label": "Only when the synthesis detected grant-work",
|
|
239
|
+
"expression": "steps.assess.output.grantDetected === \"true\"",
|
|
240
|
+
"_note": "Bare-path + operator + quoted literal (the correct, non-fail-open condition grammar). Fans out from `assess` independently of enrich-context — a contextSummary propose failure never blocks grant detection, and vice versa (the decoupled-chains pattern from Stellar 'Client Sync')."
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"id": "propose-submission",
|
|
245
|
+
"type": "playbook_run",
|
|
246
|
+
"position": {
|
|
247
|
+
"x": 220,
|
|
248
|
+
"y": 600
|
|
249
|
+
},
|
|
250
|
+
"data": {
|
|
251
|
+
"label": "Propose a grant_submission (via is-agent playbook — never auto-create)",
|
|
252
|
+
"playbookName": "Arch — Propose Grant Submission",
|
|
253
|
+
"paramsMapping": {
|
|
254
|
+
"subjectId": "{{trigger.payload.data.entityId}}",
|
|
255
|
+
"client": "{{trigger.payload.data.entityId}}",
|
|
256
|
+
"programName": "{{steps.assess.output.grantProgram}}",
|
|
257
|
+
"evidence": "{{steps.assess.output.grantEvidence}}"
|
|
258
|
+
},
|
|
259
|
+
"_note": "Why a PLAYBOOK, not an entity_create output node: automations SUPPRESS proposal persistence (dispatchViaCapabilityRouter sets suppressProposal:true) and an entity_create output auto-writes for an owner — neither can guarantee 'always propose, never auto-create'. An is-agent playbook runs in a proposal-persisting context, so its propose.entity (the `propose_grant_submission` skill) genuinely files a reviewable proposal even on the owner's pod. subjectId binds the session subject (executePlaybookRun reads entityId/subjectId); `client` fills the goal's {client}."
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
],
|
|
263
|
+
"edges": [
|
|
264
|
+
{
|
|
265
|
+
"id": "e-trigger-gate",
|
|
266
|
+
"source": "trigger",
|
|
267
|
+
"target": "matched-client-gate"
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
"id": "e-gate-gather",
|
|
271
|
+
"source": "matched-client-gate",
|
|
272
|
+
"target": "gather",
|
|
273
|
+
"sourceHandle": "yes"
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
"id": "e-gather-assess",
|
|
277
|
+
"source": "gather",
|
|
278
|
+
"target": "assess"
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
"id": "e-assess-enrich",
|
|
282
|
+
"source": "assess",
|
|
283
|
+
"target": "enrich-context"
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
"id": "e-assess-grantgate",
|
|
287
|
+
"source": "assess",
|
|
288
|
+
"target": "grant-gate"
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
"id": "e-grantgate-propose",
|
|
292
|
+
"source": "grant-gate",
|
|
293
|
+
"target": "propose-submission",
|
|
294
|
+
"sourceHandle": "yes"
|
|
295
|
+
}
|
|
296
|
+
]
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
"name": "Arch — Call Prep on New Booking",
|
|
301
|
+
"description": "EVENT-DRIVEN. When a new cal.com booking lands as an `event` entity (cal-com's cal_create_booking stamps properties.source:'cal.com'), read the event, gate to cal.com bookings only, and launch the 'Arch — Call Prep Brief' playbook to prep the upcoming call. Fires on every event.create but the source gate keeps the paid AI/playbook to cal.com bookings only (anti-over-automation). Seeded DRAFT — activate after a dogfood run.",
|
|
302
|
+
"triggerType": "event",
|
|
303
|
+
"triggerConfig": {
|
|
304
|
+
"eventPattern": "entity.create.completed",
|
|
305
|
+
"filters": {
|
|
306
|
+
"profileSlug": "event"
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
"status": "draft",
|
|
310
|
+
"metadata": {
|
|
311
|
+
"kind": "arch-call-prep",
|
|
312
|
+
"pairsWith": "cal-com"
|
|
313
|
+
},
|
|
314
|
+
"flowDefinition": {
|
|
315
|
+
"nodes": [
|
|
316
|
+
{
|
|
317
|
+
"id": "trigger",
|
|
318
|
+
"type": "trigger",
|
|
319
|
+
"position": {
|
|
320
|
+
"x": 0,
|
|
321
|
+
"y": 0
|
|
322
|
+
},
|
|
323
|
+
"data": {
|
|
324
|
+
"triggerType": "event",
|
|
325
|
+
"label": "New event entity created",
|
|
326
|
+
"config": {
|
|
327
|
+
"eventPattern": "entity.create.completed",
|
|
328
|
+
"filters": {
|
|
329
|
+
"profileSlug": "event"
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
"id": "read-event",
|
|
336
|
+
"type": "entity_read",
|
|
337
|
+
"position": {
|
|
338
|
+
"x": 0,
|
|
339
|
+
"y": 120
|
|
340
|
+
},
|
|
341
|
+
"data": {
|
|
342
|
+
"label": "Load the new event",
|
|
343
|
+
"entityId": "{{trigger.payload.subjectId}}",
|
|
344
|
+
"_note": "The entity.create.completed event data is only { profileSlug, title } — it does NOT carry properties. So `source` must be READ from the entity here; the gate below matches on this node's output, exactly like lead-conversion-enrollment reads the lead before switching on its source."
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
"id": "source-gate",
|
|
349
|
+
"type": "condition",
|
|
350
|
+
"position": {
|
|
351
|
+
"x": 0,
|
|
352
|
+
"y": 240
|
|
353
|
+
},
|
|
354
|
+
"data": {
|
|
355
|
+
"label": "Only cal.com bookings (skip plain calendar-sync events)",
|
|
356
|
+
"expression": "steps.read-event.output.entity.properties.source === \"cal.com\"",
|
|
357
|
+
"_note": "cal-com's cal_create_booking proposes the event with properties.source:'cal.com'. Bare-path + operator + quoted literal. Gating BEFORE the playbook keeps the paid AI/prep-brief to real bookings only — a plain calendar-sync event (no cal.com source) is skipped (anti-over-automation)."
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
"id": "prep",
|
|
362
|
+
"type": "playbook_run",
|
|
363
|
+
"position": {
|
|
364
|
+
"x": 0,
|
|
365
|
+
"y": 360
|
|
366
|
+
},
|
|
367
|
+
"data": {
|
|
368
|
+
"label": "Prep the upcoming call (is-agent playbook)",
|
|
369
|
+
"playbookName": "Arch — Call Prep Brief",
|
|
370
|
+
"paramsMapping": {
|
|
371
|
+
"subjectId": "{{trigger.payload.subjectId}}",
|
|
372
|
+
"booking": "{{trigger.payload.subjectId}}"
|
|
373
|
+
},
|
|
374
|
+
"_note": "subjectId binds the session subject (executePlaybookRun reads entityId/subjectId); `booking` fills the goal's {booking}. The playbook resolves the attendee → an existing client (identity resolution the agent has and a bare command node lacks), gathers context, and posts the brief to the TEAM channel (firewall)."
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
],
|
|
378
|
+
"edges": [
|
|
379
|
+
{
|
|
380
|
+
"id": "e-trigger-read",
|
|
381
|
+
"source": "trigger",
|
|
382
|
+
"target": "read-event"
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
"id": "e-read-gate",
|
|
386
|
+
"source": "read-event",
|
|
387
|
+
"target": "source-gate"
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
"id": "e-gate-prep",
|
|
391
|
+
"source": "source-gate",
|
|
392
|
+
"target": "prep",
|
|
393
|
+
"sourceHandle": "yes"
|
|
394
|
+
}
|
|
395
|
+
]
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
]
|
|
399
|
+
},
|
|
400
|
+
"dependencies": []
|
|
401
|
+
}
|