@vellumai/assistant 0.4.29 → 0.4.30

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 (174) hide show
  1. package/ARCHITECTURE.md +39 -37
  2. package/README.md +5 -6
  3. package/docs/runbook-trusted-contacts.md +79 -43
  4. package/package.json +1 -1
  5. package/scripts/ipc/check-swift-decoder-drift.ts +2 -3
  6. package/scripts/test.sh +1 -1
  7. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +4 -37
  8. package/src/__tests__/actor-token-service.test.ts +4 -3
  9. package/src/__tests__/app-executors.test.ts +7 -17
  10. package/src/__tests__/assistant-feature-flags-integration.test.ts +18 -10
  11. package/src/__tests__/browser-skill-endstate.test.ts +10 -1
  12. package/src/__tests__/bundled-skill-retrieval-guard.test.ts +1 -0
  13. package/src/__tests__/channel-approval-routes.test.ts +44 -44
  14. package/src/__tests__/channel-approval.test.ts +8 -0
  15. package/src/__tests__/channel-approvals.test.ts +39 -1
  16. package/src/__tests__/channel-guardian.test.ts +15 -5
  17. package/src/__tests__/channel-reply-delivery.test.ts +31 -0
  18. package/src/__tests__/commit-message-enrichment-service.test.ts +4 -0
  19. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +9 -0
  20. package/src/__tests__/gateway-only-guard.test.ts +1 -0
  21. package/src/__tests__/gemini-image-service.test.ts +2 -2
  22. package/src/__tests__/guardian-grant-minting.test.ts +6 -6
  23. package/src/__tests__/guardian-routing-invariants.test.ts +34 -11
  24. package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +4 -6
  25. package/src/__tests__/inbound-invite-redemption.test.ts +1 -1
  26. package/src/__tests__/integrations-cli.test.ts +3 -27
  27. package/src/__tests__/intent-routing.test.ts +3 -0
  28. package/src/__tests__/invite-redemption-service.test.ts +1 -1
  29. package/src/__tests__/{ingress-routes-http.test.ts → invite-routes-http.test.ts} +40 -320
  30. package/src/__tests__/ipc-snapshot.test.ts +4 -31
  31. package/src/__tests__/nl-approval-parser.test.ts +305 -0
  32. package/src/__tests__/oauth-provider-profiles.test.ts +34 -0
  33. package/src/__tests__/provider-error-scenarios.test.ts +68 -0
  34. package/src/__tests__/relay-server.test.ts +1 -1
  35. package/src/__tests__/retry-after-extraction.test.ts +111 -0
  36. package/src/__tests__/script-proxy-profile-template-fallback.test.ts +127 -0
  37. package/src/__tests__/session-media-retry.test.ts +147 -0
  38. package/src/__tests__/skill-feature-flags-integration.test.ts +9 -5
  39. package/src/__tests__/skill-feature-flags.test.ts +18 -12
  40. package/src/__tests__/skill-load-feature-flag.test.ts +4 -3
  41. package/src/__tests__/slack-block-formatting.test.ts +100 -0
  42. package/src/__tests__/slack-inbound-verification.test.ts +346 -0
  43. package/src/__tests__/slack-reaction-approvals.test.ts +77 -0
  44. package/src/__tests__/slack-skill.test.ts +3 -2
  45. package/src/__tests__/starter-task-flow.test.ts +0 -1
  46. package/src/__tests__/trusted-contact-verification.test.ts +3 -1
  47. package/src/__tests__/voice-invite-redemption.test.ts +1 -1
  48. package/src/amazon/client.ts +7 -24
  49. package/src/calls/relay-server.ts +39 -11
  50. package/src/channels/config.ts +1 -1
  51. package/src/cli/integrations.ts +10 -66
  52. package/src/config/bundled-skills/app-builder/SKILL.md +193 -1500
  53. package/src/config/bundled-skills/app-builder/TOOLS.json +70 -18
  54. package/src/config/bundled-skills/browser/TOOLS.json +59 -2
  55. package/src/config/bundled-skills/chatgpt-import/TOOLS.json +4 -0
  56. package/src/config/bundled-skills/computer-use/TOOLS.json +50 -2
  57. package/src/config/bundled-skills/contacts/SKILL.md +42 -35
  58. package/src/config/bundled-skills/contacts/TOOLS.json +22 -2
  59. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +38 -58
  60. package/src/config/bundled-skills/contacts/tools/contact-search.ts +11 -31
  61. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +19 -37
  62. package/src/config/bundled-skills/document/TOOLS.json +8 -0
  63. package/src/config/bundled-skills/email-setup/SKILL.md +10 -7
  64. package/src/config/bundled-skills/followups/TOOLS.json +12 -0
  65. package/src/config/bundled-skills/google-calendar/TOOLS.json +124 -26
  66. package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +54 -21
  67. package/src/config/bundled-skills/image-studio/TOOLS.json +12 -2
  68. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +14 -8
  69. package/src/config/bundled-skills/knowledge-graph/TOOLS.json +13 -3
  70. package/src/config/bundled-skills/media-processing/SKILL.md +1 -1
  71. package/src/config/bundled-skills/media-processing/TOOLS.json +28 -0
  72. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +26 -6
  73. package/src/config/bundled-skills/messaging/TOOLS.json +228 -182
  74. package/src/config/bundled-skills/notifications/SKILL.md +3 -2
  75. package/src/config/bundled-skills/notifications/TOOLS.json +7 -13
  76. package/src/config/bundled-skills/phone-calls/TOOLS.json +13 -1
  77. package/src/config/bundled-skills/playbooks/TOOLS.json +16 -0
  78. package/src/config/bundled-skills/reminder/TOOLS.json +15 -2
  79. package/src/config/bundled-skills/schedule/SKILL.md +33 -15
  80. package/src/config/bundled-skills/schedule/TOOLS.json +17 -1
  81. package/src/config/bundled-skills/slack/SKILL.md +30 -1
  82. package/src/config/bundled-skills/slack/TOOLS.json +89 -2
  83. package/src/config/bundled-skills/slack/tools/slack-channel-permissions.ts +146 -0
  84. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +120 -0
  85. package/src/config/bundled-skills/slack-app-setup/SKILL.md +200 -0
  86. package/src/config/bundled-skills/subagent/TOOLS.json +22 -2
  87. package/src/config/bundled-skills/tasks/TOOLS.json +86 -14
  88. package/src/config/bundled-skills/transcribe/TOOLS.json +4 -0
  89. package/src/config/bundled-skills/watcher/TOOLS.json +20 -0
  90. package/src/config/bundled-skills/weather/TOOLS.json +4 -0
  91. package/src/config/bundled-tool-registry.ts +2 -0
  92. package/src/config/channel-permission-profiles.ts +155 -0
  93. package/src/config/env.ts +4 -1
  94. package/src/contacts/contact-store.ts +195 -4
  95. package/src/contacts/types.ts +26 -0
  96. package/src/daemon/assistant-attachments.ts +23 -3
  97. package/src/daemon/guardian-verification-intent.ts +7 -4
  98. package/src/daemon/handlers/apps.ts +1 -2
  99. package/src/daemon/handlers/config-inbox.ts +16 -134
  100. package/src/daemon/handlers/guardian-actions.ts +20 -87
  101. package/src/daemon/handlers/sessions.ts +0 -1
  102. package/src/daemon/ipc-contract/apps.ts +0 -1
  103. package/src/daemon/ipc-contract/inbox.ts +7 -66
  104. package/src/daemon/ipc-contract/sessions.ts +1 -0
  105. package/src/daemon/ipc-contract/surfaces.ts +0 -1
  106. package/src/daemon/ipc-contract-inventory.json +2 -4
  107. package/src/daemon/lifecycle.ts +14 -2
  108. package/src/daemon/session-agent-loop-handlers.ts +9 -0
  109. package/src/daemon/session-agent-loop.ts +1 -0
  110. package/src/daemon/session-attachments.ts +5 -1
  111. package/src/daemon/session-error.ts +18 -0
  112. package/src/daemon/session-lifecycle.ts +4 -5
  113. package/src/daemon/session-media-retry.ts +15 -1
  114. package/src/daemon/session-surfaces.ts +0 -1
  115. package/src/daemon/session-tool-setup.ts +7 -4
  116. package/src/events/domain-events.ts +2 -1
  117. package/src/home-base/prebuilt/seed.ts +0 -1
  118. package/src/influencer/client.ts +7 -24
  119. package/src/media/gemini-image-service.ts +48 -3
  120. package/src/memory/app-store.ts +0 -4
  121. package/src/memory/conversation-attention-store.ts +3 -1
  122. package/src/memory/db-init.ts +4 -0
  123. package/src/memory/migrations/133-assistant-contact-metadata.ts +21 -0
  124. package/src/memory/migrations/index.ts +1 -0
  125. package/src/memory/schema.ts +12 -0
  126. package/src/memory/slack-thread-store.ts +187 -0
  127. package/src/messaging/providers/slack/client.ts +84 -26
  128. package/src/messaging/providers/slack/types.ts +4 -0
  129. package/src/notifications/adapters/slack.ts +90 -0
  130. package/src/notifications/destination-resolver.ts +42 -1
  131. package/src/notifications/emit-signal.ts +17 -1
  132. package/src/oauth/provider-profiles.ts +22 -0
  133. package/src/providers/anthropic/client.ts +3 -0
  134. package/src/providers/openai/client.ts +3 -0
  135. package/src/providers/retry.ts +9 -1
  136. package/src/runtime/actor-trust-resolver.ts +8 -0
  137. package/src/runtime/auth/require-bound-guardian.ts +44 -0
  138. package/src/runtime/auth/route-policy.ts +4 -8
  139. package/src/runtime/channel-approval-types.ts +18 -0
  140. package/src/runtime/channel-approvals.ts +8 -0
  141. package/src/runtime/channel-invite-transport.ts +1 -1
  142. package/src/runtime/channel-reply-delivery.ts +62 -3
  143. package/src/runtime/gateway-client.ts +36 -2
  144. package/src/runtime/gateway-internal-client.ts +86 -0
  145. package/src/runtime/guardian-action-service.ts +127 -0
  146. package/src/runtime/guardian-verification-templates.ts +16 -1
  147. package/src/runtime/http-server.ts +20 -49
  148. package/src/runtime/invite-redemption-service.ts +1 -1
  149. package/src/runtime/{ingress-service.ts → invite-service.ts} +5 -157
  150. package/src/runtime/nl-approval-parser.ts +138 -0
  151. package/src/runtime/routes/approval-routes.ts +1 -40
  152. package/src/runtime/routes/channel-route-shared.ts +35 -1
  153. package/src/runtime/routes/contact-routes.ts +196 -28
  154. package/src/runtime/routes/guardian-action-routes.ts +19 -111
  155. package/src/runtime/routes/guardian-approval-interception.ts +76 -0
  156. package/src/runtime/routes/inbound-message-handler.ts +40 -12
  157. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +222 -0
  158. package/src/runtime/routes/inbound-stages/background-dispatch.ts +108 -0
  159. package/src/runtime/routes/{ingress-routes.ts → invite-routes.ts} +10 -110
  160. package/src/runtime/slack-block-formatting.ts +176 -0
  161. package/src/schedule/scheduler.ts +11 -2
  162. package/src/tools/apps/executors.ts +16 -15
  163. package/src/tools/calls/call-end.ts +1 -1
  164. package/src/tools/computer-use/definitions.ts +16 -0
  165. package/src/tools/credentials/vault.ts +86 -2
  166. package/src/tools/network/script-proxy/session-manager.ts +28 -3
  167. package/src/tools/permission-checker.ts +18 -0
  168. package/src/tools/terminal/shell.ts +15 -5
  169. package/src/tools/tool-approval-handler.ts +48 -4
  170. package/src/tools/types.ts +38 -1
  171. package/src/util/errors.ts +5 -1
  172. package/src/util/retry.ts +21 -0
  173. package/src/watcher/providers/slack.ts +33 -3
  174. /package/src/memory/{ingress-invite-store.ts → invite-store.ts} +0 -0
