@keystrokehq/skills 0.0.3 → 0.0.6

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 (45) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +24 -15
  3. package/package.json +3 -10
  4. package/{AGENTS-blurb.md → src/_AGENTS.md} +1 -1
  5. package/{keystroke-agent-authoring → src/keystroke-agent-authoring}/SKILL.md +1 -1
  6. package/{keystroke-agent-authoring → src/keystroke-agent-authoring}/references/source-map.md +1 -1
  7. package/{keystroke-agent-authoring → src/keystroke-agent-authoring}/references/testing.md +1 -1
  8. package/{keystroke-cli-workspace → src/keystroke-cli-workspace}/SKILL.md +1 -1
  9. package/{keystroke-cli-workspace → src/keystroke-cli-workspace}/references/command-map.md +3 -3
  10. package/{keystroke-cli-workspace → src/keystroke-cli-workspace}/references/project-lifecycle.md +1 -1
  11. package/{keystroke-credential-binding → src/keystroke-credential-binding}/SKILL.md +4 -3
  12. package/{keystroke-credential-binding → src/keystroke-credential-binding}/references/patterns.md +14 -15
  13. package/{keystroke-credential-binding → src/keystroke-credential-binding}/references/source-map.md +2 -1
  14. package/{keystroke-task-authoring → src/keystroke-task-authoring}/SKILL.md +4 -6
  15. package/{keystroke-task-authoring → src/keystroke-task-authoring}/references/patterns.md +7 -7
  16. package/{keystroke-task-authoring → src/keystroke-task-authoring}/references/source-map.md +4 -5
  17. package/{keystroke-trigger-authoring → src/keystroke-trigger-authoring}/SKILL.md +26 -20
  18. package/{keystroke-trigger-authoring → src/keystroke-trigger-authoring}/references/patterns.md +62 -66
  19. package/src/keystroke-trigger-authoring/references/source-map.md +166 -0
  20. package/{keystroke-trigger-authoring → src/keystroke-trigger-authoring}/references/testing.md +30 -27
  21. package/{keystroke-workflow-authoring → src/keystroke-workflow-authoring}/SKILL.md +4 -3
  22. package/{keystroke-workflow-authoring → src/keystroke-workflow-authoring}/references/patterns.md +6 -6
  23. package/{keystroke-workflow-authoring → src/keystroke-workflow-authoring}/references/prebuilt-integrations.md +1 -1
  24. package/{keystroke-workflow-authoring → src/keystroke-workflow-authoring}/references/runtime-helpers.md +2 -2
  25. package/{keystroke-workflow-authoring → src/keystroke-workflow-authoring}/references/source-map.md +1 -1
  26. package/{keystroke-workflow-authoring → src/keystroke-workflow-authoring}/references/testing.md +2 -2
  27. package/keystroke-agent-authoring/evals/evals.json +0 -29
  28. package/keystroke-cli-workspace/evals/evals.json +0 -23
  29. package/keystroke-credential-binding/evals/evals.json +0 -29
  30. package/keystroke-data-toolkit/evals/evals.json +0 -23
  31. package/keystroke-task-authoring/evals/evals.json +0 -23
  32. package/keystroke-trigger-authoring/evals/evals.json +0 -29
  33. package/keystroke-trigger-authoring/references/source-map.md +0 -128
  34. package/keystroke-workflow-as-tool-debugging/evals/evals.json +0 -23
  35. package/keystroke-workflow-authoring/evals/evals.json +0 -29
  36. /package/{keystroke-agent-authoring → src/keystroke-agent-authoring}/references/messaging-gateways.md +0 -0
  37. /package/{keystroke-agent-authoring → src/keystroke-agent-authoring}/references/patterns.md +0 -0
  38. /package/{keystroke-agent-authoring → src/keystroke-agent-authoring}/references/prebuilt-integrations.md +0 -0
  39. /package/{keystroke-agent-authoring → src/keystroke-agent-authoring}/references/sandbox-and-mcp.md +0 -0
  40. /package/{keystroke-cli-workspace → src/keystroke-cli-workspace}/references/credentials-and-connect.md +0 -0
  41. /package/{keystroke-credential-binding → src/keystroke-credential-binding}/references/cli.md +0 -0
  42. /package/{keystroke-data-toolkit → src/keystroke-data-toolkit}/SKILL.md +0 -0
  43. /package/{keystroke-data-toolkit → src/keystroke-data-toolkit}/references/usage.md +0 -0
  44. /package/{keystroke-workflow-as-tool-debugging → src/keystroke-workflow-as-tool-debugging}/SKILL.md +0 -0
  45. /package/{keystroke-workflow-as-tool-debugging → src/keystroke-workflow-as-tool-debugging}/references/playbook.md +0 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,39 @@
