@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.
- package/AGENTS-blurb.md +123 -0
- package/LICENSE +21 -0
- package/README.md +63 -0
- package/keystroke-agent-authoring/SKILL.md +225 -0
- package/keystroke-agent-authoring/evals/evals.json +29 -0
- package/keystroke-agent-authoring/references/messaging-gateways.md +242 -0
- package/keystroke-agent-authoring/references/patterns.md +417 -0
- package/keystroke-agent-authoring/references/prebuilt-integrations.md +879 -0
- package/keystroke-agent-authoring/references/sandbox-and-mcp.md +214 -0
- package/keystroke-agent-authoring/references/source-map.md +182 -0
- package/keystroke-agent-authoring/references/testing.md +85 -0
- package/keystroke-cli-workspace/SKILL.md +93 -0
- package/keystroke-cli-workspace/evals/evals.json +23 -0
- package/keystroke-cli-workspace/references/command-map.md +50 -0
- package/keystroke-cli-workspace/references/credentials-and-connect.md +79 -0
- package/keystroke-cli-workspace/references/project-lifecycle.md +85 -0
- package/keystroke-credential-binding/SKILL.md +509 -0
- package/keystroke-credential-binding/evals/evals.json +29 -0
- package/keystroke-credential-binding/references/cli.md +85 -0
- package/keystroke-credential-binding/references/patterns.md +878 -0
- package/keystroke-credential-binding/references/source-map.md +69 -0
- package/keystroke-data-toolkit/SKILL.md +59 -0
- package/keystroke-data-toolkit/evals/evals.json +23 -0
- package/keystroke-data-toolkit/references/usage.md +79 -0
- package/keystroke-task-authoring/SKILL.md +124 -0
- package/keystroke-task-authoring/evals/evals.json +23 -0
- package/keystroke-task-authoring/references/patterns.md +132 -0
- package/keystroke-task-authoring/references/source-map.md +61 -0
- package/keystroke-trigger-authoring/SKILL.md +189 -0
- package/keystroke-trigger-authoring/evals/evals.json +29 -0
- package/keystroke-trigger-authoring/references/patterns.md +265 -0
- package/keystroke-trigger-authoring/references/source-map.md +128 -0
- package/keystroke-trigger-authoring/references/testing.md +148 -0
- package/keystroke-workflow-as-tool-debugging/SKILL.md +52 -0
- package/keystroke-workflow-as-tool-debugging/evals/evals.json +23 -0
- package/keystroke-workflow-as-tool-debugging/references/playbook.md +77 -0
- package/keystroke-workflow-authoring/SKILL.md +234 -0
- package/keystroke-workflow-authoring/evals/evals.json +29 -0
- package/keystroke-workflow-authoring/references/patterns.md +265 -0
- package/keystroke-workflow-authoring/references/prebuilt-integrations.md +811 -0
- package/keystroke-workflow-authoring/references/runtime-helpers.md +264 -0
- package/keystroke-workflow-authoring/references/source-map.md +108 -0
- package/keystroke-workflow-authoring/references/testing.md +108 -0
- package/package.json +26 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Credential Feature Map
|
|
2
|
+
|
|
3
|
+
Use only the public imports a user repo can rely on:
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { CredentialSet } from '@keystrokehq/core';
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## `CredentialSet` fields
|
|
10
|
+
|
|
11
|
+
- `id`
|
|
12
|
+
- `namespace`
|
|
13
|
+
- `resolvedCredentialSetId`
|
|
14
|
+
- `name`
|
|
15
|
+
- `description`
|
|
16
|
+
- `auth`
|
|
17
|
+
- `stored`
|
|
18
|
+
- `resolve`
|
|
19
|
+
- `needsResolve`
|
|
20
|
+
|
|
21
|
+
### What they are used for
|
|
22
|
+
|
|
23
|
+
- `id`: stable credential set identifier
|
|
24
|
+
- `namespace`: optional namespace used for manifest and storage identity
|
|
25
|
+
- `resolvedCredentialSetId`: computed namespaced id used for manifest and binding infrastructure
|
|
26
|
+
- `name`: human-readable name
|
|
27
|
+
- `description`: short explanation of what the credentials are for
|
|
28
|
+
- `auth`: runtime credential schema
|
|
29
|
+
- `stored`: stored credential schema when the stored shape differs from the runtime shape
|
|
30
|
+
- `resolve`: async conversion from stored values to runtime auth values
|
|
31
|
+
- `needsResolve`: tells you whether the credential set uses the stored-plus-resolve flow
|
|
32
|
+
|
|
33
|
+
## `CredentialSet` instance methods
|
|
34
|
+
|
|
35
|
+
- `describe()`
|
|
36
|
+
- `toManifest()`
|
|
37
|
+
|
|
38
|
+
## Where a credential set can be attached
|
|
39
|
+
|
|
40
|
+
- `Operation.credentialSets`
|
|
41
|
+
- `Step.credentialSets`
|
|
42
|
+
- `Tool.credentialSets`
|
|
43
|
+
- `Agent.credentialSets`
|
|
44
|
+
- `CronTrigger.credentialSets`
|
|
45
|
+
- `WebhookTrigger.credentialSets`
|
|
46
|
+
- `PollingTrigger.credentialSets`
|
|
47
|
+
- `MessagingGateway.credentialSet`
|
|
48
|
+
- `McpServer.credentialSets`
|
|
49
|
+
|
|
50
|
+
## Where credentials can be read
|
|
51
|
+
|
|
52
|
+
- `Operation.run(..., ctx).credentials`
|
|
53
|
+
- `Step.run(..., ctx).credentials`
|
|
54
|
+
- `Tool.run(..., ctx).credentials`
|
|
55
|
+
- trigger `verify` callback and polling trigger `poll` callback (`filter`, `idempotencyKey`, and `transform` do not receive credentials)
|
|
56
|
+
- `McpServer.credentialMapper(credentials)`
|
|
57
|
+
|
|
58
|
+
## Important rules
|
|
59
|
+
|
|
60
|
+
- `Operation`, `Step`, and `Tool` are aliases for the same class
|
|
61
|
+
- if `stored` is present, `resolve` must also be present
|
|
62
|
+
- if `resolve` is present, `stored` must also be present
|
|
63
|
+
- prefer typed access through runtime context rather than ad hoc env access inside primitives
|
|
64
|
+
- runtime credential context keys use raw `id`, not `resolvedCredentialSetId`
|
|
65
|
+
|
|
66
|
+
## Where to read next
|
|
67
|
+
|
|
68
|
+
- `patterns.md` for code examples
|
|
69
|
+
- `cli.md` for upload and inspection commands
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: keystroke-data-toolkit
|
|
3
|
+
description: Use Keystroke workflow-tool refs and data companion tools. Use when an agent needs to author, explain, debug, or consume large workflow tool outputs with read_ref, slice_ref, describe_ref, truncation metadata, or deferred reducers.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Keystroke Data Toolkit
|
|
7
|
+
|
|
8
|
+
Use this skill when working with large workflow-tool outputs, ref envelopes, or auto-injected data companion tools.
|
|
9
|
+
|
|
10
|
+
Keep this skill focused on workflow-tool data handling:
|
|
11
|
+
- use `../keystroke-workflow-authoring/SKILL.md` for workflow code and replay-safe orchestration
|
|
12
|
+
- use `../keystroke-agent-authoring/SKILL.md` for agent and tool registration
|
|
13
|
+
- use `../keystroke-workflow-as-tool-debugging/SKILL.md` for debugging a failed workflow-tool run
|
|
14
|
+
|
|
15
|
+
## Current Product Behavior
|
|
16
|
+
|
|
17
|
+
Workflow tool outputs are capped before they enter LLM context. A workflow that may produce large output should opt into refs:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
new Workflow({
|
|
21
|
+
id: 'export-audit-data',
|
|
22
|
+
name: 'Export Audit Data',
|
|
23
|
+
largeResultMode: 'ref',
|
|
24
|
+
// ...
|
|
25
|
+
});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
When the output exceeds the cap, the platform stores the result and returns a small ref envelope with `inline: false`, a `ref` URI, `mimeType`, `byteSize`, and a summary.
|
|
29
|
+
|
|
30
|
+
## Companion Tools
|
|
31
|
+
|
|
32
|
+
Agents with workflow tools get bounded ref inspection tools when eligible:
|
|
33
|
+
- `describe_ref` returns shape, size, summary, and available ranges
|
|
34
|
+
- `read_ref` reads a byte, line, or row range
|
|
35
|
+
- `slice_ref` extracts a JSONPath-addressable subset from JSON refs
|
|
36
|
+
|
|
37
|
+
Reads are bounded. If a requested slice is still too large, the response includes truncation metadata such as `truncated: true` and guidance to request a smaller range.
|
|
38
|
+
|
|
39
|
+
## Rules
|
|
40
|
+
|
|
41
|
+
- Prefer `describe_ref` before reading unknown large refs.
|
|
42
|
+
- Use narrow `read_ref` ranges; do not ask for the full payload by default.
|
|
43
|
+
- Treat `truncated: true` as a signal to request a smaller or more specific range.
|
|
44
|
+
- Keep refs scoped to the current agent run; cross-run access is not supported.
|
|
45
|
+
- Do not add or teach reducer tools as active behavior. Reducers are deferred; reducer calls return unsupported validation guidance.
|
|
46
|
+
- Do not introduce DuckDB or native reducer dependencies unless the product explicitly reopens reducers.
|
|
47
|
+
|
|
48
|
+
## Default Process
|
|
49
|
+
|
|
50
|
+
1. Check whether the workflow should use `largeResultMode: 'ref'`.
|
|
51
|
+
2. Inspect the ref with `describe_ref`.
|
|
52
|
+
3. Read only the smallest useful slice with `read_ref` or `slice_ref`.
|
|
53
|
+
4. If truncated, narrow the request and try again.
|
|
54
|
+
5. If computation over large tabular refs is needed, explain that reducers are currently deferred and use bounded samples instead.
|
|
55
|
+
|
|
56
|
+
## References
|
|
57
|
+
|
|
58
|
+
Read these files as needed:
|
|
59
|
+
- `references/usage.md` for examples of ref envelopes and companion tool usage
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "keystroke-data-toolkit",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "My workflow tool can return a few megabytes of audit rows. How should I configure the workflow and how should the agent inspect the result?",
|
|
7
|
+
"expected_output": "Recommends largeResultMode: 'ref', explains the ref envelope, and uses describe_ref/read_ref/slice_ref with bounded ranges.",
|
|
8
|
+
"files": []
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"id": 2,
|
|
12
|
+
"prompt": "The agent called read_ref and got truncated: true. What should it do next?",
|
|
13
|
+
"expected_output": "Explains that truncation is signaled and the agent should request a narrower range or targeted slice rather than assuming it saw all data.",
|
|
14
|
+
"files": []
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"id": 3,
|
|
18
|
+
"prompt": "Can we add DuckDB reducers for this large CSV workflow output?",
|
|
19
|
+
"expected_output": "States that reducers and DuckDB are deferred in the active product and recommends bounded ref reads or samples instead.",
|
|
20
|
+
"files": []
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Data Toolkit Usage
|
|
2
|
+
|
|
3
|
+
Read this file when the user needs concrete patterns for large workflow-tool outputs.
|
|
4
|
+
|
|
5
|
+
## Ref-Producing Workflow
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { Workflow } from '@keystrokehq/core';
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
|
|
11
|
+
export const exportAuditData = new Workflow({
|
|
12
|
+
id: 'export-audit-data',
|
|
13
|
+
name: 'Export Audit Data',
|
|
14
|
+
description: 'Exports audit rows for an account.',
|
|
15
|
+
largeResultMode: 'ref',
|
|
16
|
+
input: z.object({
|
|
17
|
+
accountId: z.string(),
|
|
18
|
+
}),
|
|
19
|
+
output: z.array(
|
|
20
|
+
z.object({
|
|
21
|
+
accountId: z.string(),
|
|
22
|
+
eventType: z.string(),
|
|
23
|
+
createdAt: z.string(),
|
|
24
|
+
})
|
|
25
|
+
),
|
|
26
|
+
run: async () => [],
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Use `largeResultMode: 'ref'` when large output is legitimate and useful. Do not use refs to hide unbounded or poorly scoped workflows; prefer narrower workflow inputs when possible.
|
|
31
|
+
|
|
32
|
+
## Ref Envelope
|
|
33
|
+
|
|
34
|
+
The LLM receives a small envelope instead of the full output:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"inline": false,
|
|
39
|
+
"ref": "blob://run/wfr_abc/output",
|
|
40
|
+
"mimeType": "application/json",
|
|
41
|
+
"byteSize": 1048576,
|
|
42
|
+
"summary": {
|
|
43
|
+
"kind": "tabular",
|
|
44
|
+
"rows": 10000,
|
|
45
|
+
"columns": [
|
|
46
|
+
{ "name": "accountId", "type": "string", "nullPct": 0 },
|
|
47
|
+
{ "name": "eventType", "type": "string", "nullPct": 0 }
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Recommended Agent Flow
|
|
54
|
+
|
|
55
|
+
1. Call the workflow tool.
|
|
56
|
+
2. If the result has `inline: false`, call `describe_ref({ ref })`.
|
|
57
|
+
3. Read a small sample such as `read_ref({ ref, rowRange: [0, 20] })`.
|
|
58
|
+
4. Use `slice_ref` for targeted JSONPath extraction from JSON refs.
|
|
59
|
+
5. If a response is truncated, reduce the requested range.
|
|
60
|
+
|
|
61
|
+
## Bounded Reads
|
|
62
|
+
|
|
63
|
+
Good requests are specific:
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{ "ref": "blob://run/wfr_abc/output", "rowRange": [0, 25] }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Avoid full-payload reads:
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{ "ref": "blob://run/wfr_abc/output", "rowRange": [0, 1000000] }
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
If a read returns `truncated: true`, the agent should not summarize as if it saw all data. It should either request a smaller range or explain that it has inspected only a sample.
|
|
76
|
+
|
|
77
|
+
## Deferred Reducers
|
|
78
|
+
|
|
79
|
+
Reducer tools are not part of the active product. Do not teach agents to call `reduce_ref`, `query_ref`, SQL-over-ref tools, or DuckDB-backed helpers. If a reducer-shaped payload appears, expect unsupported validation guidance and fall back to bounded reads and samples.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: keystroke-task-authoring
|
|
3
|
+
description: Build Keystroke tasks with @keystrokehq/core. Use when the user wants to author a trigger-driven agent task, define task prompts with trigger templates, configure task lifecycle, or run focused task deploys instead of full workflows.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Keystroke Task Authoring
|
|
7
|
+
|
|
8
|
+
Use this skill when an agent needs to write or change Keystroke task code.
|
|
9
|
+
|
|
10
|
+
Keep this skill focused on authored task code:
|
|
11
|
+
|
|
12
|
+
- use `../keystroke-agent-authoring/SKILL.md` for the agent itself
|
|
13
|
+
- use `../keystroke-trigger-authoring/SKILL.md` for trigger authoring details
|
|
14
|
+
- use `../keystroke-workflow-authoring/SKILL.md` when the automation needs durable orchestration
|
|
15
|
+
- use `../keystroke-cli-workspace/SKILL.md` for `deploy --target`, build, and debugging flows
|
|
16
|
+
|
|
17
|
+
## Quick start
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { Task, webhookTrigger } from '@keystrokehq/core';
|
|
21
|
+
import { z } from 'zod';
|
|
22
|
+
import { welcomeAgent } from './welcome.agent';
|
|
23
|
+
|
|
24
|
+
const welcomeWebhookTrigger = webhookTrigger({
|
|
25
|
+
name: 'Welcome Webhook',
|
|
26
|
+
description: 'Receives welcome payloads.',
|
|
27
|
+
source: {
|
|
28
|
+
type: 'custom',
|
|
29
|
+
method: 'POST',
|
|
30
|
+
path: '/welcome',
|
|
31
|
+
},
|
|
32
|
+
payload: z.object({
|
|
33
|
+
name: z.string(),
|
|
34
|
+
}),
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
export const welcomeWebhookTask = new Task({
|
|
38
|
+
id: 'welcome-webhook-task',
|
|
39
|
+
name: 'Welcome Webhook Task',
|
|
40
|
+
description: 'Uses a webhook payload to drive one agent run.',
|
|
41
|
+
agent: welcomeAgent,
|
|
42
|
+
prompt:
|
|
43
|
+
'Write a greeting for this webhook payload: {{trigger.payload}}. Trigger name: {{trigger.name}}.',
|
|
44
|
+
triggers: [welcomeWebhookTrigger],
|
|
45
|
+
lifecycle: {
|
|
46
|
+
maxExecutions: 1,
|
|
47
|
+
},
|
|
48
|
+
tags: ['welcome', 'webhook', 'task'],
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Authoring model
|
|
53
|
+
|
|
54
|
+
Teach this mental model clearly:
|
|
55
|
+
|
|
56
|
+
- a task is a trigger-driven agent run
|
|
57
|
+
- a task combines an `agent`, a `prompt`, and one or more `triggers`
|
|
58
|
+
- a task is not a workflow-lite wrapper
|
|
59
|
+
- a task does not replace a workflow when durable orchestration is needed
|
|
60
|
+
|
|
61
|
+
Use a task when the real job is:
|
|
62
|
+
|
|
63
|
+
- external event or schedule arrives
|
|
64
|
+
- prompt is resolved from trigger context
|
|
65
|
+
- agent runs once for that task execution
|
|
66
|
+
|
|
67
|
+
## Trigger model
|
|
68
|
+
|
|
69
|
+
Task triggers are authored as normal triggers but attached differently than workflow triggers.
|
|
70
|
+
|
|
71
|
+
Teach these rules:
|
|
72
|
+
|
|
73
|
+
- define the trigger normally in `*.trigger.ts`
|
|
74
|
+
- place the trigger in `Task.triggers`
|
|
75
|
+
- do not call `trigger.attach(task, ...)`
|
|
76
|
+
- use workflow attachments only for workflows
|
|
77
|
+
|
|
78
|
+
## Prompt templating
|
|
79
|
+
|
|
80
|
+
Teach the supported task prompt variables:
|
|
81
|
+
|
|
82
|
+
- `{{trigger.payload}}`
|
|
83
|
+
- `{{trigger.name}}`
|
|
84
|
+
- `{{trigger.type}}`
|
|
85
|
+
|
|
86
|
+
Use prompt templating when the agent prompt should include structured trigger context without inventing a separate payload mapping layer.
|
|
87
|
+
|
|
88
|
+
## Lifecycle
|
|
89
|
+
|
|
90
|
+
Use task lifecycle when execution limits matter:
|
|
91
|
+
|
|
92
|
+
- `maxExecutions`
|
|
93
|
+
- `expiresAt`
|
|
94
|
+
- `expiresAfter`
|
|
95
|
+
|
|
96
|
+
## Task vs workflow
|
|
97
|
+
|
|
98
|
+
Choose a task when:
|
|
99
|
+
|
|
100
|
+
- the automation is one agent run driven by triggers
|
|
101
|
+
- the user wants a prompt-first agent execution path
|
|
102
|
+
- durable workflow orchestration is not the main requirement
|
|
103
|
+
|
|
104
|
+
Choose a workflow when:
|
|
105
|
+
|
|
106
|
+
- the automation needs multiple steps
|
|
107
|
+
- the automation needs waits or hooks
|
|
108
|
+
- the automation needs branching or child workflows
|
|
109
|
+
- the automation coordinates multiple agents or agent-plus-step flows
|
|
110
|
+
|
|
111
|
+
## Task rules
|
|
112
|
+
|
|
113
|
+
- Keep each exported task in its own `*.task.ts` file.
|
|
114
|
+
- Keep the referenced agent in its own `*.agent.ts` file.
|
|
115
|
+
- 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`.
|
|
117
|
+
- Keep task prompts explicit about what the agent should do with trigger data.
|
|
118
|
+
|
|
119
|
+
## References
|
|
120
|
+
|
|
121
|
+
Read these files as needed:
|
|
122
|
+
|
|
123
|
+
- `references/source-map.md` for the public task surface
|
|
124
|
+
- `references/patterns.md` for task examples and the task-vs-workflow decision guide
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "keystroke-task-authoring",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "I want a Keystroke task that runs an agent every time a webhook fires and includes the webhook payload in the prompt. How should I author that?",
|
|
7
|
+
"expected_output": "Explains Task authoring, inline triggers, prompt templating with trigger context, and keeps workflow attachments out of the task path.",
|
|
8
|
+
"files": []
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"id": 2,
|
|
12
|
+
"prompt": "Should this be a workflow or a task? The job is just: cron fires, agent writes a summary, then stop.",
|
|
13
|
+
"expected_output": "Chooses Task, explains why the task model fits better than workflow orchestration, and mentions deploy --target for focused task deploys.",
|
|
14
|
+
"files": []
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"id": 3,
|
|
18
|
+
"prompt": "How do I limit a Keystroke task to run once and expire after a week?",
|
|
19
|
+
"expected_output": "Explains task lifecycle fields such as maxExecutions and expiresAfter with authored code examples.",
|
|
20
|
+
"files": []
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Task Patterns
|
|
2
|
+
|
|
3
|
+
Read this file when the user wants concrete task-authoring examples.
|
|
4
|
+
|
|
5
|
+
## Webhook-driven task
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { Task, webhookTrigger } from '@keystrokehq/core';
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { triageAgent } from './triage.agent';
|
|
11
|
+
|
|
12
|
+
const inboundWebhook = webhookTrigger({
|
|
13
|
+
name: 'Inbound Webhook',
|
|
14
|
+
description: 'Receives inbound payloads.',
|
|
15
|
+
source: {
|
|
16
|
+
type: 'custom',
|
|
17
|
+
method: 'POST',
|
|
18
|
+
path: '/inbound',
|
|
19
|
+
},
|
|
20
|
+
payload: z.object({
|
|
21
|
+
message: z.string(),
|
|
22
|
+
priority: z.enum(['low', 'high']),
|
|
23
|
+
}),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export const inboundTask = new Task({
|
|
27
|
+
id: 'inbound-task',
|
|
28
|
+
name: 'Inbound Task',
|
|
29
|
+
agent: triageAgent,
|
|
30
|
+
prompt:
|
|
31
|
+
'Triage this inbound payload: {{trigger.payload}}. Trigger type: {{trigger.type}}.',
|
|
32
|
+
triggers: [inboundWebhook],
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Cron-driven task
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { cronTrigger, Task } from '@keystrokehq/core';
|
|
40
|
+
import { z } from 'zod';
|
|
41
|
+
import { reportAgent } from './report.agent';
|
|
42
|
+
|
|
43
|
+
const dailyReportTrigger = cronTrigger({
|
|
44
|
+
name: 'Daily Report Trigger',
|
|
45
|
+
description: 'Runs each morning.',
|
|
46
|
+
input: z.object({
|
|
47
|
+
mode: z.literal('daily'),
|
|
48
|
+
}),
|
|
49
|
+
payload: {
|
|
50
|
+
mode: 'daily',
|
|
51
|
+
},
|
|
52
|
+
schedule: '0 9 * * *',
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
export const dailyReportTask = new Task({
|
|
56
|
+
id: 'daily-report-task',
|
|
57
|
+
name: 'Daily Report Task',
|
|
58
|
+
agent: reportAgent,
|
|
59
|
+
prompt: 'Generate the daily report for {{trigger.name}} using {{trigger.payload}}.',
|
|
60
|
+
triggers: [dailyReportTrigger],
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Polling-driven task
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import { pollingTrigger, Task } from '@keystrokehq/core';
|
|
68
|
+
import { z } from 'zod';
|
|
69
|
+
import { followUpAgent } from './follow-up.agent';
|
|
70
|
+
|
|
71
|
+
const staleTicketPolling = pollingTrigger({
|
|
72
|
+
name: 'Stale Ticket Polling',
|
|
73
|
+
description: 'Polls for stale tickets.',
|
|
74
|
+
schedule: '*/15 * * * *',
|
|
75
|
+
response: z.object({
|
|
76
|
+
ticketId: z.string(),
|
|
77
|
+
status: z.string(),
|
|
78
|
+
}),
|
|
79
|
+
poll: async () => ({
|
|
80
|
+
ticketId: 'ticket_123',
|
|
81
|
+
status: 'stale',
|
|
82
|
+
}),
|
|
83
|
+
filter: (payload) => payload.status === 'stale',
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
export const staleTicketTask = new Task({
|
|
87
|
+
id: 'stale-ticket-task',
|
|
88
|
+
name: 'Stale Ticket Task',
|
|
89
|
+
agent: followUpAgent,
|
|
90
|
+
prompt: 'Follow up on stale ticket data: {{trigger.payload}}.',
|
|
91
|
+
triggers: [staleTicketPolling],
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Lifecycle examples
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
lifecycle: {
|
|
99
|
+
maxExecutions: 1,
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
lifecycle: {
|
|
105
|
+
expiresAfter: '7d',
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
lifecycle: {
|
|
111
|
+
expiresAt: new Date('2026-12-31T23:59:59.000Z'),
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Task vs workflow
|
|
116
|
+
|
|
117
|
+
Choose a task when:
|
|
118
|
+
- the job is one agent run from trigger input
|
|
119
|
+
- prompt templating is the main input mapping layer
|
|
120
|
+
- there is no need for durable orchestration across multiple steps
|
|
121
|
+
|
|
122
|
+
Choose a workflow when:
|
|
123
|
+
- the automation has multiple step boundaries
|
|
124
|
+
- waits or hooks are required
|
|
125
|
+
- orchestration logic is as important as the agent run
|
|
126
|
+
- the automation mixes steps, child workflows, and agents
|
|
127
|
+
|
|
128
|
+
## Gotchas
|
|
129
|
+
|
|
130
|
+
- Do not use `trigger.attach(...)` for tasks.
|
|
131
|
+
- Do not explain tasks as conversation entrypoints. Messaging gateways handle conversations.
|
|
132
|
+
- Do not move workflow orchestration into the task prompt.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Task Feature Map
|
|
2
|
+
|
|
3
|
+
Use only the public imports a user repo can rely on:
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { Task, type TaskConfig, type TaskLifecycle } from '@keystrokehq/core';
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## `Task` fields
|
|
10
|
+
|
|
11
|
+
- `id`
|
|
12
|
+
- `name`
|
|
13
|
+
- `description`
|
|
14
|
+
- `agent`
|
|
15
|
+
- `prompt`
|
|
16
|
+
- `triggers`
|
|
17
|
+
- `lifecycle`
|
|
18
|
+
- `tags`
|
|
19
|
+
|
|
20
|
+
## `Task` instance methods
|
|
21
|
+
|
|
22
|
+
- `describe()`
|
|
23
|
+
- `toManifest()`
|
|
24
|
+
|
|
25
|
+
## `TaskLifecycle`
|
|
26
|
+
|
|
27
|
+
- `maxExecutions`
|
|
28
|
+
- `expiresAt`
|
|
29
|
+
- `expiresAfter`
|
|
30
|
+
|
|
31
|
+
## `TriggerContext`
|
|
32
|
+
|
|
33
|
+
- `payload`
|
|
34
|
+
- `name`
|
|
35
|
+
- `type`
|
|
36
|
+
|
|
37
|
+
The current public trigger context `type` values are:
|
|
38
|
+
- `cron`
|
|
39
|
+
- `polling`
|
|
40
|
+
- `provider`
|
|
41
|
+
- `webhook`
|
|
42
|
+
|
|
43
|
+
## Prompt template tokens
|
|
44
|
+
|
|
45
|
+
Task prompts support a small set of template tokens that the platform resolves
|
|
46
|
+
at run time (just before the agent is invoked). Authors write the tokens
|
|
47
|
+
directly into the `prompt` string — there is no function to call.
|
|
48
|
+
|
|
49
|
+
Supported tokens:
|
|
50
|
+
- `{{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`)
|
|
53
|
+
|
|
54
|
+
Unknown `{{...}}` tokens are left as-is in the resolved prompt.
|
|
55
|
+
|
|
56
|
+
## Task notes
|
|
57
|
+
|
|
58
|
+
- tasks reference an agent through `agent`
|
|
59
|
+
- tasks list triggers directly in `triggers`
|
|
60
|
+
- tasks do not use `TriggerAttachment`
|
|
61
|
+
- tasks are deployed through `keystroke deploy` or focused with `keystroke deploy --target <task.task.ts>`
|