@@ -2,7 +2,7 @@
2
2
  name: "Notifications"
3
3
  description: "Send notifications through the unified notification router"
4
4
  user-invocable: true
5
- metadata: {"vellum": {"emoji": "\ud83d\udd14"}}
5
+ metadata: { "vellum": { "emoji": "\ud83d\udd14" } }
6
6
  ---
7
7
 
8
8
  Use `send_notification` for user-facing alerts and notifications. This tool routes through the unified notification pipeline, which handles channel selection, delivery, deduplication, and audit logging.
@@ -27,10 +27,11 @@ Thread grouping is handled by the LLM-powered decision engine, not by any parame
27
27
  **`source_event_name` is the primary grouping signal.** Use a stable event name for notifications that belong to the same logical stream (e.g. `dog.news.thread.reply` for all replies in a thread). Use a distinct event name when the notification represents a genuinely different kind of event.
28
28
 
29
29
  **Practical constraints:**
30
+
30
31
  - Thread candidates are scoped to the **last 24 hours** (max 5 per channel). You cannot reuse an old thread from days ago.
31
32
  - The engine will only reuse conversations originally created by the notification system (`source === 'notification'`). It will never append to a user-initiated conversation, even if it looks related.
32
33
 
33
34
  ## Important
34
35
 
35
36
  - Do **NOT** use AppleScript `display notification` or other OS-level notification commands for assistant-managed alerts. Always use `send_notification`.