1
+ # @keystrokehq/skills
2
+
3
+ ## 0.0.6
4
+
5
+ ### Patch Changes
6
+
7
+ - a1488f8: Update trigger authoring skills for declarative webhook and polling trigger APIs.
8
+
9
+ ## 0.0.5
10
+
11
+ ### Patch Changes
12
+
13
+ - a94a8e3: Rename the packaged Keystroke project context artifact to `_AGENTS.md` while preserving `AGENTS.md` as the destination filename during CLI init and skills sync.
14
+
15
+ ## 0.0.4
16
+
17
+ ### Patch Changes
18
+
19
+ - bb9fea0: Fix: Removing callbacks from triggers (except polling)
20
+
21
+ ## 0.0.3
22
+
23
+ ### Patch Changes
24
+
25
+ - c4870ce: Update public package references and authoring guidance for the provider-name integration packages.
26
+
27
+ ## 0.0.2
28
+
29
+ ### Patch Changes
30
+
31
+ - 761d44e: Add `keystroke workflows run` for manually invoking workflows from a project's current deployment, including input and workflow globals parsing plus wait/follow support.
32
+
33
+ Update Keystroke CLI and workflow authoring skills with guidance for deployed workflow manual runs.
34
+
35
+ ## 0.0.1
36
+
37
+ ### Patch Changes
38
+
39
+ - 2ff9004: Publish Keystroke skills as an npm package and let the CLI use its installed skills package as a fallback when syncing skills into projects.
package/README.md CHANGED
@@ -19,34 +19,43 @@ The packaged skills are:
19
19
 
20
20
  ## Editing
21
21
 
22
- Edit the source files in `packages/skills/`.
22
+ Edit shipped skill content in `packages/skills/src/`.
23
23
 
24
- Do not treat local editor skill directories as the source of truth for these packaged skills. Edit the canonical files in `packages/skills/` first, then use the Keystroke CLI skill sync flow when local `.cursor/skills` or `.claude/skills` copies need to be refreshed.
24
+ Do not treat local editor skill directories as the source of truth for these packaged skills. Edit the canonical files in `packages/skills/src/` first, then use the Keystroke CLI skill sync flow when project-installed skill copies need to be refreshed.
25
+
26
+ Evaluation prompts and notes live in `packages/skills/evals/`. They are repo-only authoring assets and are not published to npm or copied into user projects.
25
27
 
26
28
  ## Structure
27
29
 
28
- Each skill follows this structure:
30
+ The publishable package content follows this structure:
29
31
 
30
32
  ```text
31
- <skill-name>/
32
- ├── SKILL.md
33
- ├── references/
34
- │ ├── source-map.md
35
- │ └── ...
36
- └── evals/
37
- └── evals.json
33
+ src/
34
+ ├── _AGENTS.md
35
+ ├── <skill-name>/
36
+ │ ├── SKILL.md
37
+ │ └── references/
38
+ │ ├── source-map.md
39
+ └── ...
40
+ └── ...
38
41
  ```
39
42
 
43
+ - `src/_AGENTS.md` is the Keystroke project context written or appended to project-root `AGENTS.md` by `keystroke init` and `keystroke skills sync`.
44
+ - The leading underscore keeps the package source artifact from being loaded as repository-local editor context while preserving the destination filename.
40
45
  - `SKILL.md` stays concise and procedural.
41
46
  - `references/` holds longer examples, source maps, and gotchas.
42
- - `evals/evals.json` stores the initial evaluation prompts used with `.agents/skills/skill-creator/`.
47
+ - `evals/<skill-name>/evals.json` stores the initial evaluation prompts used with `.agents/skills/skill-creator/`.
43
48
 
44
49
  ## Wiring
45
50
 
46
- These packaged skills are intended to be copied into local editor skill directories through the Keystroke CLI:
51
+ These packaged skills are installed into project agent skill directories through the Keystroke CLI:
47
52
 
