@hailer/mcp 1.1.11 → 1.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (252) hide show
  1. package/dist/app.js +18 -5
  2. package/dist/bot/bot-config.d.ts +12 -1
  3. package/dist/bot/bot-config.js +98 -14
  4. package/dist/bot/bot-manager.d.ts +13 -3
  5. package/dist/bot/bot-manager.js +80 -25
  6. package/dist/bot/bot.d.ts +46 -0
  7. package/dist/bot/bot.js +542 -166
  8. package/dist/bot/services/message-classifier.js +17 -0
  9. package/dist/bot/services/permission-guard.d.ts +52 -0
  10. package/dist/bot/services/permission-guard.js +149 -0
  11. package/dist/bot/services/types.d.ts +5 -0
  12. package/dist/bot/services/typing-indicator.d.ts +6 -1
  13. package/dist/bot/services/typing-indicator.js +19 -3
  14. package/dist/config.d.ts +6 -1
  15. package/dist/config.js +43 -0
  16. package/dist/core.js +3 -6
  17. package/dist/mcp/UserContextCache.d.ts +5 -0
  18. package/dist/mcp/UserContextCache.js +51 -19
  19. package/dist/mcp/hailer-clients.d.ts +19 -1
  20. package/dist/mcp/hailer-clients.js +157 -20
  21. package/dist/mcp/session-store.d.ts +68 -0
  22. package/dist/mcp/session-store.js +169 -0
  23. package/dist/mcp/signal-handler.js +12 -12
  24. package/dist/mcp/tool-registry.d.ts +17 -4
  25. package/dist/mcp/tool-registry.js +37 -7
  26. package/dist/mcp/tools/activity.js +99 -7
  27. package/dist/mcp/tools/app-scaffold.js +304 -336
  28. package/dist/mcp/tools/company.d.ts +9 -0
  29. package/dist/mcp/tools/company.js +88 -0
  30. package/dist/mcp/tools/discussion.js +68 -0
  31. package/dist/mcp/tools/workflow-permissions.d.ts +15 -0
  32. package/dist/mcp/tools/workflow-permissions.js +204 -0
  33. package/dist/mcp/tools/workflow.js +57 -18
  34. package/dist/mcp/utils/index.d.ts +2 -0
  35. package/dist/mcp/utils/index.js +12 -1
  36. package/dist/mcp/utils/role-utils.d.ts +74 -0
  37. package/dist/mcp/utils/role-utils.js +151 -0
  38. package/dist/mcp/utils/types.d.ts +43 -1
  39. package/dist/mcp/utils/types.js +14 -0
  40. package/dist/mcp/webhook-handler.d.ts +6 -0
  41. package/dist/mcp/webhook-handler.js +11 -0
  42. package/dist/mcp-server.d.ts +23 -2
  43. package/dist/mcp-server.js +639 -111
  44. package/dist/plugins/vipunen/client.d.ts +150 -0
  45. package/dist/plugins/vipunen/client.js +535 -0
  46. package/dist/plugins/vipunen/config/schema-config.json +19 -0
  47. package/dist/plugins/vipunen/config/schema-doc.json +22 -0
  48. package/dist/plugins/vipunen/index.d.ts +41 -0
  49. package/dist/plugins/vipunen/index.js +88 -0
  50. package/dist/plugins/vipunen/tools.d.ts +26 -0
  51. package/dist/plugins/vipunen/tools.js +501 -0
  52. package/package.json +2 -1
  53. package/.claude/.context-watchdog.json +0 -1
  54. package/.claude/.session-checked +0 -1
  55. package/.claude/CLAUDE.md +0 -370
  56. package/.claude/agents/agent-ada-skill-builder.md +0 -94
  57. package/.claude/agents/agent-alejandro-function-fields.md +0 -342
  58. package/.claude/agents/agent-bjorn-config-audit.md +0 -103
  59. package/.claude/agents/agent-builder-agent-creator.md +0 -130
  60. package/.claude/agents/agent-code-simplifier.md +0 -53
  61. package/.claude/agents/agent-dmitri-activity-crud.md +0 -159
  62. package/.claude/agents/agent-giuseppe-app-builder.md +0 -247
  63. package/.claude/agents/agent-gunther-mcp-tools.md +0 -39
  64. package/.claude/agents/agent-helga-workflow-config.md +0 -204
  65. package/.claude/agents/agent-igor-activity-mover-automation.md +0 -125
  66. package/.claude/agents/agent-ingrid-doc-templates.md +0 -261
  67. package/.claude/agents/agent-ivan-monolith.md +0 -154
  68. package/.claude/agents/agent-kenji-data-reader.md +0 -86
  69. package/.claude/agents/agent-lars-code-inspector.md +0 -102
  70. package/.claude/agents/agent-marco-mockup-builder.md +0 -110
  71. package/.claude/agents/agent-marcus-api-documenter.md +0 -323
  72. package/.claude/agents/agent-marketplace-publisher.md +0 -280
  73. package/.claude/agents/agent-marketplace-reviewer.md +0 -309
  74. package/.claude/agents/agent-permissions-handler.md +0 -208
  75. package/.claude/agents/agent-simple-writer.md +0 -48
  76. package/.claude/agents/agent-svetlana-code-review.md +0 -171
  77. package/.claude/agents/agent-tanya-test-runner.md +0 -333
  78. package/.claude/agents/agent-ui-designer.md +0 -100
  79. package/.claude/agents/agent-viktor-sql-insights.md +0 -212
  80. package/.claude/agents/agent-web-search.md +0 -55
  81. package/.claude/agents/agent-yevgeni-discussions.md +0 -45
  82. package/.claude/agents/agent-zara-zapier.md +0 -159
  83. package/.claude/commands/app-squad.md +0 -135
  84. package/.claude/commands/audit-squad.md +0 -158
  85. package/.claude/commands/autoplan.md +0 -563
  86. package/.claude/commands/cleanup-squad.md +0 -98
  87. package/.claude/commands/config-squad.md +0 -106
  88. package/.claude/commands/crud-squad.md +0 -87
  89. package/.claude/commands/data-squad.md +0 -97
  90. package/.claude/commands/debug-squad.md +0 -303
  91. package/.claude/commands/doc-squad.md +0 -65
  92. package/.claude/commands/handoff.md +0 -137
  93. package/.claude/commands/health.md +0 -49
  94. package/.claude/commands/help.md +0 -29
  95. package/.claude/commands/help:agents.md +0 -151
  96. package/.claude/commands/help:commands.md +0 -78
  97. package/.claude/commands/help:faq.md +0 -79
  98. package/.claude/commands/help:plugins.md +0 -50
  99. package/.claude/commands/help:skills.md +0 -93
  100. package/.claude/commands/help:tools.md +0 -75
  101. package/.claude/commands/hotfix-squad.md +0 -112
  102. package/.claude/commands/integration-squad.md +0 -82
  103. package/.claude/commands/janitor-squad.md +0 -167
  104. package/.claude/commands/learn-auto.md +0 -120
  105. package/.claude/commands/learn.md +0 -120
  106. package/.claude/commands/mcp-list.md +0 -27
  107. package/.claude/commands/onboard-squad.md +0 -140
  108. package/.claude/commands/plan-workspace.md +0 -732
  109. package/.claude/commands/prd.md +0 -130
  110. package/.claude/commands/project-status.md +0 -82
  111. package/.claude/commands/publish.md +0 -138
  112. package/.claude/commands/recap.md +0 -69
  113. package/.claude/commands/restore.md +0 -64
  114. package/.claude/commands/review-squad.md +0 -152
  115. package/.claude/commands/save.md +0 -24
  116. package/.claude/commands/stats.md +0 -19
  117. package/.claude/commands/swarm.md +0 -210
  118. package/.claude/commands/tool-builder.md +0 -39
  119. package/.claude/commands/ws-pull.md +0 -44
  120. package/.claude/hooks/_shared-memory.cjs +0 -305
  121. package/.claude/hooks/_utils.cjs +0 -108
  122. package/.claude/hooks/agent-failure-detector.cjs +0 -383
  123. package/.claude/hooks/agent-usage-logger.cjs +0 -204
  124. package/.claude/hooks/app-edit-guard.cjs +0 -494
  125. package/.claude/hooks/auto-learn.cjs +0 -304
  126. package/.claude/hooks/bash-guard.cjs +0 -272
  127. package/.claude/hooks/builder-mode-manager.cjs +0 -354
  128. package/.claude/hooks/bulk-activity-guard.cjs +0 -271
  129. package/.claude/hooks/context-watchdog.cjs +0 -230
  130. package/.claude/hooks/delegation-reminder.cjs +0 -465
  131. package/.claude/hooks/design-system-lint.cjs +0 -271
  132. package/.claude/hooks/post-scaffold-hook.cjs +0 -181
  133. package/.claude/hooks/prompt-guard.cjs +0 -354
  134. package/.claude/hooks/publish-template-guard.cjs +0 -147
  135. package/.claude/hooks/session-start.cjs +0 -35
  136. package/.claude/hooks/shared-memory-writer.cjs +0 -147
  137. package/.claude/hooks/skill-injector.cjs +0 -140
  138. package/.claude/hooks/skill-usage-logger.cjs +0 -258
  139. package/.claude/hooks/src-edit-guard.cjs +0 -240
  140. package/.claude/hooks/sync-marketplace-agents.cjs +0 -346
  141. package/.claude/settings.json +0 -257
  142. package/.claude/skills/SDK-activity-patterns/SKILL.md +0 -428
  143. package/.claude/skills/SDK-document-templates/SKILL.md +0 -1033
  144. package/.claude/skills/SDK-function-fields/SKILL.md +0 -542
  145. package/.claude/skills/SDK-generate-skill/SKILL.md +0 -92
  146. package/.claude/skills/SDK-init-skill/SKILL.md +0 -127
  147. package/.claude/skills/SDK-insight-queries/SKILL.md +0 -787
  148. package/.claude/skills/SDK-ws-config-skill/SKILL.md +0 -1139
  149. package/.claude/skills/agent-structure/SKILL.md +0 -98
  150. package/.claude/skills/api-documentation-patterns/SKILL.md +0 -474
  151. package/.claude/skills/chrome-mcp-reference/SKILL.md +0 -370
  152. package/.claude/skills/delegation-routing/SKILL.md +0 -202
  153. package/.claude/skills/frontend-design/SKILL.md +0 -254
  154. package/.claude/skills/hailer-activity-mover/SKILL.md +0 -213
  155. package/.claude/skills/hailer-api-client/SKILL.md +0 -518
  156. package/.claude/skills/hailer-app-builder/SKILL.md +0 -1434
  157. package/.claude/skills/hailer-apps-pictures/SKILL.md +0 -269
  158. package/.claude/skills/hailer-design-system/SKILL.md +0 -235
  159. package/.claude/skills/hailer-monolith-automations/SKILL.md +0 -686
  160. package/.claude/skills/hailer-permissions-system/SKILL.md +0 -121
  161. package/.claude/skills/hailer-project-protocol/SKILL.md +0 -488
  162. package/.claude/skills/hailer-rest-api/SKILL.md +0 -61
  163. package/.claude/skills/hailer-rest-api/hailer-activities.md +0 -184
  164. package/.claude/skills/hailer-rest-api/hailer-admin.md +0 -473
  165. package/.claude/skills/hailer-rest-api/hailer-calendar.md +0 -256
  166. package/.claude/skills/hailer-rest-api/hailer-feed.md +0 -249
  167. package/.claude/skills/hailer-rest-api/hailer-insights.md +0 -195
  168. package/.claude/skills/hailer-rest-api/hailer-messaging.md +0 -276
  169. package/.claude/skills/hailer-rest-api/hailer-workflows.md +0 -283
  170. package/.claude/skills/insight-join-patterns/SKILL.md +0 -174
  171. package/.claude/skills/integration-patterns/SKILL.md +0 -421
  172. package/.claude/skills/json-only-output/SKILL.md +0 -72
  173. package/.claude/skills/lsp-setup/SKILL.md +0 -160
  174. package/.claude/skills/mcp-direct-tools/SKILL.md +0 -153
  175. package/.claude/skills/optional-parameters/SKILL.md +0 -72
  176. package/.claude/skills/publish-hailer-app/SKILL.md +0 -244
  177. package/.claude/skills/testing-patterns/SKILL.md +0 -630
  178. package/.claude/skills/tool-builder/SKILL.md +0 -250
  179. package/.claude/skills/tool-parameter-usage/SKILL.md +0 -126
  180. package/.claude/skills/tool-response-verification/SKILL.md +0 -92
  181. package/.claude/skills/zapier-hailer-patterns/SKILL.md +0 -581
  182. package/.hailer-mcp-port +0 -1
  183. package/.mcp.json +0 -13
  184. package/.opencode/agent/agent-ada-skill-builder.md +0 -35
  185. package/.opencode/agent/agent-alejandro-function-fields.md +0 -39
  186. package/.opencode/agent/agent-bjorn-config-audit.md +0 -36
  187. package/.opencode/agent/agent-builder-agent-creator.md +0 -39
  188. package/.opencode/agent/agent-code-simplifier.md +0 -31
  189. package/.opencode/agent/agent-dmitri-activity-crud.md +0 -40
  190. package/.opencode/agent/agent-giuseppe-app-builder.md +0 -37
  191. package/.opencode/agent/agent-gunther-mcp-tools.md +0 -39
  192. package/.opencode/agent/agent-helga-workflow-config.md +0 -204
  193. package/.opencode/agent/agent-igor-activity-mover-automation.md +0 -46
  194. package/.opencode/agent/agent-ingrid-doc-templates.md +0 -39
  195. package/.opencode/agent/agent-ivan-monolith.md +0 -46
  196. package/.opencode/agent/agent-kenji-data-reader.md +0 -53
  197. package/.opencode/agent/agent-lars-code-inspector.md +0 -28
  198. package/.opencode/agent/agent-marco-mockup-builder.md +0 -42
  199. package/.opencode/agent/agent-marcus-api-documenter.md +0 -53
  200. package/.opencode/agent/agent-marketplace-publisher.md +0 -44
  201. package/.opencode/agent/agent-marketplace-reviewer.md +0 -42
  202. package/.opencode/agent/agent-permissions-handler.md +0 -50
  203. package/.opencode/agent/agent-simple-writer.md +0 -45
  204. package/.opencode/agent/agent-svetlana-code-review.md +0 -39
  205. package/.opencode/agent/agent-tanya-test-runner.md +0 -57
  206. package/.opencode/agent/agent-ui-designer.md +0 -56
  207. package/.opencode/agent/agent-viktor-sql-insights.md +0 -34
  208. package/.opencode/agent/agent-web-search.md +0 -42
  209. package/.opencode/agent/agent-yevgeni-discussions.md +0 -37
  210. package/.opencode/agent/agent-zara-zapier.md +0 -53
  211. package/.opencode/commands/app-squad.md +0 -135
  212. package/.opencode/commands/audit-squad.md +0 -158
  213. package/.opencode/commands/autoplan.md +0 -563
  214. package/.opencode/commands/cleanup-squad.md +0 -98
  215. package/.opencode/commands/config-squad.md +0 -106
  216. package/.opencode/commands/crud-squad.md +0 -87
  217. package/.opencode/commands/data-squad.md +0 -97
  218. package/.opencode/commands/debug-squad.md +0 -303
  219. package/.opencode/commands/doc-squad.md +0 -65
  220. package/.opencode/commands/handoff.md +0 -137
  221. package/.opencode/commands/health.md +0 -49
  222. package/.opencode/commands/help-agents.md +0 -151
  223. package/.opencode/commands/help-commands.md +0 -32
  224. package/.opencode/commands/help-faq.md +0 -29
  225. package/.opencode/commands/help-plugins.md +0 -28
  226. package/.opencode/commands/help-skills.md +0 -7
  227. package/.opencode/commands/help-tools.md +0 -40
  228. package/.opencode/commands/help.md +0 -28
  229. package/.opencode/commands/hotfix-squad.md +0 -112
  230. package/.opencode/commands/integration-squad.md +0 -82
  231. package/.opencode/commands/janitor-squad.md +0 -167
  232. package/.opencode/commands/learn-auto.md +0 -120
  233. package/.opencode/commands/learn.md +0 -120
  234. package/.opencode/commands/mcp-list.md +0 -27
  235. package/.opencode/commands/onboard-squad.md +0 -140
  236. package/.opencode/commands/plan-workspace.md +0 -732
  237. package/.opencode/commands/prd.md +0 -131
  238. package/.opencode/commands/project-status.md +0 -82
  239. package/.opencode/commands/publish.md +0 -138
  240. package/.opencode/commands/recap.md +0 -69
  241. package/.opencode/commands/restore.md +0 -64
  242. package/.opencode/commands/review-squad.md +0 -152
  243. package/.opencode/commands/save.md +0 -24
  244. package/.opencode/commands/stats.md +0 -19
  245. package/.opencode/commands/swarm.md +0 -210
  246. package/.opencode/commands/tool-builder.md +0 -39
  247. package/.opencode/commands/ws-pull.md +0 -44
  248. package/.opencode/opencode.json +0 -21
  249. package/inbox/failures.log +0 -1
  250. package/inbox/usage.jsonl +0 -4
  251. package/scripts/postinstall.cjs +0 -64
  252. package/scripts/test-hal-tools.ts +0 -154