36
- - For sending messages into a specific chat, email, or SMS destination, use the messaging skill's `messaging_send` instead.
37
+ - For sending rich content (digests, summaries, reports) to a specific chat, email, or SMS destination, use the messaging skill's `messaging_send` instead. The decision engine rewrites `send_notification` content into short alerts, which strips rich formatting.
@@ -19,11 +19,7 @@
19
19
  },
20
20
  "urgency": {
21
21
  "type": "string",
22
- "enum": [
23
- "low",
24
- "medium",
25
- "high"
26
- ],
22
+ "enum": ["low", "medium", "high"],
27
23
  "description": "Urgency hint (default: \"medium\")"
28
24
  },
29
25
  "requires_action": {
@@ -46,10 +42,7 @@
46
42
  "type": "array",
47
43
  "items": {
48
44
  "type": "string",
49
- "enum": [
50
- "vellum",
51
- "telegram"
52
- ]
45
+ "enum": ["vellum", "telegram", "slack"]
53
46
  },
54
47
  "description": "Optional routing hints for preferred channels (not deterministic)"
55
48
  },
@@ -72,12 +65,13 @@
72
65
  "confidence": {
73
66
  "type": "number",
74
67
  "description": "Confidence score (0-1) for this action"
68
+ },
69
+ "reason": {
70
+ "type": "string",
71
+ "description": "Brief non-technical explanation of why this tool is being called"
75
72
  }