48
- - packaged skills are authored here
49
- - `keystroke skills sync` copies them into `.cursor/skills` and `.claude/skills`
53
+ - packaged skills are authored in `src/`
54
+ - `keystroke init` always copies them into the canonical project path `.agents/skills`
55
+ - `keystroke init --agent <agent> --method symlink` provisions selected agent-specific paths by linking back to `.agents/skills`
56
+ - `keystroke init --agent <agent> --method copy` provisions selected agent-specific paths with independent copies
57
+ - `keystroke skills sync` refreshes an existing project using the same `--agent` and `--method` flags
58
+ - eval assets stay in `evals/` and are excluded from published packages and synced project skills
50
59
 
51
60
  If the discovery story changes later, update this package and the sync flow together. Until then, edit the packaged skills here first.
52
61
 
@@ -57,7 +66,7 @@ Because these are repo-authored local skills rather than externally installed sk
57
66
  Draft and refine these skills with the existing `.agents/skills/skill-creator/` workflow:
58
67
 
59
68
  1. Draft the skill
60
- 2. Add realistic eval prompts to `evals/evals.json`
69
+ 2. Add realistic eval prompts to `evals/<skill-name>/evals.json`
61
70
  3. Run at least one evaluation pass
62
71
  4. Revise the skill based on results
63
72
  5. Improve the `description` once the body is stable
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keystrokehq/skills",
3
- "version": "0.0.3",
3
+ "version": "0.0.6",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -9,15 +9,8 @@
9
9
  },
10
10
  "files": [
11
11
  "README.md",
12
- "AGENTS-blurb.md",
13
- "keystroke-workflow-authoring",
14
- "keystroke-agent-authoring",
15
- "keystroke-data-toolkit",
16
- "keystroke-workflow-as-tool-debugging",
17
- "keystroke-credential-binding",
18
- "keystroke-trigger-authoring",
19
- "keystroke-task-authoring",
20
- "keystroke-cli-workspace"
12
+ "CHANGELOG.md",
13
+ "src"
21
14
  ],
