@keystrokehq/skills 0.0.1

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 (44) hide show
  1. package/AGENTS-blurb.md +123 -0
  2. package/LICENSE +21 -0
  3. package/README.md +63 -0
  4. package/keystroke-agent-authoring/SKILL.md +225 -0
  5. package/keystroke-agent-authoring/evals/evals.json +29 -0
  6. package/keystroke-agent-authoring/references/messaging-gateways.md +242 -0
  7. package/keystroke-agent-authoring/references/patterns.md +417 -0
  8. package/keystroke-agent-authoring/references/prebuilt-integrations.md +879 -0
  9. package/keystroke-agent-authoring/references/sandbox-and-mcp.md +214 -0
  10. package/keystroke-agent-authoring/references/source-map.md +182 -0
  11. package/keystroke-agent-authoring/references/testing.md +85 -0
  12. package/keystroke-cli-workspace/SKILL.md +93 -0
  13. package/keystroke-cli-workspace/evals/evals.json +23 -0
  14. package/keystroke-cli-workspace/references/command-map.md +50 -0
  15. package/keystroke-cli-workspace/references/credentials-and-connect.md +79 -0
  16. package/keystroke-cli-workspace/references/project-lifecycle.md +85 -0
  17. package/keystroke-credential-binding/SKILL.md +509 -0
  18. package/keystroke-credential-binding/evals/evals.json +29 -0
  19. package/keystroke-credential-binding/references/cli.md +85 -0
  20. package/keystroke-credential-binding/references/patterns.md +878 -0
  21. package/keystroke-credential-binding/references/source-map.md +69 -0
  22. package/keystroke-data-toolkit/SKILL.md +59 -0
  23. package/keystroke-data-toolkit/evals/evals.json +23 -0
  24. package/keystroke-data-toolkit/references/usage.md +79 -0
  25. package/keystroke-task-authoring/SKILL.md +124 -0
  26. package/keystroke-task-authoring/evals/evals.json +23 -0
  27. package/keystroke-task-authoring/references/patterns.md +132 -0
  28. package/keystroke-task-authoring/references/source-map.md +61 -0
  29. package/keystroke-trigger-authoring/SKILL.md +189 -0
  30. package/keystroke-trigger-authoring/evals/evals.json +29 -0
  31. package/keystroke-trigger-authoring/references/patterns.md +265 -0
  32. package/keystroke-trigger-authoring/references/source-map.md +128 -0
  33. package/keystroke-trigger-authoring/references/testing.md +148 -0
  34. package/keystroke-workflow-as-tool-debugging/SKILL.md +52 -0
  35. package/keystroke-workflow-as-tool-debugging/evals/evals.json +23 -0
  36. package/keystroke-workflow-as-tool-debugging/references/playbook.md +77 -0
  37. package/keystroke-workflow-authoring/SKILL.md +234 -0
  38. package/keystroke-workflow-authoring/evals/evals.json +29 -0
  39. package/keystroke-workflow-authoring/references/patterns.md +265 -0
  40. package/keystroke-workflow-authoring/references/prebuilt-integrations.md +811 -0
  41. package/keystroke-workflow-authoring/references/runtime-helpers.md +264 -0
  42. package/keystroke-workflow-authoring/references/source-map.md +108 -0
  43. package/keystroke-workflow-authoring/references/testing.md +108 -0
  44. package/package.json +26 -0