76
73
  },
77
- "required": [
78
- "message",
79
- "confidence"
80
- ]
74
+ "required": ["message", "confidence"]
81
75
  },
82
76
  "executor": "tools/send-notification.ts",
83
77
  "execution_target": "host"
@@ -25,6 +25,10 @@
25
25
  "type": "string",
26
26
  "enum": ["assistant_number", "user_number"],
27
27
  "description": "Which phone number to use as the caller ID. assistant_number uses the AI assistant's Twilio number; user_number uses the user's verified personal number."
28
+ },
29
+ "reason": {
30
+ "type": "string",
31
+ "description": "Brief non-technical explanation of why this tool is being called"
28
32
  }
29
33
  },
30
34
  "required": ["phone_number", "task"]
@@ -43,6 +47,10 @@
43
47
  "call_session_id": {
44
48
  "type": "string",
45
49
  "description": "Specific call session ID to check. If omitted, checks for an active call in the current conversation."
50
+ },
51
+ "reason": {
52
+ "type": "string",
53
+ "description": "Brief non-technical explanation of why this tool is being called"
46
54
  }
47
55
  },
48
56
  "required": []
@@ -62,9 +70,13 @@
62
70
  "type": "string",
63
71
  "description": "The call session ID to end"
64
72
  },
65
- "reason": {
73
+ "end_reason": {
66
74
  "type": "string",
67
75
  "description": "Reason for ending the call"
76
+ },
77
+ "reason": {
78
+ "type": "string",
79
+ "description": "Brief non-technical explanation of why this tool is being called"
68
80
  }
69
81
  },
70
82
  "required": ["call_session_id"]
@@ -33,6 +33,10 @@
33
33
  "priority": {
34
34
  "type": "number",
35
35
  "description": "Relative priority \u2014 higher numbers take precedence. Defaults to 0."
36
+ },
37
+ "reason": {
38
+ "type": "string",
39
+ "description": "Brief non-technical explanation of why this tool is being called"
36
40
  }
37
41
  },
38
42
  "required": ["trigger", "action"]
@@ -55,6 +59,10 @@
55
59
  "category": {
56
60
  "type": "string",
57
61
  "description": "Filter by category (e.g. \"scheduling\", \"triage\"). Omit to show all."
62
+ },
63
+ "reason": {
64
+ "type": "string",
65
+ "description": "Brief non-technical explanation of why this tool is being called"
58
66
  }
59
67
  }
60
68
  },
@@ -97,6 +105,10 @@
97
105
  "priority": {
98
106
  "type": "number",
99
107
  "description": "Updated priority"
108
+ },
109
+ "reason": {
110
+ "type": "string",
111
+ "description": "Brief non-technical explanation of why this tool is being called"
100
112
  }
101
113
  },
102
114
  "required": ["playbook_id"]
@@ -115,6 +127,10 @@
115
127
  "playbook_id": {
116
128
  "type": "string",
117
129
  "description": "ID of the playbook to delete (from playbook_list results)"
130
+ },
131
+ "reason": {
132
+ "type": "string",
133
+ "description": "Brief non-technical explanation of why this tool is being called"
118
134
  }
119
135
  },
120
136
  "required": ["playbook_id"]
