/triggers
MUST use when configuring triggers.
Claude Code
$ npx -y skills add windmill-labs/windmill --skill triggers --agent claude-code
Codex
$ npx skills add windmill-labs/windmill --skill triggers -a codex -y
Cursor
$ npx skills add windmill-labs/windmill --skill triggers -a cursor -y
Gemini CLI
$ npx skills add windmill-labs/windmill --skill triggers -a gemini-cli -y
GitHub Copilot
$ npx skills add windmill-labs/windmill --skill triggers -a github-copilot -y
OpenCode
$ npx skills add windmill-labs/windmill --skill triggers -a opencode -y
Windsurf
$ npx skills add windmill-labs/windmill --skill triggers -a windsurf -y
SKILL.md
triggers.SKILL.mdname: triggers
description: MUST use when configuring triggers.
Windmill Triggers
Triggers allow external events to invoke your scripts and flows.
File Naming
Trigger configuration files use the pattern: `{path}.{trigger_type}_trigger.yaml`
Examples:
- `u/user/webhook.http_trigger.yaml`
- `f/data/kafka_consumer.kafka_trigger.yaml`
- `f/sync/postgres_cdc.postgres_trigger.yaml`
- `f/inbound/orders.email_trigger.yaml`
Email Triggers
An email trigger routes incoming emails to a script or flow. Each trigger reserves a local-part: emails sent to `<local_part>@<windmill_email_domain>` are delivered to the configured runnable. Set `workspaced_local_part: true` to namespace it per workspace (the actual recipient becomes `<workspace_id>-<local_part>@…`); on Windmill Cloud this is required.
Senders may append URL-style extras to the local-part with `+`: `mytrigger+foo=bar+baz=qux@…`. They flow through to the script as `email_extra_args` (see below).
Payload
The runnable receives:
- `parsed_email` — `{ headers, text_body, html_body, attachments[] }`. Each `attachment` has `{ headers, body }`.
- `raw_email` — the raw RFC 822 message as a string, **or** an S3 object (`{ s3: "windmill_emails/<job_id>/raw.eml" }`) if the message exceeds 1 MiB.
- `email_extra_args` (optional, only when sender appended `+key=value` extras) — a flat object of the parsed extras.
With a preprocessor, all of the above are nested under `event` along with `event.kind = "email"` and `event.trigger_path` (the trigger's path). Without a preprocessor, `trigger_path` is **not** exposed — add a preprocessor if you need it.
Attachments are S3 objects
Binary attachments are uploaded to the workspace S3 bucket and surface in `parsed_email.attachments[i].body` as:
{ "s3": "windmill_emails/<job_id>/attachments/<filename>" }To read the bytes inside a script, use the wmill SDK:
// TypeScript
import * as wmill from "windmill-client"
const file = await wmill.loadS3File(parsed_email.attachments[0].body)
# Python
import wmill
data = wmill.load_s3_file(parsed_email["attachments"][0]["body"])
If the workspace has no S3 resource configured (Workspace Settings → Object storage), `body` falls back to the string `"configure s3 in the workspace settings to handle attachments"`. The same applies to large `raw_email` bodies. Email attachment storage requires the server to be built with the `parquet` feature.
Text/HTML/inline parts are placed inline in `body` as strings.
CLI Commands
Deploying local changes to the workspace can be destructive to remote state — only suggest/run a deploy when the user explicitly asks to deploy/publish/push, not when they say "run", "try", or "test". Deploy via `git push` or `wmill sync push` depending on how the repo is wired (see the **Deploying** section in `AGENTS.wmill.md`). `sync pull` is safe to run yourself — it never mutates remote state, though it does overwrite local files to match the remote (use `sync pull --dry-run` to only preview).
# Push trigger configuration — only when the user explicitly asks to deploy
wmill sync push
# Pull triggers from Windmill
wmill sync pull
Read more
name: triggers description: MUST use when configuring triggers.
Windmill Triggers
Triggers allow external events to invoke your scripts and flows.
File Naming
Trigger configuration files use the pattern: `{path}.{trigger_type}_trigger.yaml`
Examples:
- `u/user/webhook.http_trigger.yaml`
- `f/data/kafka_consumer.kafka_trigger.yaml`
- `f/sync/postgres_cdc.postgres_trigger.yaml`
- `f/inbound/orders.email_trigger.yaml`
Email Triggers
An email trigger routes incoming emails to a script or flow. Each trigger reserves a local-part: emails sent to `<local_part>@<windmill_email_domain>` are delivered to the configured runnable. Set `workspaced_local_part: true` to namespace it per workspace (the actual recipient becomes `<workspace_id>-<local_part>@…`); on Windmill Cloud this is required.
Senders may append URL-style extras to the local-part with `+`: `mytrigger+foo=bar+baz=qux@…`. They flow through to the script as `email_extra_args` (see below).
Payload
The runnable receives:
- `parsed_email` — `{ headers, text_body, html_body, attachments[] }`. Each `attachment` has `{ headers, body }`.
- `raw_email` — the raw RFC 822 message as a string, **or** an S3 object (`{ s3: "windmill_emails/<job_id>/raw.eml" }`) if the message exceeds 1 MiB.
- `email_extra_args` (optional, only when sender appended `+key=value` extras) — a flat object of the parsed extras.
With a preprocessor, all of the above are nested under `event` along with `event.kind = "email"` and `event.trigger_path` (the trigger's path). Without a preprocessor, `trigger_path` is **not** exposed — add a preprocessor if you need it.
Attachments are S3 objects
Binary attachments are uploaded to the workspace S3 bucket and surface in `parsed_email.attachments[i].body` as:
{ "s3": "windmill_emails/<job_id>/attachments/<filename>" }To read the bytes inside a script, use the wmill SDK:
// TypeScript import * as wmill from "windmill-client" const file = await wmill.loadS3File(parsed_email.attachments[0].body)
# Python import wmill data = wmill.load_s3_file(parsed_email["attachments"][0]["body"])
If the workspace has no S3 resource configured (Workspace Settings → Object storage), `body` falls back to the string `"configure s3 in the workspace settings to handle attachments"`. The same applies to large `raw_email` bodies. Email attachment storage requires the server to be built with the `parquet` feature.
Text/HTML/inline parts are placed inline in `body` as strings.
CLI Commands
Deploying local changes to the workspace can be destructive to remote state — only suggest/run a deploy when the user explicitly asks to deploy/publish/push, not when they say "run", "try", or "test". Deploy via `git push` or `wmill sync push` depending on how the repo is wired (see the **Deploying** section in `AGENTS.wmill.md`). `sync pull` is safe to run yourself — it never mutates remote state, though it does overwrite local files to match the remote (use `sync pull --dry-run` to only preview).
# Push trigger configuration — only when the user explicitly asks to deploy wmill sync push # Pull triggers from Windmill wmill sync pull
Windmill is fully open-sourced (AGPLv3) and Windmill Labs offers dedicated instances and commercial support and licenses.
Other skills on windmill.
More skills from other plugins.
browser-use
Direct browser control via CDP for web interaction: automation, scraping, testing, screenshots, and site/app work. Also covers…
agent-browser
Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling…
Questions about triggers.
- Which coding agents can use triggers?
- triggers installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

