Enable LLMs to handle webhooks with plaintext files
1---
2name: create-lure
3description: Generate a new .lure file for handling a webhook endpoint. Use when the user wants to add a new webhook handler or lure.
4---
5
6Generate a new `.lure` file for handling an incoming webhook.
7
8## Steps
9
101. **Gather requirements.** If not already provided, ask the user:
11 - What webhook source and event is this for?
12 - What path should it be mounted at? (e.g. `github/push` → `lures/github/push.lure`)
13 - Does the provider sign requests? If so:
14 - HMAC or literal token comparison?
15 - Which header or query parameter carries the signature or token?
16 - What environment variable holds the secret?
17 - For HMAC: does the provider prefix the digest (e.g. `sha256=`)?
18 - What should the LLM do when it receives this webhook?
19 - Is there any application-specific config to include?
20
212. **Write the `.lure` file** to the appropriate path under the `lures/` directory.
22
23## `.lure` file format
24
25A `.lure` file is a Markdown file with YAML frontmatter. The filename without
26the `.lure` extension determines the webhook path relative to the configured
27base path: `push.lure` handles `<basePath>/push`, and `github/push.lure`
28handles `<basePath>/github/push`.
29
30### `verify` (optional)
31
32Specifies how to authenticate incoming webhook requests. Omit if the provider
33does not sign requests. Only one strategy may be specified.
34
35HMAC (e.g. GitHub, GitLab — computes SHA-256 over the request body):
36
37```yaml
38verify:
39 hmac:
40 header: X-Hub-Signature-256 # or query: param-name
41 prefix: "sha256=" # optional: stripped before comparing the digest
42 secret: $ENV_VAR_NAME # must be an environment variable reference
43```
44
45Literal (e.g. Forgejo, Omi — compares value directly against the secret):
46
47```yaml
48verify:
49 literal:
50 header: Authorization # or query: uid
51 secret: $ENV_VAR_NAME # must be an environment variable reference
52```
53
54### `payload` (optional)
55
56```yaml
57payload:
58 contentType: json # currently the only supported value
59```
60
61### `config` (optional)
62
63An arbitrary object passed as-is to the application callback. Use this for any
64application-specific values you want to associate with this lure.
65
66```yaml
67config:
68 key: value
69```
70
71### Template body
72
73Below the frontmatter is a [Liquid](https://liquidjs.com) template. Write it
74as a natural language prompt for the LLM that will process the webhook. The
75following variables are available:
76
77- `payload` — the request body (parsed JSON for `contentType: json`)
78- `headers` — request headers as a plain object with lowercase keys (e.g. `{{ headers["x-my-header"] }}`)
79- `query` — query string as a plain object (e.g. `{{ query.foo }}`)
80
81Use `{{ expression }}` to interpolate values and `{% if %}...{% endif %}` for
82conditionals.
83
84## Notes
85
86- Secret values must always be environment variable references (`$VAR_NAME`),
87 never hardcoded.
88- The template body should read naturally as a prompt — write it in the second
89 person, as if instructing the LLM receiving it.
90- After writing the file, show it to the user for review.