@@ -3,7 +3,7 @@
3
3
  "tools": [
4
4
  {
5
5
  "name": "reminder_create",
6
- "description": "Create a one-time time-based reminder. Reminders fire at a specific future time and either notify the user or execute a message through the assistant. Use this ONLY when the user wants a time-triggered notification (e.g. \"remind me at 3pm\", \"remind me in 2 hours\"). Do NOT use this for \"add to my tasks\" or \"add to my queue\" use task_list_add for those requests.",
6
+ "description": "Create a one-time time-based reminder. Reminders fire at a specific future time and either notify the user or execute a message through the assistant. Use this ONLY when the user wants a time-triggered notification (e.g. \"remind me at 3pm\", \"remind me in 2 hours\"). Do NOT use this for \"add to my tasks\" or \"add to my queue\" \u2014 use task_list_add for those requests.",
7
7
  "category": "reminder",
8
8
  "risk": "low",
9
9
  "input_schema": {
@@ -34,6 +34,10 @@
34
34
  "routing_hints": {
35
35
  "type": "object",
36
36
  "description": "Optional hints for the routing engine (e.g. preferred channels, exclusions)."
37
+ },
38
+ "reason": {
39
+ "type": "string",
40
+ "description": "Brief non-technical explanation of why this tool is being called"
37
41
  }
38
42
  },
39
43
  "required": ["fire_at", "label", "message"]
@@ -48,7 +52,12 @@
48
52
  "risk": "low",
49
53
  "input_schema": {
50
54
  "type": "object",
51
- "properties": {},
55
+ "properties": {
56
+ "reason": {
57
+ "type": "string",
58
+ "description": "Brief non-technical explanation of why this tool is being called"
59
+ }
60
+ },
52
61
  "required": []
53
62
  },
54
63
  "executor": "tools/reminder-list.ts",
@@ -65,6 +74,10 @@
65
74
  "reminder_id": {
66
75
  "type": "string",
67
76
  "description": "Reminder ID to cancel"
77
+ },
78
+ "reason": {
79
+ "type": "string",
80
+ "description": "Brief non-technical explanation of why this tool is being called"
68
81
  }
69
82
  },
70
83
  "required": ["reminder_id"]
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: "Schedule"
3
3
  description: "Recurring automation that dispatches messages on a cron or RRULE schedule"
4
- metadata: {"vellum": {"emoji": "\ud83d\udcc5"}}
4
+ metadata: { "vellum": { "emoji": "\ud83d\udcc5" } }
5
5
  ---
6
6
 
7
7
  Manage recurring scheduled automations. Each schedule has an expression (cron or RRULE) that defines when it fires, and a message that gets dispatched to the assistant at trigger time.
@@ -12,15 +12,16 @@ Manage recurring scheduled automations. Each schedule has an expression (cron or
12
12
 
13
13
  Standard 5-field cron syntax: `minute hour day-of-month month day-of-week`
14
14
 
15
- | Field | Values | Special characters |
16
- |---------------|---------------|--------------------|
17
- | Minute | 0-59 | , - * / |
18
- | Hour | 0-23 | , - * / |
19
- | Day of month | 1-31 | , - * / |
20
- | Month | 1-12 | , - * / |
21
- | Day of week | 0-7 (0,7=Sun) | , - * / |
15
+ | Field | Values | Special characters |
16
+ | ------------ | ------------- | ------------------ |
17
+ | Minute | 0-59 | , - \* / |
18
+ | Hour | 0-23 | , - \* / |
19
+ | Day of month | 1-31 | , - \* / |
20
+ | Month | 1-12 | , - \* / |
21
+ | Day of week | 0-7 (0,7=Sun) | , - \* / |
22
22
 
23
23
  Examples:
24
+
24
25
  - `0 9 * * 1-5` — weekdays at 9:00 AM
25
26
  - `30 8 * * *` — every day at 8:30 AM
26
27
  - `0 */2 * * *` — every 2 hours
@@ -32,26 +33,29 @@ iCalendar recurrence rules for complex patterns. Must include a DTSTART line.
32
33
 
33
34
  Supported lines (all expressions must include DTSTART + at least one RRULE or RDATE):
34
35
 
35
- | Line | Purpose |
36
- |------|---------|
37
- | `DTSTART` | Start date/time anchor (required) |
38
- | `RRULE:` | Recurrence rule (multiple lines = union of occurrences) |
39
- | `RDATE` | Add one-off dates not covered by the pattern |
40
- | `EXDATE` | Exclude specific dates from the set |
41
- | `EXRULE` | Exclude an entire recurring series |
36
+ | Line | Purpose |
37
+ | --------- | ------------------------------------------------------- |
38
+ | `DTSTART` | Start date/time anchor (required) |
39
+ | `RRULE:` | Recurrence rule (multiple lines = union of occurrences) |
40
+ | `RDATE` | Add one-off dates not covered by the pattern |
41
+ | `EXDATE` | Exclude specific dates from the set |
42
+ | `EXRULE` | Exclude an entire recurring series |
42
43
 
43
44
  Exclusions (EXDATE, EXRULE) always take precedence over inclusions (RRULE, RDATE).
44
45
 
45
46
  #### Basic examples
47
+
46
48
  - `DTSTART:20250101T090000Z\nRRULE:FREQ=DAILY` — every day at 9:00 AM UTC
47
49
  - `DTSTART:20250101T090000Z\nRRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR` — Mon/Wed/Fri at 9:00 AM UTC
48
50
  - `DTSTART:20250101T090000Z\nRRULE:FREQ=MONTHLY;BYMONTHDAY=1,15` — 1st and 15th of each month
49
51
 
50
52
  #### Bounded recurrence
53
+
51
54
  - `DTSTART:20250101T090000Z\nRRULE:FREQ=DAILY;COUNT=30` — daily for 30 occurrences then stop
52
55
  - `DTSTART:20250101T090000Z\nRRULE:FREQ=WEEKLY;BYDAY=MO;UNTIL=20250331T235959Z` — every Monday until end of March
53
56
 
54
57
  #### Set construct examples
58
+
55
59
  - `DTSTART:20250101T090000Z\nRRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR\nEXDATE:20250120T090000Z` — Mon/Wed/Fri except Jan 20
56
60
  - `DTSTART:20250101T090000Z\nRRULE:FREQ=DAILY\nEXRULE:FREQ=WEEKLY;BYDAY=SA,SU` — every weekday (daily minus weekends)
57
61
  - `DTSTART:20250101T090000Z\nRRULE:FREQ=MONTHLY;BYMONTHDAY=1\nRDATE:20250704T090000Z` — 1st of each month plus July 4th
@@ -86,6 +90,20 @@ When `schedule_create` returns, it includes an integration status summary. Cross
86
90
  - If the task involves a **multi-step workflow** (e.g., book appointment → read confirmation email), trace the full dependency chain
87
91
 
88
92
  If any required capability is missing:
93
+
89
94
  1. **Do NOT tell the user the schedule is ready** — instead, explain what's missing and why the schedule won't work yet
90
95
  2. Offer to help set up the missing integration first
91
96
  3. The schedule is still created (so timing is preserved), but make it clear it won't execute successfully until dependencies are resolved
97
+
98
+ ## Delivering Results
99
+
100
+ Scheduled messages run without user interaction. If the task produces output that the user should see (e.g. a digest, summary, or report), the scheduled message **must** include an explicit instruction to deliver the results. Without this, the output only lives in the conversation log and never reaches the user.
101
+
102
+ Choose the right delivery tool based on the content:
103
+
104
+ - **Rich content** (digests, summaries, reports): Use `messaging_send` with the target platform and conversation ID. This preserves the full content and posts directly.
105
+ - **Short alerts** (status updates, completion notices): Use `send_notification` to let the notification router pick the best channel. Note: the router's decision engine rewrites content into short alerts, so it is not suitable for rich content.
106
+
107
+ Example schedule message for a Slack digest:
108
+
109
+ > "Scan my Slack channels for the last 24 hours using slack_scan_digest, then use messaging_send with platform 'slack' and conversation_id 'C0A7STRJ4G5' to post the summary to #alex-agent-messages."
@@ -3,7 +3,7 @@
3
3
  "tools": [
4
4
  {
5
5
  "name": "schedule_create",
6
- "description": "Create a recurring scheduled automation that sends a message at a cron or RRULE interval. ONLY use this when the user explicitly wants something to run on a schedule (e.g. \"every day at 9am\", \"weekly on Mondays\", \"every hour\"). Do NOT use this for \"add to my tasks\" or \"add to my queue\" use task_list_add for those requests instead.",
6
+ "description": "Create a recurring scheduled automation that sends a message at a cron or RRULE interval. ONLY use this when the user explicitly wants something to run on a schedule (e.g. \"every day at 9am\", \"weekly on Mondays\", \"every hour\"). Do NOT use this for \"add to my tasks\" or \"add to my queue\" \u2014 use task_list_add for those requests instead.",
7
7
  "category": "schedule",
8
8
  "risk": "medium",
9
9
  "input_schema": {
@@ -37,6 +37,10 @@
37
37
  "enabled": {
38
38
  "type": "boolean",
39
39
  "description": "Whether the job is enabled immediately. Defaults to true."
40
+ },
41
+ "reason": {
42
+ "type": "string",
43
+ "description": "Brief non-technical explanation of why this tool is being called"
40
44
  }
41
45
  },
42
46
  "required": ["name", "message"]
@@ -59,6 +63,10 @@
59
63
  "job_id": {
60
64
  "type": "string",
61
65
  "description": "If provided, show detailed info and recent runs for this specific job."
66
+ },
67
+ "reason": {
68
+ "type": "string",
69
+ "description": "Brief non-technical explanation of why this tool is being called"
62
70
  }
63
71
  },
64
72
  "required": []
@@ -106,6 +114,10 @@
106
114
  "enabled": {
107
115
  "type": "boolean",
108
116
  "description": "Enable or disable the job"
117
+ },
118
+ "reason": {
119
+ "type": "string",
120
+ "description": "Brief non-technical explanation of why this tool is being called"
109
121
  }
110
122
  },
111
123
  "required": ["job_id"]
@@ -124,6 +136,10 @@
124
136
  "job_id": {
125
137
  "type": "string",
126
138
  "description": "The ID of the schedule to delete"
139
+ },
140
+ "reason": {
141
+ "type": "string",
142
+ "description": "Brief non-technical explanation of why this tool is being called"
127
143
  }
128
144
  },
129
145
  "required": ["job_id"]
@@ -2,7 +2,7 @@
2
2
  name: "Slack"
3
3
  description: "Scan channels, summarize threads, and manage Slack with privacy guardrails"
4
4
  user-invocable: true
5
- metadata: {"vellum": {"emoji": "💬"}}
5
+ metadata: { "vellum": { "emoji": "💬" } }
6
6
  ---
7
7
 
8
8
  You are a Slack assistant that helps users stay on top of their Slack workspace. Use the slack tools for channel scanning, thread summarization, and Slack-specific operations.
@@ -40,6 +40,35 @@ Use `slack_configure_channels` to save and load preferred channels for scanning.
40
40
  - After a first scan, suggest configuring defaults: "Want me to remember these channels for future scans?"
41
41
  - Saved preferences are used automatically by `slack_scan_digest` when no specific channels are requested
42
42
 
43
+ ## Channel Permissions
44
+
45
+ Use `slack_channel_permissions` to manage per-channel permission profiles. These profiles control which tools are available and what trust level applies in specific Slack channels.
46
+
47
+ - **list**: Show all configured channel permission profiles
48
+ - **get**: View the permission profile for a specific channel
49
+ - **set**: Configure permissions for a channel (allowed tool categories, blocked tools, trust level)
50
+ - **remove**: Remove a channel's permission profile
51
+ - **clear**: Remove all permission profiles
52
+
53
+ When a channel has a "restricted" trust level, exercise additional caution with tool usage. Blocked tools and category restrictions are enforced automatically when processing messages from that channel.
54
+
55
+ ## Thread-Aware Conversations
56
+
57
+ When responding to messages from Slack channels, replies are automatically threaded. The assistant tracks conversation-to-thread mappings so that:
58
+
59
+ - Replies to a channel message go to the correct Slack thread
60
+ - Continuing a conversation stays in the same thread
61
+ - Thread context expires after 24 hours of inactivity, starting a fresh thread
62
+
63
+ ## Proactive Delivery
64
+
65
+ When you need to **send** content to Slack proactively (e.g. a scheduled digest, a scan summary, or a report):
66
+
67
+ - Use `messaging_send` with `platform: "slack"` and the target `conversation_id` (Slack channel or DM ID). This posts directly via `chat.postMessage` and preserves the full message content.
68
+ - Do **NOT** use `send_notification` for rich content like digests — the notification router's decision engine rewrites content into short alerts, stripping the actual digest.
69
+ - `send_notification` is appropriate for short alerts and status updates where you want the router to pick the best channel. `messaging_send` is appropriate when you have specific content to deliver to a specific Slack destination.
70
+ - For scheduled tasks (cron/RRULE), always end with a `messaging_send` call so the results actually reach the user. Without it, the output only lives in the conversation log.
71
+
43
72
  ## Watcher Integration
44
73
 
45
74
  For real-time monitoring (not just on-demand scanning), the user can set up a Slack watcher using the watcher skill with the same channel IDs. Mention this if the user wants ongoing monitoring.
@@ -11,7 +11,9 @@
11
11
  "properties": {
12
12
  "channel_ids": {
13
13
  "type": "array",
14
- "items": { "type": "string" },
14
+ "items": {
15
+ "type": "string"
16
+ },
15
17
  "description": "Specific channel IDs to scan. If omitted, scans preferred or top active channels."
16
18
  },
17
19
  "hours_back": {
@@ -25,6 +27,15 @@
25
27
  "max_channels": {
26
28
  "type": "number",
27
29
  "description": "Maximum number of channels to scan (default 20)"
30
+ },
31
+ "format": {
32
+ "type": "string",
33
+ "enum": ["text", "blocks"],
34
+ "description": "Output format: 'text' returns JSON (default), 'blocks' returns Slack Block Kit structured output"
35
+ },
36
+ "reason": {
37
+ "type": "string",
38
+ "description": "Brief non-technical explanation of why this tool is being called"
28
39
  }
29
40
  }
30
41
  },
@@ -42,6 +53,10 @@
42
53
  "channel_id": {
43
54
  "type": "string",
44
55
  "description": "The Slack channel ID to get details for"
56
+ },
57
+ "reason": {
58
+ "type": "string",
59
+ "description": "Brief non-technical explanation of why this tool is being called"
45
60
  }
46
61
  },