@@ -0,0 +1,189 @@
1
+ ---
2
+ name: keystroke-trigger-authoring
3
+ description: Build Keystroke cron, webhook, polling, and provider triggers with @keystrokehq/core. Use when the user wants to author, test, or explain trigger code, including webhook verification, polling schedules, filter and idempotency callbacks, and mapping trigger input into workflows or task-driven agent runs.
4
+ ---
5
+
6
+ # Keystroke Trigger Authoring
7
+
8
+ Use this skill when an agent needs to write or change Keystroke trigger code.
9
+
10
+ Keep this skill focused on authored trigger code:
11
+ - use `../keystroke-workflow-authoring/SKILL.md` for workflow structure
12
+ - use `../keystroke-task-authoring/SKILL.md` for task authoring
13
+ - use `../keystroke-credential-binding/SKILL.md` when the trigger needs credentials
14
+ - use `../keystroke-agent-authoring/SKILL.md` for messaging gateways and conversational agent entry
15
+
16
+ ## Quick start
17
+
18
+ ### Workflow trigger
19
+
20
+ ```ts
21
+ import { webhookTrigger, Workflow } from '@keystrokehq/core';
22
+ import { z } from 'zod';
23
+
24
+ export const paymentWebhook = webhookTrigger({
25
+ name: 'Payment Webhook',
26
+ description: 'Receives payment events from an external provider.',
27
+ source: {
28
+ type: 'custom',
29
+ method: 'POST',
30
+ path: '/payments',
31
+ },
32
+ payload: z.object({
33
+ id: z.string(),
34
+ type: z.string(),
35
+ data: z.object({
36
+ amount: z.number(),
37
+ }),
38
+ }),
39
+ filter: (payload) => payload.type === 'payment.completed',
40
+ idempotencyKey: (payload) => payload.id,
41
+ });
42
+ ```
43
+
44
+ Attach the trigger to a workflow via the `triggers` array. Call the trigger as a function to bind a `transform`:
45
+
46
+ ```ts
47
+ export const paymentWorkflow = new Workflow({
48
+ id: 'payment-workflow',
49
+ name: 'Payment Workflow',
50
+ input: z.object({ eventId: z.string(), amount: z.number() }),
51
+ output: z.object({ ok: z.boolean() }),
52
+ triggers: [
53
+ paymentWebhook({
54
+ transform: (payload) => ({
55
+ eventId: payload.id,
56
+ amount: payload.data.amount,
57
+ }),
58
+ }),
59
+ ],
60
+ run: async (input) => ({ ok: true }),
61
+ });
62
+ ```
63
+
64
+ ### Task trigger
65
+
66
+ ```ts
67
+ import { cronTrigger, Task } from '@keystrokehq/core';
68
+ import { z } from 'zod';
69
+ import { reminderAgent } from './reminder.agent';
70
+
71
+ const dailyReminderTrigger = cronTrigger({
72
+ name: 'Daily Reminder Trigger',
73
+ description: 'Runs every morning.',
74
+ input: z.object({
75
+ mode: z.literal('daily'),
76
+ }),
77
+ payload: {
78
+ mode: 'daily',
79
+ },
80
+ schedule: '0 9 * * *',
81
+ });
82
+
83
+ export const dailyReminderTask = new Task({
84
+ id: 'daily-reminder-task',
85
+ name: 'Daily Reminder Task',
86
+ agent: reminderAgent,
87
+ prompt: 'Send the daily reminder for trigger {{trigger.name}}.',
88
+ triggers: [dailyReminderTrigger],
89
+ });
90
+ ```
91
+
92
+ ## Authoring model
93
+
94
+ Teach this mental model clearly:
95
+ - a trigger defines how external input enters a workflow or task
96
+ - triggers are authored separately from workflows, tasks, and agents
97
+ - workflow triggers are listed in `Workflow({ triggers: [...] })`
98
+ - a bare trigger in the array means the trigger payload passes through directly as workflow input
99
+ - calling the trigger as a function with `{ transform }` creates a bound trigger for payload-to-input mapping
100
+ - task triggers are listed inline in `Task.triggers`
101
+ - a `MessagingGateway` is not a trigger
102
+
103
+ ## Trigger types
104
+
105
+ Teach these public trigger factory functions from `@keystrokehq/core`:
106
+ - `cronTrigger`
107
+ - `webhookTrigger`
108
+ - `pollingTrigger`
109
+ - `providerTrigger`
110
+
111
+ Default to cron, webhook, and polling first. Use provider triggers when the user specifically needs provider-event authoring.
112
+
113
+ The factories return a `CallableTrigger` — an object with trigger properties (`.name`, `.toManifest()`, etc.) that is also callable as a function to create a bound trigger with optional `transform` and `filter`. Webhook and polling triggers also expose `.filter` and `.idempotencyKey` callbacks; cron triggers do not.
114
+
115
+ ## Manual API Execution
116
+
117
+ Even without a trigger, every workflow and agent can be executed on-demand via the Keystroke API.
118
+
119
+ ### Executing a Workflow
120
+ Users can explicitly start a workflow run without needing a cron or webhook trigger.
121
+ - **Endpoint**: `POST /api/v1/workflows/execute`
122
+ - **Body requirements**: Needs `projectId`, `authoredWorkflowId`, and the input payload in an `args` array. May optionally include `workflowGlobals` and `credentialBindings`.
123
+
124
+ ### Executing an Agent Conversation
125
+ Users can start a new agent conversation directly.
126
+ - **Endpoint**: `POST /api/v1/agents/[agentId]/conversations`
127
+ - **Body requirements**: Needs a `title`.
128
+ - **Response**: Returns the `conversationId` for subsequent interactions.
129
+
130
+ ## Workflow triggers
131
+
132
+ Use workflow triggers when:
133
+ - a schedule should start a workflow
134
+ - a webhook should resolve into workflow input
135
+ - polling should feed workflow input
136
+ - the automation needs durable orchestration after the trigger fires
137
+
138
+ Workflow trigger rules:
139
+ - define the trigger in `*.trigger.ts`
140
+ - list it in `Workflow({ triggers: [...] })`
141
+ - for a bare trigger (no transform), place it directly: `triggers: [myTrigger]`
142
+ - for a bound trigger with transform, call it: `triggers: [myTrigger({ transform: (payload) => ({...}) })]`
143
+ - test the mapping by creating a bound trigger and calling `bound.transform?.(payload)`
144
+
145
+ ## Task triggers
146
+
147
+ Use task triggers when:
148
+ - the real job is "trigger -> prompt -> agent run"
149
+ - the user does not need a full workflow orchestration layer
150
+
151
+ Task trigger rules:
152
+ - define the trigger normally
153
+ - list it in `Task.triggers`
154
+ - send users to the task skill for prompt and lifecycle details
155
+
156
+ ## Trigger rules
157
+
158
+ - Keep each exported trigger in its own `*.trigger.ts` file.
159
+ - Use `verify` for authenticity or admission checks (webhook triggers only).
160
+ - Use `filter` for event gating (webhook and polling triggers only — cron triggers do not support `filter`).
161
+ - Use `idempotencyKey` for deduplication or stable identity (webhook and polling triggers only — cron triggers do not support `idempotencyKey`).
162
+ - `filter` and `idempotencyKey` receive the typed parsed payload as the first argument. Only `verify` receives credentials.
163
+ - For webhook providers, verify against the raw request data the runtime gives you.
164
+ - Keep the webhook path rooted with `/` and provide only the suffix that follows the organization id in the URL — e.g. `path: '/payments'` is served at `/api/v1/webhooks/{orgId}/payments`. Do **not** include the `/webhooks/` prefix; the router supplies it.
165
+
166
+ ## Agent Guidelines for Custom Triggers
167
+
168
+ When an agent needs to write custom triggers, it must follow these rules:
169
+ 1. **Always use prebuilt triggers** if they exist before writing custom ones.
170
+ 2. **Collect context first**: Do you have all the information you need from the user to build the trigger? If not, ask the user to clarify what they are looking for. **Do Not Guess**.
171
+ 3. **Understand API payloads**: If the trigger handles webhooks or fetches from an API endpoint, search the provider's docs to understand the payloads. If possible, hit available endpoints to inspect the actual payloads.
172
+ 4. **Always write and run tests**: You must always write tests for custom triggers that handle non-trivial logic in callbacks. Always run the tests to verify that the new triggers run (see `references/testing.md`).
173
+ 5. **Handle missing credentials**: If you cannot run tests because of missing credentials, ask the user to configure them following the `../keystroke-credential-binding/SKILL.md` skill. The user will need to upload credentials before deploying anyway.
174
+
175
+ ## Testing path
176
+
177
+ Default trigger testing guidance:
178
+ - test trigger-specific callbacks such as `verify`, `filter`, or `poll` directly on the trigger
179
+ - test webhook parsing with `trigger.payload.parse(JSON.parse(request.rawBody))`
180
+ - test polling validation with `trigger.parseResponse(response)`
181
+ - test workflow input mapping by creating a bound trigger and calling `bound.transform?.(payload)`
182
+ - keep broader workflow testing in the workflow skill
183
+
184
+ ## References
185
+
186
+ Read these files as needed:
187
+ - `references/source-map.md` for the public trigger surface
188
+ - `references/patterns.md` for field-by-field examples, including provider triggers
189
+ - `references/testing.md` for trigger and bound trigger tests
@@ -0,0 +1,29 @@
1
+ {
2
+ "skill_name": "keystroke-trigger-authoring",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "How do I create a Keystroke webhook trigger for a Stripe event and map the incoming payload into my workflow input?",
7
+ "expected_output": "Explains webhookTrigger() factory setup, required and optional fields, and the bound trigger transform pattern via Workflow({ triggers: [trigger({ transform })] }).",
8
+ "files": []
9
+ },
10
+ {
11
+ "id": 2,
12
+ "prompt": "I need a polling trigger that checks an external API every 15 minutes and only launches the workflow for new items. What should that look like?",
13
+ "expected_output": "Explains pollingTrigger() factory setup, schedule, poll/response, optional filter and idempotency behavior, and listing the trigger in Workflow({ triggers: [...] }) with optional transform binding.",
14
+ "files": []
15
+ },
16
+ {
17
+ "id": 3,
18
+ "prompt": "What is the right way to test a Keystroke trigger? I want to validate webhook verify/filter logic and the input transform into the workflow.",
19
+ "expected_output": "Points to trigger-specific callback tests (verify, filter, payload.parse) plus bound trigger transform testing via bound.transform?.(payload).",
20
+ "files": []
21
+ },
22
+ {
23
+ "id": 4,
24
+ "prompt": "I want a cron-driven agent job. Do I attach a trigger to the agent, attach it to a task, or something else?",
25
+ "expected_output": "Explains that workflow triggers are listed in Workflow({ triggers: [...] }), task triggers are listed inline on Task.triggers, and messaging gateways are not triggers.",
26
+ "files": []
27
+ }
28
+ ]
29
+ }
@@ -0,0 +1,265 @@
1
+ # Trigger Examples
2
+
3
+ Use these examples when the user wants concrete trigger patterns.
4
+
5
+ Assume `digestWorkflow` and `paymentWorkflow` are `Workflow` instances whose `input` schemas match the trigger examples below.
6
+
7
+ File layout reminder:
8
+
9
+ - keep workflows in `*.workflow.ts` files
10
+ - keep each exported trigger in its own `*.trigger.ts` file
11
+ - keep any credential set used by a trigger in its own `*.credential-set.ts` file
12
+
13
+ ## Shared advanced fields
14
+
15
+ ```ts
16
+ import type { ExecutionIdentityPolicy } from '@keystrokehq/core/types';
17
+
18
+ const executionIdentityPolicy: ExecutionIdentityPolicy = {
19
+ subjectMode: 'requiredWhenUserProvidedCredential',
20
+ };
21
+ ```
22
+
23
+ Use `executionIdentityPolicy` when the trigger should require a subject only in specific credential cases. Use `modeDefault` when the trigger should default to a specific trigger mode such as `'subscribable'`.
24
+
25
+ ## `cronTrigger`
26
+
27
+ ```ts
28
+ import { cronTrigger } from '@keystrokehq/core';
29
+ import { z } from 'zod';
30
+
31
+ export const nightlyDigestTrigger = cronTrigger({
32
+ name: 'Nightly Digest Trigger',
33
+ description: 'Runs every night.',
34
+ enabled: true,
35
+ modeDefault: 'subscribable',
36
+ executionIdentityPolicy,
37
+ input: z.object({
38
+ mode: z.literal('nightly'),
39
+ }),
40
+ payload: {
41
+ mode: 'nightly',
42
+ },
43
+ schedule: '0 0 * * *',
44
+ timezone: 'UTC',
45
+ });
46
+ ```
47
+
48
+ Use this when the workflow input can be defined as static payload on a schedule.
49
+
50
+ A cron trigger can be placed bare in the `triggers` array when its payload matches the workflow input:
51
+
52
+ ```ts
53
+ export const digestWorkflow = new Workflow({
54
+ id: 'digest',
55
+ name: 'Digest',
56
+ input: z.object({ mode: z.literal('nightly') }),
57
+ output: z.object({ ok: z.boolean() }),
58
+ triggers: [nightlyDigestTrigger],
59
+ run: async () => ({ ok: true }),
60
+ });
61
+ ```
62
+
63
+ ## `webhookTrigger`
64
+
65
+ ```ts
66
+ import { webhookTrigger } from '@keystrokehq/core';
67
+ import { z } from 'zod';
68
+
69
+ export const paymentWebhook = webhookTrigger({
70
+ name: 'Payment Webhook',
71
+ description: 'Handles payment events.',
72
+ enabled: true,
73
+ modeDefault: 'subscribable',
74
+ source: {
75
+ type: 'custom',
76
+ method: 'POST',
77
+ path: '/payments',
78
+ verify: async (request) => {
79
+ if (!request.headers['x-signature']) {
80
+ throw new Error('Missing signature header');
81
+ }
82
+ },
83
+ response: {
84
+ successStatus: 202,
85
+ successBody: {
86
+ accepted: true,
87
+ },
88
+ },
89
+ },
90
+ payload: z.object({
91
+ id: z.string(),
92
+ type: z.string(),
93
+ amount: z.number(),
94
+ }),
95
+ filter: (payload) => payload.type === 'payment.completed',
96
+ idempotencyKey: (payload) => payload.id,
97
+ });
98
+ ```
99
+
100
+ Use `request.rawBody` in `verify` when a provider expects raw request verification. To parse a webhook body, use `trigger.payload.parse(JSON.parse(request.rawBody))`.
101
+
102
+ ## Binding a webhook trigger to a workflow with `transform`
103
+
104
+ When the webhook payload shape differs from the workflow input, call the trigger with a `transform`:
105
+
106
+ ```ts
107
+ export const paymentWorkflow = new Workflow({
108
+ id: 'payment-workflow',
109
+ name: 'Payment Workflow',
110
+ input: z.object({ eventId: z.string(), amount: z.number() }),
111
+ output: z.object({ ok: z.boolean() }),
112
+ triggers: [
113
+ paymentWebhook({
114
+ transform: (payload) => ({
115
+ eventId: payload.id,
116
+ amount: payload.amount,
117
+ }),
118
+ }),
119
+ ],
120
+ run: async () => ({ ok: true }),
121
+ });
122
+ ```
123
+
124
+ ## `pollingTrigger`
125
+
126
+ ```ts
127
+ import { pollingTrigger } from '@keystrokehq/core';
128
+ import { z } from 'zod';
129
+
130
+ export const orderPolling = pollingTrigger({
131
+ name: 'Order Polling',
132
+ description: 'Polls for the newest order.',
133
+ enabled: true,
134
+ schedule: '*/15 * * * *',
135
+ response: z.object({
136
+ orderId: z.string(),
137
+ status: z.string(),
138
+ }),
139
+ poll: async (ctx) => {
140
+ const previousOrder = ctx.lastResponse?.orderId ?? 'none';
141
+
142
+ return {
143
+ orderId: previousOrder === 'none' ? 'order_123' : 'order_124',
144
+ status: 'created',
145
+ };
146
+ },
147
+ filter: (payload) => payload.status === 'created',
148
+ idempotencyKey: (payload) => payload.orderId,
149
+ });
150
+ ```
151
+
152
+ Use this when the workflow should be entered from periodic remote-state checks.
153
+
154
+ ## `pollingTrigger.parseResponse(...)`
155
+
156
+ ```ts
157
+ const parsedResponse = orderPolling.parseResponse({
158
+ orderId: 'order_123',
159
+ status: 'created',
160
+ });
161
+ ```
162
+
163
+ Use `parseResponse(...)` when you want the trigger's response schema validation without running polling logic.
164
+
165
+ ## `providerTrigger`
166
+
167
+ ```ts
168
+ import { providerTrigger } from '@keystrokehq/core';
169
+
170
+ export const githubIssueTrigger = providerTrigger({
171
+ name: 'GitHub Issue Trigger',
172
+ description: 'Receives GitHub provider events for issue activity.',
173
+ provider: 'github',
174
+ eventTypes: ['issues.opened', 'issues.edited'],
175
+ filter: async (event) => event.type === 'issues.opened',
176
+ idempotencyKey: async (event) => event.id,
177
+ });
178
+ ```
179
+
180
+ Use a provider trigger when the user is authoring around normalized provider events instead of a raw webhook or polling loop.
181
+
182
+ ## Bare trigger in workflow (no transform)
183
+
184
+ ```ts
185
+ triggers: [nightlyDigestTrigger]
186
+ ```
187
+
188
+ Use this when the trigger payload already matches the workflow input. The trigger is placed directly in the array.
189
+
190
+ ## Bound trigger with `transform`
191
+
192
+ ```ts
193
+ triggers: [
194
+ paymentWebhook({
195
+ transform: (payload) => ({
196
+ eventId: payload.id,
197
+ amount: payload.amount,
198
+ }),
199
+ }),
200
+ ]
201
+ ```
202
+
203
+ Call the trigger as a function with `{ transform }` when the trigger payload and workflow input are different shapes. This returns a `BoundTrigger`.
204
+
205
+ ## Bound trigger with additional `filter`
206
+
207
+ ```ts
208
+ triggers: [
209
+ paymentWebhook({
210
+ filter: (payload) => payload.amount > 100,
211
+ transform: (payload) => ({
212
+ eventId: payload.id,
213
+ amount: payload.amount,
214
+ }),
215
+ }),
216
+ ]
217
+ ```
218
+
219
+ An additional filter on the binding composes with the trigger's own filter.
220
+
221
+ ## Task trigger note
222
+
223
+ For task-driven agent runs, author the trigger normally and place it in `Task.triggers`.
224
+
225
+ Use the task skill when the user needs prompt templating, task lifecycle, or focused task deploys.
226
+
227
+ ## Trigger credentials
228
+
229
+ ```ts
230
+ import { CredentialSet, webhookTrigger } from '@keystrokehq/core';
231
+ import { z } from 'zod';
232
+
233
+ const signingCredentials = new CredentialSet({
234
+ id: 'webhookSigning',
235
+ auth: z.object({
236
+ secret: z.string(),
237
+ }),
238
+ });
239
+
240
+ const signedWebhook = webhookTrigger({
241
+ name: 'Signed Webhook',
242
+ description: 'Verifies a signed webhook.',
243
+ source: {
244
+ type: 'custom',
245
+ method: 'POST',
246
+ path: '/signed',
247
+ credentialSets: [signingCredentials],
248
+ verify: async (_request, ctx) => {
249
+ if (!ctx.credentials.webhookSigning.secret) {
250
+ throw new Error('Missing signing secret');
251
+ }
252
+ },
253
+ },
254
+ payload: z.object({
255
+ id: z.string(),
256
+ }),
257
+ });
258
+ ```
259
+
260
+ ## `describe()` and `toManifest()`
261
+
262
+ ```ts
263
+ const triggerSummary = paymentWebhook.describe();
264
+ const triggerManifest = paymentWebhook.toManifest();
265
+ ```
@@ -0,0 +1,128 @@
1
+ # Trigger Feature Map
2
+
3
+ Use only the public imports a user repo can rely on:
4
+
5
+ ```ts
6
+ import {
7
+ cronTrigger,
8
+ pollingTrigger,
9
+ providerTrigger,
10
+ webhookTrigger,
11
+ } from '@keystrokehq/core';
12
+ import type {
13
+ BoundTrigger,
14
+ CallableTrigger,
15
+ ExecutionIdentityPolicy,
16
+ TriggerBindOptions,
17
+ TriggerEntry,
18
+ TriggerInstance,
19
+ } from '@keystrokehq/core/types';
20
+ ```
21
+
22
+ When a trigger explanation also needs to talk about workflow steps or agent tools, use the terminology from the other Keystroke skills:
23
+
24
+ - `Step`, `Tool`, and `Operation` are aliases for the same `Operation` class
25
+ - use the workflow skill for workflow-side operation guidance
26
+ - use the agent skill for agent-side tool guidance
27
+
28
+ ## Common trigger fields
29
+
30
+ - `name`
31
+ - `description`
32
+ - `enabled`
33
+ - `credentialSets`
34
+ - `executionIdentityPolicy`
35
+ - `modeDefault`
36
+
37
+ ## Common trigger methods
38
+
39
+ - `describe()`
40
+ - `toManifest()`
41
+
42
+ ## `cronTrigger` fields
43
+
44
+ - `input`
45
+ - `payload`
46
+ - `schedule`
47
+ - `timezone`
48
+
49
+ ## `cronTrigger` instance properties
50
+
51
+ - `.name`
52
+ - `.payload`
53
+ - `.schedule`
54
+ - `.timezone`
55
+ - `.toManifest()`
56
+ - `.describe()`
57
+
58
+ ## `webhookTrigger` fields
59
+
60
+ - `path`
61
+ - `method`
62
+ - `payload`
63
+ - `verify`
64
+ - `filter`
65
+ - `idempotencyKey`
66
+ - `response`
67
+
68
+ ## `webhookTrigger` instance methods
69
+
70
+ - `.payload.parse(data)` — validate parsed body against the payload schema
71
+ - `.verify?(request, ctx)` — raw request + credentials for authenticity checks
72
+ - `.filter?(payload, request?)` — typed parsed body, optional raw request (no credentials)
73
+ - `.idempotencyKey?(payload, request?)` — typed parsed body, optional raw request (no credentials)
74
+
75
+ ## `pollingTrigger` fields
76
+
77
+ - `schedule`
78
+ - `response`
79
+ - `poll`
80
+ - `filter`
81
+ - `idempotencyKey`
82
+
83
+ ## `pollingTrigger` instance methods
84
+
85
+ - `.poll(ctx)`
86
+ - `.parseResponse(response)`
87
+ - `.filter?(payload)` — typed parsed payload (no credentials)
88
+ - `.idempotencyKey?(payload)` — typed parsed payload (no credentials)
89
+
90
+ ## `providerTrigger` fields
91
+
92
+ - `provider`
93
+ - `eventTypes`
94
+ - `appRef`
95
+ - `filter`
96
+ - `idempotencyKey`
97
+
98
+ ## Calling a trigger (creating a bound trigger)
99
+
100
+ All factory-created triggers are callable. Calling one returns a `BoundTrigger`:
101
+
102
+ - `trigger()` — bare binding (no transform)
103
+ - `trigger({ transform })` — bound with payload-to-input mapping
104
+ - `trigger({ filter })` — bound with additional filter
105
+ - `trigger({ transform, filter })` — bound with both
106
+
107
+ ## `BoundTrigger`
108
+
109
+ - `.isBoundTrigger` — always `true`
110
+ - `.trigger` — reference to the underlying trigger instance
111
+ - `.filter?` — composed filter (trigger's filter + binding filter)
112
+ - `.transform?` — payload-to-workflow-input mapping function
113
+
114
+ ## Workflow `triggers` array
115
+
116
+ `Workflow({ triggers: [...] })` accepts a `TriggerEntry[]`:
117
+ - a bare `CallableTrigger` (trigger payload passes through as workflow input)
118
+ - a `BoundTrigger` (returned by calling the trigger with options)
119
+
120
+ ## Task note
121
+
122
+ - task triggers are declared inline in `Task.triggers`
123
+ - messaging gateways belong to agent authoring, not trigger authoring
124
+
125
+ ## Where to read next
126
+
127
+ - `patterns.md` for trigger field examples
128
+ - `testing.md` for trigger callback and bound trigger tests