@@ -1,174 +0,0 @@
1
- ---
2
- name: insight-join-patterns
3
- description: Correct JOIN syntax for Hailer insights with ActivityLink fields
4
- version: 1.0.0
5
- triggers: JOIN query errors, missing columns, NULL results in insight queries
6
- ---
7
-
8
- **Prerequisite:** Before using JOINs, review `SDK-insight-queries` skill for basic insight syntax and single-workflow queries.
9
-
10
- <problem>
11
- When joining workflows with ActivityLink fields in Hailer insights, you must:
12
- 1. Include `_id` meta field in BOTH source definitions
13
- 2. Join ON the activitylink field value equals target _id
14
- 3. Use the activitylink fieldId (NOT the key) for the JOIN condition
15
- </problem>
16
-
17
- <rules>
18
- - Both workflows need `{ name: 'id', meta: '_id' }` in their fields array
19
- - JOIN condition: `source1.activityLinkFieldName = source2.id`
20
- - Use LEFT JOIN for optional relationships (activitylink can be null)
21
- - Use INNER JOIN only when relationship must exist
22
- </rules>
23
-
24
- <correct>
25
- ```javascript
26
- // Players workflow has "club" field (activitylink to Clubs workflow)
27
- {
28
- sources: [
29
- {
30
- name: 'p',
31
- workflowId: '68446dc05b30685f67c6fcd4',
32
- fields: [
33
- { name: 'player_name', meta: 'name' },
34
- { name: 'id', meta: '_id' }, // Required!
35
- { name: 'club', fieldId: '684d5e45...' } // ActivityLink field
36
- ]
37
- },
38
- {
39
- name: 'c',
40
- workflowId: '691ea936ccb6bdeebc0cbf77',
41
- fields: [
42
- { name: 'club_name', meta: 'name' },
43
- { name: 'id', meta: '_id' } // Required!
44
- ]
45
- }
46
- ],
47
- query: 'SELECT p.player_name, c.club_name FROM p LEFT JOIN c ON p.club = c.id'
48
- }
49
- ```
50
- </correct>
51
-
52
- <wrong>
53
- ```javascript
54
- // ❌ WRONG - Missing _id in clubs source
55
- {
56
- sources: [
57
- {
58
- name: 'p',
59
- workflowId: 'players-id',
60
- fields: [
61
- { name: 'player_name', meta: 'name' },
62
- { name: 'id', meta: '_id' },
63
- { name: 'club', fieldId: 'club-field-id' }
64
- ]
65
- },
66
- {
67
- name: 'c',
68
- workflowId: 'clubs-id',
69
- fields: [
70
- { name: 'club_name', meta: 'name' }
71
- // Missing: { name: 'id', meta: '_id' }
72
- ]
73
- }
74
- ],
75
- query: 'SELECT p.player_name, c.club_name FROM p LEFT JOIN c ON p.club = c.id'
76
- }
77
- // Error: "no such column: c.id"
78
- ```
79
- </wrong>
80
-
81
- <examples>
82
- ### Three-Way JOIN (Tasks -> Topics -> Projects)
83
- ```javascript
84
- {
85
- sources: [
86
- {
87
- name: 't',
88
- workflowId: 'tasks-workflow-id',
89
- fields: [
90
- { name: 'task_name', meta: 'name' },
91
- { name: 'id', meta: '_id' },
92
- { name: 'topic', fieldId: 'topic-field-id' }
93
- ]
94
- },
95
- {
96
- name: 'top',
97
- workflowId: 'topics-workflow-id',
98
- fields: [
99
- { name: 'topic_name', meta: 'name' },
100
- { name: 'id', meta: '_id' },
101
- { name: 'project', fieldId: 'project-field-id' }
102
- ]
103
- },
104
- {
105
- name: 'p',
106
- workflowId: 'projects-workflow-id',
107
- fields: [
108
- { name: 'project_name', meta: 'name' },
109
- { name: 'id', meta: '_id' }
110
- ]
111
- }
112
- ],
113
- query: `
114
- SELECT t.task_name, top.topic_name, p.project_name
115
- FROM t
116
- LEFT JOIN top ON t.topic = top.id
117
- LEFT JOIN p ON top.project = p.id
118
- `
119
- }
120
- ```
121
-
122
- ### Aggregation with JOIN
123
- ```javascript
124
- {
125
- sources: [
126
- {
127
- name: 'matches',
128
- workflowId: 'matches-workflow-id',
129
- fields: [
130
- { name: 'match_date', fieldId: 'date-field-id' },
131
- { name: 'id', meta: '_id' },
132
- { name: 'home_team', fieldId: 'home-team-field-id' }
133
- ]
134
- },
135
- {
136
- name: 'teams',
137
- workflowId: 'teams-workflow-id',
138
- fields: [
139
- { name: 'team_name', meta: 'name' },
140
- { name: 'id', meta: '_id' }
141
- ]
142
- }
143
- ],
144
- query: `
145
- SELECT teams.team_name, COUNT(*) as match_count
146
- FROM matches
147
- LEFT JOIN teams ON matches.home_team = teams.id
148
- GROUP BY teams.team_name
149
- `
150
- }
151
- ```
152
- </examples>
153
-
154
- <troubleshooting>
155
- **Error: "no such column: c.id"**
156
- - Missing `{ name: 'id', meta: '_id' }` in target workflow source
157
-
158
- **Error: "no such column: p.club"**
159
- - ActivityLink field not included in source fields array
160
- - Check you used correct fieldId from `get_workflow_schema`
161
-
162
- **NULL results for joined data**
163
- - ActivityLink field is empty/null for some activities (expected with LEFT JOIN)
164
- - Use INNER JOIN if you only want activities with relationships
165
- </troubleshooting>
166
-
167
- <checklist>
168
- Before creating an insight with JOINs:
169
- - [ ] Both workflow sources include `{ name: 'id', meta: '_id' }`
170
- - [ ] ActivityLink field uses `fieldId` (NOT `key`)
171
- - [ ] JOIN condition uses column names from sources (e.g., `p.club = c.id`)
172
- - [ ] Using LEFT JOIN (unless relationship required)
173
- - [ ] Tested with `preview_insight` first
174
- </checklist>
@@ -1,421 +0,0 @@
1
- ---
2
- name: integration-patterns
3
- description: Hailer integration microservice patterns - activity movers, webhooks, SCIM, Kafka consumers
4
- version: 1.0.0
5
- triggers: Build integration, activity mover, webhook handler, SCIM endpoint, Kafka consumer
6
- ---
7
-
8
- # Integration Patterns
9
-
10
- ## Architecture Overview
11
-
12
- ```
13
- ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
14
- │ External │ │ Integration │ │ Hailer API │
15
- │ System │────▶│ Service │────▶│ │
16
- │ (Kafka/HTTP) │ │ (Node.js) │ │ (WebSocket) │
17
- └─────────────────┘ └─────────────────┘ └─────────────────┘
18
-
19
-
20
- ┌─────────────────┐
21
- │ Logging & │
22
- │ Monitoring │
23
- └─────────────────┘
24
- ```
25
-
26
- ---
27
-
28
- ## 1. Activity Mover Pattern
29
-
30
- Monitors activities and moves linked activities when triggers fire.
31
-
32
- ### Configuration Structure
33
-
34
- ```typescript
35
- interface ActivityMoverConfig {
36
- logDiscussionId: string; // Discussion for audit logging
37
- email: string; // Integration user email
38
- password: string; // Or "ENV:HAILER_PASSWORD"
39
- project: string; // Project identifier
40
- triggers: Trigger[];
41
- }
42
-
43
- interface Trigger {
44
- processId: string; // Source workflow ID
45
- phaseId: string; // Phase that triggers action
46
- metaDataId: string; // Hidden field for tracking ("Seen"/"Not seen")
47
- linkedProcesses: LinkedProcess[];
48
- }
49
-
50
- interface LinkedProcess {
51
- processId: string; // Target workflow ID
52
- sourcePhases: string[]; // Move FROM these phases
53
- targetPhase: string; // Move TO this phase
54
- }
55
- ```
56
-
57
- ### Example Config
58
-
59
- ```json
60
- {
61
- "logDiscussionId": "694c9536acfa30f6df13201b",
62
- "email": "integration@workspace.com",
63
- "password": "ENV:HAILER_PASSWORD",
64
- "project": "orders-sync",
65
- "triggers": [
66
- {
67
- "processId": "67dc1b7d3d2c9f6cf9a5468d",
68
- "phaseId": "67dc1b7d3d2c9f6cf9a546c4",
69
- "metaDataId": "67e697da6ada809b961c35b5",
70
- "linkedProcesses": [
71
- {
72
- "processId": "67dc1b7d3d2c9f6cf9a54690",
73
- "sourcePhases": ["67dc1b7d3d2c9f6cf9a54691", "67dc1b7d3d2c9f6cf9a54692"],
74
- "targetPhase": "67dc1b7d3d2c9f6cf9a54695"
75
- }
76
- ]
77
- }
78
- ]
79
- }
80
- ```
81
-
82
- ### Hailer Setup Requirements
83
-
84
- 1. **Metadata field** on trigger workflow:
85
- - Type: TEXT (hidden)
86
- - Default value: "Not seen"
87
- - Used to track processed activities
88
-
89
- 2. **Link field** connecting workflows:
90
- - Activity link from trigger workflow to target workflow
91
-
92
- 3. **Integration user**:
93
- - Dedicated user account
94
- - Edit permissions on both workflows
95
-
96
- 4. **Discussion activity**:
97
- - For audit logging
98
- - Integration user must have access
99
-
100
- ### Core Logic
101
-
102
- ```typescript
103
- // Listen for activity updates
104
- client.on('activities.updated', async (data) => {
105
- for (const trigger of config.triggers) {
106
- if (data.processId === trigger.processId && data.phaseId === trigger.phaseId) {
107
- await processTrigger(data.activityId, trigger);
108
- }
109
- }
110
- });
111
-
112
- async function processTrigger(activityId: string, trigger: Trigger) {
113
- // Check if already processed
114
- const activity = await client.request('v3.activity.get', [activityId]);
115
- if (activity.fields[trigger.metaDataId]?.value === 'Seen') return;
116
-
117
- // Get linked activities
118
- const linked = await client.request('v3.activity.linkedFrom.overview', [activityId]);
119
-
120
- // Move matching activities
121
- for (const process of trigger.linkedProcesses) {
122
- const toMove = linked.filter(a =>
123
- a.processId === process.processId &&
124
- process.sourcePhases.includes(a.phaseId)
125
- );
126
-
127
- if (toMove.length > 0) {
128
- await client.request('v3.activity.updateMany', [
129
- toMove.map(a => a._id),
130
- { phaseId: process.targetPhase }
131
- ]);
132
- }
133
- }
134
-
135
- // Mark as processed
136
- await client.request('v3.activity.update', [activityId, {
137
- fields: { [trigger.metaDataId]: 'Seen' }
138
- }]);
139
- }
140
- ```
141
-
142
- ---
143
-
144
- ## 2. Webhook Handler Pattern
145
-
146
- HTTP endpoints that trigger Hailer operations.
147
-
148
- ### Express Setup
149
-
150
- ```typescript
151
- import express from 'express';
152
- import crypto from 'crypto';
153
-
154
- const app = express();
155
- app.use(express.json());
156
-
157
- // Webhook signature validation
158
- function validateSignature(req: express.Request, secret: string): boolean {
159
- const signature = req.headers['x-webhook-signature'];
160
- const payload = JSON.stringify(req.body);
161
- const expected = crypto.createHmac('sha256', secret).update(payload).digest('hex');
162
- return signature === expected;
163
- }
164
-
165
- // Webhook endpoint
166
- app.post('/api/v1/webhook/:type', async (req, res) => {
167
- const { type } = req.params;
168
-
169
- if (!validateSignature(req, config.webhookSecret)) {
170
- return res.status(401).json({ error: 'Invalid signature' });
171
- }
172
-
173
- try {
174
- switch (type) {
175
- case 'order.created':
176
- await handleOrderCreated(req.body);
177
- break;
178
- case 'order.updated':
179
- await handleOrderUpdated(req.body);
180
- break;
181
- default:
182
- logger.warn({ type }, 'Unknown webhook type');
183
- }
184
- res.json({ status: 'ok' });
185
- } catch (error) {
186
- logger.error({ error, type }, 'Webhook processing failed');
187
- res.status(500).json({ error: 'Processing failed' });
188
- }
189
- });
190
- ```
191
-
192
- ### Webhook Handler Example
193
-
194
- ```typescript
195
- async function handleOrderCreated(payload: OrderPayload) {
196
- // Map external data to Hailer fields
197
- const fields = {
198
- [FieldIds.external_id]: payload.orderId,
199
- [FieldIds.customer_name]: payload.customer.name,
200
- [FieldIds.total_amount]: payload.total,
201
- [FieldIds.order_date]: new Date(payload.createdAt).getTime()
202
- };
203
-
204
- // Create activity in Hailer
205
- const result = await hailerClient.createActivity(
206
- WorkflowIds.orders,
207
- PhaseIds.new,
208
- fields
209
- );
210
-
211
- logger.info({ orderId: payload.orderId, activityId: result._id }, 'Order created in Hailer');
212
- }
213
- ```
214
-
215
- ---
216
-
217
- ## 3. SCIM 2.0 Pattern
218
-
219
- User provisioning from identity providers (Microsoft Entra, Okta).
220
-
221
- ### Endpoints
222
-
223
- | Method | Path | Description |
224
- |--------|------|-------------|
225
- | POST | /scim/v2/Users | Create user |
226
- | GET | /scim/v2/Users/:id | Get user |
227
- | PATCH | /scim/v2/Users/:id | Update user |
228
- | DELETE | /scim/v2/Users/:id | Deactivate user |
229
- | GET | /scim/v2/Users | List/filter users |
230
-
231
- ### User Mapping
232
-
233
- ```typescript
234
- interface ScimUser {
235
- schemas: string[];
236
- userName: string;
237
- name: { givenName: string; familyName: string };
238
- emails: { value: string; primary: boolean }[];
239
- active: boolean;
240
- roles?: { value: string }[];
241
- }
242
-
243
- function mapScimToHailer(scim: ScimUser): HailerUserPayload {
244
- return {
245
- email: scim.emails.find(e => e.primary)?.value || scim.userName,
246
- firstName: scim.name.givenName,
247
- lastName: scim.name.familyName,
248
- active: scim.active,
249
- teams: mapRolesToTeams(scim.roles)
250
- };
251
- }
252
-
253
- function mapRolesToTeams(roles?: { value: string }[]): string[] {
254
- const teamMapping: Record<string, string> = {
255
- 'admin': TeamIds.admins,
256
- 'manager': TeamIds.managers,
257
- 'user': TeamIds.users
258
- };
259
- return (roles || [])
260
- .map(r => teamMapping[r.value])
261
- .filter(Boolean);
262
- }
263
- ```
264
-
265
- ### SCIM Response Format
266
-
267
- ```typescript
268
- function toScimUser(hailerUser: HailerUser, baseUrl: string): ScimUser {
269
- return {
270
- schemas: ['urn:ietf:params:scim:schemas:core:2.0:User'],
271
- id: hailerUser._id,
272
- userName: hailerUser.email,
273
- name: {
274
- givenName: hailerUser.firstName,
275
- familyName: hailerUser.lastName
276
- },
277
- emails: [{ value: hailerUser.email, primary: true }],
278
- active: hailerUser.active,
279
- meta: {
280
- resourceType: 'User',
281
- location: `${baseUrl}/scim/v2/Users/${hailerUser._id}`
282
- }
283
- };
284
- }
285
- ```
286
-
287
- ---
288
-
289
- ## 4. Kafka Consumer Pattern
290
-
291
- Event-driven processing from message queues.
292
-
293
- ### Consumer Setup
294
-
295
- ```typescript
296
- import { Kafka, Consumer, EachMessagePayload } from 'kafkajs';
297
-
298
- const kafka = new Kafka({
299
- clientId: 'hailer-integration',
300
- brokers: config.kafkaBrokers,
301
- ssl: {
302
- ca: [fs.readFileSync(config.caCertPath)],
303
- key: fs.readFileSync(config.keyPath),
304
- cert: fs.readFileSync(config.certPath)
305
- }
306
- });
307
-
308
- const consumer = kafka.consumer({ groupId: 'hailer-consumer-group' });
309
-
310
- async function startConsumer() {
311
- await consumer.connect();
312
- await consumer.subscribe({ topic: 'events', fromBeginning: false });
313
-
314
- await consumer.run({
315
- eachMessage: async ({ topic, partition, message }: EachMessagePayload) => {
316
- const event = JSON.parse(message.value.toString());
317
-
318
- try {
319
- await processEvent(event);
320
- logger.info({ eventId: event.id, offset: message.offset }, 'Event processed');
321
- } catch (error) {
322
- logger.error({ error, event }, 'Event processing failed');
323
- await sendToDeadLetterQueue(message);
324
- }
325
- }
326
- });
327
- }
328
- ```
329
-
330
- ### Event Processing
331
-
332
- ```typescript
333
- async function processEvent(event: ExternalEvent) {
334
- switch (event.type) {
335
- case 'student.created':
336
- await createStudent(event.data);
337
- break;
338
- case 'student.updated':
339
- await updateStudent(event.data);
340
- break;
341
- case 'student.deleted':
342
- await deactivateStudent(event.data);
343
- break;
344
- default:
345
- logger.warn({ eventType: event.type }, 'Unknown event type');
346
- }
347
- }
348
- ```
349
-
350
- ---
351
-
352
- ## Common Patterns
353
-
354
- ### Retry with Exponential Backoff
355
-
356
- ```typescript
357
- async function withRetry<T>(
358
- fn: () => Promise<T>,
359
- maxRetries: number = 3,
360
- baseDelay: number = 1000
361
- ): Promise<T> {
362
- let lastError: Error;
363
-
364
- for (let i = 0; i < maxRetries; i++) {
365
- try {
366
- return await fn();
367
- } catch (error) {
368
- lastError = error;
369
- const delay = baseDelay * Math.pow(2, i);
370
- logger.warn({ attempt: i + 1, delay, error: error.message }, 'Retrying...');
371
- await sleep(delay);
372
- }
373
- }
374
-
375
- throw lastError;
376
- }
377
- ```
378
-
379
- ### Graceful Shutdown
380
-
381
- ```typescript
382
- async function gracefulShutdown(signal: string) {
383
- logger.info({ signal }, 'Shutdown signal received');
384
-
385
- // Stop accepting new requests
386
- server.close();
387
-
388
- // Disconnect from Hailer
389
- await hailerClient.disconnect();
390
-
391
- // Disconnect from Kafka
392
- await consumer.disconnect();
393
-
394
- logger.info('Graceful shutdown complete');
395
- process.exit(0);
396
- }
397
-
398
- process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
399
- process.on('SIGINT', () => gracefulShutdown('SIGINT'));
400
- ```
401
-
402
- ### Health Check
403
-
404
- ```typescript
405
- app.get('/api/v1/health', async (req, res) => {
406
- const checks = {
407
- hailer: await checkHailerConnection(),
408
- kafka: await checkKafkaConnection(),
409
- uptime: process.uptime(),
410
- memory: process.memoryUsage(),
411
- lastActivity: lastActivityTimestamp
412
- };
413
-
414
- const healthy = checks.hailer.connected && checks.kafka.connected;
415
- res.status(healthy ? 200 : 503).json({
416
- status: healthy ? 'healthy' : 'unhealthy',
417
- timestamp: new Date().toISOString(),
418
- checks
419
- });
420
- });
421
- ```
@@ -1,72 +0,0 @@
1
- ---
2
- name: json-only-output
3
- description: Fix agents adding prose after JSON responses
4
- version: 1.0.1
5
- triggers: Agent outputs explanation text after valid JSON
6
- ---
7
-
8
- # JSON Only Output
9
-
10
- <purpose>
11
- Ensure agents output ONLY valid JSON with no prose, explanations, or commentary after the closing brace.
12
- </purpose>
13
-
14
- <why-this-happens>
15
- ## Why Agents Add Prose
16
-
17
- LLMs have a natural tendency to be helpful and explanatory. After completing a task, they want to:
18
- - Explain what they did
19
- - Suggest next steps
20
- - Provide context
21
- - Confirm their understanding
22
-
23
- This is normally good behavior, but for **subagents** returning structured data to an orchestrator, it breaks JSON parsing.
24
-
25
- **The `<protocol>` section isn't enough** because:
26
- - LLMs treat protocol as "guidelines" not hard rules
27
- - The helpful instinct overrides weak instructions
28
- - Protocol is at the end of the prompt, less salient
29
-
30
- **Why identity/rules work:**
31
- - `<identity>` shapes the agent's core persona ("I output JSON. Full stop.")
32
- - `<rules>` are processed as constraints, not suggestions
33
- - Positioned early in prompt, higher salience
34
- - Explicit prohibition is stronger than implicit expectation
35
- </why-this-happens>
36
-
37
- <patterns>
38
- ## Pattern 1: Stop at the Closing Brace
39
-
40
- Output JSON. Full stop. Nothing after the closing brace.
41
-
42
- ## Pattern 2: Agent Configuration Fix
43
-
44
- 1. Add to `<identity>`: "Output JSON. Full stop."
45
- 2. Add to `<rules>`: **JSON ONLY** - Output closing brace, then STOP. Zero prose after JSON.
46
- 3. Protocol section is NOT enough - agents ignore it without identity/rules reinforcement.
47
-
48
- ## Pattern 3: Include Summary Inside JSON
49
-
50
- If context is helpful, include it IN the JSON `summary` field, not after the JSON.
51
- </patterns>
52
-
53
- <examples>
54
- ## Example 1: Correct - Pure JSON Output
55
-
56
- ```json
57
- {"status":"success","result":{"fields":["taskName","priority"]},"summary":"Read 2 fields"}
58
- ```
59
- **STOP HERE. Nothing after closing brace.**
60
-
61
- ## Example 2: Wrong - Prose After JSON
62
-
63
- ```json
64
- {"status":"success","result":{"fields":["taskName","priority"]},"summary":"Read 2 fields"}
65
- ```
66
-
67
- The workflow has 2 fields defined in workspace/Tasks_123/fields.ts. You can now use these field IDs with dmitri for activity creation.
68
-
69
- **Action Required**: Run `npm run pull` to refresh.
70
-
71
- This violates JSON-only protocol by adding explanation text AFTER the valid JSON response.
72
- </examples>