47
62
  "required": ["channel_id"]
@@ -64,8 +79,14 @@
64
79
  },
65
80
  "channel_ids": {
66
81
  "type": "array",
67
- "items": { "type": "string" },
82
+ "items": {
83
+ "type": "string"
84
+ },
68
85
  "description": "Channel IDs to add, remove, or set (not needed for 'list')"
86
+ },
87
+ "reason": {
88
+ "type": "string",
89
+ "description": "Brief non-technical explanation of why this tool is being called"
69
90
  }
70
91
  },
71
92
  "required": ["action"]
@@ -96,6 +117,10 @@
96
117
  "confidence": {
97
118
  "type": "number",
98
119
  "description": "Confidence score (0-1) for this action"
120
+ },
121
+ "reason": {
122
+ "type": "string",
123
+ "description": "Brief non-technical explanation of why this tool is being called"
99
124
  }
100
125
  },
101
126
  "required": ["channel", "timestamp", "emoji", "confidence"]
@@ -122,6 +147,10 @@
122
147
  "confidence": {
123
148
  "type": "number",
124
149
  "description": "Confidence score (0-1) for this action"
150
+ },
151
+ "reason": {
152
+ "type": "string",
153
+ "description": "Brief non-technical explanation of why this tool is being called"
125
154
  }