22
15
  "scripts": {
23
16
  "build": "node -e \"process.exit(0)\"",
@@ -103,7 +103,7 @@ Required structure:
103
103
 
104
104
  - exported primitives should be top-level and statically visible
105
105
  - helper files such as `schemas.ts`, `utils.ts`, or `prompts.ts` should not export primitives
106
- - a `*.trigger.ts` file may also export that trigger's `TriggerAttachment` values
106
+ - a `*.trigger.ts` file may also export narrowed trigger variants or bound trigger helpers
107
107
  - tests are exempt, but authored project code should follow the typed-file convention everywhere
108
108
 
109
109
  Example layout:
@@ -172,7 +172,7 @@ Teach these rules explicitly:
172
172
  - Do not use `process.env` in authored agent or tool code.
173
173
  - Expect the default agent sandbox to be persistent.
174
174
  - Create a custom `Sandbox` only when the default sandbox needs customization.
175
- - Follow Zod v4 syntax in examples and authored code. See `../../../.agents/rules/zod-v4-requirements.md`.
175
+ - Follow Zod v4 syntax in examples and authored code. See `../../../.agents/skills/zod-4/SKILL.md` for deep schema guidance.
176
176
 
177
177
  ## Agent Guidelines for Custom Tools & Operations
178
178
 
@@ -88,7 +88,7 @@ import {
88
88
  ### What they are used for
89
89
 
90
90
  - `credentialSets`: credentials attached directly to the agent
91
- - `allCredentialSets`: combined credential surface from the agent, its tools, its MCP servers, and its messaging gateways
91
+ - `allCredentialSets`: combined credential requirements from the agent, its tools, its MCP servers, and its messaging gateways
92
92
  - `messaging`: `MessagingGateway[]` conversational entry configuration
93
93
  - `runtimeKind`: whether the agent is declarative-only or has `run` / `stream` implementations
94
94
  - `workflowSafeReference`: stable reference shape used by other primitives such as `Task`
@@ -17,7 +17,7 @@ Default testing targets:
17
17
 
18
18
  ```ts
19
19
  import { defineConfig } from 'vitest/config';
20
- import { keystrokeTestPlugin } from '@keystrokehq/testing/vitest';
20
+ import { keystrokeTestPlugin } from '@keystrokehq/testing';
21
21
 
22
22
  export default defineConfig({
23
23
  plugins: [keystrokeTestPlugin()],
@@ -87,7 +87,7 @@ Important distinctions:
87
87
  - Use `keystroke connect <integration>` for official integration connection flows.
88
88
  - Use `keystroke credentials ...` for credential inspection and upload flows.
89
89
  - Use `keystroke skills sync` to copy `@keystrokehq/skills` into local editor skill directories.
90
- - Use `keystroke workflows run <authoredWorkflowId>` for deployed-workflow manual invocation; use `try-deploy` only when testing a temporary build artifact.
90
+ - Use `keystroke workflows run <authoredWorkflowId>` for deployed-workflow manual invocation; use `keystroke workflows test <workflow>` when testing a temporary build artifact.
91
91
 
92
92
  ## References
93
93
 
@@ -36,8 +36,8 @@ Root help shows these directly. Subcommand help focuses on the local flags for t
36
36
  - `projects`: inspect cached project state
37
37
  - `connect`: connect official integrations through OAuth
38
38
  - `credentials`: list requirements and upload credentials
39
- - `workflows`: build, validate, inspect, diff, env, logs, paused, run, try-deploy
40
- - `test`: test workflows and agent-callable tools
39
+ - `workflows`: build, validate, inspect, diff, env, logs, paused, test, run
40
+ - `test`: test agent-callable tools
41
41
  - `deploy`: deploy workflows, agents, tasks, or focused targets via `--target <file>`
42
42
  - `sync`: local sync operations
43
43
  - `skills`: Keystroke skills sync flows
@@ -47,7 +47,7 @@ Root help shows these directly. Subcommand help focuses on the local flags for t
47
47
 
48
48
  - `keystroke workflows logs` is different from `keystroke logs`
49
49
  - `keystroke workflows run <authoredWorkflowId>` executes the current deployed workflow snapshot via the workflow execute API; it does not build or upload local code
50
- - `keystroke workflows try-deploy <workflow>` builds local code, uploads or references a test bundle, and runs that temporary artifact
50
+ - `keystroke workflows test <workflow>` builds local code, uploads or references a test bundle, and runs that temporary artifact
51
51
  - `keystroke deploy --target <file>` is the focused deploy path
52
52
  - many commands support `--json`
53
53
 
@@ -77,7 +77,7 @@ keystroke workflows run wf_onboard_user --input '{"email":"user@example.com"}'
77
77
 
78
78
  Notes:
79
79
  - `workflows run` executes the current deployed snapshot through `client.workflows.execute()` / `POST /api/v1/workflows/execute`
80
- - it does not build or upload local source; use `workflows try-deploy` for temporary local artifact testing
80
+ - it does not build or upload local source; use `workflows test` for temporary local artifact testing
81
81
  - pass `--project-id <uuid>` outside a project checkout, otherwise the CLI resolves `projectId` from `keystroke.config.ts`
82
82
  - pass `--workflow-globals` or `--workflow-globals-file` when the deployed manifest declares required workflow globals without defaults
83
83
  - use `--wait` to poll to a terminal status and `--follow` to poll logs/events while waiting
@@ -87,7 +87,8 @@ Do not assume one credential location covers every layer. An agent can need prov
87
87
 
88
88
  Teach these rules:
89
89
  - steps and tools read credentials from `ctx.credentials`
90
- - only the trigger `verify` callback receives credentials through its callback context (`filter`, `idempotencyKey`, and `transform` do not receive credentials)
90
+ - polling triggers read credentials from `poll(ctx).credentials` when they attach credential sets
91
+ - webhook filters, webhook idempotency, and workflow trigger transforms are declarative or mapping-only paths and do not receive credentials
91
92
  - MCP servers map credentials through `credentialMapper`
92
93
  - authored code should not read secrets from `process.env`
93
94
 
@@ -117,7 +118,7 @@ This matters for integration authors and when explaining `createOperationFactory
117
118
  - If `stored` is present, `resolve` must also be present.
118
119
  - If `resolve` is present, `stored` must also be present.
119
120
  - Use `CredentialSet` instead of env-based secret handling inside authored primitives.
120
- - Follow Zod v4 syntax in examples and authored code. See `../../../.agents/rules/zod-v4-requirements.md`.
121
+ - Follow Zod v4 syntax in examples and authored code. See `../../../.agents/skills/zod-4/SKILL.md` for deep schema guidance.
121
122
  - The drawer-label rule is enforced at three layers today: compile-time on a single primitive (`AssertUniqueCredentialSetIds`), build-time across the project (`assertUniqueCredentialDefinitionIds`), and deploy-time schema-drift detection (`detectSchemaDrifts`). Cluster 07 of the reconciled credential plan adds two more layers: construction-time identity registry and vault-row schema fingerprint. You do not need to do anything special in authored code beyond following the rule above.
122
123
 
123
124
  ### Vault-row schema mismatch
@@ -439,6 +440,6 @@ For wider command usage, cross-link to `../keystroke-cli-workspace/SKILL.md`.
439
440
  ## References
440
441
 
441
442
  Read these files as needed:
442
- - `references/source-map.md` for the public credential surface
443
+ - `references/source-map.md` for public credential APIs
443
444
  - `references/cli.md` for the current credential command cookbook
444
445
  - `references/patterns.md` for field-by-field code examples
@@ -410,7 +410,7 @@ drop it from `stored` and have `rotate` return `'needs-reinput'` instead.
410
410
  - Example: HubSpot's auth-modality normalization — `stored` accepts
411
411
  either `ACCESS_TOKEN` (OAuth) or `API_KEY` (private app); `resolve`
412
412
  picks whichever is populated and returns `{ HUBSPOT_ACCESS_TOKEN }`.
413
- Throws when neither is present so a missing credential surfaces as
413
+ Throws when neither is present so a missing credential becomes
414
414
  an actionable resolver error rather than a provider 401. One
415
415
  credential set covers both authorization paths; splitting into two
416
416
  sets would force every consumer to branch on modality.
@@ -640,28 +640,27 @@ This attaches credentials directly to the agent and also allows tools on the age
640
640
  ## Trigger usage
641
641
 
642
642
  ```ts
643
- import { WebhookTrigger } from '@keystrokehq/core';
643
+ import { pollingTrigger } from '@keystrokehq/core';
644
644
  import { z } from 'zod';
645
645
 
646
- export const signedWebhook = new WebhookTrigger({
647
- name: 'Signed Webhook',
648
- description: 'Verifies a webhook with a credential-backed secret.',
649
- path: '/signed',
650
- method: 'POST',
646
+ export const crmPolling = pollingTrigger({
647
+ id: 'crm-polling',
648
+ description: 'Polls CRM records with credential-backed API access.',
651
649
  credentialSets: [crmCredentials],
652
- payload: z.object({
653
- id: z.string(),
650
+ schedule: '5m',
651
+ response: z.object({
652
+ records: z.array(z.object({ id: z.string() })),
654
653
  }),
655
- verify: async (_request, ctx) => {
656
- const secret = ctx.credentials.crmApi.apiKey;
657
- if (!secret) {
658
- throw new Error('Missing signing secret');
659
- }
654
+ poll: async (ctx) => {
655
+ const apiKey = ctx.credentials.crmApi.apiKey;
656
+ return {
657
+ records: [{ id: `record-for-${apiKey}` }],
658
+ };
660
659
  },
661
660
  });
662
661
  ```
663
662
 
664
- This pattern is useful when the trigger itself must verify or authenticate incoming events.
663
+ This pattern is useful when polling logic needs credentials. Webhook triggers do not attach per-trigger credential sets in the current custom/app source model.
665
664
 
666
665
  ## MCP server usage
667
666
 
@@ -52,7 +52,8 @@ import { CredentialSet } from '@keystrokehq/core';
52
52
  - `Operation.run(..., ctx).credentials`
53
53
  - `Step.run(..., ctx).credentials`
54
54
  - `Tool.run(..., ctx).credentials`
55
- - trigger `verify` callback and polling trigger `poll` callback (`filter`, `idempotencyKey`, and `transform` do not receive credentials)
55
+ - polling trigger `poll(ctx).credentials`
56
+ - not webhook `filter`, webhook `idempotencyKey`, or workflow trigger `transform`
56
57
  - `McpServer.credentialMapper(credentials)`
57
58
 
58
59
  ## Important rules
@@ -22,12 +22,10 @@ import { z } from 'zod';
22
22
  import { welcomeAgent } from './welcome.agent';
23
23
 
24
24
  const welcomeWebhookTrigger = webhookTrigger({
25
- name: 'Welcome Webhook',
25
+ id: 'welcome-webhook',
26
26
  description: 'Receives welcome payloads.',
27
27
  source: {
28
28
  type: 'custom',
29
- method: 'POST',
30
- path: '/welcome',
31
29
  },
32
30
  payload: z.object({
33
31
  name: z.string(),
@@ -40,7 +38,7 @@ export const welcomeWebhookTask = new Task({
40
38
  description: 'Uses a webhook payload to drive one agent run.',
41
39
  agent: welcomeAgent,
42
40
  prompt:
43
- 'Write a greeting for this webhook payload: {{trigger.payload}}. Trigger name: {{trigger.name}}.',
41
+ 'Write a greeting for this webhook payload: {{trigger.payload}}. Trigger id: {{trigger.id}}.',
44
42
  triggers: [welcomeWebhookTrigger],
45
43
  lifecycle: {
46
44
  maxExecutions: 1,
@@ -80,7 +78,7 @@ Teach these rules:
80
78
  Teach the supported task prompt variables:
81
79
 
82
80
  - `{{trigger.payload}}`
83
- - `{{trigger.name}}`
81
+ - `{{trigger.id}}`
84
82
  - `{{trigger.type}}`
85
83
 
86
84
  Use prompt templating when the agent prompt should include structured trigger context without inventing a separate payload mapping layer.
@@ -113,7 +111,7 @@ Choose a workflow when:
113
111
  - Keep each exported task in its own `*.task.ts` file.
114
112
  - Keep the referenced agent in its own `*.agent.ts` file.
115
113
  - Keep triggers in their own `*.trigger.ts` files.
116
- - Use Zod v4 syntax in all examples and authored code. See `../../../.agents/rules/zod-v4-requirements.md`.
114
+ - Use Zod v4 syntax in all examples and authored code. See `../../../.agents/skills/zod-4/SKILL.md` for deep schema guidance.
117
115
  - Keep task prompts explicit about what the agent should do with trigger data.
118
116
 
119
117
  ## References
@@ -10,12 +10,10 @@ import { z } from 'zod';
10
10
  import { triageAgent } from './triage.agent';
11
11
 
12
12
  const inboundWebhook = webhookTrigger({
13
- name: 'Inbound Webhook',
13
+ id: 'inbound-webhook',
14
14
  description: 'Receives inbound payloads.',
15
15
  source: {
16
16
  type: 'custom',
17
- method: 'POST',
18
- path: '/inbound',
19
17
  },
20
18
  payload: z.object({
21
19
  message: z.string(),
@@ -41,7 +39,7 @@ import { z } from 'zod';
41
39
  import { reportAgent } from './report.agent';
42
40
 
43
41
  const dailyReportTrigger = cronTrigger({
44
- name: 'Daily Report Trigger',
42
+ id: 'daily-report-trigger',
45
43
  description: 'Runs each morning.',
46
44
  input: z.object({
47
45
  mode: z.literal('daily'),
@@ -56,7 +54,7 @@ export const dailyReportTask = new Task({
56
54
  id: 'daily-report-task',
57
55
  name: 'Daily Report Task',
58
56
  agent: reportAgent,
59
- prompt: 'Generate the daily report for {{trigger.name}} using {{trigger.payload}}.',
57
+ prompt: 'Generate the daily report for {{trigger.id}} using {{trigger.payload}}.',
60
58
  triggers: [dailyReportTrigger],
61
59
  });
62
60
  ```
@@ -69,7 +67,7 @@ import { z } from 'zod';
69
67
  import { followUpAgent } from './follow-up.agent';
70
68
 
71
69
  const staleTicketPolling = pollingTrigger({
72
- name: 'Stale Ticket Polling',
70
+ id: 'stale-ticket-polling',
73
71
  description: 'Polls for stale tickets.',
74
72
  schedule: '*/15 * * * *',
75
73
  response: z.object({
@@ -80,7 +78,9 @@ const staleTicketPolling = pollingTrigger({
80
78
  ticketId: 'ticket_123',
81
79
  status: 'stale',
82
80
  }),
83
- filter: (payload) => payload.status === 'stale',
81
+ filter: z.object({
82
+ status: z.literal('stale'),
83
+ }),
84
84
  });
85
85
 
86
86
  export const staleTicketTask = new Task({
@@ -31,13 +31,12 @@ import { Task, type TaskConfig, type TaskLifecycle } from '@keystrokehq/core';
31
31
  ## `TriggerContext`
32
32
 
33
33
  - `payload`
34
- - `name`
34
+ - `id`
35
35
  - `type`
36
36
 
37
37
  The current public trigger context `type` values are:
38
38
  - `cron`
39
39
  - `polling`
40
- - `provider`
41
40
  - `webhook`
42
41
 
43
42
  ## Prompt template tokens
@@ -48,8 +47,8 @@ directly into the `prompt` string — there is no function to call.
48
47
 
49
48
  Supported tokens:
50
49
  - `{{trigger.payload}}` — resolved to `JSON.stringify` of the trigger payload
51
- - `{{trigger.name}}` — resolved to the trigger name
52
- - `{{trigger.type}}` — resolved to the trigger type (one of `cron`, `polling`, `provider`, `webhook`)
50
+ - `{{trigger.id}}` — resolved to the trigger id
51
+ - `{{trigger.type}}` — resolved to the trigger type (one of `cron`, `polling`, `webhook`)
53
52
 
54
53
  Unknown `{{...}}` tokens are left as-is in the resolved prompt.
55
54
 
@@ -57,5 +56,5 @@ Unknown `{{...}}` tokens are left as-is in the resolved prompt.
57
56
 
58
57
  - tasks reference an agent through `agent`
59
58
  - tasks list triggers directly in `triggers`
60
- - tasks do not use `TriggerAttachment`
59
+ - tasks do not bind triggers with workflow-style `{ transform }`
61
60
  - tasks are deployed through `keystroke deploy` or focused with `keystroke deploy --target <task.task.ts>`
@@ -1,6 +1,6 @@
1
1
  ---
2
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.
3
+ description: Build Keystroke cron, webhook, and polling triggers with @keystrokehq/core. Use when the user wants to author, test, or explain trigger code, including webhook app/custom sources, declarative filter schemas, webhook idempotency config, polling schedules, trigger narrowing, and mapping trigger input into workflows or task-driven agent runs.
4
4
  ---
5
5
 
6
6
  # Keystroke Trigger Authoring
@@ -22,12 +22,10 @@ import { webhookTrigger, Workflow } from '@keystrokehq/core';
22
22
  import { z } from 'zod';
23
23
 
24
24
  export const paymentWebhook = webhookTrigger({
25
- name: 'Payment Webhook',
25
+ id: 'payment-webhook',
26
26
  description: 'Receives payment events from an external provider.',
27
27
  source: {
28
28
  type: 'custom',
29
- method: 'POST',
30
- path: '/payments',
31
29
  },
32
30
  payload: z.object({
33
31
  id: z.string(),
@@ -36,8 +34,13 @@ export const paymentWebhook = webhookTrigger({
36
34
  amount: z.number(),
37
35
  }),
38
36
  }),
39
- filter: (payload) => payload.type === 'payment.completed',
40
- idempotencyKey: (payload) => payload.id,
37
+ filter: z.object({
38
+ type: z.literal('payment.completed'),
39
+ }),
40
+ idempotencyKey: {
41
+ from: 'payload',
42
+ path: 'id',
43
+ },
41
44
  });
42
45
  ```
43
46
 
@@ -69,7 +72,7 @@ import { z } from 'zod';
69
72
  import { reminderAgent } from './reminder.agent';
70
73
 
71
74
  const dailyReminderTrigger = cronTrigger({
72
- name: 'Daily Reminder Trigger',
75
+ id: 'daily-reminder-trigger',
73
76
  description: 'Runs every morning.',
74
77
  input: z.object({
75
78
  mode: z.literal('daily'),
@@ -84,7 +87,7 @@ export const dailyReminderTask = new Task({
84
87
  id: 'daily-reminder-task',
85
88
  name: 'Daily Reminder Task',
86
89
  agent: reminderAgent,
87
- prompt: 'Send the daily reminder for trigger {{trigger.name}}.',
90
+ prompt: 'Send the daily reminder for trigger {{trigger.id}}.',
88
91
  triggers: [dailyReminderTrigger],
89
92
  });
90
93
  ```
@@ -97,6 +100,8 @@ Teach this mental model clearly:
97
100
  - workflow triggers are listed in `Workflow({ triggers: [...] })`
98
101
  - a bare trigger in the array means the trigger payload passes through directly as workflow input
99
102
  - calling the trigger as a function with `{ transform }` creates a bound trigger for payload-to-input mapping
103
+ - filtering lives on the trigger as a pure Zod schema, or on a narrowed child trigger with `.narrow({ id, filter })`
104
+ - webhook idempotency is declarative config, not a callback
100
105
  - task triggers are listed inline in `Task.triggers`
101
106
  - a `MessagingGateway` is not a trigger
102
107
 
@@ -106,11 +111,10 @@ Teach these public trigger factory functions from `@keystrokehq/core`:
106
111
  - `cronTrigger`
107
112
  - `webhookTrigger`
108
113
  - `pollingTrigger`
109
- - `providerTrigger`
110
114
 
111
- Default to cron, webhook, and polling first. Use provider triggers when the user specifically needs provider-event authoring.
115
+ Use webhook triggers with `source: { type: 'app', appRef }` when events are fanned out by a Keystroke-managed provider app. Use `source: { type: 'custom' }` when the platform should create a Keystroke-owned custom webhook surface.
112
116
 
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.
117
+ The factories return a `CallableTrigger` — an object with trigger properties (`.id`, `.toManifest()`, etc.) that is also callable as a function to create a bound trigger with optional `transform`. Bindings carry only `transform`; they do not carry filter or idempotency callbacks.
114
118
 
115
119
  ## Manual API Execution
116
120
 
@@ -140,6 +144,7 @@ Workflow trigger rules:
140
144
  - list it in `Workflow({ triggers: [...] })`
141
145
  - for a bare trigger (no transform), place it directly: `triggers: [myTrigger]`
142
146
  - for a bound trigger with transform, call it: `triggers: [myTrigger({ transform: (payload) => ({...}) })]`
147
+ - for per-workflow filtering, attach a narrowed trigger: `triggers: [myTrigger.narrow({ id: '...', filter: z.object({...}) })({ transform })]`
143
148
  - test the mapping by creating a bound trigger and calling `bound.transform?.(payload)`
144
149
 
145
150
  ## Task triggers
@@ -156,12 +161,13 @@ Task trigger rules:
156
161
  ## Trigger rules
157
162
 
158
163
  - 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.
164
+ - Use `id`, not `name`, as the stable authored trigger identity.
165
+ - Use `filter` for event gating on webhook and polling triggers. It must be a pure Zod schema that can be converted to JSON Schema; do not use `.refine()`, `.superRefine()`, `.transform()`, `.preprocess()`, `.pipe()`, or `z.custom()`.
166
+ - Put conditional logic that cannot be expressed as a pure Zod schema at the start of the workflow body, or behind an integration `mapPayload` helper that throws when the declarative filter was too broad.
167
+ - Use `idempotencyKey` only on webhook triggers. It is declarative config such as `{ from: 'payload', path: 'id' }`, `{ from: 'payload', strategy: 'hash' }`, `{ from: 'header', name: 'x-event-id' }`, or `{ from: 'header', strategy: 'hash' }`.
168
+ - Polling triggers do not support idempotency config.
169
+ - `source: { type: 'custom' }` means the platform owns the HTTP surface and authenticates with a Keystroke-issued secret. Do not add `method`, `path`, `verify`, or `response`.
170
+ - `source: { type: 'app', appRef }` means a Keystroke-managed provider app fans out events centrally.
165
171
 
166
172
  ## Agent Guidelines for Custom Triggers
167
173
 
@@ -169,13 +175,13 @@ When an agent needs to write custom triggers, it must follow these rules:
169
175
  1. **Always use prebuilt triggers** if they exist before writing custom ones.
170
176
  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
177
  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`).
178
+ 4. **Always write and run tests**: You must always write tests for custom triggers that handle polling logic, payload mapping, or non-trivial filter schemas. Always run the tests to verify that the new triggers run (see `references/testing.md`).
173
179
  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
180
 
175
181
  ## Testing path
176
182
 
177
183
  Default trigger testing guidance:
178
- - test trigger-specific callbacks such as `verify`, `filter`, or `poll` directly on the trigger
184
+ - test declarative filter and idempotency metadata through `trigger.toManifest().runtime`
179
185
  - test webhook parsing with `trigger.payload.parse(JSON.parse(request.rawBody))`
180
186
  - test polling validation with `trigger.parseResponse(response)`
181
187
  - test workflow input mapping by creating a bound trigger and calling `bound.transform?.(payload)`
@@ -185,5 +191,5 @@ Default trigger testing guidance:
185
191
 
186
192
  Read these files as needed:
187
193
  - `references/source-map.md` for the public trigger surface
188
- - `references/patterns.md` for field-by-field examples, including provider triggers
194
+ - `references/patterns.md` for field-by-field examples, including webhook app sources
189
195
  - `references/testing.md` for trigger and bound trigger tests