126
155
  },
127
156
  "required": ["channel", "timestamp", "confidence"]
@@ -152,6 +181,10 @@
152
181
  "confidence": {
153
182
  "type": "number",
154
183
  "description": "Confidence score (0-1) for this action"
184
+ },
185
+ "reason": {
186
+ "type": "string",
187
+ "description": "Brief non-technical explanation of why this tool is being called"
155
188
  }
156
189
  },
157
190
  "required": ["channel", "timestamp", "text", "confidence"]
@@ -174,12 +207,66 @@
174
207
  "confidence": {
175
208
  "type": "number",
176
209
  "description": "Confidence score (0-1) for this action"
210
+ },
211
+ "reason": {
212
+ "type": "string",
213
+ "description": "Brief non-technical explanation of why this tool is being called"
177
214
  }
178
215
  },
179
216
  "required": ["channel", "confidence"]
180
217
  },
181
218
  "executor": "tools/slack-leave-channel.ts",
182
219
  "execution_target": "host"
220
+ },
221
+ {
222
+ "name": "slack_channel_permissions",
223
+ "description": "Manage per-channel permission profiles for Slack channels. Configure which tools are available, set trust levels, and manage permission overrides on a per-channel basis.",
224
+ "category": "slack",
225
+ "risk": "medium",
226
+ "input_schema": {
227
+ "type": "object",
228
+ "properties": {
229
+ "action": {
230
+ "type": "string",
231
+ "enum": ["list", "get", "set", "remove", "clear"],
232
+ "description": "Action to perform: list all profiles, get a specific channel's profile, set a channel's profile, remove a channel's profile, or clear all profiles"
233
+ },
234
+ "channel_id": {
235
+ "type": "string",
236
+ "description": "Slack channel ID (required for get, set, remove)"
237
+ },
238
+ "label": {
239
+ "type": "string",
240
+ "description": "Human-readable label for this channel's permission set (for 'set' action)"
241
+ },
242
+ "allowed_tool_categories": {
243
+ "type": "array",
244
+ "items": {
245
+ "type": "string"
246
+ },
247
+ "description": "Tool categories allowed in this channel. When set, only tools in these categories can be invoked (for 'set' action)"
248
+ },
249
+ "blocked_tools": {
250
+ "type": "array",
251
+ "items": {
252
+ "type": "string"
253
+ },
254
+ "description": "Specific tool names blocked in this channel (for 'set' action)"
255
+ },
256
+ "trust_level": {
257
+ "type": "string",
258
+ "enum": ["restricted", "standard"],
259
+ "description": "Trust level override: 'restricted' limits tool access, 'standard' uses defaults (for 'set' action)"
260
+ },
261
+ "reason": {
262
+ "type": "string",
263
+ "description": "Brief non-technical explanation of why this tool is being called"
264
+ }
265
+ },
266
+ "required": ["action"]
267
+ },
268
+ "executor": "tools/slack-channel-permissions.ts",
269
+ "execution_target": "host"
183
270
  }
184
271
  ]
185
272
  }